aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ObsoleteFiles.inc13
-rw-r--r--UPDATING5
-rw-r--r--bin/cp/cp.151
-rw-r--r--bin/cp/cp.c90
-rw-r--r--bin/cp/extern.h2
-rwxr-xr-xbin/cp/tests/cp_test.sh195
-rw-r--r--bin/cp/utils.c4
-rw-r--r--contrib/kyua/utils/fs/operations.cpp2
-rw-r--r--contrib/kyua/utils/fs/operations_test.cpp14
-rw-r--r--lib/libc/gen/Symbol.map3
-rw-r--r--lib/libc/gen/elf_utils.c26
-rw-r--r--lib/libc/gen/fts.32
-rw-r--r--lib/libc/gen/gen-private.h4
-rw-r--r--lib/libc/gen/libc_interposing_table.c1
-rw-r--r--lib/libc/gen/opendir2.c9
-rw-r--r--lib/libc/gen/readdir.c4
-rw-r--r--lib/libc/gen/scandir.c6
-rw-r--r--lib/libc/gen/telldir.c4
-rw-r--r--lib/libc/gen/telldir.h6
-rw-r--r--lib/libc/include/libc_private.h4
-rw-r--r--lib/libnvmf/libnvmf.h6
-rw-r--r--lib/libnvmf/nvmf_host.c21
-rw-r--r--lib/libsys/getdirentries.210
-rw-r--r--lib/libthr/pthread.map1
-rw-r--r--lib/libthr/thread/thr_list.c38
-rw-r--r--lib/libthr/thread/thr_private.h2
-rw-r--r--libexec/flua/modules/lfbsd.c95
-rw-r--r--libexec/rtld-elf/rtld.c157
-rw-r--r--sbin/bectl/bectl.8121
-rw-r--r--sbin/devd/Makefile5
-rw-r--r--sbin/devd/devd.conf.54
-rw-r--r--sbin/devd/nvmf.conf7
-rw-r--r--sbin/nvmecontrol/connect.c11
-rw-r--r--sbin/nvmecontrol/nvmecontrol.831
-rw-r--r--sbin/nvmecontrol/reconnect.c17
-rw-r--r--sbin/pfctl/parse.y39
-rw-r--r--sbin/pfctl/pfctl.822
-rw-r--r--sbin/pfctl/pfctl.c293
-rw-r--r--sbin/pfctl/pfctl.h12
-rw-r--r--sbin/pfctl/pfctl_optimize.c5
-rw-r--r--sbin/pfctl/pfctl_osfp.c2
-rw-r--r--sbin/pfctl/pfctl_parser.c16
-rw-r--r--sbin/pfctl/pfctl_parser.h1
-rw-r--r--sbin/pfctl/pfctl_table.c15
-rwxr-xr-xsbin/pfctl/tests/macro.sh1
-rw-r--r--sbin/pfctl/tests/pfctl_test.c25
-rw-r--r--share/examples/Makefile7
-rw-r--r--share/examples/drivers/README42
-rw-r--r--share/examples/drivers/make_pseudo_driver.sh435
-rw-r--r--share/man/man1/Makefile1
-rw-r--r--share/man/man1/builtin.1269
-rw-r--r--share/man/man4/Makefile12
-rw-r--r--share/man/man4/hwt.4142
-rw-r--r--share/man/man7/Makefile1
-rw-r--r--share/man/man7/named_attribute.7275
-rw-r--r--stand/efi/libefi/efinet.c2
-rw-r--r--stand/efi/loader/arch/amd64/elf64_freebsd.c8
-rw-r--r--stand/efi/loader/arch/arm/exec.c11
-rw-r--r--stand/efi/loader/arch/arm64/exec.c8
-rw-r--r--stand/efi/loader/arch/i386/elf64_freebsd.c9
-rw-r--r--stand/efi/loader/arch/riscv/exec.c12
-rw-r--r--sys/cam/ata/ata_da.c5
-rw-r--r--sys/cam/cam_periph.c42
-rw-r--r--sys/cam/cam_xpt.c5
-rw-r--r--sys/cam/cam_xpt.h18
-rw-r--r--sys/cam/mmc/mmc_da.c5
-rw-r--r--sys/cam/scsi/scsi_all.c12
-rw-r--r--sys/cam/scsi/scsi_cd.c8
-rw-r--r--sys/cam/scsi/scsi_ch.c6
-rw-r--r--sys/cam/scsi/scsi_da.c19
-rw-r--r--sys/cam/scsi/scsi_enc_ses.c5
-rw-r--r--sys/cam/scsi/scsi_sa.c7
-rw-r--r--sys/dev/hyperv/vmbus/vmbus_chan.c6
-rw-r--r--sys/dev/hyperv/vmbus/vmbus_reg.h10
-rw-r--r--sys/dev/mlx5/mlx5_en/mlx5_en_hw_tls_rx.c97
-rw-r--r--sys/dev/nvmf/host/nvmf.c119
-rw-r--r--sys/dev/nvmf/host/nvmf_var.h6
-rw-r--r--sys/dev/nvmf/nvmf.h11
-rw-r--r--sys/fs/nfsclient/nfs_clvnops.c5
-rw-r--r--sys/fs/nfsserver/nfs_nfsdport.c32
-rw-r--r--sys/kern/subr_pctrie.c36
-rw-r--r--sys/kern/vfs_inotify.c2
-rw-r--r--sys/kern/vfs_syscalls.c17
-rw-r--r--sys/net/pfvar.h7
-rw-r--r--sys/netinet/in_pcb.c17
-rw-r--r--sys/netinet/in_pcb.h1
-rw-r--r--sys/netinet/tcp_subr.c65
-rw-r--r--sys/netpfil/pf/if_pflog.c2
-rw-r--r--sys/netpfil/pf/if_pfsync.c11
-rw-r--r--sys/netpfil/pf/pf.c8
-rw-r--r--sys/netpfil/pf/pf_ioctl.c177
-rw-r--r--sys/netpfil/pf/pf_nl.c68
-rw-r--r--tests/atf_python/sys/net/vnet.py8
-rw-r--r--tests/sys/kern/Makefile1
-rw-r--r--tests/sys/kern/getdirentries_test.c172
-rw-r--r--tests/sys/netpfil/pf/anchor.sh57
-rw-r--r--tests/sys/netpfil/pf/header.py23
-rw-r--r--tests/sys/netpfil/pf/icmp.py10
-rw-r--r--tests/sys/netpfil/pf/ioctl/validation.c35
-rw-r--r--tests/sys/netpfil/pf/pfsync.sh85
-rw-r--r--tools/build/cross-build/include/common/exterr.h14
-rw-r--r--tools/build/cross-build/include/common/sys/exterrvar.h6
-rw-r--r--tools/build/mk/OptionalObsoleteFiles.inc4
-rw-r--r--usr.bin/Makefile1
-rw-r--r--usr.bin/kyua/Makefile2
-rw-r--r--usr.bin/lockf/lockf.130
-rw-r--r--usr.bin/lockf/lockf.c123
-rw-r--r--usr.bin/lockf/tests/lockf_test.sh103
-rw-r--r--usr.bin/shar/Makefile4
-rw-r--r--usr.bin/shar/Makefile.depend10
-rw-r--r--usr.bin/shar/shar.1121
-rw-r--r--usr.bin/shar/shar.sh78
-rw-r--r--usr.bin/truncate/truncate.130
-rw-r--r--usr.sbin/crunch/examples/really-big.conf2
114 files changed, 2760 insertions, 1624 deletions
diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc
index faf7c421af80..a5e41d9ac6d6 100644
--- a/ObsoleteFiles.inc
+++ b/ObsoleteFiles.inc
@@ -51,6 +51,15 @@
# xargs -n1 | sort | uniq -d;
# done
+# 20250710: share: Delete bitrotted make_*_driver.sh scripts
+OLD_FILES+=usr/share/examples/drivers/README
+OLD_FILES+=usr/share/examples/drivers/make_device_driver.sh
+OLD_FILES+=usr/share/examples/drivers/make_pseudo_driver.sh
+OLD_DIRS+=usr/share/examples/drivers
+
+# 20250710: shar(1) removed
+OLD_FILES+=usr/bin/shar
+
# 20250708: For 34 days 15.0-CURRENT installed libkadm5clnt symlink without .so
OLD_FILES+=usr/lib/libkadm5clnt
@@ -60,10 +69,6 @@ MOVED_LIBS+=usr/lib/libtpool.so.2
# 20250626: replace yaml.lua with lyaml
OLD_FILES+=usr/share/flua/yaml.lua
-# 20250623: fscandir() renamed to fdscandir()
-OLD_FILES+=usr/share/man/man3/fscandir.3.gz
-OLD_FILES+=usr/share/man/man3/fscandir_b.3.gz
-
# 20250615: don't install man page for absent function
OLD_FILES+=usr/share/man/man9/vm_map_simplify_entry.9.gz
diff --git a/UPDATING b/UPDATING
index 8205086dbab5..2b8320c1204d 100644
--- a/UPDATING
+++ b/UPDATING
@@ -27,6 +27,11 @@ 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".)
+20250710:
+ The shar(1) utility has been removed from base. The
+ sysutils/freebsd-shar port was created to maintain this version of
+ shar(1) past its removal from base.
+
20250704:
LinuxKPI device.h and acpi changes effecting drivers and drm-kmod.
Bump __FreeBSD_version 1500050 to be able to detect these changes.
diff --git a/bin/cp/cp.1 b/bin/cp/cp.1
index 2856391a029e..5231fa72621c 100644
--- a/bin/cp/cp.1
+++ b/bin/cp/cp.1
@@ -29,7 +29,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd March 28, 2024
+.Dd July 9, 2025
.Dt CP 1
.Os
.Sh NAME
@@ -84,16 +84,16 @@ If the
.Fl R
option is specified, symbolic links on the command line are followed.
(Symbolic links encountered in the tree traversal are not followed.)
-.It Fl L
+.It Fl L , Fl -dereference
If the
.Fl R
option is specified, all symbolic links are followed.
-.It Fl P
+.It Fl P , Fl -no-dereference
No symbolic links are followed.
This is the default if the
.Fl R
option is specified.
-.It Fl R
+.It Fl R , Fl -recursive
If
.Ar source_file
designates a directory,
@@ -121,11 +121,11 @@ If you need to preserve hard links, consider using
or
.Xr pax 1
instead.
-.It Fl a
+.It Fl a , Fl -archive
Archive mode.
Same as
.Fl RpP .
-.It Fl f
+.It Fl f , Fl -force
For each existing destination pathname, remove it and
create a new file, without prompting for confirmation
regardless of its permissions.
@@ -136,10 +136,8 @@ option overrides any previous
or
.Fl n
options.)
-.It Fl i
-Cause
-.Nm
-to write a prompt to the standard error output before copying a file
+.It Fl i , Fl -interactive
+Write a prompt to the standard error output before copying a file
that would overwrite an existing file.
If the response from the standard input begins with the character
.Sq Li y
@@ -153,13 +151,13 @@ option overrides any previous
or
.Fl n
options.)
-.It Fl l
+.It Fl l , Fl -link
Create hard links to regular files in a hierarchy instead of copying.
.It Fl N
When used with
.Fl p ,
suppress copying file flags.
-.It Fl n
+.It Fl n , Fl -no-clobber
Do not overwrite an existing file.
(The
.Fl n
@@ -169,9 +167,7 @@ or
.Fl i
options.)
.It Fl p
-Cause
-.Nm
-to preserve the following attributes of each source
+Preserve the following attributes of each source
file in the copy: modification time, access time,
file flags, file mode, ACL, user ID, and group ID, as allowed by permissions.
.Pp
@@ -188,14 +184,25 @@ If the source file has both its set-user-ID and set-group-ID bits on,
and either the user ID or group ID cannot be preserved, neither
the set-user-ID nor set-group-ID bits are preserved in the copy's
permissions.
-.It Fl s
-Create symbolic links to regular files in a hierarchy instead of copying.
-.It Fl v
-Cause
+.It Fl -sort
+Visit and traverse sources in (non-localized) lexicographical order.
+Normally,
.Nm
-to be verbose, showing files as they are copied.
-.It Fl x
-File system mount points are not traversed.
+visits the sources in the order they were listed on the command line,
+and if recursing, traverses their contents in whichever order they
+were returned in by the kernel, which may be the order in which they
+were created, lexicographical order, or something else entirely.
+With
+.Fl -sort ,
+the sources are both visited and traversed in lexicographical order.
+This is mostly useful for testing.
+.It Fl s , Fl -symbolic-link
+Create symbolic links to regular files in a hierarchy instead of copying.
+.It Fl v , Fl -verbose
+Be verbose, showing both the source and destination path of each file
+as is copied.
+.It Fl x , Fl -one-file-system
+Do not traverse file system mount points.
.El
.Pp
For each destination file that already exists, its contents are
diff --git a/bin/cp/cp.c b/bin/cp/cp.c
index 7e97715c3ef4..38fe65399d06 100644
--- a/bin/cp/cp.c
+++ b/bin/cp/cp.c
@@ -55,6 +55,7 @@
#include <errno.h>
#include <fcntl.h>
#include <fts.h>
+#include <getopt.h>
#include <limits.h>
#include <signal.h>
#include <stdbool.h>
@@ -69,8 +70,8 @@ static char dot[] = ".";
#define END(buf) (buf + sizeof(buf))
PATH_T to = { .dir = -1, .end = to.path };
-int Nflag, fflag, iflag, lflag, nflag, pflag, sflag, vflag;
-static int Hflag, Lflag, Pflag, Rflag, rflag;
+bool Nflag, fflag, iflag, lflag, nflag, pflag, sflag, vflag;
+static bool Hflag, Lflag, Pflag, Rflag, rflag, Sflag;
volatile sig_atomic_t info;
enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
@@ -78,6 +79,27 @@ enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
static int copy(char *[], enum op, int, struct stat *);
static void siginfo(int __unused);
+enum {
+ SORT_OPT = CHAR_MAX,
+};
+
+static const struct option long_opts[] =
+{
+ { "archive", no_argument, NULL, 'a' },
+ { "force", no_argument, NULL, 'f' },
+ { "interactive", no_argument, NULL, 'i' },
+ { "dereference", no_argument, NULL, 'L' },
+ { "link", no_argument, NULL, 'l' },
+ { "no-clobber", no_argument, NULL, 'n' },
+ { "no-dereference", no_argument, NULL, 'P' },
+ { "recursive", no_argument, NULL, 'R' },
+ { "symbolic-link", no_argument, NULL, 's' },
+ { "verbose", no_argument, NULL, 'v' },
+ { "one-file-system", no_argument, NULL, 'x' },
+ { "sort", no_argument, NULL, SORT_OPT },
+ { 0 }
+};
+
int
main(int argc, char *argv[])
{
@@ -88,63 +110,67 @@ main(int argc, char *argv[])
bool have_trailing_slash = false;
fts_options = FTS_NOCHDIR | FTS_PHYSICAL;
- while ((ch = getopt(argc, argv, "HLPRafilNnprsvx")) != -1)
+ while ((ch = getopt_long(argc, argv, "+HLPRafilNnprsvx", long_opts,
+ NULL)) != -1)
switch (ch) {
case 'H':
- Hflag = 1;
- Lflag = Pflag = 0;
+ Hflag = true;
+ Lflag = Pflag = false;
break;
case 'L':
- Lflag = 1;
- Hflag = Pflag = 0;
+ Lflag = true;
+ Hflag = Pflag = false;
break;
case 'P':
- Pflag = 1;
- Hflag = Lflag = 0;
+ Pflag = true;
+ Hflag = Lflag = false;
break;
case 'R':
- Rflag = 1;
+ Rflag = true;
break;
case 'a':
- pflag = 1;
- Rflag = 1;
- Pflag = 1;
- Hflag = Lflag = 0;
+ pflag = true;
+ Rflag = true;
+ Pflag = true;
+ Hflag = Lflag = false;
break;
case 'f':
- fflag = 1;
- iflag = nflag = 0;
+ fflag = true;
+ iflag = nflag = false;
break;
case 'i':
- iflag = 1;
- fflag = nflag = 0;
+ iflag = true;
+ fflag = nflag = false;
break;
case 'l':
- lflag = 1;
+ lflag = true;
break;
case 'N':
- Nflag = 1;
+ Nflag = true;
break;
case 'n':
- nflag = 1;
- fflag = iflag = 0;
+ nflag = true;
+ fflag = iflag = false;
break;
case 'p':
- pflag = 1;
+ pflag = true;
break;
case 'r':
- rflag = Lflag = 1;
- Hflag = Pflag = 0;
+ rflag = Lflag = true;
+ Hflag = Pflag = false;
break;
case 's':
- sflag = 1;
+ sflag = true;
break;
case 'v':
- vflag = 1;
+ vflag = true;
break;
case 'x':
fts_options |= FTS_XDEV;
break;
+ case SORT_OPT:
+ Sflag = true;
+ break;
default:
usage();
}
@@ -159,7 +185,7 @@ main(int argc, char *argv[])
if (lflag && sflag)
errx(1, "the -l and -s options may not be specified together");
if (rflag)
- Rflag = 1;
+ Rflag = true;
if (Rflag) {
if (Hflag)
fts_options |= FTS_COMFOLLOW;
@@ -263,6 +289,12 @@ main(int argc, char *argv[])
}
static int
+ftscmp(const FTSENT * const *a, const FTSENT * const *b)
+{
+ return (strcmp((*a)->fts_name, (*b)->fts_name));
+}
+
+static int
copy(char *argv[], enum op type, int fts_options, struct stat *root_stat)
{
char rootname[NAME_MAX];
@@ -305,7 +337,7 @@ copy(char *argv[], enum op type, int fts_options, struct stat *root_stat)
}
level = FTS_ROOTLEVEL;
- if ((ftsp = fts_open(argv, fts_options, NULL)) == NULL)
+ if ((ftsp = fts_open(argv, fts_options, Sflag ? ftscmp : NULL)) == NULL)
err(1, "fts_open");
for (badcp = rval = 0;
(curr = fts_read(ftsp)) != NULL;
diff --git a/bin/cp/extern.h b/bin/cp/extern.h
index c0c524756980..683e6e5f289f 100644
--- a/bin/cp/extern.h
+++ b/bin/cp/extern.h
@@ -37,7 +37,7 @@ typedef struct {
} PATH_T;
extern PATH_T to;
-extern int Nflag, fflag, iflag, lflag, nflag, pflag, sflag, vflag;
+extern bool Nflag, fflag, iflag, lflag, nflag, pflag, sflag, vflag;
extern volatile sig_atomic_t info;
__BEGIN_DECLS
diff --git a/bin/cp/tests/cp_test.sh b/bin/cp/tests/cp_test.sh
index 1d2cd4292459..999993bfad67 100755
--- a/bin/cp/tests/cp_test.sh
+++ b/bin/cp/tests/cp_test.sh
@@ -34,6 +34,10 @@ check_size()
}
atf_test_case basic
+basic_head()
+{
+ atf_set "descr" "Copy a file"
+}
basic_body()
{
echo "foo" > bar
@@ -43,18 +47,26 @@ basic_body()
}
atf_test_case basic_symlink
+basic_symlink_head()
+{
+ atf_set "descr" "Copy a symlink to a file"
+}
basic_symlink_body()
{
echo "foo" > bar
ln -s bar baz
atf_check cp baz foo
- atf_check test '!' -L foo
+ atf_check test ! -L foo
atf_check cmp foo bar
}
atf_test_case chrdev
+chrdev_head()
+{
+ atf_set "descr" "Copy a character device"
+}
chrdev_body()
{
echo "foo" > bar
@@ -69,6 +81,10 @@ chrdev_body()
}
atf_test_case hardlink
+hardlink_head()
+{
+ atf_set "descr" "Create a hard link to a file"
+}
hardlink_body()
{
echo "foo" >foo
@@ -78,6 +94,11 @@ hardlink_body()
}
atf_test_case hardlink_exists
+hardlink_exists_head()
+{
+ atf_set "descr" "Attempt to create a hard link to a file, " \
+ "but the destination already exists"
+}
hardlink_exists_body()
{
echo "foo" >foo
@@ -88,6 +109,11 @@ hardlink_exists_body()
}
atf_test_case hardlink_exists_force
+hardlink_exists_force_head()
+{
+ atf_set "descr" "Force creation of a hard link to a file " \
+ "when the destination already exists"
+}
hardlink_exists_force_body()
{
echo "foo" >foo
@@ -98,9 +124,12 @@ hardlink_exists_force_body()
}
atf_test_case matching_srctgt
+matching_srctgt_head()
+{
+ atf_set "descr" "Avoid infinite loop when copying a directory to itself"
+}
matching_srctgt_body()
{
-
# PR235438: `cp -R foo foo` would previously infinitely recurse and
# eventually error out.
mkdir foo
@@ -110,13 +139,17 @@ matching_srctgt_body()
atf_check cp -R foo foo
atf_check -o inline:"qux\n" cat foo/foo/bar
atf_check -o inline:"qux\n" cat foo/foo/zoo
- atf_check -e not-empty -s not-exit:0 stat foo/foo/foo
+ atf_check test ! -e foo/foo/foo
}
atf_test_case matching_srctgt_contained
+matching_srctgt_contained_head()
+{
+ atf_set "descr" "Avoid infinite loop when copying a directory " \
+ "into an existing subdirectory of itself"
+}
matching_srctgt_contained_body()
{
-
# Let's do the same thing, except we'll try to recursively copy foo into
# one of its subdirectories.
mkdir foo
@@ -142,9 +175,13 @@ matching_srctgt_contained_body()
}
atf_test_case matching_srctgt_link
+matching_srctgt_link_head()
+{
+ atf_set "descr" "Avoid infinite loop when recursively copying a " \
+ "symlink to a directory into the directory it links to"
+}
matching_srctgt_link_body()
{
-
mkdir foo
echo "qux" > foo/bar
cp foo/bar foo/zoo
@@ -156,9 +193,13 @@ matching_srctgt_link_body()
}
atf_test_case matching_srctgt_nonexistent
+matching_srctgt_nonexistent_head()
+{
+ atf_set "descr" "Avoid infinite loop when recursively copying a " \
+ "directory into a new subdirectory of itself"
+}
matching_srctgt_nonexistent_body()
{
-
# We'll copy foo to a nonexistent subdirectory; ideally, we would
# skip just the directory and end up with a layout like;
#
@@ -180,6 +221,10 @@ matching_srctgt_nonexistent_body()
}
atf_test_case pflag_acls
+pflag_acls_head()
+{
+ atf_set "descr" "Verify that -p preserves access control lists"
+}
pflag_acls_body()
{
mkdir dir
@@ -216,6 +261,10 @@ pflag_acls_body()
}
atf_test_case pflag_flags
+pflag_flags_head()
+{
+ atf_set "descr" "Verify that -p preserves file flags"
+}
pflag_flags_body()
{
mkdir dir
@@ -263,6 +312,11 @@ recursive_link_setup()
}
atf_test_case recursive_link_dflt
+recursive_link_dflt_head()
+{
+ atf_set "descr" "Copy a directory containing a subdirectory and a " \
+ "symlink to that subdirectory"
+}
recursive_link_dflt_body()
{
recursive_link_setup
@@ -270,9 +324,15 @@ recursive_link_dflt_body()
# -P is the default, so this should work and preserve the link.
atf_check cp -R foo foo-mirror
atf_check test -L foo-mirror/foo/baz
+ atf_check test -d foo-mirror/foo/baz
}
atf_test_case recursive_link_Hflag
+recursive_link_Hflag_head()
+{
+ atf_set "descr" "Copy a directory containing a subdirectory and a " \
+ "symlink to that subdirectory"
+}
recursive_link_Hflag_body()
{
recursive_link_setup
@@ -281,22 +341,32 @@ recursive_link_Hflag_body()
# link.
atf_check cp -RH foo foo-mirror
atf_check test -L foo-mirror/foo/baz
+ atf_check test -d foo-mirror/foo/baz
}
atf_test_case recursive_link_Lflag
+recursive_link_Lflag_head()
+{
+ atf_set "descr" "Copy a directory containing a subdirectory and a " \
+ "symlink to that subdirectory"
+}
recursive_link_Lflag_body()
{
recursive_link_setup -L
# -L will work, but foo/baz ends up expanded to a directory.
- atf_check test -d foo-mirror/foo/baz -a \
- '(' ! -L foo-mirror/foo/baz ')'
+ atf_check test ! -L foo-mirror/foo/baz
+ atf_check test -d foo-mirror/foo/baz
atf_check cp -RL foo foo-mirror
- atf_check test -d foo-mirror/foo/baz -a \
- '(' ! -L foo-mirror/foo/baz ')'
+ atf_check test ! -L foo-mirror/foo/baz
+ atf_check test -d foo-mirror/foo/baz
}
atf_test_case samefile
+samefile_head()
+{
+ atf_set "descr" "Copy a file to itself"
+}
samefile_body()
{
echo "foo" >foo
@@ -324,6 +394,10 @@ files_are_equal()
}
atf_test_case sparse_leading_hole
+sparse_leading_hole_head()
+{
+ atf_set "descr" "Copy a sparse file stat starts with a hole"
+}
sparse_leading_hole_body()
{
# A 16-megabyte hole followed by one megabyte of data
@@ -337,6 +411,10 @@ sparse_leading_hole_body()
}
atf_test_case sparse_multiple_holes
+sparse_multiple_hole_head()
+{
+ atf_set "descr" "Copy a sparse file with multiple holes"
+}
sparse_multiple_holes_body()
{
# Three one-megabyte blocks of data preceded, separated, and
@@ -356,6 +434,10 @@ sparse_multiple_holes_body()
}
atf_test_case sparse_only_hole
+sparse_only_hole_head()
+{
+ atf_set "descr" "Copy a sparse file consisting entirely of a hole"
+}
sparse_only_hole_body()
{
# A 16-megabyte hole
@@ -368,6 +450,10 @@ sparse_only_hole_body()
}
atf_test_case sparse_to_dev
+sparse_to_dev_head()
+{
+ atf_set "descr" "Copy a sparse file to a device"
+}
sparse_to_dev_body()
{
# Three one-megabyte blocks of data preceded, separated, and
@@ -385,6 +471,10 @@ sparse_to_dev_body()
}
atf_test_case sparse_trailing_hole
+sparse_trailing_hole_head()
+{
+ atf_set "descr" "Copy a sparse file that ends with a hole"
+}
sparse_trailing_hole_body()
{
# One megabyte of data followed by a 16-megabyte hole
@@ -398,16 +488,24 @@ sparse_trailing_hole_body()
}
atf_test_case standalone_Pflag
+standalone_Pflag_head()
+{
+ atf_set "descr" "Test -P without -R"
+}
standalone_Pflag_body()
{
echo "foo" > bar
ln -s bar foo
atf_check cp -P foo baz
- atf_check -o inline:'Symbolic Link\n' stat -f %SHT baz
+ atf_check test -L baz
}
atf_test_case symlink
+symlink_head()
+{
+ atf_set "descr" "Create a symbolic link to a file"
+}
symlink_body()
{
echo "foo" >foo
@@ -417,6 +515,11 @@ symlink_body()
}
atf_test_case symlink_exists
+symlink_exists_head()
+{
+ atf_set "descr" "Attempt to create a symbolic link to a file, " \
+ "but the destination already exists"
+}
symlink_exists_body()
{
echo "foo" >foo
@@ -426,6 +529,11 @@ symlink_exists_body()
}
atf_test_case symlink_exists_force
+symlink_exists_force_head()
+{
+ atf_set "descr" "Force creation of a symbolic link to a file " \
+ "when the destination already exists"
+}
symlink_exists_force_body()
{
echo "foo" >foo
@@ -436,6 +544,10 @@ symlink_exists_force_body()
}
atf_test_case directory_to_symlink
+directory_to_symlink_head()
+{
+ atf_set "descr" "Attempt to copy a directory to a symlink"
+}
directory_to_symlink_body()
{
mkdir -p foo
@@ -449,6 +561,10 @@ directory_to_symlink_body()
}
atf_test_case overwrite_directory
+overwrite_directory_head()
+{
+ atf_set "descr" "Attempt to overwrite a directory with a file"
+}
overwrite_directory_body()
{
mkdir -p foo/bar/baz
@@ -465,6 +581,10 @@ overwrite_directory_body()
}
atf_test_case to_dir_dne
+to_dir_dne_head()
+{
+ atf_set "descr" "Copy a directory to a nonexistent directory"
+}
to_dir_dne_body()
{
mkdir dir
@@ -476,6 +596,10 @@ to_dir_dne_body()
}
atf_test_case to_nondir
+to_dir_dne_head()
+{
+ atf_set "descr" "Copy one or more files to a non-directory"
+}
to_nondir_body()
{
echo "foo" >foo
@@ -490,6 +614,10 @@ to_nondir_body()
}
atf_test_case to_deadlink
+to_deadlink_head()
+{
+ atf_set "descr" "Copy a file to a dead symbolic link"
+}
to_deadlink_body()
{
echo "foo" >foo
@@ -499,6 +627,10 @@ to_deadlink_body()
}
atf_test_case to_deadlink_append
+to_deadlink_append_head()
+{
+ atf_set "descr" "Copy multiple files to a dead symbolic link"
+}
to_deadlink_append_body()
{
echo "foo" >foo
@@ -517,6 +649,10 @@ to_deadlink_append_body()
}
atf_test_case to_dirlink
+to_dirlink_head()
+{
+ atf_set "descr" "Copy things to a symbolic link to a directory"
+}
to_dirlink_body()
{
mkdir src dir
@@ -542,6 +678,11 @@ to_dirlink_body()
}
atf_test_case to_deaddirlink
+to_deaddirlink_head()
+{
+ atf_set "descr" "Copy things to a symbolic link to a nonexistent " \
+ "directory"
+}
to_deaddirlink_body()
{
mkdir src
@@ -572,6 +713,11 @@ to_deaddirlink_body()
}
atf_test_case to_link_outside
+to_link_outside_head()
+{
+ atf_set "descr" "Recursively copy a directory containing a symbolic " \
+ "link that points to somewhere outside the source directory"
+}
to_link_outside_body()
{
mkdir dir dst dst/dir
@@ -584,6 +730,11 @@ to_link_outside_body()
}
atf_test_case dstmode
+dstmode_head()
+{
+ atf_set "descr" "Verify that directories are created with the " \
+ "correct permissions"
+}
dstmode_body()
{
mkdir -m 0755 dir
@@ -646,6 +797,7 @@ atf_test_case unrdir
unrdir_head()
{
atf_set "descr" "Test handling of unreadable directories"
+ atf_set "require.user" "unprivileged"
}
unrdir_body()
{
@@ -657,7 +809,7 @@ unrdir_body()
atf_check \
-s exit:1 \
-e match:"^cp: src/b: Permission denied" \
- cp -R src dst
+ cp -R --sort src dst
atf_check test -d dst/a
atf_check cmp src/a/f dst/a/f
atf_check test -d dst/b
@@ -670,6 +822,7 @@ atf_test_case unrfile
unrfile_head()
{
atf_set "descr" "Test handling of unreadable files"
+ atf_set "require.user" "unprivileged"
}
unrfile_body()
{
@@ -681,13 +834,28 @@ unrfile_body()
atf_check \
-s exit:1 \
-e match:"^cp: src/b: Permission denied" \
- cp -R src dst
+ cp -R --sort src dst
atf_check test -d dst
atf_check cmp src/a dst/a
atf_check test ! -e dst/b
atf_check cmp src/c dst/c
}
+atf_test_case nopermute
+nopermute_head()
+{
+ atf_set descr "Check that getopt_long does not permute options"
+}
+nopermute_body()
+{
+ mkdir src dst
+ atf_check \
+ -s exit:1 \
+ -e match:'cp: -p: No such file' \
+ cp -R src -p dst
+ atf_check test -d dst/src
+}
+
atf_init_test_cases()
{
atf_add_test_case basic
@@ -729,4 +897,5 @@ atf_init_test_cases()
atf_add_test_case dirloop
atf_add_test_case unrdir
atf_add_test_case unrfile
+ atf_add_test_case nopermute
}
diff --git a/bin/cp/utils.c b/bin/cp/utils.c
index cfc0f0f12603..2036056ada68 100644
--- a/bin/cp/utils.c
+++ b/bin/cp/utils.c
@@ -105,7 +105,7 @@ copy_file(const FTSENT *entp, bool dne, bool beneath)
ssize_t wcount;
off_t wtotal;
int ch, checkch, from_fd, rval, to_fd;
- int use_copy_file_range = 1;
+ bool use_copy_file_range = true;
fs = entp->fts_statp;
from_fd = to_fd = -1;
@@ -210,7 +210,7 @@ copy_file(const FTSENT *entp, bool dne, bool beneath)
to_fd, NULL, SSIZE_MAX, 0);
if (wcount < 0 && errno == EINVAL) {
/* probably a non-seekable descriptor */
- use_copy_file_range = 0;
+ use_copy_file_range = false;
}
}
if (!use_copy_file_range) {
diff --git a/contrib/kyua/utils/fs/operations.cpp b/contrib/kyua/utils/fs/operations.cpp
index 7a96d0b2058a..185d164b88d7 100644
--- a/contrib/kyua/utils/fs/operations.cpp
+++ b/contrib/kyua/utils/fs/operations.cpp
@@ -692,6 +692,7 @@ fs::rm_r(const fs::path& directory)
{
const fs::directory dir(directory);
+ ::chmod(directory.c_str(), 0700);
for (fs::directory::const_iterator iter = dir.begin(); iter != dir.end();
++iter) {
if (iter->name == "." || iter->name == "..")
@@ -701,6 +702,7 @@ fs::rm_r(const fs::path& directory)
if (fs::is_directory(entry)) {
LD(F("Descending into %s") % entry);
+ ::chmod(entry.c_str(), 0700);
fs::rm_r(entry);
} else {
LD(F("Removing file %s") % entry);
diff --git a/contrib/kyua/utils/fs/operations_test.cpp b/contrib/kyua/utils/fs/operations_test.cpp
index f1349351166e..6f0fa52811c9 100644
--- a/contrib/kyua/utils/fs/operations_test.cpp
+++ b/contrib/kyua/utils/fs/operations_test.cpp
@@ -664,6 +664,19 @@ ATF_TEST_CASE_BODY(rm_r__files_and_directories)
}
+ATF_TEST_CASE_WITHOUT_HEAD(rm_r__bad_perms);
+ATF_TEST_CASE_BODY(rm_r__bad_perms)
+{
+ fs::mkdir(fs::path("root"), 0755);
+ fs::mkdir(fs::path("root/dir"), 0755);
+ atf::utils::create_file("root/dir/file", "");
+ ::chmod(fs::path("root/dir").c_str(), 0000);
+ ATF_REQUIRE(lookup(".", "root", S_IFDIR));
+ fs::rm_r(fs::path("root"));
+ ATF_REQUIRE(!lookup(".", "root", S_IFDIR));
+}
+
+
ATF_TEST_CASE_WITHOUT_HEAD(rmdir__ok)
ATF_TEST_CASE_BODY(rmdir__ok)
{
@@ -811,6 +824,7 @@ ATF_INIT_TEST_CASES(tcs)
ATF_ADD_TEST_CASE(tcs, rm_r__empty);
ATF_ADD_TEST_CASE(tcs, rm_r__files_and_directories);
+ ATF_ADD_TEST_CASE(tcs, rm_r__bad_perms);
ATF_ADD_TEST_CASE(tcs, rmdir__ok);
ATF_ADD_TEST_CASE(tcs, rmdir__fail);
diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map
index 50dbf3425964..26f638568efc 100644
--- a/lib/libc/gen/Symbol.map
+++ b/lib/libc/gen/Symbol.map
@@ -458,8 +458,6 @@ FBSD_1.8 {
aio_read2;
aio_write2;
execvpe;
- fscandir;
- fscandir_b;
fdscandir;
fdscandir_b;
fts_open_b;
@@ -598,7 +596,6 @@ FBSDprivate_1.0 {
__libc_tcdrain;
- __pthread_distribute_static_tls;
__pthread_map_stacks_exec;
__fillcontextx;
__fillcontextx2;
diff --git a/lib/libc/gen/elf_utils.c b/lib/libc/gen/elf_utils.c
index 330aa8f17f7e..3714a0dc42b5 100644
--- a/lib/libc/gen/elf_utils.c
+++ b/lib/libc/gen/elf_utils.c
@@ -41,7 +41,6 @@
#include "libc_private.h"
void __pthread_map_stacks_exec(void);
-void __pthread_distribute_static_tls(size_t, void *, size_t, size_t);
int
__elf_phdr_match_addr(struct dl_phdr_info *phdr_info, void *addr)
@@ -105,28 +104,3 @@ __pthread_map_stacks_exec(void)
((void (*)(void))__libc_interposing[INTERPOS_map_stacks_exec])();
}
-
-void
-__libc_distribute_static_tls(size_t offset, void *src, size_t len,
- size_t total_len)
-{
- char *tlsbase;
-
-#ifdef TLS_VARIANT_I
- tlsbase = (char *)_tcb_get() + offset;
-#else
- tlsbase = (char *)_tcb_get() - offset;
-#endif
- memcpy(tlsbase, src, len);
- memset(tlsbase + len, 0, total_len - len);
-}
-
-#pragma weak __pthread_distribute_static_tls
-void
-__pthread_distribute_static_tls(size_t offset, void *src, size_t len,
- size_t total_len)
-{
-
- ((void (*)(size_t, void *, size_t, size_t))__libc_interposing[
- INTERPOS_distribute_static_tls])(offset, src, len, total_len);
-}
diff --git a/lib/libc/gen/fts.3 b/lib/libc/gen/fts.3
index 5860d1be1a1e..ee558b892c8c 100644
--- a/lib/libc/gen/fts.3
+++ b/lib/libc/gen/fts.3
@@ -394,7 +394,7 @@ must be specified.
The options are selected by
.Em or Ns 'ing
the following values:
-.Bl -tag -width "FTS_PHYSICAL"
+.Bl -tag -width "FTS_COMFOLLOWDIR"
.It Dv FTS_COMFOLLOW
This option causes any symbolic link specified as a root path to be
followed immediately whether or not
diff --git a/lib/libc/gen/gen-private.h b/lib/libc/gen/gen-private.h
index 3792a61ff942..b6749b3435cd 100644
--- a/lib/libc/gen/gen-private.h
+++ b/lib/libc/gen/gen-private.h
@@ -43,8 +43,8 @@ struct pthread_mutex;
*/
struct _dirdesc {
int dd_fd; /* file descriptor associated with directory */
- long dd_loc; /* offset in current buffer */
- long dd_size; /* amount of data returned by getdirentries */
+ size_t dd_loc; /* offset in current buffer */
+ size_t dd_size; /* amount of data returned by getdirentries */
char *dd_buf; /* data buffer */
int dd_len; /* size of data buffer */
off_t dd_seek; /* magic cookie returned by getdirentries */
diff --git a/lib/libc/gen/libc_interposing_table.c b/lib/libc/gen/libc_interposing_table.c
index 8eae6c7f5d95..025a67ac3eac 100644
--- a/lib/libc/gen/libc_interposing_table.c
+++ b/lib/libc/gen/libc_interposing_table.c
@@ -42,7 +42,6 @@ interpos_func_t __libc_interposing[INTERPOS_MAX] = {
SLOT(spinlock, __libc_spinlock_stub),
SLOT(spinunlock, __libc_spinunlock_stub),
SLOT(map_stacks_exec, __libc_map_stacks_exec),
- SLOT(distribute_static_tls, __libc_distribute_static_tls),
SLOT(uexterr_gettext, __libc_uexterr_gettext),
};
#undef SLOT
diff --git a/lib/libc/gen/opendir2.c b/lib/libc/gen/opendir2.c
index 928145b468c1..c5c2e662efd8 100644
--- a/lib/libc/gen/opendir2.c
+++ b/lib/libc/gen/opendir2.c
@@ -264,6 +264,7 @@ DIR *
__opendir_common(int fd, int flags, bool use_current_pos)
{
DIR *dirp;
+ ssize_t ret;
int incr;
int saved_errno;
bool unionstack;
@@ -313,13 +314,11 @@ __opendir_common(int fd, int flags, bool use_current_pos)
* to prime dd_seek. This also checks if the
* fd passed to fdopendir() is a directory.
*/
- dirp->dd_size = _getdirentries(dirp->dd_fd,
+ ret = _getdirentries(dirp->dd_fd,
dirp->dd_buf, dirp->dd_len, &dirp->dd_seek);
- if (dirp->dd_size < 0) {
- if (errno == EINVAL)
- errno = ENOTDIR;
+ if (ret < 0)
goto fail;
- }
+ dirp->dd_size = (size_t)ret;
dirp->dd_flags |= __DTF_SKIPREAD;
} else {
dirp->dd_size = 0;
diff --git a/lib/libc/gen/readdir.c b/lib/libc/gen/readdir.c
index 2a2fa999b7ce..32603c0b4677 100644
--- a/lib/libc/gen/readdir.c
+++ b/lib/libc/gen/readdir.c
@@ -48,8 +48,8 @@ struct dirent *
_readdir_unlocked(DIR *dirp, int flags)
{
struct dirent *dp;
- long initial_seek;
- long initial_loc = 0;
+ off_t initial_seek;
+ size_t initial_loc = 0;
for (;;) {
if (dirp->dd_loc >= dirp->dd_size) {
diff --git a/lib/libc/gen/scandir.c b/lib/libc/gen/scandir.c
index 8e62fe980868..fb589f4b36b6 100644
--- a/lib/libc/gen/scandir.c
+++ b/lib/libc/gen/scandir.c
@@ -252,9 +252,3 @@ scandir_thunk_cmp(const void *p1, const void *p2, void *thunk)
return (dc((const struct dirent **)p1, (const struct dirent **)p2));
}
#endif
-
-#ifdef I_AM_SCANDIR_B
-__weak_reference(fdscandir_b, fscandir_b);
-#else
-__weak_reference(fdscandir, fscandir);
-#endif
diff --git a/lib/libc/gen/telldir.c b/lib/libc/gen/telldir.c
index b751fafd975f..1731cc4d7a2c 100644
--- a/lib/libc/gen/telldir.c
+++ b/lib/libc/gen/telldir.c
@@ -118,7 +118,7 @@ _seekdir(DIR *dirp, long loc)
struct dirent *dp;
union ddloc_packed ddloc;
off_t loc_seek;
- long loc_loc;
+ size_t loc_loc;
ddloc.l = loc;
@@ -171,7 +171,7 @@ _seekdir(DIR *dirp, long loc)
* fetching a new block to fix any such telldir locations.
*/
void
-_fixtelldir(DIR *dirp, long oldseek, long oldloc)
+_fixtelldir(DIR *dirp, off_t oldseek, size_t oldloc)
{
struct ddloc_mem *lp;
diff --git a/lib/libc/gen/telldir.h b/lib/libc/gen/telldir.h
index 6d113491e819..02fd52af9060 100644
--- a/lib/libc/gen/telldir.h
+++ b/lib/libc/gen/telldir.h
@@ -46,9 +46,9 @@
*/
struct ddloc_mem {
LIST_ENTRY(ddloc_mem) loc_lqe; /* entry in list */
- long loc_index; /* key associated with structure */
+ size_t loc_index; /* key associated with structure */
off_t loc_seek; /* magic cookie returned by getdirentries */
- long loc_loc; /* offset of entry in buffer */
+ size_t loc_loc; /* offset of entry in buffer */
};
#ifdef __LP64__
@@ -102,7 +102,7 @@ bool _filldir(DIR *, bool);
struct dirent *_readdir_unlocked(DIR *, int);
void _reclaim_telldir(DIR *);
void _seekdir(DIR *, long);
-void _fixtelldir(DIR *dirp, long oldseek, long oldloc);
+void _fixtelldir(DIR *dirp, off_t oldseek, size_t oldloc);
DIR *__opendir_common(int, int, bool);
#define RDU_SKIP 0x0001
diff --git a/lib/libc/include/libc_private.h b/lib/libc/include/libc_private.h
index 1bc22f3931a5..db4cbc32be35 100644
--- a/lib/libc/include/libc_private.h
+++ b/lib/libc/include/libc_private.h
@@ -249,7 +249,7 @@ enum {
INTERPOS_map_stacks_exec,
INTERPOS_fdatasync,
INTERPOS_clock_nanosleep,
- INTERPOS_distribute_static_tls,
+ INTERPOS__reserved0, /* was distribute_static_tls */
INTERPOS_pdfork,
INTERPOS_uexterr_gettext,
INTERPOS_MAX
@@ -361,8 +361,6 @@ struct dl_phdr_info;
int __elf_phdr_match_addr(struct dl_phdr_info *, void *);
void __init_elf_aux_vector(void);
void __libc_map_stacks_exec(void);
-void __libc_distribute_static_tls(__size_t, void *, __size_t, __size_t);
-__uintptr_t __libc_static_tls_base(__size_t);
void _pthread_cancel_enter(int);
void _pthread_cancel_leave(int);
diff --git a/lib/libnvmf/libnvmf.h b/lib/libnvmf/libnvmf.h
index 9840e190a24f..7cdd7e433455 100644
--- a/lib/libnvmf/libnvmf.h
+++ b/lib/libnvmf/libnvmf.h
@@ -342,7 +342,8 @@ int nvmf_host_request_queues(struct nvmf_qpair *qp, u_int requested,
*/
int nvmf_handoff_host(const struct nvme_discovery_log_entry *dle,
const char *hostnqn, struct nvmf_qpair *admin_qp, u_int num_queues,
- struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata);
+ struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata,
+ uint32_t reconnect_delay, uint32_t controller_loss_timeout);
/*
* Disconnect an active host association previously handed off to the
@@ -370,7 +371,8 @@ int nvmf_reconnect_params(int fd, nvlist_t **nvlp);
*/
int nvmf_reconnect_host(int fd, const struct nvme_discovery_log_entry *dle,
const char *hostnqn, struct nvmf_qpair *admin_qp, u_int num_queues,
- struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata);
+ struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata,
+ uint32_t reconnect_delay, uint32_t controller_loss_timeout);
/*
* Fetch connection status from an existing kernel host.
diff --git a/lib/libnvmf/nvmf_host.c b/lib/libnvmf/nvmf_host.c
index 89cdd5c6bb70..3266f8898296 100644
--- a/lib/libnvmf/nvmf_host.c
+++ b/lib/libnvmf/nvmf_host.c
@@ -792,7 +792,8 @@ static int
prepare_queues_for_handoff(struct nvmf_ioc_nv *nv,
const struct nvme_discovery_log_entry *dle, const char *hostnqn,
struct nvmf_qpair *admin_qp, u_int num_queues,
- struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata)
+ struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata,
+ uint32_t reconnect_delay, uint32_t controller_loss_timeout)
{
const struct nvmf_association *na = admin_qp->nq_association;
nvlist_t *nvl, *nvl_qp, *nvl_rparams;
@@ -820,6 +821,9 @@ prepare_queues_for_handoff(struct nvmf_ioc_nv *nv,
nvlist_add_string(nvl_rparams, "hostnqn", hostnqn);
nvlist_add_number(nvl_rparams, "num_io_queues", num_queues);
nvlist_add_number(nvl_rparams, "kato", admin_qp->nq_kato);
+ nvlist_add_number(nvl_rparams, "reconnect_delay", reconnect_delay);
+ nvlist_add_number(nvl_rparams, "controller_loss_timeout",
+ controller_loss_timeout);
nvlist_add_number(nvl_rparams, "io_qsize", io_queues[0]->nq_qsize);
nvlist_add_bool(nvl_rparams, "sq_flow_control",
na->na_params.sq_flow_control);
@@ -842,6 +846,9 @@ prepare_queues_for_handoff(struct nvmf_ioc_nv *nv,
nvl = nvlist_create(0);
nvlist_add_number(nvl, "trtype", na->na_trtype);
nvlist_add_number(nvl, "kato", admin_qp->nq_kato);
+ nvlist_add_number(nvl, "reconnect_delay", reconnect_delay);
+ nvlist_add_number(nvl, "controller_loss_timeout",
+ controller_loss_timeout);
nvlist_move_nvlist(nvl, "rparams", nvl_rparams);
/* First, the admin queue. */
@@ -872,7 +879,8 @@ prepare_queues_for_handoff(struct nvmf_ioc_nv *nv,
int
nvmf_handoff_host(const struct nvme_discovery_log_entry *dle,
const char *hostnqn, struct nvmf_qpair *admin_qp, u_int num_queues,
- struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata)
+ struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata,
+ uint32_t reconnect_delay, uint32_t controller_loss_timeout)
{
struct nvmf_ioc_nv nv;
u_int i;
@@ -885,7 +893,8 @@ nvmf_handoff_host(const struct nvme_discovery_log_entry *dle,
}
error = prepare_queues_for_handoff(&nv, dle, hostnqn, admin_qp,
- num_queues, io_queues, cdata);
+ num_queues, io_queues, cdata, reconnect_delay,
+ controller_loss_timeout);
if (error != 0)
goto out;
@@ -981,14 +990,16 @@ nvmf_reconnect_params(int fd, nvlist_t **nvlp)
int
nvmf_reconnect_host(int fd, const struct nvme_discovery_log_entry *dle,
const char *hostnqn, struct nvmf_qpair *admin_qp, u_int num_queues,
- struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata)
+ struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata,
+ uint32_t reconnect_delay, uint32_t controller_loss_timeout)
{
struct nvmf_ioc_nv nv;
u_int i;
int error;
error = prepare_queues_for_handoff(&nv, dle, hostnqn, admin_qp,
- num_queues, io_queues, cdata);
+ num_queues, io_queues, cdata, reconnect_delay,
+ controller_loss_timeout);
if (error != 0)
goto out;
diff --git a/lib/libsys/getdirentries.2 b/lib/libsys/getdirentries.2
index 0e5840ce25cd..202ae133f548 100644
--- a/lib/libsys/getdirentries.2
+++ b/lib/libsys/getdirentries.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd September 5, 2023
+.Dd July 8, 2025
.Dt GETDIRENTRIES 2
.Os
.Sh NAME
@@ -178,9 +178,7 @@ or non-NULL
.Fa basep
point outside the allocated address space.
.It Bq Er EINVAL
-The file referenced by
-.Fa fd
-is not a directory, or
+The value of
.Fa nbytes
is too small for returning a directory entry or block of entries,
or the current position pointer is invalid.
@@ -192,6 +190,10 @@ error occurred while reading from or writing to the file system.
Corrupted data was detected while reading from the file system.
.It Bq Er ENOENT
Directory unlinked but still open.
+.It Bq Er ENOTDIR
+The file referenced by
+.Fa fd
+is not a directory.
.El
.Sh SEE ALSO
.Xr lseek 2 ,
diff --git a/lib/libthr/pthread.map b/lib/libthr/pthread.map
index 1c8dde03367b..3a5353a32dc3 100644
--- a/lib/libthr/pthread.map
+++ b/lib/libthr/pthread.map
@@ -136,7 +136,6 @@ FBSDprivate_1.0 {
__pthread_mutex_lock;
__pthread_mutex_timedlock;
__pthread_mutex_trylock;
- __pthread_distribute_static_tls;
_pthread_atfork;
_pthread_barrier_destroy;
_pthread_barrier_init;
diff --git a/lib/libthr/thread/thr_list.c b/lib/libthr/thread/thr_list.c
index 820766f6f5e0..cbf16179f619 100644
--- a/lib/libthr/thread/thr_list.c
+++ b/lib/libthr/thread/thr_list.c
@@ -363,41 +363,3 @@ _thr_find_thread(struct pthread *curthread, struct pthread *thread,
THREAD_LIST_UNLOCK(curthread);
return (ret);
}
-
-static void
-thr_distribute_static_tls(char *tlsbase, void *src, size_t len,
- size_t total_len)
-{
-
- memcpy(tlsbase, src, len);
- memset(tlsbase + len, 0, total_len - len);
-}
-
-void
-__pthread_distribute_static_tls(size_t offset, void *src, size_t len,
- size_t total_len)
-{
- struct pthread *curthread, *thrd;
- char *tlsbase;
-
- if (!_thr_is_inited()) {
-#ifdef TLS_VARIANT_I
- tlsbase = (char *)_tcb_get() + offset;
-#else
- tlsbase = (char *)_tcb_get() - offset;
-#endif
- thr_distribute_static_tls(tlsbase, src, len, total_len);
- return;
- }
- curthread = _get_curthread();
- THREAD_LIST_RDLOCK(curthread);
- TAILQ_FOREACH(thrd, &_thread_list, tle) {
-#ifdef TLS_VARIANT_I
- tlsbase = (char *)thrd->tcb + offset;
-#else
- tlsbase = (char *)thrd->tcb - offset;
-#endif
- thr_distribute_static_tls(tlsbase, src, len, total_len);
- }
- THREAD_LIST_UNLOCK(curthread);
-}
diff --git a/lib/libthr/thread/thr_private.h b/lib/libthr/thread/thr_private.h
index bca890829057..d7b889930365 100644
--- a/lib/libthr/thread/thr_private.h
+++ b/lib/libthr/thread/thr_private.h
@@ -986,8 +986,6 @@ void __pthread_cxa_finalize(struct dl_phdr_info *phdr_info);
void _thr_tsd_unload(struct dl_phdr_info *phdr_info) __hidden;
void _thr_sigact_unload(struct dl_phdr_info *phdr_info) __hidden;
void _thr_stack_fix_protection(struct pthread *thrd);
-void __pthread_distribute_static_tls(size_t offset, void *src, size_t len,
- size_t total_len);
int *__error_threaded(void) __hidden;
void __thr_interpose_libc(void) __hidden;
diff --git a/libexec/flua/modules/lfbsd.c b/libexec/flua/modules/lfbsd.c
index a361fa25601b..ef660ba9fd77 100644
--- a/libexec/flua/modules/lfbsd.c
+++ b/libexec/flua/modules/lfbsd.c
@@ -31,6 +31,7 @@
#include <errno.h>
#include <fcntl.h>
#include <spawn.h>
+#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
@@ -44,6 +45,7 @@
struct fbsd_process {
int pid;
int stdin_fileno;
+ int stdout_fileno;
};
extern char **environ;
@@ -70,6 +72,16 @@ luaL_checkarraystrings(lua_State *L, int arg)
return ret;
}
+static void
+close_pipes(int pipes[2])
+{
+
+ if (pipes[0] != -1)
+ close(pipes[0]);
+ if (pipes[1] != -1)
+ close(pipes[1]);
+}
+
static int
lua_exec(lua_State *L)
{
@@ -77,31 +89,57 @@ lua_exec(lua_State *L)
int r;
posix_spawn_file_actions_t action;
int stdin_pipe[2] = {-1, -1};
+ int stdout_pipe[2] = {-1, -1};
pid_t pid;
const char **argv;
int n = lua_gettop(L);
- luaL_argcheck(L, n == 1, n > 1 ? 2 : n,
- "fbsd.exec takes exactly one argument");
+ bool capture_stdout;
+ luaL_argcheck(L, n > 0 && n <= 2, n >= 2 ? 2 : n,
+ "fbsd.exec takes exactly one or two arguments");
+ capture_stdout = lua_toboolean(L, 2);
if (pipe(stdin_pipe) < 0) {
lua_pushnil(L);
lua_pushstring(L, strerror(errno));
lua_pushinteger(L, errno);
return (3);
}
+ if (capture_stdout && pipe(stdout_pipe) < 0) {
+ close_pipes(stdin_pipe);
+ lua_pushnil(L);
+ lua_pushstring(L, strerror(errno));
+ lua_pushinteger(L, errno);
+ return (3);
+ }
proc = lua_newuserdata(L, sizeof(*proc));
proc->stdin_fileno = stdin_pipe[1];
-
+ proc->stdout_fileno = stdout_pipe[1];
posix_spawn_file_actions_init(&action);
posix_spawn_file_actions_adddup2(&action, stdin_pipe[0], STDIN_FILENO);
posix_spawn_file_actions_addclose(&action, stdin_pipe[1]);
+ if (stdin_pipe[0] != STDIN_FILENO)
+ posix_spawn_file_actions_addclose(&action, stdin_pipe[0]);
+
+ /*
+ * Setup stdout to be captured if requested. Otherwise, we just let it
+ * go to our own stdout.
+ */
+ if (stdout_pipe[0] != -1) {
+ posix_spawn_file_actions_adddup2(&action, stdout_pipe[0],
+ STDOUT_FILENO);
+ posix_spawn_file_actions_addclose(&action, stdout_pipe[1]);
+ if (stdout_pipe[0] != STDOUT_FILENO) {
+ posix_spawn_file_actions_addclose(&action,
+ stdout_pipe[0]);
+ }
+ }
argv = luaL_checkarraystrings(L, 1);
if (0 != (r = posix_spawnp(&pid, argv[0], &action, NULL,
(char*const*)argv, environ))) {
- close(stdin_pipe[0]);
- close(stdin_pipe[1]);
+ close_pipes(stdin_pipe);
+ close_pipes(stdout_pipe);
posix_spawn_file_actions_destroy(&action);
lua_pop(L, 2); /* Pop off the process handle and args. */
@@ -114,12 +152,14 @@ lua_exec(lua_State *L)
lua_pop(L, 1);
close(stdin_pipe[0]);
+ if (stdout_pipe[0] != -1)
+ close(stdout_pipe[0]);
posix_spawn_file_actions_destroy(&action);
proc->pid = pid;
luaL_setmetatable(L, FBSD_PROCESSHANDLE);
- return 1;
+ return (1);
}
static int
@@ -144,24 +184,34 @@ lua_process_close(lua_State *L)
return (2);
}
- if (proc->stdin_fileno >= 0)
+ if (proc->stdin_fileno >= 0) {
close(proc->stdin_fileno);
- proc->stdin_fileno = -1;
+ proc->stdin_fileno = -1;
+ }
+
+ if (proc->stdout_fileno >= 0) {
+ close(proc->stdout_fileno);
+ proc->stdout_fileno = -1;
+ }
lua_pushboolean(L, 1);
- return 1;
+ return (1);
}
static int
-lua_process_stdin(lua_State *L)
+lua_process_makestdio(lua_State *L, int fd, const char *mode)
{
- struct fbsd_process *proc;
luaL_Stream *p;
FILE *fp;
int r;
- proc = luaL_checkudata(L, 1, FBSD_PROCESSHANDLE);
- fp = fdopen(proc->stdin_fileno, "w");
+ if (fd == -1) {
+ lua_pushnil(L);
+ lua_pushstring(L, "Stream not captured");
+ return (2);
+ }
+
+ fp = fdopen(fd, mode);
if (fp == NULL) {
r = errno;
@@ -178,10 +228,29 @@ lua_process_stdin(lua_State *L)
return (1);
}
+static int
+lua_process_stdin(lua_State *L)
+{
+ struct fbsd_process *proc;
+
+ proc = luaL_checkudata(L, 1, FBSD_PROCESSHANDLE);
+ return (lua_process_makestdio(L, proc->stdin_fileno, "w"));
+}
+
+static int
+lua_process_stdout(lua_State *L)
+{
+ struct fbsd_process *proc;
+
+ proc = luaL_checkudata(L, 1, FBSD_PROCESSHANDLE);
+ return (lua_process_makestdio(L, proc->stdout_fileno, "r"));
+}
+
#define PROCESS_SIMPLE(n) { #n, lua_process_ ## n }
static const struct luaL_Reg fbsd_process[] = {
PROCESS_SIMPLE(close),
PROCESS_SIMPLE(stdin),
+ PROCESS_SIMPLE(stdout),
{ NULL, NULL },
};
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index 1459b38f3720..17196f55c271 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -82,9 +82,15 @@ struct dlerror_save {
char *msg;
};
+struct tcb_list_entry {
+ TAILQ_ENTRY(tcb_list_entry) next;
+};
+
/*
* Function declarations.
*/
+static bool allocate_tls_offset_common(size_t *offp, size_t tlssize,
+ size_t tlsalign, size_t tlspoffset);
static const char *basename(const char *);
static void digest_dynamic1(Obj_Entry *, int, const Elf_Dyn **,
const Elf_Dyn **, const Elf_Dyn **);
@@ -92,7 +98,7 @@ static bool digest_dynamic2(Obj_Entry *, const Elf_Dyn *, const Elf_Dyn *,
const Elf_Dyn *);
static bool digest_dynamic(Obj_Entry *, int);
static Obj_Entry *digest_phdr(const Elf_Phdr *, int, caddr_t, const char *);
-static void distribute_static_tls(Objlist *, RtldLockState *);
+static void distribute_static_tls(Objlist *);
static Obj_Entry *dlcheck(void *);
static int dlclose_locked(void *, RtldLockState *);
static Obj_Entry *dlopen_object(const char *name, int fd, Obj_Entry *refobj,
@@ -303,6 +309,10 @@ static size_t tls_static_max_align;
Elf_Addr tls_dtv_generation = 1; /* Used to detect when dtv size changes */
int tls_max_index = 1; /* Largest module index allocated */
+static TAILQ_HEAD(, tcb_list_entry) tcb_list =
+ TAILQ_HEAD_INITIALIZER(tcb_list);
+static size_t tcb_list_entry_offset;
+
static bool ld_library_path_rpath = false;
bool ld_fast_sigblock = false;
@@ -929,6 +939,19 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
allocate_tls_offset(entry->obj);
}
+ if (!allocate_tls_offset_common(&tcb_list_entry_offset,
+ sizeof(struct tcb_list_entry), _Alignof(struct tcb_list_entry),
+ 0)) {
+ /*
+ * This should be impossible as the static block size is not
+ * yet fixed, but catch and diagnose it failing if that ever
+ * changes or somehow turns out to be false.
+ */
+ _rtld_error("Could not allocate offset for tcb_list_entry");
+ rtld_die();
+ }
+ dbg("tcb_list_entry_offset %zu", tcb_list_entry_offset);
+
if (relocate_objects(obj_main,
ld_bind_now != NULL && *ld_bind_now != '\0', &obj_rtld,
SYMLOOK_EARLY, NULL) == -1)
@@ -3973,7 +3996,7 @@ dlopen_object(const char *name, int fd, Obj_Entry *refobj, int lo_flags,
if ((lo_flags & RTLD_LO_EARLY) == 0) {
map_stacks_exec(lockstate);
if (obj != NULL)
- distribute_static_tls(&initlist, lockstate);
+ distribute_static_tls(&initlist);
}
if (initlist_objects_ifunc(&initlist, (mode & RTLD_MODEMASK) ==
@@ -5400,6 +5423,44 @@ tls_get_addr_common(struct tcb *tcb, int index, size_t offset)
return (tls_get_addr_slow(tcb, index, offset, false));
}
+static struct tcb *
+tcb_from_tcb_list_entry(struct tcb_list_entry *tcbelm)
+{
+#ifdef TLS_VARIANT_I
+ return ((struct tcb *)((char *)tcbelm - tcb_list_entry_offset));
+#else
+ return ((struct tcb *)((char *)tcbelm + tcb_list_entry_offset));
+#endif
+}
+
+static struct tcb_list_entry *
+tcb_list_entry_from_tcb(struct tcb *tcb)
+{
+#ifdef TLS_VARIANT_I
+ return ((struct tcb_list_entry *)((char *)tcb + tcb_list_entry_offset));
+#else
+ return ((struct tcb_list_entry *)((char *)tcb - tcb_list_entry_offset));
+#endif
+}
+
+static void
+tcb_list_insert(struct tcb *tcb)
+{
+ struct tcb_list_entry *tcbelm;
+
+ tcbelm = tcb_list_entry_from_tcb(tcb);
+ TAILQ_INSERT_TAIL(&tcb_list, tcbelm, next);
+}
+
+static void
+tcb_list_remove(struct tcb *tcb)
+{
+ struct tcb_list_entry *tcbelm;
+
+ tcbelm = tcb_list_entry_from_tcb(tcb);
+ TAILQ_REMOVE(&tcb_list, tcbelm, next);
+}
+
#ifdef TLS_VARIANT_I
/*
@@ -5513,6 +5574,7 @@ allocate_tls(Obj_Entry *objs, void *oldtcb, size_t tcbsize, size_t tcbalign)
}
}
+ tcb_list_insert(tcb);
return (tcb);
}
@@ -5524,6 +5586,8 @@ free_tls(void *tcb, size_t tcbsize, size_t tcbalign __unused)
size_t post_size;
size_t i, tls_init_align __unused;
+ tcb_list_remove(tcb);
+
assert(tcbsize >= TLS_TCB_SIZE);
tls_init_align = MAX(obj_main->tlsalign, 1);
@@ -5624,6 +5688,7 @@ allocate_tls(Obj_Entry *objs, void *oldtcb, size_t tcbsize, size_t tcbalign)
}
}
+ tcb_list_insert(tcb);
return (tcb);
}
@@ -5635,6 +5700,8 @@ free_tls(void *tcb, size_t tcbsize __unused, size_t tcbalign)
size_t i;
uintptr_t tlsstart, tlsend;
+ tcb_list_remove(tcb);
+
/*
* Figure out the size of the initial TLS block so that we can
* find stuff which ___tls_get_addr() allocated dynamically.
@@ -5698,32 +5765,22 @@ allocate_module_tls(struct tcb *tcb, int index)
return (p);
}
-bool
-allocate_tls_offset(Obj_Entry *obj)
+static bool
+allocate_tls_offset_common(size_t *offp, size_t tlssize, size_t tlsalign,
+ size_t tlspoffset __unused)
{
size_t off;
- if (obj->tls_dynamic)
- return (false);
-
- if (obj->tls_static)
- return (true);
-
- if (obj->tlssize == 0) {
- obj->tls_static = true;
- return (true);
- }
-
if (tls_last_offset == 0)
- off = calculate_first_tls_offset(obj->tlssize, obj->tlsalign,
- obj->tlspoffset);
+ off = calculate_first_tls_offset(tlssize, tlsalign,
+ tlspoffset);
else
off = calculate_tls_offset(tls_last_offset, tls_last_size,
- obj->tlssize, obj->tlsalign, obj->tlspoffset);
+ tlssize, tlsalign, tlspoffset);
- obj->tlsoffset = off;
+ *offp = off;
#ifdef TLS_VARIANT_I
- off += obj->tlssize;
+ off += tlssize;
#endif
/*
@@ -5735,12 +5792,34 @@ allocate_tls_offset(Obj_Entry *obj)
if (tls_static_space != 0) {
if (off > tls_static_space)
return (false);
- } else if (obj->tlsalign > tls_static_max_align) {
- tls_static_max_align = obj->tlsalign;
+ } else if (tlsalign > tls_static_max_align) {
+ tls_static_max_align = tlsalign;
}
tls_last_offset = off;
- tls_last_size = obj->tlssize;
+ tls_last_size = tlssize;
+
+ return (true);
+}
+
+bool
+allocate_tls_offset(Obj_Entry *obj)
+{
+ if (obj->tls_dynamic)
+ return (false);
+
+ if (obj->tls_static)
+ return (true);
+
+ if (obj->tlssize == 0) {
+ obj->tls_static = true;
+ return (true);
+ }
+
+ if (!allocate_tls_offset_common(&obj->tlsoffset, obj->tlssize,
+ obj->tlsalign, obj->tlspoffset))
+ return (false);
+
obj->tls_static = true;
return (true);
@@ -6124,25 +6203,29 @@ map_stacks_exec(RtldLockState *lockstate)
}
static void
-distribute_static_tls(Objlist *list, RtldLockState *lockstate)
+distribute_static_tls(Objlist *list)
{
- Objlist_Entry *elm;
+ struct tcb_list_entry *tcbelm;
+ Objlist_Entry *objelm;
+ struct tcb *tcb;
Obj_Entry *obj;
- void (*distrib)(size_t, void *, size_t, size_t);
+ char *tlsbase;
- distrib = (void (*)(size_t, void *, size_t, size_t))(
- uintptr_t)get_program_var_addr("__pthread_distribute_static_tls",
- lockstate);
- if (distrib == NULL)
- return;
- STAILQ_FOREACH(elm, list, link) {
- obj = elm->obj;
+ STAILQ_FOREACH(objelm, list, link) {
+ obj = objelm->obj;
if (obj->marker || !obj->tls_static || obj->static_tls_copied)
continue;
- lock_release(rtld_bind_lock, lockstate);
- distrib(obj->tlsoffset, obj->tlsinit, obj->tlsinitsize,
- obj->tlssize);
- wlock_acquire(rtld_bind_lock, lockstate);
+ TAILQ_FOREACH(tcbelm, &tcb_list, next) {
+ tcb = tcb_from_tcb_list_entry(tcbelm);
+#ifdef TLS_VARIANT_I
+ tlsbase = (char *)tcb + obj->tlsoffset;
+#else
+ tlsbase = (char *)tcb - obj->tlsoffset;
+#endif
+ memcpy(tlsbase, obj->tlsinit, obj->tlsinitsize);
+ memset(tlsbase + obj->tlsinitsize, 0,
+ obj->tlssize - obj->tlsinitsize);
+ }
obj->static_tls_copied = true;
}
}
diff --git a/sbin/bectl/bectl.8 b/sbin/bectl/bectl.8
index cc88c7019d13..0e08b3383e9a 100644
--- a/sbin/bectl/bectl.8
+++ b/sbin/bectl/bectl.8
@@ -3,12 +3,12 @@
.\"
.\" SPDX-License-Identifier: BSD-2-Clause
.\"
-.Dd April 9, 2024
+.Dd June 13, 2025
.Dt BECTL 8
.Os
.Sh NAME
.Nm bectl
-.Nd Utility to manage boot environments on ZFS
+.Nd manage ZFS boot environments
.Sh SYNOPSIS
.Nm
.Op Fl h
@@ -80,34 +80,31 @@
.Sh DESCRIPTION
The
.Nm
-command is used to setup and interact with ZFS boot environments, which are
-bootable clones of datasets.
-.Pp
-A boot environment allows the system to be upgraded, while preserving the
-pre-upgrade system environment.
-.Pp
-.Nm
-itself accepts an
-.Fl r
-flag specified before the command to indicate the
-.Ar beroot
-that should be used as the boot environment root, or the dataset whose children
-are all boot environments.
-Normally this information is derived from the bootfs property of the pool that
-is mounted at
-.Pa / ,
-but it is useful when the system has not been booted into a ZFS root or a
-different pool should be operated on.
-For instance, booting into the recovery media and manually importing a pool from
-one of the system's resident disks will require the
-.Fl r
-flag to work.
+utility manages bootable ZFS clones called boot environments.
+Boot envionments allow system changes to be tested safely,
+as they are selectable directly from the boot
+.Xr loader 8 .
+This utility can
+.Cm create ,
+.Cm list ,
+.Cm mount ,
+or
+.Cm jail
+boot environments.
+Once the changes have been tested, the boot environment can be
+.Cm unmount Ns ed ,
+.Cm activate Ns d ,
+.Cm rename Ns d ,
+and
+.Cm destroy Ns ed .
.Ss Supported Subcommands and Flags
-.Bl -tag -width activate
-.It Xo
-.Fl h
-.Xc
+.Bl -tag -width indent
+.It Fl h
Print usage information and exit.
+.It Fl r Ar beroot Sy Ar subcommand
+Specify a parent dataset for the boot environment to use for
+.Ar subcommand
+for operation on manually imported pools or unusual layouts.
.It Xo
.Cm activate
.Op Fl t | Fl T
@@ -122,19 +119,19 @@ flag is given, this takes effect only for the next boot.
Flag
.Fl T
removes temporary boot once configuration.
-Without temporary configuration, the next boot will use zfs dataset specified
-in boot pool
+Without temporary configuration,
+the next boot will use zfs dataset specified in boot pool
.Ar bootfs
property.
.It Xo
.Cm check
.Xc
-Performs a silent sanity check on the current system.
+Perform a check to see if the current system can use boot environments.
If boot environments are supported and used,
.Nm
will exit with a status code of 0.
-Any other status code is not currently defined and may, in the future, grow
-special meaning for different degrees of sanity check failures.
+Any other status code is not currently defined and may, in the future,
+grow special meaning for different degrees of sanity check failures.
.It Xo
.Cm create
.Op Fl r
@@ -162,8 +159,8 @@ environment.
.Pp
If
.Nm
-is creating from another boot environment, a snapshot of that boot environment
-will be created to clone from.
+is creating from another boot environment,
+a snapshot of that boot environment will be created to clone from.
.It Xo
.Cm create
.Op Fl r
@@ -174,8 +171,10 @@ Create a snapshot of the boot environment named
.Pp
If the
.Fl r
-flag is given, a recursive snapshot of the boot environment will be created.
-A snapshot is created for each descendant dataset of the boot environment.
+flag is given,
+a recursive snapshot of the boot environment will be created.
+A snapshot is created for each descendant dataset
+of the boot environment.
See
.Sx Boot Environment Structures
for a discussion on different layouts.
@@ -241,8 +240,8 @@ If
.Ar utility
is specified, it will be executed instead of
.Pa /bin/sh .
-The jail will be destroyed and the boot environment unmounted when the command
-finishes executing, unless the
+The jail will be destroyed and the boot environment unmounted
+when the command finishes executing, unless the
.Fl U
argument is specified.
.Pp
@@ -269,11 +268,11 @@ The following default parameters are provided:
.It Va allow.mount Ta Cm true
.It Va allow.mount.devfs Ta Cm true
.It Va enforce_statfs Ta Cm 1
-.It Va name Ta Set to jail ID.
+.It Va name Ta set to jail ID
.It Va host.hostname Ta Va bootenv
-.It Va path Ta Set to a path in Pa /tmp
+.It Va path Ta set to a path in Pa /tmp
generated by
-.Xr libbe 3 .
+.Xr libbe 3
.El
.Pp
All default parameters may be overwritten.
@@ -298,8 +297,8 @@ or combination of
.It Fl a
Display all datasets.
.It Fl D
-Display the full space usage for each boot environment, assuming all
-other boot environments were destroyed.
+Display the full space usage for each boot environment,
+assuming all other boot environments were destroyed.
.It Fl H
Used for scripting.
Do not print headers and separate fields by a single tab instead of
@@ -351,8 +350,8 @@ will make a directory such as
.Pa be_mount.c6Sf
in
.Pa /tmp .
-Randomness in the last four characters of the directory name will prevent
-mount point conflicts.
+Randomness in the last four characters of the directory name
+will prevent mount point conflicts.
Unmount of an environment, followed by mount of the same environment
without giving a
.Ar mountpoint ,
@@ -362,7 +361,7 @@ Rename the given
.Ar origBeName
to the given
.Ar newBeName .
-The boot environment will not be unmounted in order for this rename to occur.
+The boot environment will not be unmounted for this rename to occur.
.It Cm ujail Brq Ar jailId | jailName | beName
.It Cm unjail Brq Ar jailId | jailName | beName
Destroy the jail created from the given boot environment.
@@ -390,8 +389,8 @@ boot environment layout, as created by the Auto ZFS option to
.Xr bsdinstall 8 ,
is a
.Dq shallow
-boot environment structure, where boot environment datasets do not have any
-directly subordinate datasets.
+boot environment structure, where boot environment datasets
+do not have any directly subordinate datasets.
Instead, they're organized off in
.Pa zroot/ROOT ,
and they rely on datasets elsewhere in the pool having
@@ -419,7 +418,8 @@ set to
.Dv off ,
thus files in
.Pa /usr
-typically fall into the boot environment because this dataset is not mounted.
+typically fall into the boot environment
+because this dataset is not mounted.
.Pa zroot/usr/src
is mounted, thus files in
.Pa /usr/src
@@ -445,8 +445,8 @@ Note that the subordinate datasets now have
.Dv canmount
set to
.Dv noauto .
-These are more obviously a part of the boot environment, as indicated by their
-positioning in the layout.
+These are more obviously a part of the boot environment,
+as indicated by their positioning in the layout.
These subordinate datasets will be mounted by the
.Dv zfsbe
.Xr rc 8
@@ -468,16 +468,25 @@ A future version of
may default to handling both styles and deprecate the various
.Fl r
flags.
-.\" .Sh EXAMPLES
-.\" .Bl -bullet
-.\" .It
+.Sh EXAMPLES
+Create a boot environment, named with today's date,
+containing snapshots of the root dataset and of all child datasets:
+.Pp
+.Dl bectl create -r `date +%Y%m%d`
+.Pp
+Mount a previous boot environment,
+.Ar yesterdaysbe ,
+to
+.Pa /mnt :
+.Pp
+.Dl bectl mount yesterdaysbe /mnt
.\" To fill in with jail upgrade example when behavior is firm.
-.\" .El
.Sh SEE ALSO
.Xr libbe 3 ,
.Xr zfsprops 7 ,
.Xr beinstall.sh 8 ,
.Xr jail 8 ,
+.Xr loader 8 ,
.Xr zfs 8 ,
.Xr zpool 8
.Sh HISTORY
diff --git a/sbin/devd/Makefile b/sbin/devd/Makefile
index 4ff0187a5a22..5d5721d16884 100644
--- a/sbin/devd/Makefile
+++ b/sbin/devd/Makefile
@@ -46,6 +46,11 @@ HYPERV+= hyperv.conf
HYPERVPACKAGE= hyperv-tools
.endif
+CONFGROUPS+= NVME
+NVMEDIR= ${DEVDDIR}
+NVME+= nvmf.conf
+NVMEPACKAGE= nvme-tools
+
.if ${MK_USB} != "no"
DEVD+= uath.conf ulpt.conf
.endif
diff --git a/sbin/devd/devd.conf.5 b/sbin/devd/devd.conf.5
index 4dbd7338edb1..baf4b9d3a183 100644
--- a/sbin/devd/devd.conf.5
+++ b/sbin/devd/devd.conf.5
@@ -38,7 +38,7 @@
.\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
.\" SOFTWARE.
.\"
-.Dd July 8, 2025
+.Dd July 9, 2025
.Dt DEVD.CONF 5
.Os
.Sh NAME
@@ -517,6 +517,8 @@ and
representing the start of a controller reset, the successful completion of a
controller reset, or a timeout while waiting for the controller to reset,
respectively.
+.It Li nvme Ta Li controller Ta Li RECONNECT Ta
+An NVMe over Fabrics host has disconnected and is requesting a reconnect.
.El
.Pp
.Bl -column "SYSTEM" "SUBSYSTEM" "SHUTDOWN-THRESHOLD" -compact
diff --git a/sbin/devd/nvmf.conf b/sbin/devd/nvmf.conf
new file mode 100644
index 000000000000..eaf3ebe86cec
--- /dev/null
+++ b/sbin/devd/nvmf.conf
@@ -0,0 +1,7 @@
+# Attempt to reconnect NVMeoF host devices when requested
+notify 100 {
+ match "system" "nvme";
+ match "subsystem" "controller";
+ match "type" "RECONNECT";
+ action "nvmecontrol reconnect $name";
+};
diff --git a/sbin/nvmecontrol/connect.c b/sbin/nvmecontrol/connect.c
index c1d5d2cbaf5a..3d6d12bf2c48 100644
--- a/sbin/nvmecontrol/connect.c
+++ b/sbin/nvmecontrol/connect.c
@@ -31,6 +31,8 @@ static struct options {
const char *subnqn;
const char *hostnqn;
uint32_t kato;
+ uint32_t reconnect_delay;
+ uint32_t controller_loss_timeout;
uint16_t num_io_queues;
uint16_t queue_size;
bool data_digests;
@@ -43,6 +45,8 @@ static struct options {
.subnqn = NULL,
.hostnqn = NULL,
.kato = NVMF_KATO_DEFAULT / 1000,
+ .reconnect_delay = NVMF_DEFAULT_RECONNECT_DELAY,
+ .controller_loss_timeout = NVMF_DEFAULT_CONTROLLER_LOSS,
.num_io_queues = 1,
.queue_size = 0,
.data_digests = false,
@@ -107,7 +111,7 @@ connect_nvm_controller(enum nvmf_trtype trtype, int adrfam, const char *address,
}
error = nvmf_handoff_host(dle, hostnqn, admin, opt.num_io_queues, io,
- &cdata);
+ &cdata, opt.reconnect_delay, opt.controller_loss_timeout);
if (error != 0) {
warnc(error, "Failed to handoff queues to kernel");
free(io);
@@ -259,6 +263,11 @@ static const struct opts connect_opts[] = {
"Number of entries in each I/O queue"),
OPT("keep-alive-tmo", 'k', arg_uint32, opt, kato,
"Keep Alive timeout (in seconds)"),
+ OPT("reconnect-delay", 'r', arg_uint32, opt, reconnect_delay,
+ "Delay between reconnect attempts after connection loss "
+ "(in seconds)"),
+ OPT("ctrl-loss-tmo", 'l', arg_uint32, opt, controller_loss_timeout,
+ "Controller loss timeout after connection loss (in seconds)"),
OPT("hostnqn", 'q', arg_string, opt, hostnqn,
"Host NQN"),
OPT("flow_control", 'F', arg_none, opt, flow_control,
diff --git a/sbin/nvmecontrol/nvmecontrol.8 b/sbin/nvmecontrol/nvmecontrol.8
index d886b60a2545..624a0c93719b 100644
--- a/sbin/nvmecontrol/nvmecontrol.8
+++ b/sbin/nvmecontrol/nvmecontrol.8
@@ -33,7 +33,7 @@
.\"
.\" Author: Jim Harris <jimharris@FreeBSD.org>
.\"
-.Dd April 29, 2025
+.Dd July 9, 2025
.Dt NVMECONTROL 8
.Os
.Sh NAME
@@ -216,6 +216,8 @@
.Op Fl c Ar cntl-id
.Op Fl i Ar queues
.Op Fl k Ar seconds
+.Op Fl l Ar seconds
+.Op Fl r Ar seconds
.Op Fl t Ar transport
.Op Fl q Ar HostNQN
.Op Fl Q Ar entries
@@ -226,6 +228,8 @@
.Op Fl FGg
.Op Fl i Ar queues
.Op Fl k Ar seconds
+.Op Fl l Ar seconds
+.Op Fl r Ar seconds
.Op Fl t Ar transport
.Op Fl q Ar HostNQN
.Op Fl Q Ar entries
@@ -241,6 +245,8 @@
.Op Fl FGg
.Op Fl i Ar queues
.Op Fl k Ar seconds
+.Op Fl l Ar seconds
+.Op Fl r Ar seconds
.Op Fl t Ar transport
.Op Fl q Ar HostNQN
.Op Fl Q Ar entries
@@ -786,6 +792,29 @@ The default is 1.
.It Fl k Ar seconds
Keep Alive timer duration in seconds.
The default is 120.
+.It Fl l Ar seconds
+Controller Loss timer duration in seconds.
+The default is 600.
+.Pp
+This timer starts when an association is lost with a remote I/O controller
+and is cancelled when a new association is established.
+If the timer expires, the controller device is deleted.
+A setting of zero disables this timer.
+.It Fl r Ar seconds
+Reconnect timer duration in seconds.
+The default is 10.
+.Pp
+When an association is lost with a remote I/O controller,
+the controller device will request reconnection via periodic
+.Xr devctl 4
+notifications until either a new association is established or the controller
+device is deleted.
+This timer sets the interval between each
+.Xr devctl 4
+notification.
+Note that the first notification is triggered immediately after an association
+is lost.
+A setting of zero disables this timer.
.It Fl t Ar transport
Transport to use.
The default is
diff --git a/sbin/nvmecontrol/reconnect.c b/sbin/nvmecontrol/reconnect.c
index adf1edac662b..06af40624177 100644
--- a/sbin/nvmecontrol/reconnect.c
+++ b/sbin/nvmecontrol/reconnect.c
@@ -27,6 +27,8 @@ static struct options {
const char *transport;
const char *hostnqn;
uint32_t kato;
+ uint32_t reconnect_delay;
+ uint32_t controller_loss_timeout;
uint16_t num_io_queues;
uint16_t queue_size;
bool data_digests;
@@ -37,6 +39,8 @@ static struct options {
.transport = "tcp",
.hostnqn = NULL,
.kato = NVMF_KATO_DEFAULT / 1000,
+ .reconnect_delay = NVMF_DEFAULT_RECONNECT_DELAY,
+ .controller_loss_timeout = NVMF_DEFAULT_CONTROLLER_LOSS,
.num_io_queues = 1,
.queue_size = 0,
.data_digests = false,
@@ -59,6 +63,7 @@ static int
reconnect_nvm_controller(int fd, const struct nvmf_association_params *aparams,
enum nvmf_trtype trtype, int adrfam, const char *address, const char *port,
uint16_t cntlid, const char *subnqn, const char *hostnqn, uint32_t kato,
+ uint32_t reconnect_delay, uint32_t controller_loss_timeout,
u_int num_io_queues, u_int queue_size,
const struct nvme_discovery_log_entry *dle)
{
@@ -88,7 +93,7 @@ reconnect_nvm_controller(int fd, const struct nvmf_association_params *aparams,
}
error = nvmf_reconnect_host(fd, dle, hostnqn, admin, num_io_queues, io,
- &cdata);
+ &cdata, reconnect_delay, controller_loss_timeout);
if (error != 0) {
warnc(error, "Failed to handoff queues to kernel");
free(io);
@@ -137,7 +142,8 @@ reconnect_by_address(int fd, const nvlist_t *rparams, const char *addr)
error = reconnect_nvm_controller(fd, &aparams, trtype, AF_UNSPEC,
address, port, le16toh(dle->cntlid), subnqn, hostnqn,
- opt.kato * 1000, opt.num_io_queues, opt.queue_size, NULL);
+ opt.kato * 1000, opt.reconnect_delay, opt.controller_loss_timeout,
+ opt.num_io_queues, opt.queue_size, NULL);
free(subnqn);
free(tofree);
return (error);
@@ -196,6 +202,8 @@ reconnect_by_params(int fd, const nvlist_t *rparams)
address, port, le16toh(dle->cntlid), dle->subnqn,
nvlist_get_string(rparams, "hostnqn"),
dnvlist_get_number(rparams, "kato", 0),
+ dnvlist_get_number(rparams, "reconnect_delay", 0),
+ dnvlist_get_number(rparams, "controller_loss_timeout", 0),
nvlist_get_number(rparams, "num_io_queues"),
nvlist_get_number(rparams, "io_qsize"), dle);
free(subnqn);
@@ -291,6 +299,11 @@ static const struct opts reconnect_opts[] = {
"Number of entries in each I/O queue"),
OPT("keep-alive-tmo", 'k', arg_uint32, opt, kato,
"Keep Alive timeout (in seconds)"),
+ OPT("reconnect-delay", 'r', arg_uint32, opt, reconnect_delay,
+ "Delay between reconnect attempts after connection loss "
+ "(in seconds)"),
+ OPT("ctrl-loss-tmo", 'l', arg_uint32, opt, controller_loss_timeout,
+ "Controller loss timeout after connection loss (in seconds)"),
OPT("hostnqn", 'q', arg_string, opt, hostnqn,
"Host NQN"),
OPT("flow_control", 'F', arg_none, opt, flow_control,
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index af1fb95398f8..28f461bf715d 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -95,7 +95,7 @@ static struct file {
int eof_reached;
int lineno;
int errors;
-} *file;
+} *file, *topfile;
struct file *pushfile(const char *, int);
int popfile(void);
int check_file_secrecy(int, const char *);
@@ -3905,7 +3905,7 @@ uid_item : uid {
$$->tail = $$;
}
| unaryop uid {
- if ($2 == UID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
+ if ($2 == -1 && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
yyerror("user unknown requires operator = or "
"!=");
YYERROR;
@@ -3920,7 +3920,7 @@ uid_item : uid {
$$->tail = $$;
}
| uid PORTBINARY uid {
- if ($1 == UID_MAX || $3 == UID_MAX) {
+ if ($1 == -1 || $3 == -1) {
yyerror("user unknown requires operator = or "
"!=");
YYERROR;
@@ -3938,7 +3938,7 @@ uid_item : uid {
uid : STRING {
if (!strcmp($1, "unknown"))
- $$ = UID_MAX;
+ $$ = -1;
else {
uid_t uid;
@@ -3983,7 +3983,7 @@ gid_item : gid {
$$->tail = $$;
}
| unaryop gid {
- if ($2 == GID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
+ if ($2 == -1 && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
yyerror("group unknown requires operator = or "
"!=");
YYERROR;
@@ -3998,7 +3998,7 @@ gid_item : gid {
$$->tail = $$;
}
| gid PORTBINARY gid {
- if ($1 == GID_MAX || $3 == GID_MAX) {
+ if ($1 == -1 || $3 == -1) {
yyerror("group unknown requires operator = or "
"!=");
YYERROR;
@@ -4016,7 +4016,7 @@ gid_item : gid {
gid : STRING {
if (!strcmp($1, "unknown"))
- $$ = GID_MAX;
+ $$ = -1;
else {
gid_t gid;
@@ -6743,7 +6743,7 @@ lgetc(int quotec)
if (quotec) {
if ((c = igetc()) == EOF) {
yyerror("reached end of file while parsing quoted string");
- if (popfile() == EOF)
+ if (file == topfile || popfile() == EOF)
return (EOF);
return (quotec);
}
@@ -6771,7 +6771,7 @@ lgetc(int quotec)
return ('\n');
}
while (c == EOF) {
- if (popfile() == EOF)
+ if (file == topfile || popfile() == EOF)
return (EOF);
c = igetc();
}
@@ -7069,17 +7069,17 @@ popfile(void)
{
struct file *prev;
- if ((prev = TAILQ_PREV(file, files, entry)) != NULL) {
+ if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
prev->errors += file->errors;
- TAILQ_REMOVE(&files, file, entry);
- fclose(file->stream);
- free(file->name);
- free(file->ungetbuf);
- free(file);
- file = prev;
- return (0);
- }
- return (EOF);
+
+ TAILQ_REMOVE(&files, file, entry);
+ fclose(file->stream);
+ free(file->name);
+ free(file->ungetbuf);
+ free(file);
+ file = prev;
+
+ return (file ? 0 : EOF);
}
int
@@ -7102,6 +7102,7 @@ parse_config(char *filename, struct pfctl *xpf)
warn("cannot open the main config file!");
return (-1);
}
+ topfile = file;
yyparse();
errors = file->errors;
diff --git a/sbin/pfctl/pfctl.8 b/sbin/pfctl/pfctl.8
index 28efff896956..508dcc6ea8d4 100644
--- a/sbin/pfctl/pfctl.8
+++ b/sbin/pfctl/pfctl.8
@@ -24,7 +24,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd July 2, 2025
+.Dd July 7, 2025
.Dt PFCTL 8
.Os
.Sh NAME
@@ -186,6 +186,13 @@ as the anchor name:
.Bd -literal -offset indent
# pfctl -a '*' -sr
.Ed
+.Pp
+To flush all rulesets and tables recursively, specify only
+.Sq *
+as the anchor name:
+.Bd -literal -offset indent
+# pfctl -a '*' -Fa
+.Ed
.It Fl D Ar macro Ns = Ns Ar value
Define
.Ar macro
@@ -231,6 +238,19 @@ for details.
.It Fl F Cm all
Flush all of the above.
.El
+.Pp
+If
+.Fl a
+is specified as well and
+.Ar anchor
+is terminated with a
+.Sq *
+character,
+.Cm rules ,
+.Cm Tables
+and
+.Cm all
+flush the given anchor recursively.
.It Fl f Ar file
Load the rules contained in
.Ar file .
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
index defba3b56c44..8d2b556d7085 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -59,6 +59,8 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <stdarg.h>
+#include <libgen.h>
#include "pfctl_parser.h"
#include "pfctl.h"
@@ -72,7 +74,7 @@ void pfctl_check_skip_ifaces(char *);
void pfctl_adjust_skip_ifaces(struct pfctl *);
void pfctl_clear_interface_flags(int, int);
void pfctl_flush_eth_rules(int, int, char *);
-void pfctl_flush_rules(int, int, char *);
+int pfctl_flush_rules(int, int, char *);
void pfctl_flush_nat(int, int, char *);
int pfctl_clear_altq(int, int);
void pfctl_clear_src_nodes(int, int);
@@ -124,6 +126,17 @@ int pfctl_load_ruleset(struct pfctl *, char *,
int pfctl_load_rule(struct pfctl *, char *, struct pfctl_rule *, int);
const char *pfctl_lookup_option(char *, const char * const *);
void pfctl_reset(int, int);
+int pfctl_walk_show(int, struct pfioc_ruleset *, void *);
+int pfctl_walk_get(int, struct pfioc_ruleset *, void *);
+int pfctl_walk_anchors(int, int, const char *,
+ int(*)(int, struct pfioc_ruleset *, void *), void *);
+struct pfr_anchors *
+ pfctl_get_anchors(int, char *, int);
+int pfctl_recurse(int, int, char *,
+ int(*)(int, int, struct pfr_anchoritem *));
+int pfctl_call_clearrules(int, int, struct pfr_anchoritem *);
+int pfctl_call_cleartables(int, int, struct pfr_anchoritem *);
+int pfctl_call_clearanchors(int, int, struct pfr_anchoritem *);
static struct pfctl_anchor_global pf_anchors;
struct pfctl_anchor pf_main_anchor;
@@ -151,6 +164,7 @@ int dev = -1;
struct pfctl_handle *pfh = NULL;
static int first_title = 1;
static int labels = 0;
+static int exit_val = 0;
#define INDENT(d, o) do { \
if (o) { \
@@ -269,6 +283,40 @@ usage(void)
exit(1);
}
+void
+pfctl_err(int opts, int eval, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ if ((opts & PF_OPT_IGNFAIL) == 0)
+ verr(eval, fmt, ap);
+ else
+ vwarn(fmt, ap);
+
+ va_end(ap);
+
+ exit_val = eval;
+}
+
+void
+pfctl_errx(int opts, int eval, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ if ((opts & PF_OPT_IGNFAIL) == 0)
+ verrx(eval, fmt, ap);
+ else
+ vwarnx(fmt, ap);
+
+ va_end(ap);
+
+ exit_val = eval;
+}
+
/*
* Cache protocol number to name translations.
*
@@ -361,7 +409,7 @@ pfctl_clear_stats(struct pfctl_handle *h, int opts)
{
int ret;
if ((ret = pfctl_clear_status(h)) != 0)
- errc(1, ret, "DIOCCLRSTATUS");
+ pfctl_err(opts, 1, "DIOCCLRSTATUS");
if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "pf: statistics cleared\n");
}
@@ -469,16 +517,19 @@ pfctl_flush_eth_rules(int dev, int opts, char *anchorname)
fprintf(stderr, "Ethernet rules cleared\n");
}
-void
+int
pfctl_flush_rules(int dev, int opts, char *anchorname)
{
int ret;
ret = pfctl_clear_rules(dev, anchorname);
- if (ret != 0)
- err(1, "pfctl_clear_rules");
- if ((opts & PF_OPT_QUIET) == 0)
+ if (ret != 0) {
+ pfctl_err(opts, 1, "%s", __func__);
+ return (1);
+ } else if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "rules cleared\n");
+
+ return (0);
}
void
@@ -515,7 +566,7 @@ void
pfctl_clear_src_nodes(int dev, int opts)
{
if (ioctl(dev, DIOCCLRSRCNODES))
- err(1, "DIOCCLRSRCNODES");
+ pfctl_err(opts, 1, "DIOCCLRSRCNODES");
if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "source tracking entries cleared\n");
}
@@ -530,13 +581,13 @@ pfctl_clear_iface_states(int dev, const char *iface, int opts)
memset(&kill, 0, sizeof(kill));
if (iface != NULL && strlcpy(kill.ifname, iface,
sizeof(kill.ifname)) >= sizeof(kill.ifname))
- errx(1, "invalid interface: %s", iface);
+ pfctl_errx(opts, 1, "invalid interface: %s", iface);
if (opts & PF_OPT_KILLMATCH)
kill.kill_match = true;
if ((ret = pfctl_clear_states_h(pfh, &kill, &killed)) != 0)
- errc(1, ret, "DIOCCLRSTATES");
+ pfctl_err(opts, 1, "DIOCCLRSTATUS");
if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "%d states cleared\n", killed);
}
@@ -687,7 +738,7 @@ pfctl_net_kill_states(int dev, const char *iface, int opts)
memset(&last_dst, 0xff, sizeof(last_dst));
if (iface != NULL && strlcpy(kill.ifname, iface,
sizeof(kill.ifname)) >= sizeof(kill.ifname))
- errx(1, "invalid interface: %s", iface);
+ pfctl_errx(opts, 1, "invalid interface: %s", iface);
if (state_killers == 2 && (strcmp(state_kill[0], "nat") == 0)) {
kill.nat = true;
@@ -740,13 +791,13 @@ pfctl_net_kill_states(int dev, const char *iface, int opts)
resp[1]->ai_addr);
if ((ret = pfctl_kill_states_h(pfh, &kill, &newkilled)) != 0)
- errc(1, ret, "DIOCKILLSTATES");
+ pfctl_errx(opts, 1, "DIOCKILLSTATES");
killed += newkilled;
}
freeaddrinfo(res[1]);
} else {
if ((ret = pfctl_kill_states_h(pfh, &kill, &newkilled)) != 0)
- errc(1, ret, "DIOCKILLSTATES");
+ pfctl_errx(opts, 1, "DIOCKILLSTATES");
killed += newkilled;
}
}
@@ -778,7 +829,7 @@ pfctl_gateway_kill_states(int dev, const char *iface, int opts)
memset(&last_src, 0xff, sizeof(last_src));
if (iface != NULL && strlcpy(kill.ifname, iface,
sizeof(kill.ifname)) >= sizeof(kill.ifname))
- errx(1, "invalid interface: %s", iface);
+ pfctl_errx(opts, 1, "invalid interface: %s", iface);
if (opts & PF_OPT_KILLMATCH)
kill.kill_match = true;
@@ -799,7 +850,7 @@ pfctl_gateway_kill_states(int dev, const char *iface, int opts)
copy_satopfaddr(&kill.rt_addr.addr.v.a.addr,
resp->ai_addr);
if (pfctl_kill_states_h(pfh, &kill, &newkilled))
- err(1, "DIOCKILLSTATES");
+ pfctl_errx(opts, 1, "DIOCKILLSTATES");
killed += newkilled;
}
@@ -823,7 +874,7 @@ pfctl_label_kill_states(int dev, const char *iface, int opts)
memset(&kill, 0, sizeof(kill));
if (iface != NULL && strlcpy(kill.ifname, iface,
sizeof(kill.ifname)) >= sizeof(kill.ifname))
- errx(1, "invalid interface: %s", iface);
+ pfctl_errx(opts, 1, "invalid interface: %s", iface);
if (opts & PF_OPT_KILLMATCH)
kill.kill_match = true;
@@ -833,7 +884,7 @@ pfctl_label_kill_states(int dev, const char *iface, int opts)
errx(1, "label too long: %s", state_kill[1]);
if ((ret = pfctl_kill_states_h(pfh, &kill, &killed)) != 0)
- errc(1, ret, "DIOCKILLSTATES");
+ pfctl_errx(opts, 1, "DIOCKILLSTATES");
if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "killed %d states\n", killed);
@@ -871,7 +922,7 @@ pfctl_id_kill_states(int dev, const char *iface, int opts)
}
if ((ret = pfctl_kill_states_h(pfh, &kill, &killed)) != 0)
- errc(1, ret, "DIOCKILLSTATES");
+ pfctl_errx(opts, 1, "DIOCKILLSTATES");
if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "killed %d states\n", killed);
@@ -895,7 +946,7 @@ pfctl_key_kill_states(int dev, const char *iface, int opts)
if (iface != NULL &&
strlcpy(kill.ifname, iface, sizeof(kill.ifname)) >=
sizeof(kill.ifname))
- errx(1, "invalid interface: %s", iface);
+ pfctl_errx(opts, 1, "invalid interface: %s", iface);
s = strdup(state_kill[1]);
if (!s)
@@ -931,7 +982,7 @@ pfctl_key_kill_states(int dev, const char *iface, int opts)
errx(1, "invalid host: %s", tokens[didx]);
if ((ret = pfctl_kill_states_h(pfh, &kill, &killed)) != 0)
- errc(1, ret, "DIOCKILLSTATES");
+ pfctl_errx(opts, 1, "DIOCKILLSTATES");
if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "killed %d states\n", killed);
@@ -2038,8 +2089,8 @@ pfctl_load_ruleset(struct pfctl *pf, char *path, struct pfctl_ruleset *rs,
if ((pf->opts & PF_OPT_NOACTION) == 0 &&
(error = pfctl_ruleset_trans(pf,
path, rs->anchor, false))) {
- printf("pfctl_load_rulesets: "
- "pfctl_ruleset_trans %d\n", error);
+ printf("%s: "
+ "pfctl_ruleset_trans %d\n", __func__, error);
goto error;
}
} else if (pf->opts & PF_OPT_VERBOSE)
@@ -2805,7 +2856,7 @@ pfctl_set_interface_flags(struct pfctl *pf, char *ifname, int flags, int how)
if ((pf->opts & PF_OPT_NOACTION) == 0) {
if (how == 0) {
if (ioctl(pf->dev, DIOCCLRIFFLAG, &pi))
- err(1, "DIOCCLRIFFLAG");
+ pfctl_err(pf->opts, 1, "DIOCCLRIFFLAG");
} else {
if (ioctl(pf->dev, DIOCSETIFFLAG, &pi))
err(1, "DIOCSETIFFLAG");
@@ -2864,17 +2915,56 @@ pfctl_test_altqsupport(int dev, int opts)
}
int
-pfctl_show_anchors(int dev, int opts, char *anchorname)
+pfctl_walk_show(int opts, struct pfioc_ruleset *pr, void *warg)
+{
+ if (pr->path[0]) {
+ if (pr->path[0] != '_' || (opts & PF_OPT_VERBOSE))
+ printf(" %s/%s\n", pr->path, pr->name);
+ } else if (pr->name[0] != '_' || (opts & PF_OPT_VERBOSE))
+ printf(" %s\n", pr->name);
+
+ return (0);
+}
+
+int
+pfctl_walk_get(int opts, struct pfioc_ruleset *pr, void *warg)
+{
+ struct pfr_anchoritem *pfra;
+ struct pfr_anchors *anchors;
+ int e;
+
+ anchors = (struct pfr_anchors *)warg;
+
+ pfra = malloc(sizeof(*pfra));
+ if (pfra == NULL)
+ err(1, "%s", __func__);
+
+ if (pr->path[0])
+ e = asprintf(&pfra->pfra_anchorname, "%s/%s", pr->path,
+ pr->name);
+ else
+ e = asprintf(&pfra->pfra_anchorname, "%s", pr->name);
+
+ if (e == -1)
+ err(1, "%s", __func__);
+
+ SLIST_INSERT_HEAD(anchors, pfra, pfra_sle);
+
+ return (0);
+}
+
+int
+pfctl_walk_anchors(int dev, int opts, const char *anchor,
+ int(walkf)(int, struct pfioc_ruleset *, void *), void *warg)
{
struct pfioc_ruleset pr;
u_int32_t mnr, nr;
int ret;
memset(&pr, 0, sizeof(pr));
- if ((ret = pfctl_get_rulesets(pfh, anchorname, &mnr)) != 0) {
+ if ((ret = pfctl_get_rulesets(pfh, anchor, &mnr)) != 0) {
if (ret == EINVAL)
- fprintf(stderr, "Anchor '%s' not found.\n",
- anchorname);
+ fprintf(stderr, "Anchor '%s' not found.\n", anchor);
else
errc(1, ret, "DIOCGETRULESETS");
return (-1);
@@ -2882,25 +2972,123 @@ pfctl_show_anchors(int dev, int opts, char *anchorname)
for (nr = 0; nr < mnr; ++nr) {
char sub[MAXPATHLEN];
- if ((ret = pfctl_get_ruleset(pfh, anchorname, nr, &pr)) != 0)
+ if ((ret = pfctl_get_ruleset(pfh, anchor, nr, &pr)) != 0)
errc(1, ret, "DIOCGETRULESET");
if (!strcmp(pr.name, PF_RESERVED_ANCHOR))
continue;
sub[0] = '\0';
- if (pr.path[0]) {
- strlcat(sub, pr.path, sizeof(sub));
- strlcat(sub, "/", sizeof(sub));
- }
- strlcat(sub, pr.name, sizeof(sub));
- if (sub[0] != '_' || (opts & PF_OPT_VERBOSE))
- printf(" %s\n", sub);
- if ((opts & PF_OPT_VERBOSE) && pfctl_show_anchors(dev, opts, sub))
+ if (walkf(opts, &pr, warg))
+ return (-1);
+
+ if (pr.path[0])
+ snprintf(sub, sizeof(sub), "%s/%s", pr.path, pr.name);
+ else
+ snprintf(sub, sizeof(sub), "%s", pr.name);
+ if (pfctl_walk_anchors(dev, opts, sub, walkf, warg))
return (-1);
}
return (0);
}
int
+pfctl_show_anchors(int dev, int opts, char *anchor)
+{
+ return (
+ pfctl_walk_anchors(dev, opts, anchor, pfctl_walk_show, NULL));
+}
+
+struct pfr_anchors *
+pfctl_get_anchors(int dev, char *anchor, int opts)
+{
+ struct pfioc_ruleset pr;
+ static struct pfr_anchors anchors;
+ char *n;
+
+ SLIST_INIT(&anchors);
+
+ memset(&pr, 0, sizeof(pr));
+ if (*anchor != '\0') {
+ n = dirname(anchor);
+ if (n[0] != '.' && n[1] != '\0')
+ strlcpy(pr.path, n, sizeof(pr.path));
+ n = basename(anchor);
+ if (n != NULL)
+ strlcpy(pr.name, n, sizeof(pr.name));
+ }
+
+ /* insert a root anchor first. */
+ pfctl_walk_get(opts, &pr, &anchors);
+
+ if (pfctl_walk_anchors(dev, opts, anchor, pfctl_walk_get, &anchors))
+ errx(1, "%s failed to retrieve list of anchors, can't continue",
+ __func__);
+
+ return (&anchors);
+}
+
+int
+pfctl_call_cleartables(int dev, int opts, struct pfr_anchoritem *pfra)
+{
+ /*
+ * PF_OPT_QUIET makes pfctl_clear_tables() to stop printing number of
+ * tables cleared for given anchor.
+ */
+ opts |= PF_OPT_QUIET;
+ return ((pfctl_do_clear_tables(pfra->pfra_anchorname, opts) == -1) ?
+ 1 : 0);
+}
+
+int
+pfctl_call_clearrules(int dev, int opts, struct pfr_anchoritem *pfra)
+{
+ /*
+ * PF_OPT_QUIET makes pfctl_clear_rules() to stop printing a 'rules
+ * cleared' message for every anchor it deletes.
+ */
+ opts |= PF_OPT_QUIET;
+ return (pfctl_flush_rules(dev, opts, pfra->pfra_anchorname));
+}
+
+int
+pfctl_call_clearanchors(int dev, int opts, struct pfr_anchoritem *pfra)
+{
+ int rv = 0;
+
+ rv |= pfctl_call_cleartables(dev, opts, pfra);
+ rv |= pfctl_call_clearrules(dev, opts, pfra);
+
+ return (rv);
+}
+
+int
+pfctl_recurse(int dev, int opts, char *anchorname,
+ int(*walkf)(int, int, struct pfr_anchoritem *))
+{
+ int rv = 0;
+ struct pfr_anchors *anchors;
+ struct pfr_anchoritem *pfra, *pfra_save;
+
+ anchors = pfctl_get_anchors(dev, anchorname, opts);
+ /*
+ * While traversing the list, pfctl_clear_*() must always return
+ * so that failures on one anchor do not prevent clearing others.
+ */
+ opts |= PF_OPT_IGNFAIL;
+ printf("Removing:\n");
+ SLIST_FOREACH_SAFE(pfra, anchors, pfra_sle, pfra_save) {
+ printf(" %s\n",
+ (*pfra->pfra_anchorname == '\0') ? "/" :
+ pfra->pfra_anchorname);
+ rv |= walkf(dev, opts, pfra);
+ SLIST_REMOVE(anchors, pfra, pfr_anchoritem, pfra_sle);
+ free(pfra->pfra_anchorname);
+ free(pfra);
+ }
+
+ return (rv);
+}
+
+int
pfctl_show_eth_anchors(int dev, int opts, char *anchorname)
{
struct pfctl_eth_rulesets_info ri;
@@ -2990,7 +3178,6 @@ pfctl_reset(int dev, int opts)
int
main(int argc, char *argv[])
{
- int error = 0;
int ch;
int mode = O_RDONLY;
int opts = 0;
@@ -3218,7 +3405,7 @@ main(int argc, char *argv[])
if (opts & PF_OPT_DISABLE)
if (pfctl_disable(dev, opts))
- error = 1;
+ exit_val = 1;
if ((path = calloc(1, MAXPATHLEN)) == NULL)
errx(1, "%s: calloc", __func__);
@@ -3259,7 +3446,7 @@ main(int argc, char *argv[])
pfctl_show_status(dev, opts);
break;
case 'R':
- error = pfctl_show_running(dev);
+ exit_val = pfctl_show_running(dev);
break;
case 't':
pfctl_show_timeouts(dev, opts);
@@ -3321,7 +3508,11 @@ main(int argc, char *argv[])
pfctl_flush_eth_rules(dev, opts, anchorname);
break;
case 'r':
- pfctl_flush_rules(dev, opts, anchorname);
+ if (opts & PF_OPT_RECURSE)
+ pfctl_recurse(dev, opts, anchorname,
+ pfctl_call_clearrules);
+ else
+ pfctl_flush_rules(dev, opts, anchorname);
break;
case 'n':
pfctl_flush_nat(dev, opts, anchorname);
@@ -3347,7 +3538,13 @@ main(int argc, char *argv[])
pfctl_flush_eth_rules(dev, opts, anchorname);
pfctl_flush_rules(dev, opts, anchorname);
pfctl_flush_nat(dev, opts, anchorname);
- pfctl_do_clear_tables(anchorname, opts);
+ if (opts & PF_OPT_RECURSE)
+ pfctl_recurse(dev, opts, anchorname,
+ pfctl_call_clearanchors);
+ else {
+ pfctl_do_clear_tables(anchorname, opts);
+ pfctl_flush_rules(dev, opts, anchorname);
+ }
if (!*anchorname) {
pfctl_clear_altq(dev, opts);
pfctl_clear_iface_states(dev, ifaceopt, opts);
@@ -3361,7 +3558,11 @@ main(int argc, char *argv[])
pfctl_clear_fingerprints(dev, opts);
break;
case 'T':
- pfctl_do_clear_tables(anchorname, opts);
+ if ((opts & PF_OPT_RECURSE) == 0)
+ pfctl_do_clear_tables(anchorname, opts);
+ else
+ pfctl_recurse(dev, opts, anchorname,
+ pfctl_call_cleartables);
break;
case 'R':
pfctl_reset(dev, opts);
@@ -3385,7 +3586,7 @@ main(int argc, char *argv[])
pfctl_kill_src_nodes(dev, opts);
if (tblcmdopt != NULL) {
- error = pfctl_table(argc, argv, tableopt,
+ exit_val = pfctl_table(argc, argv, tableopt,
tblcmdopt, rulesopt, anchorname, opts);
rulesopt = NULL;
}
@@ -3411,17 +3612,17 @@ main(int argc, char *argv[])
if (rulesopt != NULL && !(opts & PF_OPT_MERGE) &&
!anchorname[0] && (loadopt & PFCTL_FLAG_OPTION))
if (pfctl_file_fingerprints(dev, opts, PF_OSFP_FILE))
- error = 1;
+ exit_val = 1;
if (rulesopt != NULL) {
if (pfctl_rules(dev, rulesopt, opts, optimize,
anchorname, NULL))
- error = 1;
+ exit_val = 1;
}
if (opts & PF_OPT_ENABLE)
if (pfctl_enable(dev, opts))
- error = 1;
+ exit_val = 1;
if (debugopt != NULL) {
switch (*debugopt) {
@@ -3440,5 +3641,5 @@ main(int argc, char *argv[])
}
}
- exit(error);
+ exit(exit_val);
}
diff --git a/sbin/pfctl/pfctl.h b/sbin/pfctl/pfctl.h
index d8196c129187..5b5b3d3e5fff 100644
--- a/sbin/pfctl/pfctl.h
+++ b/sbin/pfctl/pfctl.h
@@ -55,6 +55,13 @@ struct pfr_buffer {
(var) != NULL; \
(var) = pfr_buf_next((buf), (var)))
+struct pfr_anchoritem {
+ SLIST_ENTRY(pfr_anchoritem) pfra_sle;
+ char *pfra_anchorname;
+};
+
+SLIST_HEAD(pfr_anchors, pfr_anchoritem);
+
int pfr_get_fd(void);
int pfr_add_table(struct pfr_table *, int *, int);
int pfr_del_table(struct pfr_table *, int *, int);
@@ -81,7 +88,7 @@ int pfi_get_ifaces(const char *, struct pfi_kif *, int *);
int pfi_clr_istats(const char *, int *, int);
void pfctl_print_title(char *);
-void pfctl_do_clear_tables(const char *, int);
+int pfctl_do_clear_tables(const char *, int);
void pfctl_show_tables(const char *, int);
int pfctl_table(int, char *[], char *, const char *, char *,
const char *, int);
@@ -150,4 +157,7 @@ void expand_label(char *, size_t, struct pfctl_rule *);
const char *pfctl_proto2name(int);
+void pfctl_err(int, int, const char *, ...);
+void pfctl_errx(int, int, const char *, ...);
+
#endif /* _PFCTL_H_ */
diff --git a/sbin/pfctl/pfctl_optimize.c b/sbin/pfctl/pfctl_optimize.c
index b58bace326c2..e727324bbf40 100644
--- a/sbin/pfctl/pfctl_optimize.c
+++ b/sbin/pfctl/pfctl_optimize.c
@@ -273,7 +273,10 @@ pfctl_optimize_ruleset(struct pfctl *pf, struct pfctl_ruleset *rs)
struct pfctl_rule *r;
struct pfctl_rulequeue *old_rules;
- DEBUG("optimizing ruleset");
+ if (TAILQ_EMPTY(rs->rules[PF_RULESET_FILTER].active.ptr))
+ return (0);
+
+ DEBUG("optimizing ruleset \"%s\"", rs->anchor->path);
memset(&table_buffer, 0, sizeof(table_buffer));
skip_init();
TAILQ_INIT(&opt_queue);
diff --git a/sbin/pfctl/pfctl_osfp.c b/sbin/pfctl/pfctl_osfp.c
index 3a94c2e8c81b..5770c8343a46 100644
--- a/sbin/pfctl/pfctl_osfp.c
+++ b/sbin/pfctl/pfctl_osfp.c
@@ -264,7 +264,7 @@ void
pfctl_clear_fingerprints(int dev, int opts)
{
if (ioctl(dev, DIOCOSFPFLUSH))
- err(1, "DIOCOSFPFLUSH");
+ pfctl_err(opts, 1, "DIOCOSFPFLUSH");
}
/* flush pfctl's view of the fingerprints */
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
index 26a213c3ffd9..bd2c10c8080f 100644
--- a/sbin/pfctl/pfctl_parser.c
+++ b/sbin/pfctl/pfctl_parser.c
@@ -68,7 +68,7 @@
void print_op (u_int8_t, const char *, const char *);
void print_port (u_int8_t, u_int16_t, u_int16_t, const char *, int);
-void print_ugid (u_int8_t, unsigned, unsigned, const char *, unsigned);
+void print_ugid (u_int8_t, id_t, id_t, const char *);
void print_flags (uint16_t);
void print_fromto(struct pf_rule_addr *, pf_osfp_t,
struct pf_rule_addr *, sa_family_t, u_int8_t, int, int);
@@ -364,14 +364,14 @@ print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, const char *proto, int numer
}
void
-print_ugid(u_int8_t op, unsigned u1, unsigned u2, const char *t, unsigned umax)
+print_ugid(u_int8_t op, id_t i1, id_t i2, const char *t)
{
char a1[11], a2[11];
- snprintf(a1, sizeof(a1), "%u", u1);
- snprintf(a2, sizeof(a2), "%u", u2);
+ snprintf(a1, sizeof(a1), "%ju", (uintmax_t)i1);
+ snprintf(a2, sizeof(a2), "%ju", (uintmax_t)i2);
printf(" %s", t);
- if (u1 == umax && (op == PF_OP_EQ || op == PF_OP_NE))
+ if (i1 == -1 && (op == PF_OP_EQ || op == PF_OP_NE))
print_op(op, "unknown", a2);
else
print_op(op, a1, a2);
@@ -977,11 +977,9 @@ print_rule(struct pfctl_rule *r, const char *anchor_call, int verbose, int numer
printf(" %sreceived-on %s", r->rcvifnot ? "!" : "",
r->rcv_ifname);
if (r->uid.op)
- print_ugid(r->uid.op, r->uid.uid[0], r->uid.uid[1], "user",
- UID_MAX);
+ print_ugid(r->uid.op, r->uid.uid[0], r->uid.uid[1], "user");
if (r->gid.op)
- print_ugid(r->gid.op, r->gid.gid[0], r->gid.gid[1], "group",
- GID_MAX);
+ print_ugid(r->gid.op, r->gid.gid[0], r->gid.gid[1], "group");
if (r->flags || r->flagset) {
printf(" flags ");
print_flags(r->flags);
diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h
index b91d37c791ae..778105c2b96d 100644
--- a/sbin/pfctl/pfctl_parser.h
+++ b/sbin/pfctl/pfctl_parser.h
@@ -55,6 +55,7 @@
#define PF_OPT_RECURSE 0x04000
#define PF_OPT_KILLMATCH 0x08000
#define PF_OPT_NODNS 0x10000
+#define PF_OPT_IGNFAIL 0x20000
#define PF_NAT_PROXY_PORT_LOW 50001
#define PF_NAT_PROXY_PORT_HIGH 65535
diff --git a/sbin/pfctl/pfctl_table.c b/sbin/pfctl/pfctl_table.c
index 0842b042df41..0b52f88eafbb 100644
--- a/sbin/pfctl/pfctl_table.c
+++ b/sbin/pfctl/pfctl_table.c
@@ -79,7 +79,8 @@ static const char *istats_text[2][2][2] = {
if ((!(opts & PF_OPT_NOACTION) || \
(opts & PF_OPT_DUMMYACTION)) && \
(fct)) { \
- radix_perror(); \
+ if ((opts & PF_OPT_RECURSE) == 0) \
+ radix_perror(); \
goto _error; \
} \
} while (0)
@@ -103,11 +104,17 @@ static const char *istats_text[2][2][2] = {
table.pfrt_flags &= ~PFR_TFLAG_PERSIST; \
} while(0)
-void
+int
pfctl_do_clear_tables(const char *anchor, int opts)
{
- if (pfctl_table(0, NULL, NULL, "-F", NULL, anchor, opts))
- exit(1);
+ int rv;
+
+ if ((rv = pfctl_table(0, NULL, NULL, "-F", NULL, anchor, opts)) == -1) {
+ if ((opts & PF_OPT_IGNFAIL) == 0)
+ exit(1);
+ }
+
+ return (rv);
}
void
diff --git a/sbin/pfctl/tests/macro.sh b/sbin/pfctl/tests/macro.sh
index 9c48dbbc69f0..071c6cb4f426 100755
--- a/sbin/pfctl/tests/macro.sh
+++ b/sbin/pfctl/tests/macro.sh
@@ -3,6 +3,7 @@ atf_test_case "space" cleanup
space_head()
{
atf_set descr "Test macros with spaces"
+ atf_set require.kmods "pf"
}
space_body()
diff --git a/sbin/pfctl/tests/pfctl_test.c b/sbin/pfctl/tests/pfctl_test.c
index dbdcaa4900ea..5f0aa7826bb4 100644
--- a/sbin/pfctl/tests/pfctl_test.c
+++ b/sbin/pfctl/tests/pfctl_test.c
@@ -65,24 +65,6 @@
* Copied from OpenBSD.
*/
-static bool
-check_pf_module_available(void)
-{
- int modid;
- struct module_stat stat;
-
- if ((modid = modfind("pf")) < 0) {
- warn("pf module not found");
- return false;
- }
- stat.version = sizeof(struct module_stat);
- if (modstat(modid, &stat) < 0) {
- warn("can't stat pf module id %d", modid);
- return false;
- }
- return (true);
-}
-
extern char **environ;
static struct sbuf *
@@ -185,9 +167,6 @@ run_pfctl_test(const char *input_path, const char *output_path,
struct sbuf *expected_output;
struct sbuf *real_output;
- if (!check_pf_module_available())
- atf_tc_skip("pf(4) is not loaded");
-
/* The test inputs need to be able to use relative includes. */
snprintf(input_files_path, sizeof(input_files_path), "%s/files",
atf_tc_get_config_var(tc, "srcdir"));
@@ -292,6 +271,7 @@ do_selfpf_test(const char *number, const atf_tc_t *tc)
ATF_TC_HEAD(pf##number, tc) \
{ \
atf_tc_set_md_var(tc, "descr", descr); \
+ atf_tc_set_md_var(tc, "require.kmods", "pf"); \
} \
ATF_TC_BODY(pf##number, tc) \
{ \
@@ -301,6 +281,7 @@ do_selfpf_test(const char *number, const atf_tc_t *tc)
ATF_TC_HEAD(selfpf##number, tc) \
{ \
atf_tc_set_md_var(tc, "descr", "Self " descr); \
+ atf_tc_set_md_var(tc, "require.kmods", "pf"); \
} \
ATF_TC_BODY(selfpf##number, tc) \
{ \
@@ -312,6 +293,7 @@ do_selfpf_test(const char *number, const atf_tc_t *tc)
ATF_TC_HEAD(pf##number, tc) \
{ \
atf_tc_set_md_var(tc, "descr", descr); \
+ atf_tc_set_md_var(tc, "require.kmods", "pf"); \
} \
ATF_TC_BODY(pf##number, tc) \
{ \
@@ -325,6 +307,7 @@ do_selfpf_test(const char *number, const atf_tc_t *tc)
atf_tc_set_md_var(tc, "descr", descr); \
atf_tc_set_md_var(tc, "execenv", "jail"); \
atf_tc_set_md_var(tc, "execenv.jail.params", "vnet"); \
+ atf_tc_set_md_var(tc, "require.kmods", "pf"); \
} \
ATF_TC_BODY(pf##number, tc) \
{ \
diff --git a/share/examples/Makefile b/share/examples/Makefile
index f0c050a36306..0a65b8c40d39 100644
--- a/share/examples/Makefile
+++ b/share/examples/Makefile
@@ -10,7 +10,6 @@ LDIRS= BSD_daemon \
FreeBSD_version \
bootforth \
csh \
- drivers \
etc \
find_interface \
flua \
@@ -74,12 +73,6 @@ SE_DIRS+= csh
SE_CSHPACKAGE= csh
SE_CSH= dot.cshrc
-SE_DIRS+= drivers
-SE_DRIVERS= \
- README \
- make_device_driver.sh \
- make_pseudo_driver.sh
-
SE_DIRS+= etc
SE_ETC= \
README.examples \
diff --git a/share/examples/drivers/README b/share/examples/drivers/README
deleted file mode 100644
index 8628029a62f8..000000000000
--- a/share/examples/drivers/README
+++ /dev/null
@@ -1,42 +0,0 @@
-
-Author: Julian Elischer
-
-The files in this directory are shell scripts.
-
-They will, when run, create an example skeleton driver
-for you. You can use this driver as a starting point for
-writing drivers for your own devices. They have all the hooks needed
-for initialization, probing, attaching, as well as DEVFS
-node creation. They also create sample ioctl commands and a sample
-ioctl definition .h file in /sys/sys. In other words they are fully
-functional in a 'skeleton' sort of a way. They support multiple devices
-so that you may have several of your 'foobar' devices probed and attached
-at once.
-
-I expect that these scripts will improve with time.
-
-At present these scripts also link the newly created driver into
-the kernel sources in /sys. Possibly a better way would be
-to make them interactive. (and ask what kernel tree to use as well as
-a name for the driver.).
-
-There are presently two scripts.
-One for making a real device driver for ISA devices, and
-one for making a device driver for pseudo devices (e.g. /dev/null).
-Hopefully they will be joined by similar scripts for creating
-skeletons for PCI devices as well.
-
-Give them a single argument: the name of the driver.
-They will use this given name in many places within the driver,
-both in lower and upper case form. (conforming to normal usage).
-
-The skeleton driver should already link with the kernel
-and in fact the shell script will compile a kernel with the new
-drive linked in.. The new kernel should still be
-runnable and the new driver should be
-fully callable (once you get your device to probe).
-You should simply edit the driver and continue to use
-'make' (as done in the script) until your driver does what you want.
-
-The driver will end up in /sys/i386/isa for the device driver script,
-and in /sys/dev for the pseudo driver script.
diff --git a/share/examples/drivers/make_pseudo_driver.sh b/share/examples/drivers/make_pseudo_driver.sh
deleted file mode 100644
index 5d6d09aa9648..000000000000
--- a/share/examples/drivers/make_pseudo_driver.sh
+++ /dev/null
@@ -1,435 +0,0 @@
-#!/bin/sh
-# This writes a skeleton driver and puts it into the kernel tree for you
-#
-# arg1 is lowercase "foo"
-# arg2 path to the kernel sources, "/sys" if omitted
-#
-# Trust me, RUN THIS SCRIPT :)
-#
-#
-#-------cut here------------------
-
-if [ "${1}X" = "X" ]
-then
- echo "Hey , how about some help here.. give me a device name!"
- exit 1
-fi
-if [ "X${2}" = "X" ]; then
- TOP=`cd /sys; pwd -P`
- echo "Using ${TOP} as the path to the kernel sources!"
-else
- TOP=${2}
-fi
-
-for i in "" "conf" "i386" "i386/conf" "dev" "sys" "modules"
-do
- if [ -d ${TOP}/${i} ]
- then
- continue
- fi
- echo "${TOP}/${i}: no such directory."
- echo "Please, correct the error and try again."
- exit 1
-done
-
-UPPER=`echo ${1} |tr "[:lower:]" "[:upper:]"`
-
-if [ -d ${TOP}/modules/${1} ]; then
- echo "There appears to already be a module called ${1}"
- echo -n "Should it be overwritten? [Y]"
- read VAL
- if [ "-z" "$VAL" ]; then
- VAL=YES
- fi
- case ${VAL} in
- [yY]*)
- echo "Cleaning up from prior runs"
- rm -rf ${TOP}/dev/${1}
- rm -rf ${TOP}/modules/${1}
- rm ${TOP}/conf/files.${UPPER}
- rm ${TOP}/i386/conf/${UPPER}
- rm ${TOP}/sys/${1}io.h
- ;;
- *)
- exit 1
- ;;
- esac
-fi
-
-echo "The following files will be created:"
-echo ${TOP}/modules/${1}
-echo ${TOP}/conf/files.${UPPER}
-echo ${TOP}/i386/conf/${UPPER}
-echo ${TOP}/dev/${1}
-echo ${TOP}/dev/${1}/${1}.c
-echo ${TOP}/sys/${1}io.h
-echo ${TOP}/modules/${1}
-echo ${TOP}/modules/${1}/Makefile
-
-mkdir ${TOP}/modules/${1}
-
-cat >${TOP}/conf/files.${UPPER} <<DONE
-dev/${1}/${1}.c optional ${1}
-DONE
-
-cat >${TOP}/i386/conf/${UPPER} <<DONE
-# Configuration file for kernel type: ${UPPER}
-
-files "${TOP}/conf/files.${UPPER}"
-
-include GENERIC
-
-ident ${UPPER}
-
-# trust me, you'll need this
-options KDB
-options DDB
-device ${1}
-DONE
-
-if [ ! -d ${TOP}/dev/${1} ]; then
- mkdir -p ${TOP}/dev/${1}
-fi
-
-cat >${TOP}/dev/${1}/${1}.c <<DONE
-/*
- * Copyright (c) [year] [your name]
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * ${1} driver
- */
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/kernel.h> /* SYSINIT stuff */
-#include <sys/uio.h> /* SYSINIT stuff */
-#include <sys/conf.h> /* cdevsw stuff */
-#include <sys/malloc.h> /* malloc region definitions */
-#include <sys/proc.h>
-#include <sys/${1}io.h> /* ${1} IOCTL definitions */
-
-#include <machine/clock.h> /* DELAY() */
-
-#define N${UPPER} 3 /* defines number of instances */
-
-/* XXX These should be defined in terms of bus-space ops. */
-#define ${UPPER}_INB(port) inb(port)
-#define ${UPPER}_OUTB(port, val) (port, (val))
-
-/* Function prototypes (these should all be static) */
-static d_open_t ${1}open;
-static d_close_t ${1}close;
-static d_read_t ${1}read;
-static d_write_t ${1}write;
-static d_ioctl_t ${1}ioctl;
-static d_mmap_t ${1}mmap;
-static d_poll_t ${1}poll;
-
-#define CDEV_MAJOR 20
-static struct cdevsw ${1}_cdevsw = {
- .d_version = D_VERSION,
- .d_open = ${1}open,
- .d_close = ${1}close,
- .d_read = ${1}read,
- .d_write = ${1}write,
- .d_ioctl = ${1}ioctl,
- .d_poll = ${1}poll,
- .d_mmap = ${1}mmap,
- .d_name = "${1}",
-};
-
-/*
- * device specific Misc defines
- */
-#define BUFFERSIZE 1024
-#define UNIT(dev) dev2unit(dev) /* assume one minor number per unit */
-
-/*
- * One of these per allocated device
- */
-struct ${1}_softc {
- u_long iobase;
- char buffer[BUFFERSIZE];
- struct cdev *dev;
-};
-
-typedef struct ${1}_softc *sc_p;
-
-static sc_p sca[N${UPPER}];
-
-/*
- * Macro to check that the unit number is valid
- * Often this isn't needed as once the open() is performed,
- * the unit number is pretty much safe.. The exception would be if we
- * implemented devices that could "go away". in which case all these routines
- * would be wise to check the number, DIAGNOSTIC or not.
- */
-#define CHECKUNIT(RETVAL) \
-do { /* the do-while is a safe way to do this grouping */ \
- if (unit > N${UPPER}) { \
- printf("%s: bad unit %d\n", __func__, unit); \
- return (RETVAL); \
- } \
- if (scp == NULL) { \
- printf("%s: unit %d not attached\n", __func__, unit); \
- return (RETVAL); \
- } \
-} while (0)
-
-#ifdef DIAGNOSTIC
-#define CHECKUNIT_DIAG(RETVAL) CHECKUNIT(RETVAL)
-#else /* DIAGNOSTIC */
-#define CHECKUNIT_DIAG(RETVAL)
-#endif /* DIAGNOSTIC */
-
-static int
-${1}ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
-{
- int unit = UNIT(dev);
- sc_p scp = sca[unit];
-
- CHECKUNIT_DIAG(ENXIO);
-
- switch (cmd) {
- case DHIOCRESET:
- /* whatever resets it */
- (void)scp; /* Delete this line after using scp. */
-#if 0
- ${UPPER}_OUTB(scp->iobase, 0xff);
-#endif
- break;
- default:
- return ENXIO;
- }
- return (0);
-}
-
-/*
- * You also need read, write, open, close routines.
- * This should get you started
- */
-static int
-${1}open(struct cdev *dev, int oflags, int devtype, struct thread *td)
-{
- int unit = UNIT(dev);
- sc_p scp = sca[unit];
-
- CHECKUNIT(ENXIO);
-
- (void)scp; /* Delete this line after using scp. */
- /*
- * Do processing
- */
- return (0);
-}
-
-static int
-${1}close(struct cdev *dev, int fflag, int devtype, struct thread *td)
-{
- int unit = UNIT(dev);
- sc_p scp = sca[unit];
-
- CHECKUNIT_DIAG(ENXIO);
-
- (void)scp; /* Delete this line after using scp. */
- /*
- * Do processing
- */
- return (0);
-}
-
-static int
-${1}read(struct cdev *dev, struct uio *uio, int ioflag)
-{
- int unit = UNIT(dev);
- sc_p scp = sca[unit];
- int toread;
-
-
- CHECKUNIT_DIAG(ENXIO);
-
- /*
- * Do processing
- * read from buffer
- */
- toread = (min(uio->uio_resid, sizeof(scp->buffer)));
- return(uiomove(scp->buffer, toread, uio));
-}
-
-static int
-${1}write(struct cdev *dev, struct uio *uio, int ioflag)
-{
- int unit = UNIT(dev);
- sc_p scp = sca[unit];
- int towrite;
-
- CHECKUNIT_DIAG(ENXIO);
-
- /*
- * Do processing
- * write to buffer
- */
- towrite = (min(uio->uio_resid, sizeof(scp->buffer)));
- return(uiomove(scp->buffer, towrite, uio));
-}
-
-static int
-${1}mmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
-{
- int unit = UNIT(dev);
- sc_p scp = sca[unit];
-
- CHECKUNIT_DIAG(-1);
-
- (void)scp; /* Delete this line after using scp. */
- /*
- * Do processing
- */
-#if 0 /* if we had a frame buffer or whatever.. do this */
- if (offset > FRAMEBUFFERSIZE - PAGE_SIZE) {
- return (-1);
- }
- return i386_btop((FRAMEBASE + offset));
-#else
- return (-1);
-#endif
-}
-
-static int
-${1}poll(struct cdev *dev, int which, struct thread *td)
-{
- int unit = UNIT(dev);
- sc_p scp = sca[unit];
-
- CHECKUNIT_DIAG(ENXIO);
-
- (void)scp; /* Delete this line after using scp. */
- /*
- * Do processing
- */
- return (0); /* this is the wrong value I'm sure */
-}
-
-/*
- * Now for some driver initialisation.
- * Occurs ONCE during boot (very early).
- */
-static void
-${1}_drvinit(void *unused)
-{
- int unit;
- sc_p scp;
-
- for (unit = 0; unit < N${UPPER}; unit++) {
- /*
- * Allocate storage for this instance .
- */
- scp = malloc(sizeof(*scp), M_DEVBUF, M_NOWAIT | M_ZERO);
- if( scp == NULL) {
- printf("${1}%d failed to allocate strorage\n", unit);
- return;
- }
- sca[unit] = scp;
- scp->dev = make_dev(&${1}_cdevsw, unit,
- UID_ROOT, GID_KMEM, 0640, "${1}%d", unit);
- }
-}
-
-SYSINIT(${1}dev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+CDEV_MAJOR,
- ${1}_drvinit, NULL);
-DONE
-
-cat >${TOP}/sys/${1}io.h <<DONE
-/*
- * Definitions needed to access the ${1} device (ioctls etc)
- * see mtio.h , ioctl.h as examples
- */
-#ifndef SYS_DHIO_H
-#define SYS_DHIO_H
-
-#ifndef KERNEL
-#include <sys/types.h>
-#endif
-#include <sys/ioccom.h>
-
-/*
- * define an ioctl here
- */
-#define DHIOCRESET _IO('D', 0) /* reset the ${1} device */
-#endif
-DONE
-
-if [ ! -d ${TOP}/modules/${1} ]; then
- mkdir -p ${TOP}/modules/${1}
-fi
-
-cat >${TOP}/modules/${1}/Makefile <<DONE
-# ${UPPER} Loadable Kernel Module
-
-.PATH: \${.CURDIR}/../../dev/${1}
-KMOD = ${1}
-SRCS = ${1}.c
-
-.include <bsd.kmod.mk>
-DONE
-
-echo -n "Do you want to build the '${1}' module? [Y]"
-read VAL
-if [ "-z" "$VAL" ]; then
- VAL=YES
-fi
-case ${VAL} in
-[yY]*)
- (cd ${TOP}/modules/${1}; make depend; make )
- ;;
-*)
-# exit
- ;;
-esac
-
-echo ""
-echo -n "Do you want to build the '${UPPER}' kernel? [Y]"
-read VAL
-if [ "-z" "$VAL" ]; then
- VAL=YES
-fi
-case ${VAL} in
-[yY]*)
- (
- cd ${TOP}/i386/conf; \
- config ${UPPER}; \
- cd ${TOP}/i386/compile/${UPPER}; \
- make depend; \
- make; \
- )
- ;;
-*)
-# exit
- ;;
-esac
-
-#--------------end of script---------------
-#
-#edit to your taste..
-#
-#
diff --git a/share/man/man1/Makefile b/share/man/man1/Makefile
index e5ab6597ead2..5b1d3ac1091d 100644
--- a/share/man/man1/Makefile
+++ b/share/man/man1/Makefile
@@ -55,6 +55,7 @@ MLINKS= builtin.1 alias.1 \
builtin.1 if.1 \
builtin.1 jobid.1 \
builtin.1 jobs.1 \
+ builtin.1 keybinds.1 \
builtin.1 limit.1 \
builtin.1 log.1 \
builtin.1 logout.1 \
diff --git a/share/man/man1/builtin.1 b/share/man/man1/builtin.1
index d546548ab4e5..ee89006caea5 100644
--- a/share/man/man1/builtin.1
+++ b/share/man/man1/builtin.1
@@ -1,4 +1,6 @@
.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
.\" Copyright (c) 1999 Sheldon Hearn
.\"
.\" All rights reserved.
@@ -24,175 +26,33 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd December 21, 2010
+.Dd March 29, 2025
.Dt BUILTIN 1
.Os
.Sh NAME
.Nm builtin ,
-.Nm \&! ,
-.Nm % ,
-.Nm \&. ,
-.Nm \&: ,
-.Nm @ ,
-.Nm \&[ ,
-.Nm { ,
-.Nm } ,
-.Nm alias ,
-.Nm alloc ,
-.Nm bg ,
-.Nm bind ,
-.Nm bindkey ,
-.Nm break ,
-.Nm breaksw ,
-.Nm builtins ,
-.Nm case ,
-.Nm cd ,
-.Nm chdir ,
-.Nm command ,
-.Nm complete ,
-.Nm continue ,
-.Nm default ,
-.Nm dirs ,
-.Nm do ,
-.Nm done ,
-.Nm echo ,
-.Nm echotc ,
-.Nm elif ,
-.Nm else ,
-.Nm end ,
-.Nm endif ,
-.Nm endsw ,
-.Nm esac ,
-.Nm eval ,
-.Nm exec ,
-.Nm exit ,
-.Nm export ,
-.Nm false ,
-.Nm fc ,
-.Nm fg ,
-.Nm filetest ,
-.Nm fi ,
-.Nm for ,
-.Nm foreach ,
-.Nm getopts ,
-.Nm glob ,
-.Nm goto ,
-.Nm hash ,
-.Nm hashstat ,
-.Nm history ,
-.Nm hup ,
-.Nm if ,
-.Nm jobid ,
-.Nm jobs ,
-.Nm kill ,
-.Nm limit ,
-.Nm local ,
-.Nm log ,
-.Nm login ,
-.Nm logout ,
-.Nm ls-F ,
-.Nm nice ,
-.Nm nohup ,
-.Nm notify ,
-.Nm onintr ,
-.Nm popd ,
-.Nm printenv ,
-.Nm printf ,
-.Nm pushd ,
-.Nm pwd ,
-.Nm read ,
-.Nm readonly ,
-.Nm rehash ,
-.Nm repeat ,
-.Nm return ,
-.Nm sched ,
-.Nm set ,
-.Nm setenv ,
-.Nm settc ,
-.Nm setty ,
-.Nm setvar ,
-.Nm shift ,
-.Nm source ,
-.Nm stop ,
-.Nm suspend ,
-.Nm switch ,
-.Nm telltc ,
-.Nm test ,
-.Nm then ,
-.Nm time ,
-.Nm times ,
-.Nm trap ,
-.Nm true ,
-.Nm type ,
-.Nm ulimit ,
-.Nm umask ,
-.Nm unalias ,
-.Nm uncomplete ,
-.Nm unhash ,
-.Nm unlimit ,
-.Nm unset ,
-.Nm unsetenv ,
-.Nm until ,
-.Nm wait ,
-.Nm where ,
-.Nm which ,
-.Nm while
-.Nd shell built-in commands
+.Nm keybinds
+.Nd index of FreeBSD shell built-in commands
.Sh SYNOPSIS
-See the built-in command description in the appropriate shell manual page.
+See the manual for your shell for operation details.
.Sh DESCRIPTION
-Shell builtin commands are commands that can be executed within the
-running shell's process.
-Note that, in the case of
-.Xr csh 1
-builtin commands, the command is executed in a subshell if it occurs as
-any component of a pipeline except the last.
-.Pp
-If a command specified to the shell contains a slash
-.Ql / ,
-the shell will not execute a builtin command, even if the last component
-of the specified command matches the name of a builtin command.
-Thus, while specifying
-.Dq Li echo
-causes a builtin command to be executed under shells that support the
-.Nm echo
-builtin command,
-specifying
-.Dq Li /bin/echo
-or
-.Dq Li ./echo
-does not.
-.Pp
-While some builtin commands may exist in more than one shell, their
-operation may be different under each shell which supports them.
-Below is a table which lists shell builtin commands, the standard shells
-that support them and whether they exist as standalone utilities.
-.Pp
-Only builtin commands for the
+This page provides an index of
+.Nm
+commands, keywords, and keyboard bindings provided by
.Xr csh 1
and
-.Xr sh 1
-shells are listed here.
-Consult a shell's manual page for
-details on the operation its builtin commands.
-Beware that the
-.Xr sh 1
-manual page, at least, calls some of these commands
-.Dq built-in commands
-and some of them
-.Dq reserved words .
-Users of other shells may need to consult an
-.Xr info 1
-page or other sources of documentation.
-.Pp
-Commands marked
-.Dq Li No**
-under
-.Em External
-do exist externally,
-but are implemented as scripts using a builtin command of the same name.
-.Bl -column ".Ic uncomplete" ".Em External" ".Xr csh 1" ".Xr sh 1" -offset indent
-.It Em Command Ta Em External Ta Xr csh 1 Ta Xr sh 1
+.Xr sh 1 ,
+the command line interpreters which comprise the
+.Bx
+user environment.
+.Ss Commands
+Below is a table which lists
+.Nm
+commands and keywords,
+whether they exist as standalone utilities,
+and the standard shells that provide them.
+.Bl -column "uncomplete" "Standalone" "csh(1)" "sh(1)" -offset indent
+.It Em Command Ta Em Standalone Ta Xr csh 1 Ta Xr sh 1
.It Ic \&! Ta \&No Ta \&No Ta Yes
.It Ic % Ta \&No Ta Yes Ta \&No
.It Ic \&. Ta \&No Ta \&No Ta Yes
@@ -201,9 +61,9 @@ but are implemented as scripts using a builtin command of the same name.
.It Ic \&[ Ta Yes Ta \&No Ta Yes
.It Ic { Ta \&No Ta \&No Ta Yes
.It Ic } Ta \&No Ta \&No Ta Yes
-.It Ic alias Ta No** Ta Yes Ta Yes
+.It Ic alias Ta No* Ta Yes Ta Yes
.It Ic alloc Ta \&No Ta Yes Ta \&No
-.It Ic bg Ta No** Ta Yes Ta Yes
+.It Ic bg Ta No* Ta Yes Ta Yes
.It Ic bind Ta \&No Ta \&No Ta Yes
.It Ic bindkey Ta \&No Ta Yes Ta \&No
.It Ic break Ta \&No Ta Yes Ta Yes
@@ -211,9 +71,9 @@ but are implemented as scripts using a builtin command of the same name.
.It Ic builtin Ta \&No Ta \&No Ta Yes
.It Ic builtins Ta \&No Ta Yes Ta \&No
.It Ic case Ta \&No Ta Yes Ta Yes
-.It Ic cd Ta No** Ta Yes Ta Yes
+.It Ic cd Ta No* Ta Yes Ta Yes
.It Ic chdir Ta \&No Ta Yes Ta Yes
-.It Ic command Ta No** Ta \&No Ta Yes
+.It Ic command Ta No* Ta \&No Ta Yes
.It Ic complete Ta \&No Ta Yes Ta \&No
.It Ic continue Ta \&No Ta Yes Ta Yes
.It Ic default Ta \&No Ta Yes Ta \&No
@@ -233,22 +93,22 @@ but are implemented as scripts using a builtin command of the same name.
.It Ic exit Ta \&No Ta Yes Ta Yes
.It Ic export Ta \&No Ta \&No Ta Yes
.It Ic false Ta Yes Ta \&No Ta Yes
-.It Ic fc Ta No** Ta \&No Ta Yes
-.It Ic fg Ta No** Ta Yes Ta Yes
+.It Ic fc Ta No* Ta \&No Ta Yes
+.It Ic fg Ta No* Ta Yes Ta Yes
.It Ic filetest Ta \&No Ta Yes Ta \&No
.It Ic fi Ta \&No Ta \&No Ta Yes
.It Ic for Ta \&No Ta \&No Ta Yes
.It Ic foreach Ta \&No Ta Yes Ta \&No
-.It Ic getopts Ta No** Ta \&No Ta Yes
+.It Ic getopts Ta No* Ta \&No Ta Yes
.It Ic glob Ta \&No Ta Yes Ta \&No
.It Ic goto Ta \&No Ta Yes Ta \&No
-.It Ic hash Ta No** Ta \&No Ta Yes
+.It Ic hash Ta No* Ta \&No Ta Yes
.It Ic hashstat Ta \&No Ta Yes Ta \&No
.It Ic history Ta \&No Ta Yes Ta \&No
.It Ic hup Ta \&No Ta Yes Ta \&No
.It Ic if Ta \&No Ta Yes Ta Yes
.It Ic jobid Ta \&No Ta \&No Ta Yes
-.It Ic jobs Ta No** Ta Yes Ta Yes
+.It Ic jobs Ta No* Ta Yes Ta Yes
.It Ic kill Ta Yes Ta Yes Ta Yes
.It Ic limit Ta \&No Ta Yes Ta \&No
.It Ic local Ta \&No Ta \&No Ta Yes
@@ -265,7 +125,7 @@ but are implemented as scripts using a builtin command of the same name.
.It Ic printf Ta Yes Ta \&No Ta Yes
.It Ic pushd Ta \&No Ta Yes Ta \&No
.It Ic pwd Ta Yes Ta \&No Ta Yes
-.It Ic read Ta No** Ta \&No Ta Yes
+.It Ic read Ta No* Ta \&No Ta Yes
.It Ic readonly Ta \&No Ta \&No Ta Yes
.It Ic rehash Ta \&No Ta Yes Ta \&No
.It Ic repeat Ta \&No Ta Yes Ta \&No
@@ -288,26 +148,68 @@ but are implemented as scripts using a builtin command of the same name.
.It Ic times Ta \&No Ta \&No Ta Yes
.It Ic trap Ta \&No Ta \&No Ta Yes
.It Ic true Ta Yes Ta \&No Ta Yes
-.It Ic type Ta No** Ta \&No Ta Yes
-.It Ic ulimit Ta No** Ta \&No Ta Yes
-.It Ic umask Ta No** Ta Yes Ta Yes
-.It Ic unalias Ta No** Ta Yes Ta Yes
+.It Ic type Ta No* Ta \&No Ta Yes
+.It Ic ulimit Ta No* Ta \&No Ta Yes
+.It Ic umask Ta No* Ta Yes Ta Yes
+.It Ic unalias Ta No* Ta Yes Ta Yes
.It Ic uncomplete Ta \&No Ta Yes Ta \&No
.It Ic unhash Ta \&No Ta Yes Ta \&No
.It Ic unlimit Ta \&No Ta Yes Ta \&No
.It Ic unset Ta \&No Ta Yes Ta Yes
.It Ic unsetenv Ta \&No Ta Yes Ta \&No
.It Ic until Ta \&No Ta \&No Ta Yes
-.It Ic wait Ta No** Ta Yes Ta Yes
+.It Ic wait Ta No* Ta Yes Ta Yes
.It Ic where Ta \&No Ta Yes Ta \&No
.It Ic which Ta Yes Ta Yes Ta \&No
.It Ic while Ta \&No Ta Yes Ta Yes
.El
+.Pp
+\&No*: Commands marked
+.Ql No*
+exist externally, but are implemented as scripts using a
+.Nm
+command of the same name.
+.Ss Keybinds
+The command line environment also provides the following
+default keyboard bindings:
+.Bl -column "Process Info (SIGINFO)" "^M | ^J" "^M | ^J" -offset indent
+.It Em Signal Ta Xr csh 1 Ta Xr sh 1
+.It Ic Backspace Ta ^H Ta ^H
+.It Ic Carriage Return Ta ^M | ^J Ta ^M | ^J
+.It Ic Tab Ta ^I Ta ^I
+.It Ic Beginning of Line Ta ^A Ta ^A
+.It Ic End of Line Ta ^E Ta ^E
+.It Ic Cursor Forward Ta ^F Ta ^F
+.It Ic Cursor Backward Ta ^B Ta ^B
+.It Ic Clear Screen Ta ^L Ta ^L
+.It Ic Cut Line Ta ^U Ta ^U
+.It Ic Cut Word Backwards Ta ^W Ta ^W
+.It Ic Cut Rest of Line Ta ^K Ta ^K
+.It Ic Paste Last Cut Ta ^Y Ta ^Y
+.It Ic Typo Ta ^T Ta ^T
+.It End of File Po Ic EOF Pc Ta ^D Ta ^D
+.It Interupt Po Ic SIGINT Pc Ta ^C Ta ^C
+.It Process info Po Ic SIGINFO Pc Ta ^T Ta ^T
+.It Ic Search History Ta \&No Ta ^R
+.It Ic Exit Search History Ta \&No Ta ^G
+.It Ic Previous Command Ta ^P Ta ^P
+.It Ic Next Command Ta ^N Ta ^N
+.It Ic Print Next Character Ta ^V Ta ^V
+.It Ic Pause Job Ta ^S Ta ^S
+.It Ic Resume Job Ta ^Q Ta ^Q
+.It Suspend Job Ic (SIGTSTP) Ta ^Z Ta ^Z
+.It Ic Scrollback Mode Ta ScrLk* Ta ScrLk*
+.El
+.Pp
+\&*: Bindings marked
+.Ql *
+are provided by
+.Xr vt 4 ,
+the console driver.
.Sh SEE ALSO
.Xr csh 1 ,
.Xr echo 1 ,
.Xr false 1 ,
-.Xr info 1 ,
.Xr kill 1 ,
.Xr login 1 ,
.Xr nice 1 ,
@@ -326,5 +228,18 @@ The
manual page first appeared in
.Fx 3.4 .
.Sh AUTHORS
+.An -nosplit
This manual page was written by
+.An Alexander Ziaee Aq Mt ziaee@FreeBSD.org
+from an earlier version by
.An Sheldon Hearn Aq Mt sheldonh@FreeBSD.org .
+.Sh CAVEATS
+While
+.Nm
+commands may exist in more than one shell or standalone,
+each may be implemented differently.
+.Pp
+Standalone utilities and their manuals must be called by their path
+from a shell with a
+.Nm
+command of the same name.
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index 4f12e70f2ae4..7c8a8f3afc45 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -213,6 +213,7 @@ MAN= aac.4 \
${_hv_vmbus.4} \
${_hv_vss.4} \
hwpmc.4 \
+ ${_hwt.4} \
${_hwpstate_intel.4} \
i2ctinyusb.4 \
iavf.4 \
@@ -926,6 +927,17 @@ _vmm.4= vmm.4
.endif
.endif
+.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "aarch64"
+_hwt.4= hwt.4
+.if ${MACHINE_CPUARCH} == "amd64"
+MLINKS+=hwt.4 intel_pt.4
+.endif
+.if ${MACHINE_CPUARCH} == "aarch64"
+MLINKS+=hwt.4 coresight.4
+MLINKS+=hwt.4 spe.4
+.endif
+.endif
+
.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" || \
${MACHINE_CPUARCH} == "aarch64"
_gve.4= gve.4
diff --git a/share/man/man4/hwt.4 b/share/man/man4/hwt.4
new file mode 100644
index 000000000000..7bc8ed4b396d
--- /dev/null
+++ b/share/man/man4/hwt.4
@@ -0,0 +1,142 @@
+.\"
+.\" Copyright (c) 2025 Ruslan Bukin <br@bsdpad.com>
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd July 7, 2025
+.Dt HWT 4
+.Os
+.Sh NAME
+.Nm hwt
+.Nd Hardware Trace Framework
+.Sh SYNOPSIS
+.Cd "options HWT_HOOKS"
+.Cd "device hwt"
+.Pp
+At least one of:
+.Cd "device intel_pt"
+.Pq amd64
+.Cd "device coresight"
+.Pq arm64
+.Cd "device spe"
+.Pq arm64
+.Pp
+In
+.Xr rc.conf 5 :
+.Cd kld_list="hwt"
+.Sh DESCRIPTION
+The
+.Nm
+framework provides infrastructure for hardware-assisted tracing.
+It collects detailed information about software execution and stores it as
+events in highly compressed format into DRAM.
+The events cover information about control flow changes of a program, whether
+branches taken or not, exceptions taken, timing information, cycles elapsed and
+more.
+The information collected allows to reconstruct entire program flow of a given
+application without noticeable performance impact.
+.Sh HARDWARE
+The framework supports several tracing technologies found on
+.Cd arm64
+and
+.Cd amd64
+systems:
+.Pp
+.Bl -bullet -compact
+.It
+ARM Coresight
+.It
+ARM Statistical Profiling Extension (SPE)
+.It
+Intel Processor Trace (PT)
+.El
+.Pp
+The
+.Nm
+framework supports two modes of operation:
+.Bl -tag -width "Thread mode"
+.It Em CPU mode
+Capture CPU activity in kernel mode.
+.It Em Thread mode
+Capture activity of each of a process's threads in user mode.
+.El
+.Sh MANAGEMENT
+When loaded into kernel, the
+.Nm
+framework provides
+.Pa /dev/hwt
+character device.
+The only
+.Xr ioctl 2
+request it accepts is
+.Dv HWT_IOC_ALLOC .
+This request allocates kernel tracing context (CTX) based on requested mode of
+operation, set of CPUs and/or pid.
+.Pp
+Upon successfull CTX allocation, the ioctl returns a CTX identification
+number (ident).
+.Pp
+Each CTX is then managed using its own dedicated character device found at
+.Pa "/dev/hwt_${ident}_${d}",
+where ident is a unique identification number of tracing context, d is either
+cpu_id (in HWT CPU mode) or process pid (in HWT Thread mode).
+.Sh HOOKS
+During tracing of a target process, HWT records runtime events such as threads
+creation, exec and mmap system calls.
+These events are logged as "records" within a particular CTX associated with
+traced process.
+.Pp
+Additionally, HWT can suspend the target thread upon exec or mmap system calls
+if requested by the user.
+This pause allows user-space tools to retrieve the records and adjust tracing
+settings before execution continues.
+This feature is especially useful when address range filtering is enabled,
+allowing tracing of specific functions within the target executable or a
+dynamic library.
+.Sh KERNEL OPTIONS
+The following options in the kernel configuration file are mandatory and
+related to
+.Nm
+operation:
+.Pp
+.Bl -tag -width ".Dv HWT_HOOKS" -compact
+.It Dv HWT_HOOKS
+Enable kernel hooks.
+.El
+.Sh IOCTL INTERFACE
+Once a CTX is allocated, it's management character device accepts several IOC
+requests:
+.Bl -tag -width "HWT_IOC_RECORD_GET"
+.It Dv HWT_IOC_START
+Start tracing.
+In HWT CPU mode the tracing does actually start with this
+.Xr ioctl 2
+request.
+In the Thread mode, the tracing "running" flag set, but tracing begins after
+scheduler switches the target thread onto CPU and return to user mode.
+.It Dv HWT_IOC_STOP
+Stop tracing of the particular CTX.
+.It Dv HWT_IOC_RECORD_GET
+Copy all or part of records collected during hook invocation and associated
+with this CTX to userspace.
+.It Dv HWT_IOC_BUFPTR_GET
+Get current pointer in buffer that is filled by tracing units in real-time.
+.It Dv HWT_IOC_SET_CONFIG
+Set achitecture-specific config (optional).
+.It Dv HWT_IOC_WAKEUP
+Wake up a thread that has been put to sleep by HWT framework hooks.
+.It Dv HWT_IOC_SVC_BUF
+For SPE-only, the kernel is waiting for userspace to notify that it's copied
+out a buffer to avoid data loss/overwriting buffers.
+.El
+.Sh SEE ALSO
+.Xr hwt 8
+.Sh HISTORY
+The
+.Nm
+framework first appeared in
+.Fx 15.0 .
+.Sh AUTHORS
+.An Ruslan Bukin Aq Mt br@FreeBSD.org
+.An Bojan Novković Aq Mt bnovkov@freebsd.org
+.An Zachary Leaf Aq Mt zachary.leaf@arm.com
diff --git a/share/man/man7/Makefile b/share/man/man7/Makefile
index 021bf9251bda..7daa0ffed8ea 100644
--- a/share/man/man7/Makefile
+++ b/share/man/man7/Makefile
@@ -17,6 +17,7 @@ MAN= arch.7 \
intro.7 \
maclabel.7 \
mitigations.7 \
+ named_attribute.7 \
operator.7 \
orders.7 \
ports.7 \
diff --git a/share/man/man7/named_attribute.7 b/share/man/man7/named_attribute.7
new file mode 100644
index 000000000000..7cd778620357
--- /dev/null
+++ b/share/man/man7/named_attribute.7
@@ -0,0 +1,275 @@
+.\"
+.\" Copyright (c) 2025 Rick Macklem
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd July 3, 2025
+.Dt NAMED_ATTRIBUTE 7
+.Os
+.Sh NAME
+.Nm named_attribute
+.Nd Solaris-like extended attribute system interface
+.Sh DESCRIPTION
+Description of the system interface for named attributes
+(the NFS Version 4 terminology).
+.Ss Introduction
+This document describes an alternate system interface for extended
+attributes as compared to
+.Xr extattr 2 .
+It is based on the interface provided by Solaris and NFS Version 4.
+.Pp
+This interface associates a directory, known as a named attribute directory,
+to a file system object.
+This directory is read in the same manner as a normal directory via the
+.Xr getdents 2
+or
+.Xr getdirentries 2
+system calls.
+The
+.Pa .\&
+and
+.Pa ..\&
+entries refer to the directory itself and to the associated file object,
+respectively.
+The other entries in this directory
+are the names of the extended attributes for the associated file object
+and are referred to as named attributes.
+These named attributes are regular files used to store the attribute's
+value.
+.Pp
+A named attribute directory does not live in the file system's name space.
+It is accessed via an
+.Xr open 2
+or
+.Xr openat 2
+system call done on a file to query the named attributes for the file,
+with the
+.Dv O_NAMEDATTR
+flag specified and a
+.Fa path
+argument of
+.Pa .\& .
+This file descriptor can be used as the
+.Fa fd
+argument for a variety of system calls, such as:
+.Xr fchdir 2 ,
+.Xr unlinkat 2
+and
+.Xr renameat 2 .
+.Xr renameat 2
+is only permitted to rename a named attribute within the same named
+attribute directory.
+.Pp
+When a file descriptor for a file object in the file system's namespace
+is used as the
+.Fa fd
+argument of an
+.Xr openat 2
+along with the
+.Fa flag
+.Dv O_NAMEDATTR
+and a
+.Fa path
+argument that is the name of a named attribute (not
+.Pa .\&
+or
+.Pa ..\&
+), a file descriptor for the named attribute is returned.
+If the
+.Fa flag
+.Dv O_CREAT
+is specified, the named attribute will be created if it does not exist.
+The
+.Fa path
+argument must be a single component name, with no embedded
+.Dq /
+in it.
+I/O on these named attribute file descriptors may be performed by
+standard I/O system calls
+such as:
+.Xr read 2 ,
+.Xr write 2 ,
+.Xr lseek 2
+and
+.Xr ftruncate 2 .
+.Pp
+The
+.Dv _PC_NAMEDATTR_ENABLED
+.Fa name
+argument to
+.Xr pathconf 2
+will return 1 if the file system supports named attributes.
+The
+.Dv _PC_HAS_NAMEDATTR
+.Fa name
+argument to
+.Xr pathconf 2
+will return 1 if there are one or more named attributes for the file.
+If an application does a
+.Xr openat 2
+of
+.Dq .\&
+to open a named attribute directory when no named attribute directory exists,
+an empty named attribute directory will be created.
+Testing
+.Dv _PC_HAS_NAMEDATTR
+can be done to avoid creating these named attribute directories unnecessarily.
+.Pp
+The named attribute interface is a different mechanism/system call interface for
+manipulating extended attributes compared with
+.Xr extattr 2 .
+Although the named attribute machanism might require different internal
+implementation
+of extended attributes within a file system, both ZFS and NFSv4 provide
+both mechanisms, which can be used interchangeably to manipulate
+extended attributes, but with a couple of limitations.
+.Bl -bullet
+.It
+The
+.Xr extattr 2
+interface requires that an extended attribute's value be set or acquired
+via a single system call using a single buffer.
+This limits the size of the attribute's value.
+.It
+The named attribute interface does not support system namespace
+extended attributes and,
+as such, system namespace extended attributes must be manipulated via
+.Xr extattr 2 .
+.El
+.Pp
+The named attribute mechanism/system call interface provides certain
+advantages over
+.Xr extattr 2 .
+Since the attribute's value is updated via
+.Xr read 2
+and
+.Xr write 2
+system calls, the attribute's data may be as large as any regular file
+and may be partially updated.
+(Note that this interface does not provide the atomicity guarantee that
+.Xr extattr 2
+does.)
+The permission to access a named attribute directory is determined from
+the access control information for the associated file object.
+However, access control information can be set on each individual attribute
+in a manner similar to a regular file.
+This provides
+.Dq per attribute
+granular control over attribute permissions via
+.Xr fchown 2 .
+.Pp
+At this time, the only local file system which supports this interface
+is ZFS and only if the
+.Dv xattr
+property is set to
+.Dq dir .
+(Note that, even when
+.Dq zfs get xattr <file-system>
+shows
+.Dq on
+the command
+.Dq zfs set xattr=dir <file-system>
+must be done, followed by a remount to make the setting take effect.)
+A NFSv4 mount will also support this interface, but only if the NFSv4
+server file system supports named attributes (the openattr operation).
+The
+.Fx
+NFSv4 server supports named attributes only
+for ZFS exported file systems where the
+.Dq xattr
+property is set to
+.Dq dir
+for the file system.
+.Sh EXAMPLES
+.Bd -literal
+#include <stdio.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+\&...
+
+/* For a file called "myfile". Failure checks removed for brevity. */
+int file_fd, nameddir_fd, namedattr_fd;
+ssize_t siz;
+char buf[DIRBLKSIZ], *cp;
+struct dirent *dp;
+long named_enabled, has_named_attrs;
+
+\&...
+/* Check to see if named attributes are supported. */
+named_enabled = pathconf("myfile", _PC_NAMEDATTR_ENABLED);
+if (named_enabled <= 0)
+ err(1, "Named attributes not enabled");
+/* Test to see if named attribute(s) exist for the file. */
+has_named_attrs = pathconf("myfile", _PC_HAS_NAMEDATTR);
+if (has_named_attrs == 1)
+ printf("myfile has named attribute(s)\\n");
+else
+ printf("myfile does not have any named attributes\\n");
+/* Open a named attribute directory. */
+file_fd = open("myfile", O_RDONLY, 0);
+nameddir_fd = openat(file_fd, ".", O_NAMEDATTR, 0);
+\&...
+/* and read it, assuming it all fits in DIRBLKSIZ for simplicity. */
+siz = getdents(fd, buf, sizeof(buf));
+cp = buf;
+while (cp < &buf[siz]) {
+ dp = (struct dirent *)cp;
+ printf("name=%s\\n", dp->d_name);
+ cp += dp->d_reclen;
+}
+\&...
+/* Open/create a named attribute called "foo". */
+namedattr_fd = openat(file_fd, "foo", O_CREAT | O_RDWR |
+ O_TRUNC | O_NAMEDATTR, 0600);
+\&...
+/* Write foo's attribute value. */
+write(namedattr_fd, "xxxyyy", 6);
+\&...
+/* Read foo's attribute value. */
+lseek(namedattr_fd, 0, SEEK_SET);
+siz = read(namedattr_fd, buf, sizeof(buf));
+\&...
+/* And close "foo". */
+close(namedattr_fd);
+\&...
+/* Rename "foo" to "oldfoo". */
+renameat(nameddir_fd, "foo", nameddir_fd, "oldfoo");
+/* and delete "oldfoo". */
+unlinkat(nameddir_fd, "oldfoo", AT_RESOLVE_BENEATH);
+.Ed
+.Pp
+The
+.Xr runat 1
+command may be used to perform shell commands on named attributes.
+For example:
+.Bd -literal
+$ runat myfile cp /etc/hosts attrhosts # creates attrhosts
+$ runat myfile cat attrhosts # displays contents of attrhosts
+$ runat myfile ls -l # lists the attributes for myfile
+.Ed
+.Pp
+If using the
+.Xr bash 1
+shell, the command
+.Dq cd -@ foo
+enters the named attribute directory for the file object
+.Dq foo .
+.Sh SEE ALSO
+.Xr bash 1 ,
+.Xr runat 1 ,
+.Xr chdir 2 ,
+.Xr extattr 2 ,
+.Xr lseek 2 ,
+.Xr open 2 ,
+.Xr pathconf 2 ,
+.Xr read 2 ,
+.Xr rename 2 ,
+.Xr truncate 2 ,
+.Xr unlinkat 2 ,
+.Xr write 2 ,
+.Xr zfsprops 7
+.Sh HISTORY
+This interface first appeared in
+.Fx 15.0 .
diff --git a/stand/efi/libefi/efinet.c b/stand/efi/libefi/efinet.c
index 186d816cd323..e872110ef08f 100644
--- a/stand/efi/libefi/efinet.c
+++ b/stand/efi/libefi/efinet.c
@@ -256,6 +256,7 @@ efi_env_net_params(struct iodesc *desc)
rootip.s_addr = rootaddr;
#ifdef EFINET_DEBUG
+ printf("%s: proto=%d\n", __func__, netproto);
printf("%s: ip=%s\n", __func__, inet_ntoa(myip));
printf("%s: mask=%s\n", __func__, intoa(netmask));
printf("%s: gateway=%s\n", __func__, inet_ntoa(gateip));
@@ -427,6 +428,7 @@ efinet_dev_init(void)
dif->dif_private = handles2[i];
}
+ efinet_dev.dv_cleanup = netdev.dv_cleanup;
efinet_dev.dv_open = netdev.dv_open;
efinet_dev.dv_close = netdev.dv_close;
efinet_dev.dv_strategy = netdev.dv_strategy;
diff --git a/stand/efi/loader/arch/amd64/elf64_freebsd.c b/stand/efi/loader/arch/amd64/elf64_freebsd.c
index c4265aca035e..35bd4d6c1419 100644
--- a/stand/efi/loader/arch/amd64/elf64_freebsd.c
+++ b/stand/efi/loader/arch/amd64/elf64_freebsd.c
@@ -209,6 +209,12 @@ elf64_exec(struct preloaded_file *fp)
trampoline, PT4);
printf("Start @ 0x%lx ...\n", ehdr->e_entry);
+ /*
+ * we have to cleanup here because net_cleanup() doesn't work after
+ * we call ExitBootServices
+ */
+ dev_cleanup();
+
efi_time_fini();
err = bi_load(fp->f_args, &modulep, &kernend, true);
if (err != 0) {
@@ -218,8 +224,6 @@ elf64_exec(struct preloaded_file *fp)
return (err);
}
- dev_cleanup();
-
trampoline(trampstack, copy_staging == COPY_STAGING_ENABLE ?
efi_copy_finish : efi_copy_finish_nop, kernend, modulep,
PT4, ehdr->e_entry);
diff --git a/stand/efi/loader/arch/arm/exec.c b/stand/efi/loader/arch/arm/exec.c
index c2a79523c02a..3963b6c0104b 100644
--- a/stand/efi/loader/arch/arm/exec.c
+++ b/stand/efi/loader/arch/arm/exec.c
@@ -74,16 +74,17 @@ __elfN(arm_exec)(struct preloaded_file *fp)
printf("Kernel entry at %p...\n", entry);
printf("Kernel args: %s\n", fp->f_args);
+ /*
+ * we have to cleanup here because net_cleanup() doesn't work after
+ * we call ExitBootServices
+ */
+ dev_cleanup();
+
if ((error = bi_load(fp->f_args, &modulep, &kernend, true)) != 0) {
efi_time_init();
return (error);
}
- /* At this point we've called ExitBootServices, so we can't call
- * printf or any other function that uses Boot Services */
-
- dev_cleanup();
-
(*entry)((void *)modulep);
panic("exec returned");
}
diff --git a/stand/efi/loader/arch/arm64/exec.c b/stand/efi/loader/arch/arm64/exec.c
index 91a0503a976f..89e2ad7521a8 100644
--- a/stand/efi/loader/arch/arm64/exec.c
+++ b/stand/efi/loader/arch/arm64/exec.c
@@ -69,6 +69,12 @@ elf64_exec(struct preloaded_file *fp)
ehdr = (Elf_Ehdr *)&(md->md_data);
entry = efi_translate(ehdr->e_entry);
+ /*
+ * we have to cleanup here because net_cleanup() doesn't work after
+ * we call ExitBootServices
+ */
+ dev_cleanup();
+
efi_time_fini();
err = bi_load(fp->f_args, &modulep, &kernendp, true);
if (err != 0) {
@@ -76,8 +82,6 @@ elf64_exec(struct preloaded_file *fp)
return (err);
}
- dev_cleanup();
-
/* Clean D-cache under kernel area and invalidate whole I-cache */
clean_addr = (vm_offset_t)efi_translate(fp->f_addr);
clean_size = (vm_offset_t)efi_translate(kernendp) - clean_addr;
diff --git a/stand/efi/loader/arch/i386/elf64_freebsd.c b/stand/efi/loader/arch/i386/elf64_freebsd.c
index b02cda2269bc..22cdd685ea9b 100644
--- a/stand/efi/loader/arch/i386/elf64_freebsd.c
+++ b/stand/efi/loader/arch/i386/elf64_freebsd.c
@@ -252,6 +252,13 @@ elf64_exec(struct preloaded_file *fp)
ehdr->e_entry
);
+
+ /*
+ * we have to cleanup here because net_cleanup() doesn't work after
+ * we call ExitBootServices
+ */
+ dev_cleanup();
+
efi_time_fini();
err = bi_load(fp->f_args, &modulep, &kernend, true);
if (err != 0) {
@@ -259,8 +266,6 @@ elf64_exec(struct preloaded_file *fp)
return (err);
}
- dev_cleanup();
-
trampoline(trampstack, type == AllocateMaxAddress ? efi_copy_finish :
efi_copy_finish_nop, kernend, modulep, PT4, gdtr, ehdr->e_entry);
diff --git a/stand/efi/loader/arch/riscv/exec.c b/stand/efi/loader/arch/riscv/exec.c
index 9da61229ef68..a53fbd9442b0 100644
--- a/stand/efi/loader/arch/riscv/exec.c
+++ b/stand/efi/loader/arch/riscv/exec.c
@@ -86,17 +86,17 @@ __elfN(exec)(struct preloaded_file *fp)
printf("Kernel entry at %p...\n", entry);
printf("Kernel args: %s\n", fp->f_args);
+ /*
+ * we have to cleanup here because net_cleanup() doesn't work after
+ * we call ExitBootServices
+ */
+ dev_cleanup();
+
if ((error = bi_load(fp->f_args, &modulep, &kernend, true)) != 0) {
efi_time_init();
return (error);
}
- /*
- * At this point we've called ExitBootServices, so we can't call
- * printf or any other function that uses Boot Services
- */
- dev_cleanup();
-
(*entry)((void *)modulep);
panic("exec returned");
}
diff --git a/sys/cam/ata/ata_da.c b/sys/cam/ata/ata_da.c
index ae7cf14c8f8e..1facab47473c 100644
--- a/sys/cam/ata/ata_da.c
+++ b/sys/cam/ata/ata_da.c
@@ -1359,10 +1359,7 @@ adaasync(void *callback_arg, uint32_t code,
case AC_GETDEV_CHANGED:
{
softc = (struct ada_softc *)periph->softc;
- memset(&cgd, 0, sizeof(cgd));
- xpt_setup_ccb(&cgd.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
- cgd.ccb_h.func_code = XPT_GDEV_TYPE;
- xpt_action((union ccb *)&cgd);
+ xpt_gdev_type(&cgd, periph->path);
/*
* Update our information based on the new Identify data.
diff --git a/sys/cam/cam_periph.c b/sys/cam/cam_periph.c
index 833df6cfb99b..730656684e2a 100644
--- a/sys/cam/cam_periph.c
+++ b/sys/cam/cam_periph.c
@@ -767,27 +767,28 @@ camperiphfree(struct cam_periph *periph)
CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("Periph destroyed\n"));
if (periph->flags & CAM_PERIPH_NEW_DEV_FOUND) {
- union ccb ccb;
- void *arg;
-
- memset(&ccb, 0, sizeof(ccb));
switch (periph->deferred_ac) {
- case AC_FOUND_DEVICE:
- ccb.ccb_h.func_code = XPT_GDEV_TYPE;
- xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
- xpt_action(&ccb);
- arg = &ccb;
+ case AC_FOUND_DEVICE: {
+ struct ccb_getdev cgd;
+
+ xpt_gdev_type(&cgd, periph->path);
+ periph->deferred_callback(NULL, periph->deferred_ac,
+ periph->path, &cgd);
break;
- case AC_PATH_REGISTERED:
- xpt_path_inq(&ccb.cpi, periph->path);
- arg = &ccb;
+ }
+ case AC_PATH_REGISTERED: {
+ struct ccb_pathinq cpi;
+
+ xpt_path_inq(&cpi, periph->path);
+ periph->deferred_callback(NULL, periph->deferred_ac,
+ periph->path, &cpi);
break;
+ }
default:
- arg = NULL;
+ periph->deferred_callback(NULL, periph->deferred_ac,
+ periph->path, NULL);
break;
}
- periph->deferred_callback(NULL, periph->deferred_ac,
- periph->path, arg);
}
xpt_free_path(periph->path);
free(periph, M_CAMPERIPH);
@@ -1682,10 +1683,7 @@ camperiphscsisenseerror(union ccb *ccb, union ccb **orig,
/*
* Grab the inquiry data for this device.
*/
- memset(&cgd, 0, sizeof(cgd));
- xpt_setup_ccb(&cgd.ccb_h, ccb->ccb_h.path, CAM_PRIORITY_NORMAL);
- cgd.ccb_h.func_code = XPT_GDEV_TYPE;
- xpt_action((union ccb *)&cgd);
+ xpt_gdev_type(&cgd, ccb->ccb_h.path);
err_action = scsi_error_action(&ccb->csio, &cgd.inq_data,
sense_flags);
@@ -2133,11 +2131,7 @@ cam_periph_devctl_notify(union ccb *ccb)
sbuf_cat(&sb, "serial=\"");
if ((cgd = (struct ccb_getdev *)xpt_alloc_ccb_nowait()) != NULL) {
- xpt_setup_ccb(&cgd->ccb_h, ccb->ccb_h.path,
- CAM_PRIORITY_NORMAL);
- cgd->ccb_h.func_code = XPT_GDEV_TYPE;
- xpt_action((union ccb *)cgd);
-
+ xpt_gdev_type(cgd, ccb->ccb_h.path);
if (cgd->ccb_h.status == CAM_REQ_CMP)
sbuf_bcat(&sb, cgd->serial_num, cgd->serial_num_len);
xpt_free_ccb((union ccb *)cgd);
diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c
index 38bc82c69aad..2ec736e7f4ac 100644
--- a/sys/cam/cam_xpt.c
+++ b/sys/cam/cam_xpt.c
@@ -2471,15 +2471,12 @@ xptsetasyncfunc(struct cam_ed *device, void *arg)
if ((device->flags & CAM_DEV_UNCONFIGURED) != 0)
return (1);
- memset(&cgd, 0, sizeof(cgd));
xpt_compile_path(&path,
NULL,
device->target->bus->path_id,
device->target->target_id,
device->lun_id);
- xpt_setup_ccb(&cgd.ccb_h, &path, CAM_PRIORITY_NORMAL);
- cgd.ccb_h.func_code = XPT_GDEV_TYPE;
- xpt_action((union ccb *)&cgd);
+ xpt_gdev_type(&cgd, &path);
csa->callback(csa->callback_arg,
AC_FOUND_DEVICE,
&path, &cgd);
diff --git a/sys/cam/cam_xpt.h b/sys/cam/cam_xpt.h
index 57225a0ae92d..3815f42cba40 100644
--- a/sys/cam/cam_xpt.h
+++ b/sys/cam/cam_xpt.h
@@ -145,8 +145,8 @@ uint32_t xpt_poll_setup(union ccb *start_ccb);
void xpt_sim_poll(struct cam_sim *sim);
/*
- * Perform a path inquiry at the request priority. bzero may be redundant for
- * allocated CCBs, but for the on-stack CCBs it's required.
+ * Perform a path inquiry. bzero may be redundant for allocated CCBs, but for
+ * the on-stack CCBs it's required.
*/
static inline void
xpt_path_inq(struct ccb_pathinq *cpi, struct cam_path *path)
@@ -158,6 +158,20 @@ xpt_path_inq(struct ccb_pathinq *cpi, struct cam_path *path)
xpt_action((union ccb *)cpi);
}
+/*
+ * Perform get device type. bzero may be redundant for allocated CCBs, but for
+ * the on-stack CCBs it's required.
+ */
+static inline void
+xpt_gdev_type(struct ccb_getdev *cgd, struct cam_path *path)
+{
+
+ bzero(cgd, sizeof(*cgd));
+ xpt_setup_ccb(&cgd->ccb_h, path, CAM_PRIORITY_NONE);
+ cgd->ccb_h.func_code = XPT_GDEV_TYPE;
+ xpt_action((union ccb *)cgd);
+}
+
#endif /* _KERNEL */
#endif /* _CAM_CAM_XPT_H */
diff --git a/sys/cam/mmc/mmc_da.c b/sys/cam/mmc/mmc_da.c
index f7c478076144..7f8bf3516804 100644
--- a/sys/cam/mmc/mmc_da.c
+++ b/sys/cam/mmc/mmc_da.c
@@ -692,10 +692,7 @@ sddaasync(void *callback_arg, uint32_t code,
case AC_GETDEV_CHANGED:
{
CAM_DEBUG(path, CAM_DEBUG_TRACE, ("=> AC_GETDEV_CHANGED\n"));
- memset(&cgd, 0, sizeof(cgd));
- xpt_setup_ccb(&cgd.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
- cgd.ccb_h.func_code = XPT_GDEV_TYPE;
- xpt_action((union ccb *)&cgd);
+ xpt_gdev_type(&cgd, periph->path);
cam_periph_async(periph, code, path, arg);
break;
}
diff --git a/sys/cam/scsi/scsi_all.c b/sys/cam/scsi/scsi_all.c
index 13a376ebb6e3..b518f84454ad 100644
--- a/sys/cam/scsi/scsi_all.c
+++ b/sys/cam/scsi/scsi_all.c
@@ -3708,11 +3708,7 @@ scsi_command_string(struct cam_device *device, struct ccb_scsiio *csio,
/*
* Get the device information.
*/
- xpt_setup_ccb(&cgd->ccb_h,
- csio->ccb_h.path,
- CAM_PRIORITY_NORMAL);
- cgd->ccb_h.func_code = XPT_GDEV_TYPE;
- xpt_action((union ccb *)cgd);
+ xpt_gdev_type(cgd, csio->ccb_h.path);
/*
* If the device is unconfigured, just pretend that it is a hard
@@ -5144,11 +5140,7 @@ scsi_sense_sbuf(struct cam_device *device, struct ccb_scsiio *csio,
/*
* Get the device information.
*/
- xpt_setup_ccb(&cgd->ccb_h,
- csio->ccb_h.path,
- CAM_PRIORITY_NORMAL);
- cgd->ccb_h.func_code = XPT_GDEV_TYPE;
- xpt_action((union ccb *)cgd);
+ xpt_gdev_type(cgd, csio->ccb_h.path);
/*
* If the device is unconfigured, just pretend that it is a hard
diff --git a/sys/cam/scsi/scsi_cd.c b/sys/cam/scsi/scsi_cd.c
index 00a417f65052..e622a96ec77e 100644
--- a/sys/cam/scsi/scsi_cd.c
+++ b/sys/cam/scsi/scsi_cd.c
@@ -1240,13 +1240,7 @@ cddone(struct cam_periph *periph, union ccb *done_ccb)
/*getcount_only*/0);
status = done_ccb->ccb_h.status;
-
- bzero(&cgd, sizeof(cgd));
- xpt_setup_ccb(&cgd.ccb_h,
- done_ccb->ccb_h.path,
- CAM_PRIORITY_NORMAL);
- cgd.ccb_h.func_code = XPT_GDEV_TYPE;
- xpt_action((union ccb *)&cgd);
+ xpt_gdev_type(&cgd, done_ccb->ccb_h.path);
if (scsi_extract_sense_ccb(done_ccb,
&error_code, &sense_key, &asc, &ascq))
diff --git a/sys/cam/scsi/scsi_ch.c b/sys/cam/scsi/scsi_ch.c
index 89a817c1b488..3da22ba61392 100644
--- a/sys/cam/scsi/scsi_ch.c
+++ b/sys/cam/scsi/scsi_ch.c
@@ -1705,11 +1705,7 @@ chscsiversion(struct cam_periph *periph)
/*
* Get the device information.
*/
- xpt_setup_ccb(&cgd->ccb_h,
- periph->path,
- CAM_PRIORITY_NORMAL);
- cgd->ccb_h.func_code = XPT_GDEV_TYPE;
- xpt_action((union ccb *)cgd);
+ xpt_gdev_type(cgd, periph->path);
if (cgd->ccb_h.status != CAM_REQ_CMP) {
xpt_free_ccb((union ccb *)cgd);
diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c
index 0a2389cd9b5d..d02750aaacaf 100644
--- a/sys/cam/scsi/scsi_da.c
+++ b/sys/cam/scsi/scsi_da.c
@@ -5035,11 +5035,7 @@ dadone_proberc(struct cam_periph *periph, union ccb *done_ccb)
/*timeout*/0,
/*getcount_only*/0);
- memset(&cgd, 0, sizeof(cgd));
- xpt_setup_ccb(&cgd.ccb_h, done_ccb->ccb_h.path,
- CAM_PRIORITY_NORMAL);
- cgd.ccb_h.func_code = XPT_GDEV_TYPE;
- xpt_action((union ccb *)&cgd);
+ xpt_gdev_type(&cgd, done_ccb->ccb_h.path);
if (scsi_extract_sense_ccb(done_ccb,
&error_code, &sense_key, &asc, &ascq))
@@ -5077,6 +5073,18 @@ dadone_proberc(struct cam_periph *periph, union ccb *done_ccb)
* behind a SATL translation that's fallen into a
* terminally fatal state.
*
+ * 4/2 happens on some HGST drives that are quite
+ * ill. We've already sent the start unit command (for
+ * which we ignore a 44/0 asc/ascq, which I'm hesitant
+ * to change since it's so basic and there's other error
+ * conditions to the START UNIT we should ignore). So to
+ * require initialization at this point when it should
+ * be fine implies to me, at least, that we should
+ * invalidate. Since we do read capacity in geom tasting
+ * a lot, and since this timeout is long, this leads to
+ * up to a 10 minute delay in booting.
+ *
+ * 4/2: LOGICAL UNIT NOT READY, INITIALIZING COMMAND REQUIRED
* 25/0: LOGICAL UNIT NOT SUPPORTED
* 44/0: INTERNAL TARGET FAILURE
* 44/1: PERSISTENT RESERVATION INFORMATION LOST
@@ -5084,6 +5092,7 @@ dadone_proberc(struct cam_periph *periph, union ccb *done_ccb)
*/
if ((have_sense)
&& (asc != 0x25) && (asc != 0x44)
+ && (asc != 0x04 && ascq != 0x02)
&& (error_code == SSD_CURRENT_ERROR
|| error_code == SSD_DESC_CURRENT_ERROR)) {
const char *sense_key_desc;
diff --git a/sys/cam/scsi/scsi_enc_ses.c b/sys/cam/scsi/scsi_enc_ses.c
index c429e820a1fd..435874a9874a 100644
--- a/sys/cam/scsi/scsi_enc_ses.c
+++ b/sys/cam/scsi/scsi_enc_ses.c
@@ -979,10 +979,7 @@ ses_paths_iter(enc_softc_t *enc, enc_element_t *elm,
!= CAM_REQ_CMP)
return;
- memset(&cgd, 0, sizeof(cgd));
- xpt_setup_ccb(&cgd.ccb_h, path, CAM_PRIORITY_NORMAL);
- cgd.ccb_h.func_code = XPT_GDEV_TYPE;
- xpt_action((union ccb *)&cgd);
+ xpt_gdev_type(&cgd, path);
if (cam_ccb_success((union ccb *)&cgd))
callback(enc, elm, path, callback_arg);
diff --git a/sys/cam/scsi/scsi_sa.c b/sys/cam/scsi/scsi_sa.c
index cfd48c98f30e..88147393192f 100644
--- a/sys/cam/scsi/scsi_sa.c
+++ b/sys/cam/scsi/scsi_sa.c
@@ -4731,12 +4731,7 @@ saextget(struct cdev *dev, struct cam_periph *periph, struct sbuf *sb,
SASBADDVARSTR(sb, indent, periph->periph_name, %s, periph_name,
strlen(periph->periph_name) + 1);
SASBADDUINT(sb, indent, periph->unit_number, %u, unit_number);
- memset(&cgd, 0, sizeof(cgd));
- xpt_setup_ccb(&cgd.ccb_h,
- periph->path,
- CAM_PRIORITY_NORMAL);
- cgd.ccb_h.func_code = XPT_GDEV_TYPE;
- xpt_action((union ccb *)&cgd);
+ xpt_gdev_type(&cgd, periph->path);
if ((cgd.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
g->status = MT_EXT_GET_ERROR;
snprintf(g->error_str, sizeof(g->error_str),
diff --git a/sys/dev/hyperv/vmbus/vmbus_chan.c b/sys/dev/hyperv/vmbus/vmbus_chan.c
index 189a3e66a039..7ea60a499c72 100644
--- a/sys/dev/hyperv/vmbus/vmbus_chan.c
+++ b/sys/dev/hyperv/vmbus/vmbus_chan.c
@@ -1555,7 +1555,7 @@ vmbus_event_flags_proc(struct vmbus_softc *sc, volatile u_long *event_flags,
continue;
flags = atomic_swap_long(&event_flags[f], 0);
- chid_base = f << VMBUS_EVTFLAG_SHIFT;
+ chid_base = f * VMBUS_EVTFLAG_LEN;
while ((chid_ofs = ffsl(flags)) != 0) {
struct vmbus_channel *chan;
@@ -1599,7 +1599,7 @@ vmbus_event_proc_compat(struct vmbus_softc *sc, int cpu)
eventf = VMBUS_PCPU_GET(sc, event_flags, cpu) + VMBUS_SINT_MESSAGE;
if (atomic_testandclear_long(&eventf->evt_flags[0], 0)) {
vmbus_event_flags_proc(sc, sc->vmbus_rx_evtflags,
- VMBUS_CHAN_MAX_COMPAT >> VMBUS_EVTFLAG_SHIFT);
+ VMBUS_CHAN_MAX_COMPAT / VMBUS_EVTFLAG_LEN);
}
}
@@ -1903,7 +1903,7 @@ vmbus_chan_msgproc_choffer(struct vmbus_softc *sc,
* Setup event flag.
*/
chan->ch_evtflag =
- &sc->vmbus_tx_evtflags[chan->ch_id >> VMBUS_EVTFLAG_SHIFT];
+ &sc->vmbus_tx_evtflags[chan->ch_id / VMBUS_EVTFLAG_LEN];
chan->ch_evtflag_mask = 1UL << (chan->ch_id & VMBUS_EVTFLAG_MASK);
/*
diff --git a/sys/dev/hyperv/vmbus/vmbus_reg.h b/sys/dev/hyperv/vmbus/vmbus_reg.h
index 4aa729475b5d..76cdca0ebeb2 100644
--- a/sys/dev/hyperv/vmbus/vmbus_reg.h
+++ b/sys/dev/hyperv/vmbus/vmbus_reg.h
@@ -60,16 +60,10 @@ CTASSERT(sizeof(struct vmbus_message) == VMBUS_MSG_SIZE);
* Hyper-V SynIC event flags
*/
-#ifdef __LP64__
-#define VMBUS_EVTFLAGS_MAX 32
-#define VMBUS_EVTFLAG_SHIFT 6
-#else
-#define VMBUS_EVTFLAGS_MAX 64
-#define VMBUS_EVTFLAG_SHIFT 5
-#endif
-#define VMBUS_EVTFLAG_LEN (1 << VMBUS_EVTFLAG_SHIFT)
+#define VMBUS_EVTFLAG_LEN (sizeof(u_long) * 8)
#define VMBUS_EVTFLAG_MASK (VMBUS_EVTFLAG_LEN - 1)
#define VMBUS_EVTFLAGS_SIZE 256
+#define VMBUS_EVTFLAGS_MAX (VMBUS_EVTFLAGS_SIZE / sizeof(u_long))
struct vmbus_evtflags {
u_long evt_flags[VMBUS_EVTFLAGS_MAX];
diff --git a/sys/dev/mlx5/mlx5_en/mlx5_en_hw_tls_rx.c b/sys/dev/mlx5/mlx5_en/mlx5_en_hw_tls_rx.c
index 8b8f2e570245..4de451f1b039 100644
--- a/sys/dev/mlx5/mlx5_en/mlx5_en_hw_tls_rx.c
+++ b/sys/dev/mlx5/mlx5_en/mlx5_en_hw_tls_rx.c
@@ -42,13 +42,30 @@
static if_snd_tag_free_t mlx5e_tls_rx_snd_tag_free;
static if_snd_tag_modify_t mlx5e_tls_rx_snd_tag_modify;
+static if_snd_tag_status_str_t mlx5e_tls_rx_snd_tag_status_str;
static const struct if_snd_tag_sw mlx5e_tls_rx_snd_tag_sw = {
.snd_tag_modify = mlx5e_tls_rx_snd_tag_modify,
.snd_tag_free = mlx5e_tls_rx_snd_tag_free,
+ .snd_tag_status_str = mlx5e_tls_rx_snd_tag_status_str,
.type = IF_SND_TAG_TYPE_TLS_RX
};
+static const char *mlx5e_tls_rx_progress_params_auth_state_str[] = {
+ [MLX5E_TLS_RX_PROGRESS_PARAMS_AUTH_STATE_NO_OFFLOAD] = "no_offload",
+ [MLX5E_TLS_RX_PROGRESS_PARAMS_AUTH_STATE_OFFLOAD] = "offload",
+ [MLX5E_TLS_RX_PROGRESS_PARAMS_AUTH_STATE_AUTHENTICATION] =
+ "authentication",
+};
+
+static const char *mlx5e_tls_rx_progress_params_record_tracker_state_str[] = {
+ [MLX5E_TLS_RX_PROGRESS_PARAMS_RECORD_TRACKER_STATE_START] = "start",
+ [MLX5E_TLS_RX_PROGRESS_PARAMS_RECORD_TRACKER_STATE_TRACKING] =
+ "tracking",
+ [MLX5E_TLS_RX_PROGRESS_PARAMS_RECORD_TRACKER_STATE_SEARCHING] =
+ "searching",
+};
+
MALLOC_DEFINE(M_MLX5E_TLS_RX, "MLX5E_TLS_RX", "MLX5 ethernet HW TLS RX");
/* software TLS RX context */
@@ -250,7 +267,8 @@ mlx5e_tls_rx_send_progress_parameters_sync(struct mlx5e_iq *iq,
mtx_unlock(&iq->lock);
while (1) {
- if (wait_for_completion_timeout(&ptag->progress_complete, hz) != 0)
+ if (wait_for_completion_timeout(&ptag->progress_complete,
+ msecs_to_jiffies(1000)) != 0)
break;
priv = container_of(iq, struct mlx5e_channel, iq)->priv;
if (priv->mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR ||
@@ -331,7 +349,8 @@ done:
* Zero is returned upon success, else some error happened.
*/
static int
-mlx5e_tls_rx_receive_progress_parameters(struct mlx5e_iq *iq, struct mlx5e_tls_rx_tag *ptag)
+mlx5e_tls_rx_receive_progress_parameters(struct mlx5e_iq *iq,
+ struct mlx5e_tls_rx_tag *ptag, mlx5e_iq_callback_t *cb)
{
struct mlx5e_get_tls_progress_params_wqe *wqe;
const u32 ds_cnt = DIV_ROUND_UP(sizeof(*wqe), MLX5_SEND_WQE_DS);
@@ -367,7 +386,7 @@ mlx5e_tls_rx_receive_progress_parameters(struct mlx5e_iq *iq, struct mlx5e_tls_r
memcpy(iq->doorbell.d32, &wqe->ctrl, sizeof(iq->doorbell.d32));
iq->data[pi].num_wqebbs = DIV_ROUND_UP(ds_cnt, MLX5_SEND_WQEBB_NUM_DS);
- iq->data[pi].callback = &mlx5e_tls_rx_receive_progress_parameters_cb;
+ iq->data[pi].callback = cb;
iq->data[pi].arg = ptag;
m_snd_tag_ref(&ptag->tag);
@@ -819,6 +838,7 @@ mlx5e_tls_rx_snd_tag_alloc(if_t ifp,
}
ptag->flow_rule = flow_rule;
+ init_completion(&ptag->progress_complete);
return (0);
@@ -968,7 +988,8 @@ mlx5e_tls_rx_snd_tag_modify(struct m_snd_tag *pmt, union if_snd_tag_modify_param
params->tls_rx.tls_rec_length,
params->tls_rx.tls_seq_number) &&
ptag->tcp_resync_pending == 0) {
- err = mlx5e_tls_rx_receive_progress_parameters(iq, ptag);
+ err = mlx5e_tls_rx_receive_progress_parameters(iq, ptag,
+ &mlx5e_tls_rx_receive_progress_parameters_cb);
if (err != 0) {
MLX5E_TLS_RX_STAT_INC(ptag, rx_resync_err, 1);
} else {
@@ -1001,6 +1022,74 @@ mlx5e_tls_rx_snd_tag_free(struct m_snd_tag *pmt)
queue_work(priv->tls_rx.wq, &ptag->work);
}
+static void
+mlx5e_tls_rx_str_status_cb(void *arg)
+{
+ struct mlx5e_tls_rx_tag *ptag;
+
+ ptag = (struct mlx5e_tls_rx_tag *)arg;
+ complete_all(&ptag->progress_complete);
+ m_snd_tag_rele(&ptag->tag);
+}
+
+static int
+mlx5e_tls_rx_snd_tag_status_str(struct m_snd_tag *pmt, char *buf, size_t *sz)
+{
+ int err, out_size;
+ struct mlx5e_iq *iq;
+ void *buffer;
+ uint32_t tracker_state_val;
+ uint32_t auth_state_val;
+ struct mlx5e_priv *priv;
+ struct mlx5e_tls_rx_tag *ptag =
+ container_of(pmt, struct mlx5e_tls_rx_tag, tag);
+
+ if (buf == NULL)
+ return (0);
+
+ MLX5E_TLS_RX_TAG_LOCK(ptag);
+ priv = container_of(ptag->tls_rx, struct mlx5e_priv, tls_rx);
+ iq = mlx5e_tls_rx_get_iq(priv, ptag->flowid, ptag->flowtype);
+ reinit_completion(&ptag->progress_complete);
+ err = mlx5e_tls_rx_receive_progress_parameters(iq, ptag,
+ &mlx5e_tls_rx_str_status_cb);
+ MLX5E_TLS_RX_TAG_UNLOCK(ptag);
+ if (err != 0)
+ return (err);
+
+ for (;;) {
+ if (wait_for_completion_timeout(&ptag->progress_complete,
+ msecs_to_jiffies(1000)) != 0)
+ break;
+ if (priv->mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR ||
+ pci_channel_offline(priv->mdev->pdev) != 0)
+ return (ENXIO);
+ }
+ buffer = mlx5e_tls_rx_get_progress_buffer(ptag);
+ tracker_state_val = MLX5_GET(tls_progress_params, buffer,
+ record_tracker_state);
+ auth_state_val = MLX5_GET(tls_progress_params, buffer, auth_state);
+
+ /* Validate tracker state value is in range */
+ if (tracker_state_val >
+ MLX5E_TLS_RX_PROGRESS_PARAMS_RECORD_TRACKER_STATE_SEARCHING)
+ return (EINVAL);
+
+ /* Validate auth state value is in range */
+ if (auth_state_val >
+ MLX5E_TLS_RX_PROGRESS_PARAMS_AUTH_STATE_AUTHENTICATION)
+ return (EINVAL);
+
+ out_size = snprintf(buf, *sz, "tracker_state: %s, auth_state: %s",
+ mlx5e_tls_rx_progress_params_record_tracker_state_str[
+ tracker_state_val],
+ mlx5e_tls_rx_progress_params_auth_state_str[auth_state_val]);
+
+ if (out_size <= *sz)
+ *sz = out_size;
+ return (0);
+}
+
#else
int
diff --git a/sys/dev/nvmf/host/nvmf.c b/sys/dev/nvmf/host/nvmf.c
index dbdd4568bdf1..1ac0d142443b 100644
--- a/sys/dev/nvmf/host/nvmf.c
+++ b/sys/dev/nvmf/host/nvmf.c
@@ -27,6 +27,7 @@
#include <dev/nvmf/host/nvmf_var.h>
static struct cdevsw nvmf_cdevsw;
+static struct taskqueue *nvmf_tq;
bool nvmf_fail_disconnect = false;
SYSCTL_BOOL(_kern_nvmf, OID_AUTO, fail_on_disconnection, CTLFLAG_RWTUN,
@@ -34,7 +35,10 @@ SYSCTL_BOOL(_kern_nvmf, OID_AUTO, fail_on_disconnection, CTLFLAG_RWTUN,
MALLOC_DEFINE(M_NVMF, "nvmf", "NVMe over Fabrics host");
+static void nvmf_controller_loss_task(void *arg, int pending);
static void nvmf_disconnect_task(void *arg, int pending);
+static void nvmf_request_reconnect(struct nvmf_softc *sc);
+static void nvmf_request_reconnect_task(void *arg, int pending);
static void nvmf_shutdown_pre_sync(void *arg, int howto);
static void nvmf_shutdown_post_sync(void *arg, int howto);
@@ -294,6 +298,9 @@ nvmf_establish_connection(struct nvmf_softc *sc, nvlist_t *nvl)
admin = nvlist_get_nvlist(nvl, "admin");
io = nvlist_get_nvlist_array(nvl, "io", &num_io_queues);
kato = dnvlist_get_number(nvl, "kato", 0);
+ sc->reconnect_delay = dnvlist_get_number(nvl, "reconnect_delay", 0);
+ sc->controller_loss_timeout = dnvlist_get_number(nvl,
+ "controller_loss_timeout", 0);
/* Setup the admin queue. */
sc->admin = nvmf_init_qp(sc, trtype, admin, "admin queue", 0);
@@ -504,6 +511,10 @@ nvmf_attach(device_t dev)
callout_init(&sc->ka_tx_timer, 1);
sx_init(&sc->connection_lock, "nvmf connection");
TASK_INIT(&sc->disconnect_task, 0, nvmf_disconnect_task, sc);
+ TIMEOUT_TASK_INIT(nvmf_tq, &sc->controller_loss_task, 0,
+ nvmf_controller_loss_task, sc);
+ TIMEOUT_TASK_INIT(nvmf_tq, &sc->request_reconnect_task, 0,
+ nvmf_request_reconnect_task, sc);
oid = SYSCTL_ADD_NODE(device_get_sysctl_ctx(dev),
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "ioq",
@@ -603,7 +614,9 @@ out:
nvmf_destroy_aer(sc);
- taskqueue_drain(taskqueue_thread, &sc->disconnect_task);
+ taskqueue_drain_timeout(nvmf_tq, &sc->request_reconnect_task);
+ taskqueue_drain_timeout(nvmf_tq, &sc->controller_loss_task);
+ taskqueue_drain(nvmf_tq, &sc->disconnect_task);
sx_destroy(&sc->connection_lock);
nvlist_destroy(sc->rparams);
free(sc->cdata, M_NVMF);
@@ -613,7 +626,7 @@ out:
void
nvmf_disconnect(struct nvmf_softc *sc)
{
- taskqueue_enqueue(taskqueue_thread, &sc->disconnect_task);
+ taskqueue_enqueue(nvmf_tq, &sc->disconnect_task);
}
static void
@@ -676,6 +689,74 @@ nvmf_disconnect_task(void *arg, int pending __unused)
nvmf_destroy_qp(sc->admin);
sc->admin = NULL;
+ if (sc->reconnect_delay != 0)
+ nvmf_request_reconnect(sc);
+ if (sc->controller_loss_timeout != 0)
+ taskqueue_enqueue_timeout(nvmf_tq,
+ &sc->controller_loss_task, sc->controller_loss_timeout *
+ hz);
+
+ sx_xunlock(&sc->connection_lock);
+}
+
+static void
+nvmf_controller_loss_task(void *arg, int pending)
+{
+ struct nvmf_softc *sc = arg;
+ device_t dev;
+ int error;
+
+ bus_topo_lock();
+ sx_xlock(&sc->connection_lock);
+ if (sc->admin != NULL || sc->detaching) {
+ /* Reconnected or already detaching. */
+ sx_xunlock(&sc->connection_lock);
+ bus_topo_unlock();
+ return;
+ }
+
+ sc->controller_timedout = true;
+ sx_xunlock(&sc->connection_lock);
+
+ /*
+ * XXX: Doing this from here is a bit ugly. We don't have an
+ * extra reference on `dev` but bus_topo_lock should block any
+ * concurrent device_delete_child invocations.
+ */
+ dev = sc->dev;
+ error = device_delete_child(root_bus, dev);
+ if (error != 0)
+ device_printf(dev,
+ "failed to detach after controller loss: %d\n", error);
+ bus_topo_unlock();
+}
+
+static void
+nvmf_request_reconnect(struct nvmf_softc *sc)
+{
+ char buf[64];
+
+ sx_assert(&sc->connection_lock, SX_LOCKED);
+
+ snprintf(buf, sizeof(buf), "name=\"%s\"", device_get_nameunit(sc->dev));
+ devctl_notify("nvme", "controller", "RECONNECT", buf);
+ taskqueue_enqueue_timeout(nvmf_tq, &sc->request_reconnect_task,
+ sc->reconnect_delay * hz);
+}
+
+static void
+nvmf_request_reconnect_task(void *arg, int pending)
+{
+ struct nvmf_softc *sc = arg;
+
+ sx_xlock(&sc->connection_lock);
+ if (sc->admin != NULL || sc->detaching || sc->controller_timedout) {
+ /* Reconnected or already detaching. */
+ sx_xunlock(&sc->connection_lock);
+ return;
+ }
+
+ nvmf_request_reconnect(sc);
sx_xunlock(&sc->connection_lock);
}
@@ -699,7 +780,7 @@ nvmf_reconnect_host(struct nvmf_softc *sc, struct nvmf_ioc_nv *nv)
}
sx_xlock(&sc->connection_lock);
- if (sc->admin != NULL || sc->detaching) {
+ if (sc->admin != NULL || sc->detaching || sc->controller_timedout) {
error = EBUSY;
goto out;
}
@@ -745,6 +826,9 @@ nvmf_reconnect_host(struct nvmf_softc *sc, struct nvmf_ioc_nv *nv)
nvmf_reconnect_sim(sc);
nvmf_rescan_all_ns(sc);
+
+ taskqueue_cancel_timeout(nvmf_tq, &sc->request_reconnect_task, NULL);
+ taskqueue_cancel_timeout(nvmf_tq, &sc->controller_loss_task, NULL);
out:
sx_xunlock(&sc->connection_lock);
nvlist_destroy(nvl);
@@ -852,7 +936,21 @@ nvmf_detach(device_t dev)
}
free(sc->io, M_NVMF);
- taskqueue_drain(taskqueue_thread, &sc->disconnect_task);
+ taskqueue_drain(nvmf_tq, &sc->disconnect_task);
+ if (taskqueue_cancel_timeout(nvmf_tq, &sc->request_reconnect_task,
+ NULL) != 0)
+ taskqueue_drain_timeout(nvmf_tq, &sc->request_reconnect_task);
+
+ /*
+ * Don't cancel/drain the controller loss task if that task
+ * has fired and is triggering the detach.
+ */
+ if (!sc->controller_timedout) {
+ if (taskqueue_cancel_timeout(nvmf_tq, &sc->controller_loss_task,
+ NULL) != 0)
+ taskqueue_drain_timeout(nvmf_tq,
+ &sc->controller_loss_task);
+ }
if (sc->admin != NULL)
nvmf_destroy_qp(sc->admin);
@@ -1154,14 +1252,25 @@ static struct cdevsw nvmf_cdevsw = {
static int
nvmf_modevent(module_t mod, int what, void *arg)
{
+ int error;
+
switch (what) {
case MOD_LOAD:
- return (nvmf_ctl_load());
+ error = nvmf_ctl_load();
+ if (error != 0)
+ return (error);
+
+ nvmf_tq = taskqueue_create("nvmf", M_WAITOK | M_ZERO,
+ taskqueue_thread_enqueue, &nvmf_tq);
+ taskqueue_start_threads(&nvmf_tq, 1, PWAIT, "nvmf taskq");
+ return (0);
case MOD_QUIESCE:
return (0);
case MOD_UNLOAD:
nvmf_ctl_unload();
destroy_dev_drain(&nvmf_cdevsw);
+ if (nvmf_tq != NULL)
+ taskqueue_free(nvmf_tq);
return (0);
default:
return (EOPNOTSUPP);
diff --git a/sys/dev/nvmf/host/nvmf_var.h b/sys/dev/nvmf/host/nvmf_var.h
index e45a31f413a4..606245b3969c 100644
--- a/sys/dev/nvmf/host/nvmf_var.h
+++ b/sys/dev/nvmf/host/nvmf_var.h
@@ -75,9 +75,15 @@ struct nvmf_softc {
struct callout ka_rx_timer;
sbintime_t ka_rx_sbt;
+ struct timeout_task request_reconnect_task;
+ struct timeout_task controller_loss_task;
+ uint32_t reconnect_delay;
+ uint32_t controller_loss_timeout;
+
struct sx connection_lock;
struct task disconnect_task;
bool detaching;
+ bool controller_timedout;
u_int num_aer;
struct nvmf_aer *aer;
diff --git a/sys/dev/nvmf/nvmf.h b/sys/dev/nvmf/nvmf.h
index d4e7b1511e9d..9b2b4c1dea40 100644
--- a/sys/dev/nvmf/nvmf.h
+++ b/sys/dev/nvmf/nvmf.h
@@ -27,6 +27,13 @@
#define NVMF_NN (1024)
/*
+ * Default timeouts for Fabrics hosts. These match values used by
+ * Linux.
+ */
+#define NVMF_DEFAULT_RECONNECT_DELAY 10
+#define NVMF_DEFAULT_CONTROLLER_LOSS 600
+
+/*
* (data, size) is the userspace buffer for a packed nvlist.
*
* For requests that copyout an nvlist, len is the amount of data
@@ -68,6 +75,8 @@ struct nvmf_ioc_nv {
*
* number trtype
* number kato (optional)
+ * number reconnect_delay (optional)
+ * number controller_loss_timeout (optional)
* qpair handoff nvlist admin
* qpair handoff nvlist array io
* binary cdata struct nvme_controller_data
@@ -81,6 +90,8 @@ struct nvmf_ioc_nv {
* string hostnqn
* number num_io_queues
* number kato (optional)
+ * number reconnect_delay (optional)
+ * number controller_loss_timeout (optional)
* number io_qsize
* bool sq_flow_control
*
diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c
index fbfcdafaa06b..fa451887e73e 100644
--- a/sys/fs/nfsclient/nfs_clvnops.c
+++ b/sys/fs/nfsclient/nfs_clvnops.c
@@ -1096,12 +1096,11 @@ nfs_setattr(struct vop_setattr_args *ap)
/*
* Disallow write attempts if the filesystem is mounted read-only.
*/
- if ((vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
+ if ((vap->va_flags != (u_long)VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
vap->va_mtime.tv_sec != VNOVAL ||
vap->va_birthtime.tv_sec != VNOVAL ||
- vap->va_mode != (mode_t)VNOVAL ||
- vap->va_flags != (u_long)VNOVAL) &&
+ vap->va_mode != (mode_t)VNOVAL) &&
(vp->v_mount->mnt_flag & MNT_RDONLY))
return (EROFS);
if (vap->va_size != VNOVAL) {
diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c
index a81f1492ef95..43ee0383669f 100644
--- a/sys/fs/nfsserver/nfs_nfsdport.c
+++ b/sys/fs/nfsserver/nfs_nfsdport.c
@@ -1652,10 +1652,11 @@ nfsvno_rename(struct nameidata *fromndp, struct nameidata *tondp,
}
if (fvp == tvp) {
/*
- * If source and destination are the same, there is nothing to
- * do. Set error to -1 to indicate this.
+ * If source and destination are the same, there is
+ * nothing to do. Set error to EJUSTRETURN to indicate
+ * this.
*/
- error = -1;
+ error = EJUSTRETURN;
goto out;
}
if (nd->nd_flag & ND_NFSV4) {
@@ -1697,10 +1698,26 @@ nfsvno_rename(struct nameidata *fromndp, struct nameidata *tondp,
" dsdvp=%p\n", dsdvp[0]);
}
out:
- if (!error) {
+ mp = NULL;
+ if (error == 0) {
+ error = VOP_GETWRITEMOUNT(tondp->ni_dvp, &mp);
+ if (error == 0) {
+ if (mp == NULL) {
+ error = ENOENT;
+ } else {
+ error = lockmgr(&mp->mnt_renamelock,
+ LK_EXCLUSIVE | LK_NOWAIT, NULL);
+ if (error != 0)
+ error = ERELOOKUP;
+ }
+ }
+ }
+ if (error == 0) {
error = VOP_RENAME(fromndp->ni_dvp, fromndp->ni_vp,
&fromndp->ni_cnd, tondp->ni_dvp, tondp->ni_vp,
&tondp->ni_cnd);
+ lockmgr(&mp->mnt_renamelock, LK_RELEASE, 0);
+ vfs_rel(mp);
} else {
if (tdvp == tvp)
vrele(tdvp);
@@ -1710,8 +1727,13 @@ out:
vput(tvp);
vrele(fromndp->ni_dvp);
vrele(fvp);
- if (error == -1)
+ if (error == EJUSTRETURN) {
error = 0;
+ } else if (error == ERELOOKUP && mp != NULL) {
+ lockmgr(&mp->mnt_renamelock, LK_EXCLUSIVE, 0);
+ lockmgr(&mp->mnt_renamelock, LK_RELEASE, 0);
+ vfs_rel(mp);
+ }
}
/*
diff --git a/sys/kern/subr_pctrie.c b/sys/kern/subr_pctrie.c
index 3a3548bad52b..bb86c779b936 100644
--- a/sys/kern/subr_pctrie.c
+++ b/sys/kern/subr_pctrie.c
@@ -691,21 +691,23 @@ _pctrie_lookup_ge(struct pctrie *ptree, struct pctrie_node *node,
*/
if (node == PCTRIE_NULL || *pctrie_toval(node) < index) {
/* Climb the path to find a node with a descendant > index. */
- for (node = parent; node != NULL; node = pctrie_parent(node)) {
- slot = pctrie_slot(node, index) + 1;
- if ((node->pn_popmap >> slot) != 0)
+ node = NULL;
+ while (parent != NULL) {
+ slot = pctrie_slot(parent, index) + 1;
+ if ((parent->pn_popmap >> slot) != 0)
break;
+ node = parent;
+ parent = pctrie_parent(node);
}
- if (node == NULL) {
+ if (parent == NULL) {
if (parent_out != NULL)
- *parent_out = NULL;
+ *parent_out = node;
return (NULL);
}
/* Step to the least child with a descendant > index. */
- slot += ffs(node->pn_popmap >> slot) - 1;
- parent = node;
- node = pctrie_node_load(&node->pn_child[slot], NULL,
+ slot += ffs(parent->pn_popmap >> slot) - 1;
+ node = pctrie_node_load(&parent->pn_child[slot], NULL,
PCTRIE_LOCKED);
}
/* Descend to the least leaf of the subtrie. */
@@ -785,21 +787,23 @@ _pctrie_lookup_le(struct pctrie *ptree, struct pctrie_node *node,
*/
if (node == PCTRIE_NULL || *pctrie_toval(node) > index) {
/* Climb the path to find a node with a descendant < index. */
- for (node = parent; node != NULL; node = pctrie_parent(node)) {
- slot = pctrie_slot(node, index);
- if ((node->pn_popmap & ((1 << slot) - 1)) != 0)
+ node = NULL;
+ while (parent != NULL) {
+ slot = pctrie_slot(parent, index);
+ if ((parent->pn_popmap & ((1 << slot) - 1)) != 0)
break;
+ node = parent;
+ parent = pctrie_parent(node);
}
- if (node == NULL) {
+ if (parent == NULL) {
if (parent_out != NULL)
- *parent_out = NULL;
+ *parent_out = node;
return (NULL);
}
/* Step to the greatest child with a descendant < index. */
- slot = ilog2(node->pn_popmap & ((1 << slot) - 1));
- parent = node;
- node = pctrie_node_load(&node->pn_child[slot], NULL,
+ slot = ilog2(parent->pn_popmap & ((1 << slot) - 1));
+ node = pctrie_node_load(&parent->pn_child[slot], NULL,
PCTRIE_LOCKED);
}
/* Descend to the greatest leaf of the subtrie. */
diff --git a/sys/kern/vfs_inotify.c b/sys/kern/vfs_inotify.c
index 41e73bb41a49..2b42228465a4 100644
--- a/sys/kern/vfs_inotify.c
+++ b/sys/kern/vfs_inotify.c
@@ -760,9 +760,11 @@ vn_inotify_add_watch(struct vnode *vp, struct inotify_softc *sc, uint32_t mask,
* directory if it's specified as a vnode.
*/
vrefact(vp);
+ VOP_UNLOCK(vp);
NDINIT_ATVP(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE,
dp->d_name, vp);
error = namei(&nd);
+ vn_lock(vp, LK_SHARED | LK_RETRY);
if (error != 0)
break;
vn_irflag_set_cond(nd.ni_vp, VIRF_INOTIFY_PARENT);
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index d880733cbfe7..c71e0d9ee569 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -4314,10 +4314,6 @@ kern_getdirentries(struct thread *td, int fd, char *buf, size_t count,
vp = fp->f_vnode;
foffset = foffset_lock(fp, 0);
unionread:
- if (vp->v_type != VDIR) {
- error = EINVAL;
- goto fail;
- }
if (__predict_false((vp->v_vflag & VV_UNLINKED) != 0)) {
error = ENOENT;
goto fail;
@@ -4330,6 +4326,19 @@ unionread:
auio.uio_segflg = bufseg;
auio.uio_td = td;
vn_lock(vp, LK_SHARED | LK_RETRY);
+ /*
+ * We want to return ENOTDIR for anything that is not VDIR, but
+ * not for VBAD, and we can't check for VBAD while the vnode is
+ * unlocked.
+ */
+ if (vp->v_type != VDIR) {
+ if (vp->v_type == VBAD)
+ error = EBADF;
+ else
+ error = ENOTDIR;
+ VOP_UNLOCK(vp);
+ goto fail;
+ }
AUDIT_ARG_VNODE1(vp);
loff = auio.uio_offset = foffset;
#ifdef MAC
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 1416f0c2cdbe..36fab1a03ee6 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -551,6 +551,9 @@ extern struct sx pf_end_lock;
#endif /* PF_INET_INET6 */
#ifdef _KERNEL
+
+void unhandled_af(int) __dead2;
+
static void inline
pf_addrcpy(struct pf_addr *dst, const struct pf_addr *src, sa_family_t af)
{
@@ -565,6 +568,8 @@ pf_addrcpy(struct pf_addr *dst, const struct pf_addr *src, sa_family_t af)
memcpy(&dst->v6, &src->v6, sizeof(dst->v6));
break;
#endif /* INET6 */
+ default:
+ unhandled_af(af);
}
}
#endif
@@ -2300,7 +2305,6 @@ VNET_DECLARE(struct pf_krule *, pf_rulemarker);
#define V_pf_rulemarker VNET(pf_rulemarker)
#endif
-void unhandled_af(int) __dead2;
int pf_start(void);
int pf_stop(void);
void pf_initialize(void);
@@ -2670,6 +2674,7 @@ int pf_ioctl_get_addrs(struct pf_nl_pooladdr *);
int pf_ioctl_get_addr(struct pf_nl_pooladdr *);
int pf_ioctl_get_rulesets(struct pfioc_ruleset *);
int pf_ioctl_get_ruleset(struct pfioc_ruleset *);
+int pf_ioctl_natlook(struct pfioc_natlook *);
void pf_krule_free(struct pf_krule *);
void pf_krule_clear_counters(struct pf_krule *);
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index bccd4b84561a..dbe48242381d 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -1745,6 +1745,23 @@ in_pcbrele(struct inpcb *inp, const inp_lookup_t lock)
}
/*
+ * Dereference and rlock inp, for which the caller must own the
+ * reference. Returns true if inp no longer usable, false otherwise.
+ */
+bool
+in_pcbrele_rlock(struct inpcb *inp)
+{
+ INP_RLOCK(inp);
+ if (in_pcbrele_rlocked(inp))
+ return (true);
+ if ((inp->inp_flags & INP_FREED) != 0) {
+ INP_RUNLOCK(inp);
+ return (true);
+ }
+ return (false);
+}
+
+/*
* Unconditionally schedule an inpcb to be freed by decrementing its
* reference count, which should occur only after the inpcb has been detached
* from its socket. If another thread holds a temporary reference (acquired
diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h
index 57cf15ca37fc..9e0618e87601 100644
--- a/sys/netinet/in_pcb.h
+++ b/sys/netinet/in_pcb.h
@@ -681,6 +681,7 @@ void in_pcbref(struct inpcb *);
bool in_pcbrele(struct inpcb *, inp_lookup_t);
bool in_pcbrele_rlocked(struct inpcb *);
bool in_pcbrele_wlocked(struct inpcb *);
+bool in_pcbrele_rlock(struct inpcb *inp);
typedef bool inp_match_t(const struct inpcb *, void *);
struct inpcb_iterator {
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index cd42a67294a6..db415f6bdf03 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -2720,9 +2720,15 @@ tcp_ktlslist_locked(SYSCTL_HANDLER_ARGS, bool export_keys)
ksr->snd_tag->sw->snd_tag_status_str !=
NULL) {
sz = SND_TAG_STATUS_MAXLEN;
- ksr->snd_tag->sw->snd_tag_status_str(
+ in_pcbref(inp);
+ INP_RUNLOCK(inp);
+ error = ksr->snd_tag->sw->
+ snd_tag_status_str(
ksr->snd_tag, NULL, &sz);
- len += sz;
+ if (in_pcbrele_rlock(inp))
+ return (EDEADLK);
+ if (error == 0)
+ len += sz;
}
}
kss = so->so_snd.sb_tls_info;
@@ -2739,9 +2745,15 @@ tcp_ktlslist_locked(SYSCTL_HANDLER_ARGS, bool export_keys)
kss->snd_tag->sw->snd_tag_status_str !=
NULL) {
sz = SND_TAG_STATUS_MAXLEN;
- kss->snd_tag->sw->snd_tag_status_str(
+ in_pcbref(inp);
+ INP_RUNLOCK(inp);
+ error = kss->snd_tag->sw->
+ snd_tag_status_str(
kss->snd_tag, NULL, &sz);
- len += sz;
+ if (in_pcbrele_rlock(inp))
+ return (EDEADLK);
+ if (error == 0)
+ len += sz;
}
}
if (p) {
@@ -2811,9 +2823,16 @@ tcp_ktlslist_locked(SYSCTL_HANDLER_ARGS, bool export_keys)
if (ksr->snd_tag != NULL &&
ksr->snd_tag->sw->snd_tag_status_str != NULL) {
sz = SND_TAG_STATUS_MAXLEN;
- ksr->snd_tag->sw->snd_tag_status_str(
+ in_pcbref(inp);
+ INP_RUNLOCK(inp);
+ error = ksr->snd_tag->sw->snd_tag_status_str(
ksr->snd_tag, buf + len, &sz);
- len += sz;
+ if (in_pcbrele_rlock(inp))
+ return (EDEADLK);
+ if (error == 0) {
+ xktls->rcv.drv_st_len = sz;
+ len += sz;
+ }
}
}
if (kss != NULL && kss->gen == xig.xig_gen) {
@@ -2828,9 +2847,16 @@ tcp_ktlslist_locked(SYSCTL_HANDLER_ARGS, bool export_keys)
if (kss->snd_tag != NULL &&
kss->snd_tag->sw->snd_tag_status_str != NULL) {
sz = SND_TAG_STATUS_MAXLEN;
- kss->snd_tag->sw->snd_tag_status_str(
+ in_pcbref(inp);
+ INP_RUNLOCK(inp);
+ error = kss->snd_tag->sw->snd_tag_status_str(
kss->snd_tag, buf + len, &sz);
- len += sz;
+ if (in_pcbrele_rlock(inp))
+ return (EDEADLK);
+ if (error == 0) {
+ xktls->snd.drv_st_len = sz;
+ len += sz;
+ }
}
}
len = roundup2(len, __alignof(*xktls));
@@ -2858,12 +2884,23 @@ tcp_ktlslist_locked(SYSCTL_HANDLER_ARGS, bool export_keys)
static int
tcp_ktlslist1(SYSCTL_HANDLER_ARGS, bool export_keys)
{
- int res;
-
- sx_xlock(&ktlslist_lock);
- res = tcp_ktlslist_locked(oidp, arg1, arg2, req, export_keys);
- sx_xunlock(&ktlslist_lock);
- return (res);
+ int repeats, error;
+
+ for (repeats = 0; repeats < 100; repeats++) {
+ if (sx_xlock_sig(&ktlslist_lock))
+ return (EINTR);
+ error = tcp_ktlslist_locked(oidp, arg1, arg2, req,
+ export_keys);
+ sx_xunlock(&ktlslist_lock);
+ if (error != EDEADLK)
+ break;
+ if (sig_intr() != 0) {
+ error = EINTR;
+ break;
+ }
+ req->oldidx = 0;
+ }
+ return (error);
}
static int
diff --git a/sys/netpfil/pf/if_pflog.c b/sys/netpfil/pf/if_pflog.c
index 6a87ea2471cb..0a84f9d680ac 100644
--- a/sys/netpfil/pf/if_pflog.c
+++ b/sys/netpfil/pf/if_pflog.c
@@ -289,7 +289,7 @@ pflog_packet(uint8_t action, u_int8_t reason,
if (pd->lookup.done > 0)
hdr.uid = pd->lookup.uid;
else
- hdr.uid = UID_MAX;
+ hdr.uid = -1;
hdr.pid = NO_PID;
hdr.rule_uid = rm->cuid;
hdr.rule_pid = rm->cpid;
diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c
index fdedb9424117..2391edaf1a5a 100644
--- a/sys/netpfil/pf/if_pfsync.c
+++ b/sys/netpfil/pf/if_pfsync.c
@@ -763,6 +763,10 @@ pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version)
__func__, msg_version);
}
+ if (! (st->act.rtableid == -1 ||
+ (st->act.rtableid >= 0 && st->act.rtableid < rt_numfibs)))
+ goto cleanup;
+
st->id = sp->pfs_1301.id;
st->creatorid = sp->pfs_1301.creatorid;
pf_state_peer_ntoh(&sp->pfs_1301.src, &st->src);
@@ -1083,7 +1087,7 @@ pfsync_in_ins(struct mbuf *m, int offset, int count, int flags, int action)
msg_version = PFSYNC_MSG_VERSION_1400;
break;
default:
- V_pfsyncstats.pfsyncs_badact++;
+ V_pfsyncstats.pfsyncs_badver++;
return (-1);
}
@@ -1110,9 +1114,8 @@ pfsync_in_ins(struct mbuf *m, int offset, int count, int flags, int action)
continue;
}
- if (pfsync_state_import(sp, flags, msg_version) == ENOMEM)
- /* Drop out, but process the rest of the actions. */
- break;
+ if (pfsync_state_import(sp, flags, msg_version) != 0)
+ V_pfsyncstats.pfsyncs_badact++;
}
return (total_len);
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index 127b29320acb..d5f01e5c4956 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -4579,7 +4579,7 @@ pf_match_port(u_int8_t op, u_int16_t a1, u_int16_t a2, u_int16_t p)
static int
pf_match_uid(u_int8_t op, uid_t a1, uid_t a2, uid_t u)
{
- if (u == UID_MAX && op != PF_OP_EQ && op != PF_OP_NE)
+ if (u == -1 && op != PF_OP_EQ && op != PF_OP_NE)
return (0);
return (pf_match(op, a1, a2, u));
}
@@ -4587,7 +4587,7 @@ pf_match_uid(u_int8_t op, uid_t a1, uid_t a2, uid_t u)
static int
pf_match_gid(u_int8_t op, gid_t a1, gid_t a2, gid_t g)
{
- if (g == GID_MAX && op != PF_OP_EQ && op != PF_OP_NE)
+ if (g == -1 && op != PF_OP_EQ && op != PF_OP_NE)
return (0);
return (pf_match(op, a1, a2, g));
}
@@ -4914,8 +4914,8 @@ pf_socket_lookup(struct pf_pdesc *pd)
struct inpcbinfo *pi;
struct inpcb *inp;
- pd->lookup.uid = UID_MAX;
- pd->lookup.gid = GID_MAX;
+ pd->lookup.uid = -1;
+ pd->lookup.gid = -1;
switch (pd->proto) {
case IPPROTO_TCP:
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index 357b2be194a5..c96741023db9 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -2155,51 +2155,51 @@ pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket,
rule->rcv_kif = NULL;
if (rule->rtableid > 0 && rule->rtableid >= rt_numfibs)
- error = EBUSY;
+ ERROUT(EBUSY);
#ifdef ALTQ
/* set queue IDs */
if (rule->qname[0] != 0) {
if ((rule->qid = pf_qname2qid(rule->qname)) == 0)
- error = EBUSY;
+ ERROUT(EBUSY);
else if (rule->pqname[0] != 0) {
if ((rule->pqid =
pf_qname2qid(rule->pqname)) == 0)
- error = EBUSY;
+ ERROUT(EBUSY);
} else
rule->pqid = rule->qid;
}
#endif
if (rule->tagname[0])
if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0)
- error = EBUSY;
+ ERROUT(EBUSY);
if (rule->match_tagname[0])
if ((rule->match_tag =
pf_tagname2tag(rule->match_tagname)) == 0)
- error = EBUSY;
+ ERROUT(EBUSY);
if (rule->rt && !rule->direction)
- error = EINVAL;
+ ERROUT(EINVAL);
if (!rule->log)
rule->logif = 0;
if (! pf_init_threshold(&rule->pktrate, rule->pktrate.limit,
rule->pktrate.seconds))
- error = ENOMEM;
+ ERROUT(ENOMEM);
if (pf_addr_setup(ruleset, &rule->src.addr, rule->af))
- error = ENOMEM;
+ ERROUT(ENOMEM);
if (pf_addr_setup(ruleset, &rule->dst.addr, rule->af))
- error = ENOMEM;
+ ERROUT(ENOMEM);
if (pf_kanchor_setup(rule, ruleset, anchor_call))
- error = EINVAL;
+ ERROUT(EINVAL);
if (rule->scrub_flags & PFSTATE_SETPRIO &&
(rule->set_prio[0] > PF_PRIO_MAX ||
rule->set_prio[1] > PF_PRIO_MAX))
- error = EINVAL;
+ ERROUT(EINVAL);
for (int i = 0; i < 3; i++) {
TAILQ_FOREACH(pa, &V_pf_pabuf[i], entries)
if (pa->addr.type == PF_ADDR_TABLE) {
pa->addr.p.tbl = pfr_attach_table(ruleset,
pa->addr.v.tblname);
if (pa->addr.p.tbl == NULL)
- error = ENOMEM;
+ ERROUT(ENOMEM);
}
}
@@ -2207,7 +2207,7 @@ pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket,
if (rule->overload_tblname[0]) {
if ((rule->overload_tbl = pfr_attach_table(ruleset,
rule->overload_tblname)) == NULL)
- error = EINVAL;
+ ERROUT(EINVAL);
else
rule->overload_tbl->pfrkt_flags |=
PFR_TFLAG_ACTIVE;
@@ -2230,23 +2230,19 @@ pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket,
if (((rule->action == PF_NAT) || (rule->action == PF_RDR) ||
(rule->action == PF_BINAT)) && rule->anchor == NULL &&
TAILQ_FIRST(&rule->rdr.list) == NULL) {
- error = EINVAL;
+ ERROUT(EINVAL);
}
if (rule->rt > PF_NOPFROUTE && (TAILQ_FIRST(&rule->route.list) == NULL)) {
- error = EINVAL;
+ ERROUT(EINVAL);
}
if (rule->action == PF_PASS && (rule->rdr.opts & PF_POOL_STICKYADDR ||
rule->nat.opts & PF_POOL_STICKYADDR) && !rule->keep_state) {
- error = EINVAL;
+ ERROUT(EINVAL);
}
- if (error) {
- pf_free_rule(rule);
- rule = NULL;
- ERROUT(error);
- }
+ MPASS(error == 0);
rule->nat.cur = TAILQ_FIRST(&rule->nat.list);
rule->rdr.cur = TAILQ_FIRST(&rule->rdr.list);
@@ -2699,7 +2695,7 @@ pf_ioctl_get_addr(struct pf_nl_pooladdr *pp)
PF_RULES_RLOCK_TRACKER;
- pp->anchor[sizeof(pp->anchor) - 1] = 0;
+ pp->anchor[sizeof(pp->anchor) - 1] = '\0';
PF_RULES_RLOCK();
pool = pf_get_kpool(pp->anchor, pp->ticket, pp->r_action,
@@ -2732,7 +2728,7 @@ pf_ioctl_get_rulesets(struct pfioc_ruleset *pr)
PF_RULES_RLOCK_TRACKER;
- pr->path[sizeof(pr->path) - 1] = 0;
+ pr->path[sizeof(pr->path) - 1] = '\0';
PF_RULES_RLOCK();
if ((ruleset = pf_find_kruleset(pr->path)) == NULL) {
@@ -2771,7 +2767,7 @@ pf_ioctl_get_ruleset(struct pfioc_ruleset *pr)
return (ENOENT);
}
- pr->name[0] = 0;
+ pr->name[0] = '\0';
if (ruleset == &pf_main_ruleset) {
/* XXX kludge for pf_main_ruleset */
RB_FOREACH(anchor, pf_kanchor_global, &V_pf_anchors)
@@ -2796,6 +2792,78 @@ pf_ioctl_get_ruleset(struct pfioc_ruleset *pr)
return (error);
}
+int
+pf_ioctl_natlook(struct pfioc_natlook *pnl)
+{
+ struct pf_state_key *sk;
+ struct pf_kstate *state;
+ struct pf_state_key_cmp key;
+ int m = 0, direction = pnl->direction;
+ int sidx, didx;
+
+ /* NATLOOK src and dst are reversed, so reverse sidx/didx */
+ sidx = (direction == PF_IN) ? 1 : 0;
+ didx = (direction == PF_IN) ? 0 : 1;
+
+ if (!pnl->proto ||
+ PF_AZERO(&pnl->saddr, pnl->af) ||
+ PF_AZERO(&pnl->daddr, pnl->af) ||
+ ((pnl->proto == IPPROTO_TCP ||
+ pnl->proto == IPPROTO_UDP) &&
+ (!pnl->dport || !pnl->sport)))
+ return (EINVAL);
+
+ switch (pnl->direction) {
+ case PF_IN:
+ case PF_OUT:
+ case PF_INOUT:
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ switch (pnl->af) {
+#ifdef INET
+ case AF_INET:
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
+ break;
+#endif /* INET6 */
+ default:
+ return (EAFNOSUPPORT);
+ }
+
+ bzero(&key, sizeof(key));
+ key.af = pnl->af;
+ key.proto = pnl->proto;
+ pf_addrcpy(&key.addr[sidx], &pnl->saddr, pnl->af);
+ key.port[sidx] = pnl->sport;
+ pf_addrcpy(&key.addr[didx], &pnl->daddr, pnl->af);
+ key.port[didx] = pnl->dport;
+
+ state = pf_find_state_all(&key, direction, &m);
+ if (state == NULL)
+ return (ENOENT);
+
+ if (m > 1) {
+ PF_STATE_UNLOCK(state);
+ return (E2BIG); /* more than one state */
+ }
+
+ sk = state->key[sidx];
+ pf_addrcpy(&pnl->rsaddr,
+ &sk->addr[sidx], sk->af);
+ pnl->rsport = sk->port[sidx];
+ pf_addrcpy(&pnl->rdaddr,
+ &sk->addr[didx], sk->af);
+ pnl->rdport = sk->port[didx];
+ PF_STATE_UNLOCK(state);
+
+ return (0);
+}
+
static int
pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
{
@@ -3502,7 +3570,7 @@ DIOCADDRULENV_error:
break;
}
- pr->anchor[sizeof(pr->anchor) - 1] = 0;
+ pr->anchor[sizeof(pr->anchor) - 1] = '\0';
/* Frees rule on error */
error = pf_ioctl_addrule(rule, pr->ticket, pr->pool_ticket,
@@ -3514,7 +3582,7 @@ DIOCADDRULENV_error:
case DIOCGETRULES: {
struct pfioc_rule *pr = (struct pfioc_rule *)addr;
- pr->anchor[sizeof(pr->anchor) - 1] = 0;
+ pr->anchor[sizeof(pr->anchor) - 1] = '\0';
error = pf_ioctl_getrules(pr);
@@ -3653,7 +3721,7 @@ DIOCGETRULENV_error:
u_int32_t nr = 0;
int rs_num;
- pcr->anchor[sizeof(pcr->anchor) - 1] = 0;
+ pcr->anchor[sizeof(pcr->anchor) - 1] = '\0';
if (pcr->action < PF_CHANGE_ADD_HEAD ||
pcr->action > PF_CHANGE_GET_TICKET) {
@@ -4133,51 +4201,8 @@ DIOCGETSTATESV2_full:
case DIOCNATLOOK: {
struct pfioc_natlook *pnl = (struct pfioc_natlook *)addr;
- struct pf_state_key *sk;
- struct pf_kstate *state;
- struct pf_state_key_cmp key;
- int m = 0, direction = pnl->direction;
- int sidx, didx;
-
- /* NATLOOK src and dst are reversed, so reverse sidx/didx */
- sidx = (direction == PF_IN) ? 1 : 0;
- didx = (direction == PF_IN) ? 0 : 1;
-
- if (!pnl->proto ||
- PF_AZERO(&pnl->saddr, pnl->af) ||
- PF_AZERO(&pnl->daddr, pnl->af) ||
- ((pnl->proto == IPPROTO_TCP ||
- pnl->proto == IPPROTO_UDP) &&
- (!pnl->dport || !pnl->sport)))
- error = EINVAL;
- else {
- bzero(&key, sizeof(key));
- key.af = pnl->af;
- key.proto = pnl->proto;
- pf_addrcpy(&key.addr[sidx], &pnl->saddr, pnl->af);
- key.port[sidx] = pnl->sport;
- pf_addrcpy(&key.addr[didx], &pnl->daddr, pnl->af);
- key.port[didx] = pnl->dport;
-
- state = pf_find_state_all(&key, direction, &m);
- if (state == NULL) {
- error = ENOENT;
- } else {
- if (m > 1) {
- PF_STATE_UNLOCK(state);
- error = E2BIG; /* more than one state */
- } else {
- sk = state->key[sidx];
- pf_addrcpy(&pnl->rsaddr,
- &sk->addr[sidx], sk->af);
- pnl->rsport = sk->port[sidx];
- pf_addrcpy(&pnl->rdaddr,
- &sk->addr[didx], sk->af);
- pnl->rdport = sk->port[didx];
- PF_STATE_UNLOCK(state);
- }
- }
- }
+
+ error = pf_ioctl_natlook(pnl);
break;
}
@@ -4498,7 +4523,7 @@ DIOCGETSTATESV2_full:
struct pf_kruleset *ruleset;
struct pfi_kkif *kif = NULL;
- pca->anchor[sizeof(pca->anchor) - 1] = 0;
+ pca->anchor[sizeof(pca->anchor) - 1] = '\0';
if (pca->action < PF_CHANGE_ADD_HEAD ||
pca->action > PF_CHANGE_REMOVE) {
@@ -4629,7 +4654,7 @@ DIOCCHANGEADDR_error:
case DIOCGETRULESETS: {
struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr;
- pr->path[sizeof(pr->path) - 1] = 0;
+ pr->path[sizeof(pr->path) - 1] = '\0';
error = pf_ioctl_get_rulesets(pr);
break;
@@ -4638,7 +4663,7 @@ DIOCCHANGEADDR_error:
case DIOCGETRULESET: {
struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr;
- pr->path[sizeof(pr->path) - 1] = 0;
+ pr->path[sizeof(pr->path) - 1] = '\0';
error = pf_ioctl_get_ruleset(pr);
break;
@@ -5362,7 +5387,7 @@ DIOCCHANGEADDR_error:
PF_RULES_WLOCK();
/* First makes sure everything will succeed. */
for (i = 0, ioe = ioes; i < io->size; i++, ioe++) {
- ioe->anchor[sizeof(ioe->anchor) - 1] = 0;
+ ioe->anchor[sizeof(ioe->anchor) - 1] = '\0';
switch (ioe->rs_num) {
case PF_RULESET_ETH:
ers = pf_find_keth_ruleset(ioe->anchor);
diff --git a/sys/netpfil/pf/pf_nl.c b/sys/netpfil/pf/pf_nl.c
index d5d6dc70255e..73933c022ca2 100644
--- a/sys/netpfil/pf/pf_nl.c
+++ b/sys/netpfil/pf/pf_nl.c
@@ -1256,23 +1256,13 @@ pf_handle_clear_status(struct nlmsghdr *hdr, struct nl_pstate *npt)
return (0);
}
-struct pf_nl_natlook {
- sa_family_t af;
- uint8_t direction;
- uint8_t proto;
- struct pf_addr src;
- struct pf_addr dst;
- uint16_t sport;
- uint16_t dport;
-};
-
-#define _OUT(_field) offsetof(struct pf_nl_natlook, _field)
+#define _OUT(_field) offsetof(struct pfioc_natlook, _field)
static const struct nlattr_parser nla_p_natlook[] = {
{ .type = PF_NL_AF, .off = _OUT(af), .cb = nlattr_get_uint8 },
{ .type = PF_NL_DIRECTION, .off = _OUT(direction), .cb = nlattr_get_uint8 },
{ .type = PF_NL_PROTO, .off = _OUT(proto), .cb = nlattr_get_uint8 },
- { .type = PF_NL_SRC_ADDR, .off = _OUT(src), .cb = nlattr_get_in6_addr },
- { .type = PF_NL_DST_ADDR, .off = _OUT(dst), .cb = nlattr_get_in6_addr },
+ { .type = PF_NL_SRC_ADDR, .off = _OUT(saddr), .cb = nlattr_get_in6_addr },
+ { .type = PF_NL_DST_ADDR, .off = _OUT(daddr), .cb = nlattr_get_in6_addr },
{ .type = PF_NL_SRC_PORT, .off = _OUT(sport), .cb = nlattr_get_uint16 },
{ .type = PF_NL_DST_PORT, .off = _OUT(dport), .cb = nlattr_get_uint16 },
};
@@ -1282,63 +1272,31 @@ NL_DECLARE_PARSER(natlook_parser, struct genlmsghdr, nlf_p_empty, nla_p_natlook)
static int
pf_handle_natlook(struct nlmsghdr *hdr, struct nl_pstate *npt)
{
- struct pf_nl_natlook attrs = {};
- struct pf_state_key_cmp key = {};
+ struct pfioc_natlook attrs = {};
struct nl_writer *nw = npt->nw;
- struct pf_state_key *sk;
- struct pf_kstate *state;
struct genlmsghdr *ghdr_new;
- int error, m = 0;
- int sidx, didx;
+ int error;
error = nl_parse_nlmsg(hdr, &natlook_parser, npt, &attrs);
if (error != 0)
return (error);
- if (attrs.proto == 0 ||
- PF_AZERO(&attrs.src, attrs.af) ||
- PF_AZERO(&attrs.dst, attrs.af) ||
- ((attrs.proto == IPPROTO_TCP || attrs.proto == IPPROTO_UDP) &&
- (attrs.sport == 0 || attrs.dport == 0)))
- return (EINVAL);
-
- /* NATLOOK src and dst are reversed, so reverse sidx/didx */
- sidx = (attrs.direction == PF_IN) ? 1 : 0;
- didx = (attrs.direction == PF_IN) ? 0 : 1;
-
- key.af = attrs.af;
- key.proto = attrs.proto;
- pf_addrcpy(&key.addr[sidx], &attrs.src, attrs.af);
- key.port[sidx] = attrs.sport;
- pf_addrcpy(&key.addr[didx], &attrs.dst, attrs.af);
- key.port[didx] = attrs.dport;
-
- state = pf_find_state_all(&key, attrs.direction, &m);
- if (state == NULL)
- return (ENOENT);
- if (m > 1) {
- PF_STATE_UNLOCK(state);
- return (E2BIG);
- }
+ error = pf_ioctl_natlook(&attrs);
+ if (error != 0)
+ return (error);
- if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) {
- PF_STATE_UNLOCK(state);
+ if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
return (ENOMEM);
- }
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
ghdr_new->cmd = PFNL_CMD_NATLOOK;
ghdr_new->version = 0;
ghdr_new->reserved = 0;
- sk = state->key[sidx];
-
- nlattr_add_in6_addr(nw, PF_NL_SRC_ADDR, &sk->addr[sidx].v6);
- nlattr_add_in6_addr(nw, PF_NL_DST_ADDR, &sk->addr[didx].v6);
- nlattr_add_u16(nw, PF_NL_SRC_PORT, sk->port[sidx]);
- nlattr_add_u16(nw, PF_NL_DST_PORT, sk->port[didx]);
-
- PF_STATE_UNLOCK(state);
+ nlattr_add_in6_addr(nw, PF_NL_SRC_ADDR, &attrs.rsaddr.v6);
+ nlattr_add_in6_addr(nw, PF_NL_DST_ADDR, &attrs.rdaddr.v6);
+ nlattr_add_u16(nw, PF_NL_SRC_PORT, attrs.rsport);
+ nlattr_add_u16(nw, PF_NL_DST_PORT, attrs.rdport);
if (!nlmsg_end(nw)) {
nlmsg_abort(nw);
diff --git a/tests/atf_python/sys/net/vnet.py b/tests/atf_python/sys/net/vnet.py
index 68c8ce4e0cba..7afb5c721bf3 100644
--- a/tests/atf_python/sys/net/vnet.py
+++ b/tests/atf_python/sys/net/vnet.py
@@ -61,6 +61,7 @@ class VnetInterface(object):
self.iftype = self.IFT_LOOP
else:
self.iftype = self.IFT_ETHER
+ self.ether = ToolsHelper.get_output("/sbin/ifconfig %s ether | awk '/ether/ { print $2; }'" % iface_name).rstrip()
@property
def ifindex(self):
@@ -99,9 +100,12 @@ class VnetInterface(object):
name = run_cmd("/sbin/ifconfig {} create".format(iface_name)).rstrip()
if not name:
raise Exception("Unable to create iface {}".format(iface_name))
- ret = [cls(alias_name, name)]
+ if1 = cls(alias_name, name)
+ ret = [if1]
if name.startswith("epair"):
- ret.append(cls(alias_name, name[:-1] + "b"))
+ if2 = cls(alias_name, name[:-1] + "b")
+ if1.epairb = if2
+ ret.append(if2);
return ret
def setup_addr(self, _addr: str):
diff --git a/tests/sys/kern/Makefile b/tests/sys/kern/Makefile
index 26c0013696c7..f2c24ad9dec9 100644
--- a/tests/sys/kern/Makefile
+++ b/tests/sys/kern/Makefile
@@ -18,6 +18,7 @@ ATF_TESTS_C+= kern_descrip_test
# One test modifies the maxfiles limit, which can cause spurious test failures.
TEST_METADATA.kern_descrip_test+= is_exclusive="true"
ATF_TESTS_C+= fdgrowtable_test
+ATF_TESTS_C+= getdirentries_test
ATF_TESTS_C+= jail_lookup_root
ATF_TESTS_C+= inotify_test
ATF_TESTS_C+= kill_zombie
diff --git a/tests/sys/kern/getdirentries_test.c b/tests/sys/kern/getdirentries_test.c
new file mode 100644
index 000000000000..e66872ffe5b6
--- /dev/null
+++ b/tests/sys/kern/getdirentries_test.c
@@ -0,0 +1,172 @@
+/*-
+ * Copyright (c) 2025 Klara, Inc.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/stat.h>
+#include <sys/mount.h>
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <atf-c.h>
+
+ATF_TC(getdirentries_ok);
+ATF_TC_HEAD(getdirentries_ok, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Successfully read a directory.");
+}
+ATF_TC_BODY(getdirentries_ok, tc)
+{
+ char dbuf[4096];
+ struct dirent *d;
+ off_t base;
+ ssize_t ret;
+ int dd, n;
+
+ ATF_REQUIRE_EQ(0, mkdir("dir", 0755));
+ ATF_REQUIRE((dd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0);
+ ATF_REQUIRE((ret = getdirentries(dd, dbuf, sizeof(dbuf), &base)) > 0);
+ ATF_REQUIRE_EQ(0, getdirentries(dd, dbuf, sizeof(dbuf), &base));
+ ATF_REQUIRE_EQ(base, lseek(dd, 0, SEEK_CUR));
+ ATF_CHECK_EQ(0, close(dd));
+ for (n = 0, d = (struct dirent *)dbuf;
+ d < (struct dirent *)(dbuf + ret);
+ d = (struct dirent *)((char *)d + d->d_reclen), n++)
+ /* nothing */ ;
+ ATF_CHECK_EQ((struct dirent *)(dbuf + ret), d);
+ ATF_CHECK_EQ(2, n);
+}
+
+ATF_TC(getdirentries_ebadf);
+ATF_TC_HEAD(getdirentries_ebadf, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Attempt to read a directory "
+ "from an invalid descriptor.");
+}
+ATF_TC_BODY(getdirentries_ebadf, tc)
+{
+ char dbuf[4096];
+ off_t base;
+ int fd;
+
+ ATF_REQUIRE((fd = open("file", O_CREAT | O_WRONLY, 0644)) >= 0);
+ ATF_REQUIRE_EQ(-1, getdirentries(fd, dbuf, sizeof(dbuf), &base));
+ ATF_CHECK_EQ(EBADF, errno);
+ ATF_REQUIRE_EQ(0, close(fd));
+ ATF_REQUIRE_EQ(-1, getdirentries(fd, dbuf, sizeof(dbuf), &base));
+ ATF_CHECK_EQ(EBADF, errno);
+}
+
+ATF_TC(getdirentries_efault);
+ATF_TC_HEAD(getdirentries_efault, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Attempt to read a directory "
+ "to an invalid buffer.");
+}
+ATF_TC_BODY(getdirentries_efault, tc)
+{
+ char dbuf[4096];
+ off_t base, *basep;
+ int dd;
+
+ ATF_REQUIRE_EQ(0, mkdir("dir", 0755));
+ ATF_REQUIRE((dd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0);
+ ATF_REQUIRE_EQ(-1, getdirentries(dd, NULL, sizeof(dbuf), &base));
+ ATF_CHECK_EQ(EFAULT, errno);
+ basep = NULL;
+ basep++;
+ ATF_REQUIRE_EQ(-1, getdirentries(dd, dbuf, sizeof(dbuf), basep));
+ ATF_CHECK_EQ(EFAULT, errno);
+ ATF_CHECK_EQ(0, close(dd));
+}
+
+ATF_TC(getdirentries_einval);
+ATF_TC_HEAD(getdirentries_einval, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Attempt to read a directory "
+ "with various invalid parameters.");
+}
+ATF_TC_BODY(getdirentries_einval, tc)
+{
+ struct statfs fsb;
+ char dbuf[4096];
+ off_t base;
+ ssize_t ret;
+ int dd;
+
+ ATF_REQUIRE_EQ(0, mkdir("dir", 0755));
+ ATF_REQUIRE((dd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0);
+ ATF_REQUIRE_EQ(0, fstatfs(dd, &fsb));
+ /* nbytes too small */
+ ATF_REQUIRE_EQ(-1, getdirentries(dd, dbuf, 8, &base));
+ ATF_CHECK_EQ(EINVAL, errno);
+ /* nbytes too big */
+ ATF_REQUIRE_EQ(-1, getdirentries(dd, dbuf, SIZE_MAX, &base));
+ ATF_CHECK_EQ(EINVAL, errno);
+ /* invalid position */
+ ATF_REQUIRE((ret = getdirentries(dd, dbuf, sizeof(dbuf), &base)) > 0);
+ ATF_REQUIRE_EQ(0, getdirentries(dd, dbuf, sizeof(dbuf), &base));
+ ATF_REQUIRE(base > 0);
+ ATF_REQUIRE_EQ(base + 3, lseek(dd, 3, SEEK_CUR));
+ /* known to fail on ufs (FFS2) and zfs, and work on tmpfs */
+ if (strcmp(fsb.f_fstypename, "ufs") == 0 ||
+ strcmp(fsb.f_fstypename, "zfs") == 0) {
+ atf_tc_expect_fail("incorrectly returns 0 instead of EINVAL "
+ "on %s", fsb.f_fstypename);
+ }
+ ATF_REQUIRE_EQ(-1, getdirentries(dd, dbuf, sizeof(dbuf), &base));
+ ATF_CHECK_EQ(EINVAL, errno);
+ ATF_CHECK_EQ(0, close(dd));
+}
+
+ATF_TC(getdirentries_enoent);
+ATF_TC_HEAD(getdirentries_enoent, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Attempt to read a directory "
+ "after it is deleted.");
+}
+ATF_TC_BODY(getdirentries_enoent, tc)
+{
+ char dbuf[4096];
+ off_t base;
+ int dd;
+
+ ATF_REQUIRE_EQ(0, mkdir("dir", 0755));
+ ATF_REQUIRE((dd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0);
+ ATF_REQUIRE_EQ(0, rmdir("dir"));
+ ATF_REQUIRE_EQ(-1, getdirentries(dd, dbuf, sizeof(dbuf), &base));
+ ATF_CHECK_EQ(ENOENT, errno);
+}
+
+ATF_TC(getdirentries_enotdir);
+ATF_TC_HEAD(getdirentries_enotdir, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Attempt to read a directory "
+ "from a descriptor not associated with a directory.");
+}
+ATF_TC_BODY(getdirentries_enotdir, tc)
+{
+ char dbuf[4096];
+ off_t base;
+ int fd;
+
+ ATF_REQUIRE((fd = open("file", O_CREAT | O_RDWR, 0644)) >= 0);
+ ATF_REQUIRE_EQ(-1, getdirentries(fd, dbuf, sizeof(dbuf), &base));
+ ATF_CHECK_EQ(ENOTDIR, errno);
+ ATF_CHECK_EQ(0, close(fd));
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, getdirentries_ok);
+ ATF_TP_ADD_TC(tp, getdirentries_ebadf);
+ ATF_TP_ADD_TC(tp, getdirentries_efault);
+ ATF_TP_ADD_TC(tp, getdirentries_einval);
+ ATF_TP_ADD_TC(tp, getdirentries_enoent);
+ ATF_TP_ADD_TC(tp, getdirentries_enotdir);
+ return (atf_no_error());
+}
diff --git a/tests/sys/netpfil/pf/anchor.sh b/tests/sys/netpfil/pf/anchor.sh
index b4b52d7a24d6..4692c06142df 100644
--- a/tests/sys/netpfil/pf/anchor.sh
+++ b/tests/sys/netpfil/pf/anchor.sh
@@ -437,6 +437,62 @@ quick_cleanup()
pft_cleanup
}
+atf_test_case "recursive_flush" "cleanup"
+recursive_flush_head()
+{
+ atf_set descr 'Test recursive flushing of rules'
+ atf_set require.user root
+}
+
+recursive_flush_body()
+{
+ pft_init
+
+ epair=$(vnet_mkepair)
+ vnet_mkjail alcatraz ${epair}a
+
+ ifconfig ${epair}b 192.0.2.2/24 up
+ jexec alcatraz ifconfig ${epair}a 192.0.2.1/24 up
+
+ # Sanity check
+ atf_check -s exit:0 -o ignore ping -c 1 192.0.2.1
+
+ jexec alcatraz pfctl -e
+ pft_set_rules alcatraz \
+ "block" \
+ "anchor \"foo\" {\n\
+ pass\n\
+ }"
+
+ # We can ping thanks to the pass rule in foo
+ atf_check -s exit:0 -o ignore ping -c 1 192.0.2.1
+
+ # Only reset the main rules. I.e. not a recursive flush
+ pft_set_rules alcatraz \
+ "block" \
+ "anchor \"foo\""
+
+ # "foo" still has the pass rule, so this works
+ jexec alcatraz pfctl -a "*" -sr
+ atf_check -s exit:0 -o ignore ping -c 1 192.0.2.1
+
+ # Now do a recursive flush
+ atf_check -s exit:0 -e ignore -o ignore \
+ jexec alcatraz pfctl -a "*" -Fr
+ pft_set_rules alcatraz \
+ "block" \
+ "anchor \"foo\""
+
+ # So this fails
+ jexec alcatraz pfctl -a "*" -sr
+ atf_check -s exit:2 -o ignore ping -c 1 192.0.2.1
+}
+
+recursive_flush_cleanup()
+{
+ pft_cleanup
+}
+
atf_init_test_cases()
{
atf_add_test_case "pr183198"
@@ -450,4 +506,5 @@ atf_init_test_cases()
atf_add_test_case "nat"
atf_add_test_case "include"
atf_add_test_case "quick"
+ atf_add_test_case "recursive_flush"
}
diff --git a/tests/sys/netpfil/pf/header.py b/tests/sys/netpfil/pf/header.py
index 6832cfe6d42b..a5e36bc85d14 100644
--- a/tests/sys/netpfil/pf/header.py
+++ b/tests/sys/netpfil/pf/header.py
@@ -53,10 +53,9 @@ class TestHeader(VnetTestTemplate):
def test_too_many(self):
"Verify that we drop packets with silly numbers of headers."
- sendif = self.vnet.iface_alias_map["if1"].name
+ sendif = self.vnet.iface_alias_map["if1"]
recvif = self.vnet.iface_alias_map["if2"].name
- gw_mac = ToolsHelper.get_output("/sbin/ifconfig %s ether | awk '/ether/ { print $2; }'" % sendif)
- gw_mac = re.sub("0a$", "0b", gw_mac)
+ gw_mac = sendif.epairb.ether
ToolsHelper.print_output("/sbin/route add default 192.0.2.1")
@@ -67,7 +66,7 @@ class TestHeader(VnetTestTemplate):
pkt = sp.Ether(dst=gw_mac) \
/ sp.IP(dst="198.51.100.3") \
/ sp.ICMP(type='echo-request')
- s = DelayedSend(pkt, sendif)
+ s = DelayedSend(pkt, sendif.name)
reply = sp.sniff(iface=recvif, timeout=3)
print(reply)
@@ -89,7 +88,7 @@ class TestHeader(VnetTestTemplate):
pkt = pkt / sp.AH(nh=51, payloadlen=1)
pkt = pkt / sp.AH(nh=1, payloadlen=1) / sp.ICMP(type='echo-request')
- s = DelayedSend(pkt, sendif)
+ s = DelayedSend(pkt, sendif.name)
reply = sp.sniff(iface=recvif, timeout=3)
print(reply)
found = False
@@ -109,7 +108,7 @@ class TestHeader(VnetTestTemplate):
pkt = pkt / sp.AH(nh=51, payloadlen=1)
pkt = pkt / sp.AH(nh=1, payloadlen=1) / sp.ICMP(type='echo-request')
- s = DelayedSend(pkt, sendif)
+ s = DelayedSend(pkt, sendif.name)
reply = sp.sniff(iface=recvif, timeout=3)
print(reply)
@@ -148,10 +147,10 @@ class TestHeader6(VnetTestTemplate):
"Verify that we drop packets with silly numbers of headers."
ToolsHelper.print_output("/sbin/ifconfig")
- sendif = self.vnet.iface_alias_map["if1"].name
+ sendif = self.vnet.iface_alias_map["if1"]
recvif = self.vnet.iface_alias_map["if2"].name
- our_mac = ToolsHelper.get_output("/sbin/ifconfig %s ether | awk '/ether/ { print $2; }'" % sendif)
- gw_mac = re.sub("0a$", "0b", our_mac)
+ our_mac = sendif.ether
+ gw_mac = sendif.epairb.ether
ToolsHelper.print_output("/sbin/route -6 add default 2001:db8::1")
@@ -162,7 +161,7 @@ class TestHeader6(VnetTestTemplate):
pkt = sp.Ether(src=our_mac, dst=gw_mac) \
/ sp.IPv6(src="2001:db8::2", dst="2001:db8:1::3") \
/ sp.ICMPv6EchoRequest()
- s = DelayedSend(pkt, sendif)
+ s = DelayedSend(pkt, sendif.name)
reply = sp.sniff(iface=recvif, timeout=3)
print(reply)
@@ -182,7 +181,7 @@ class TestHeader6(VnetTestTemplate):
for i in range(0, 18):
pkt = pkt / sp.AH(nh=51, payloadlen=1)
pkt = pkt / sp.AH(nh=58, payloadlen=1) / sp.ICMPv6EchoRequest()
- s = DelayedSend(pkt, sendif)
+ s = DelayedSend(pkt, sendif.name)
reply = sp.sniff(iface=recvif, timeout=3)
print(reply)
@@ -202,7 +201,7 @@ class TestHeader6(VnetTestTemplate):
for i in range(0, 19):
pkt = pkt / sp.AH(nh=51, payloadlen=1)
pkt = pkt / sp.AH(nh=58, payloadlen=1) / sp.ICMPv6EchoRequest()
- s = DelayedSend(pkt, sendif)
+ s = DelayedSend(pkt, sendif.name)
reply = sp.sniff(iface=recvif, timeout=3)
print(reply)
diff --git a/tests/sys/netpfil/pf/icmp.py b/tests/sys/netpfil/pf/icmp.py
index 83096886691e..59f2e8190b30 100644
--- a/tests/sys/netpfil/pf/icmp.py
+++ b/tests/sys/netpfil/pf/icmp.py
@@ -91,10 +91,10 @@ class TestICMP(VnetTestTemplate):
def test_inner_match(self):
vnet = self.vnet_map["vnet1"]
dst_vnet = self.vnet_map["vnet3"]
- sendif = vnet.iface_alias_map["if1"].name
+ sendif = vnet.iface_alias_map["if1"]
- our_mac = ToolsHelper.get_output("/sbin/ifconfig %s ether | awk '/ether/ { print $2; }'" % sendif)
- dst_mac = re.sub("0a$", "0b", our_mac)
+ our_mac = sendif.ether
+ dst_mac = sendif.epairb.ether
# Import in the correct vnet, so at to not confuse Scapy
import scapy.all as sp
@@ -111,7 +111,7 @@ class TestICMP(VnetTestTemplate):
/ sp.IP(src="192.0.2.2", dst="198.51.100.2") \
/ sp.ICMP(type='echo-request') \
/ "PAYLOAD"
- sp.sendp(pkt, sendif, verbose=False)
+ sp.sendp(pkt, sendif.name, verbose=False)
# Now try to pass an ICMP error message piggy-backing on that state, but
# use a different source address
@@ -120,7 +120,7 @@ class TestICMP(VnetTestTemplate):
/ sp.ICMP(type='dest-unreach') \
/ sp.IP(src="198.51.100.2", dst="192.0.2.2") \
/ sp.ICMP(type='echo-reply')
- sp.sendp(pkt, sendif, verbose=False)
+ sp.sendp(pkt, sendif.name, verbose=False)
try:
rcvd = self.wait_object(dst_vnet.pipe, timeout=1)
diff --git a/tests/sys/netpfil/pf/ioctl/validation.c b/tests/sys/netpfil/pf/ioctl/validation.c
index 1ce8999dcb91..18fafe11c6ab 100644
--- a/tests/sys/netpfil/pf/ioctl/validation.c
+++ b/tests/sys/netpfil/pf/ioctl/validation.c
@@ -32,6 +32,7 @@
#include <net/if.h>
#include <net/pfvar.h>
+#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
@@ -893,6 +894,39 @@ ATF_TC_CLEANUP(rpool_mtx2, tc)
COMMON_CLEANUP();
}
+ATF_TC_WITH_CLEANUP(natlook);
+ATF_TC_HEAD(natlook, tc)
+{
+ atf_tc_set_md_var(tc, "require.user", "root");
+}
+
+ATF_TC_BODY(natlook, tc)
+{
+ struct pfioc_natlook nl = { 0 };
+
+ COMMON_HEAD();
+
+ nl.af = AF_INET;
+ nl.proto = IPPROTO_ICMP;
+ nl.saddr.v4.s_addr = 0x01020304;
+ nl.daddr.v4.s_addr = 0x05060708;
+
+ /* Invalid direction */
+ nl.direction = 42;
+
+ ATF_CHECK_ERRNO(EINVAL, ioctl(dev, DIOCNATLOOK, &nl) == -1);
+
+ /* Invalid af */
+ nl.direction = PF_IN;
+ nl.af = 99;
+
+ ATF_CHECK_ERRNO(EAFNOSUPPORT, ioctl(dev, DIOCNATLOOK, &nl) == -1);
+}
+
+ATF_TC_CLEANUP(natlook, tc)
+{
+ COMMON_CLEANUP();
+}
ATF_TP_ADD_TCS(tp)
{
@@ -918,6 +952,7 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, tag);
ATF_TP_ADD_TC(tp, rpool_mtx);
ATF_TP_ADD_TC(tp, rpool_mtx2);
+ ATF_TP_ADD_TC(tp, natlook);
return (atf_no_error());
}
diff --git a/tests/sys/netpfil/pf/pfsync.sh b/tests/sys/netpfil/pf/pfsync.sh
index 7f545b43a066..3be4a3024393 100644
--- a/tests/sys/netpfil/pf/pfsync.sh
+++ b/tests/sys/netpfil/pf/pfsync.sh
@@ -835,6 +835,90 @@ basic_ipv6_cleanup()
pfsynct_cleanup
}
+atf_test_case "rtable" "cleanup"
+rtable_head()
+{
+ atf_set descr 'Test handling of invalid rtableid'
+ atf_set require.user root
+}
+
+rtable_body()
+{
+ pfsynct_init
+
+ epair_sync=$(vnet_mkepair)
+ epair_one=$(vnet_mkepair)
+ epair_two=$(vnet_mkepair)
+
+ vnet_mkjail one ${epair_one}a ${epair_sync}a
+ vnet_mkjail two ${epair_two}a ${epair_sync}b
+
+ # pfsync interface
+ jexec one ifconfig ${epair_sync}a 192.0.2.1/24 up
+ jexec one ifconfig ${epair_one}a 198.51.100.1/24 up
+ jexec one ifconfig pfsync0 \
+ syncdev ${epair_sync}a \
+ maxupd 1 \
+ up
+ jexec two ifconfig ${epair_two}a 198.51.100.1/24 up
+ jexec two ifconfig ${epair_sync}b 192.0.2.2/24 up
+ jexec two ifconfig pfsync0 \
+ syncdev ${epair_sync}b \
+ maxupd 1 \
+ up
+
+ # Make life easy, give ${epair_two}a the same mac addrss as ${epair_one}a
+ mac=$(jexec one ifconfig ${epair_one}a | awk '/ether/ { print($2); }')
+ jexec two ifconfig ${epair_two}a ether ${mac}
+
+ # Enable pf!
+ jexec one /sbin/sysctl net.fibs=8
+ jexec one pfctl -e
+ pft_set_rules one \
+ "set skip on ${epair_sync}a" \
+ "pass rtable 3 keep state"
+ # No extra fibs in two
+ jexec two pfctl -e
+ pft_set_rules two \
+ "set skip on ${epair_sync}b" \
+ "pass keep state"
+
+ ifconfig ${epair_one}b 198.51.100.254/24 up
+ ifconfig ${epair_two}b 198.51.100.253/24 up
+
+ # Create a new state
+ env PYTHONPATH=${common_dir} \
+ ${common_dir}/pft_ping.py \
+ --sendif ${epair_one}b \
+ --fromaddr 198.51.100.254 \
+ --to 198.51.100.1 \
+ --recvif ${epair_one}b
+
+ # Now
+ jexec one pfctl -ss -vv
+ sleep 2
+
+ # Now try to use that state on jail two
+ env PYTHONPATH=${common_dir} \
+ ${common_dir}/pft_ping.py \
+ --sendif ${epair_two}b \
+ --fromaddr 198.51.100.254 \
+ --to 198.51.100.1 \
+ --recvif ${epair_two}b
+
+ echo one
+ jexec one pfctl -ss -vv
+ jexec one pfctl -sr -vv
+ echo two
+ jexec two pfctl -ss -vv
+ jexec two pfctl -sr -vv
+}
+
+rtable_cleanup()
+{
+ pfsynct_cleanup
+}
+
route_to_common_head()
{
pfsync_version=$1
@@ -1134,6 +1218,7 @@ atf_init_test_cases()
atf_add_test_case "timeout"
atf_add_test_case "basic_ipv6_unicast"
atf_add_test_case "basic_ipv6"
+ atf_add_test_case "rtable"
atf_add_test_case "route_to_1301"
atf_add_test_case "route_to_1301_bad_ruleset"
atf_add_test_case "route_to_1301_bad_rpool"
diff --git a/tools/build/cross-build/include/common/exterr.h b/tools/build/cross-build/include/common/exterr.h
new file mode 100644
index 000000000000..62482841c7b2
--- /dev/null
+++ b/tools/build/cross-build/include/common/exterr.h
@@ -0,0 +1,14 @@
+#ifndef _EXTERR_H_
+#define _EXTERR_H_
+
+#include <sys/types.h>
+
+static inline int
+uexterr_gettext(char *buf, size_t bufsz)
+{
+ if (bufsz > 0)
+ buf[0] = '\0';
+ return (0);
+}
+
+#endif
diff --git a/tools/build/cross-build/include/common/sys/exterrvar.h b/tools/build/cross-build/include/common/sys/exterrvar.h
new file mode 100644
index 000000000000..0ba821aadef2
--- /dev/null
+++ b/tools/build/cross-build/include/common/sys/exterrvar.h
@@ -0,0 +1,6 @@
+#ifndef _SYS_EXTERRVAR_H_
+#define _SYS_EXTERRVAR_H_
+
+#define UEXTERROR_MAXLEN 256
+
+#endif
diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc
index e0689b2d811f..1e63e4616909 100644
--- a/tools/build/mk/OptionalObsoleteFiles.inc
+++ b/tools/build/mk/OptionalObsoleteFiles.inc
@@ -1683,9 +1683,6 @@ OLD_FILES+=usr/share/examples/diskless/README.BOOTP
OLD_FILES+=usr/share/examples/diskless/README.TEMPLATING
OLD_FILES+=usr/share/examples/diskless/clone_root
OLD_FILES+=usr/share/examples/dma/mailer.conf
-OLD_FILES+=usr/share/examples/drivers/README
-OLD_FILES+=usr/share/examples/drivers/make_device_driver.sh
-OLD_FILES+=usr/share/examples/drivers/make_pseudo_driver.sh
OLD_FILES+=usr/share/examples/dwatch/profile_template
OLD_FILES+=usr/share/examples/etc/README.examples
OLD_FILES+=usr/share/examples/etc/bsd-style-copyright
@@ -1912,7 +1909,6 @@ OLD_DIRS+=usr/share/examples/bsdconfig
OLD_DIRS+=usr/share/examples/csh
OLD_DIRS+=usr/share/examples/diskless
OLD_DIRS+=usr/share/examples/dma
-OLD_DIRS+=usr/share/examples/drivers
OLD_DIRS+=usr/share/examples/dwatch
OLD_DIRS+=usr/share/examples/etc
OLD_DIRS+=usr/share/examples/etc/defaults
diff --git a/usr.bin/Makefile b/usr.bin/Makefile
index b69d25480479..512f75b5d093 100644
--- a/usr.bin/Makefile
+++ b/usr.bin/Makefile
@@ -133,7 +133,6 @@ SUBDIR= alias \
sdiff \
sed \
seq \
- shar \
showmount \
sockstat \
soelim \
diff --git a/usr.bin/kyua/Makefile b/usr.bin/kyua/Makefile
index d3a7b9b61f64..a4f95f1106d9 100644
--- a/usr.bin/kyua/Makefile
+++ b/usr.bin/kyua/Makefile
@@ -32,7 +32,7 @@ MAN= kyua-about.1 \
CFLAGS+= -I${KYUA_SRCDIR} -I${.CURDIR}
CFLAGS+= -I${SRCTOP}/contrib/lutok/include
-CFLAGS+= -I${SRCTOP}/contrib/sqlite3
+CFLAGS+= -I${SYSROOT:U${DESTDIR}}/${INCLUDEDIR}/private/sqlite3
CFLAGS+= -DHAVE_CONFIG_H
# We compile the kyua libraries as part of the main executable as this saves
diff --git a/usr.bin/lockf/lockf.1 b/usr.bin/lockf/lockf.1
index d73033101632..40b4497bc80c 100644
--- a/usr.bin/lockf/lockf.1
+++ b/usr.bin/lockf/lockf.1
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd November 25, 2023
+.Dd June 24, 2025
.Dt LOCKF 1
.Os
.Sh NAME
@@ -30,7 +30,7 @@
.Nd execute a command while holding a file lock
.Sh SYNOPSIS
.Nm
-.Op Fl knsw
+.Op Fl knpsTw
.Op Fl t Ar seconds
.Ar file
.Ar command
@@ -126,6 +126,32 @@ is not specified,
will create
.Ar file
if necessary.
+.It Fl p
+Write the pid of the
+.Ar command
+to
+.Ar file .
+This option will cause
+.Nm
+to open
+.Ar file
+for writing rather than reading.
+.It Fl T
+Upon receipt of a
+.Dv SIGTERM ,
+forward a
+.Dv SIGTERM
+along to the
+.Ar command
+before cleaning up the
+.Ar file
+and exiting.
+By default,
+.Nm
+effectively orphans the
+.Ar command
+after cleaning up the
+.Ar file .
.It Fl t Ar seconds
Specifies a timeout for waiting for the lock.
By default,
diff --git a/usr.bin/lockf/lockf.c b/usr.bin/lockf/lockf.c
index 7f88753d1743..16bae36a21e0 100644
--- a/usr.bin/lockf/lockf.c
+++ b/usr.bin/lockf/lockf.c
@@ -34,6 +34,8 @@
#include <fcntl.h>
#include <limits.h>
#include <signal.h>
+#include <stdatomic.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -50,39 +52,45 @@ union lock_subject {
static int acquire_lock(union lock_subject *subj, int flags, int silent);
static void cleanup(void);
static void killed(int sig);
+static void sigchld(int sig);
static void timeout(int sig);
static void usage(void) __dead2;
static void wait_for_lock(const char *name);
static const char *lockname;
+_Static_assert(sizeof(sig_atomic_t) >= sizeof(pid_t),
+ "PIDs cannot be managed safely from a signal handler on this platform.");
+static sig_atomic_t child = -1;
static int lockfd = -1;
-static int keep;
-static int fdlock;
-static volatile sig_atomic_t timed_out;
+static bool keep;
+static bool fdlock;
+static int status;
+static bool termchild;
+static sig_atomic_t timed_out;
/*
* Check if fdlock is implied by the given `lockname`. We'll write the fd that
* is represented by it out to ofd, and the caller is expected to do any
* necessary validation on it.
*/
-static int
+static bool
fdlock_implied(const char *name, long *ofd)
{
char *endp;
long fd;
if (strncmp(name, FDLOCK_PREFIX, sizeof(FDLOCK_PREFIX) - 1) != 0)
- return (0);
+ return (false);
/* Skip past the prefix. */
name += sizeof(FDLOCK_PREFIX) - 1;
errno = 0;
fd = strtol(name, &endp, 10);
if (errno != 0 || *endp != '\0')
- return (0);
+ return (false);
*ofd = fd;
- return (1);
+ return (true);
}
/*
@@ -91,35 +99,44 @@ fdlock_implied(const char *name, long *ofd)
int
main(int argc, char **argv)
{
- int ch, flags, silent, status;
+ struct sigaction sa_chld = {
+ .sa_handler = sigchld,
+ .sa_flags = SA_NOCLDSTOP,
+ }, sa_prev;
+ sigset_t mask, omask;
long long waitsec;
- pid_t child;
+ const char *errstr;
union lock_subject subj;
+ int ch, flags;
+ bool silent, writepid;
- silent = keep = 0;
+ silent = writepid = false;
flags = O_CREAT | O_RDONLY;
waitsec = -1; /* Infinite. */
- while ((ch = getopt(argc, argv, "knst:w")) != -1) {
+ while ((ch = getopt(argc, argv, "knpsTt:w")) != -1) {
switch (ch) {
case 'k':
- keep = 1;
+ keep = true;
break;
case 'n':
flags &= ~O_CREAT;
break;
case 's':
- silent = 1;
+ silent = true;
+ break;
+ case 'T':
+ termchild = true;
break;
case 't':
- {
- const char *errstr;
-
waitsec = strtonum(optarg, 0, UINT_MAX, &errstr);
if (errstr != NULL)
errx(EX_USAGE,
"invalid timeout \"%s\"", optarg);
- }
break;
+ case 'p':
+ writepid = true;
+ flags |= O_TRUNC;
+ /* FALLTHROUGH */
case 'w':
flags = (flags & ~O_RDONLY) | O_WRONLY;
break;
@@ -143,7 +160,7 @@ main(int argc, char **argv)
* If there aren't any arguments left, then we must be in fdlock mode.
*/
if (argc == 0 && *lockname != '/') {
- fdlock = 1;
+ fdlock = true;
subj.subj_fd = -1;
} else {
fdlock = fdlock_implied(lockname, &subj.subj_fd);
@@ -208,13 +225,16 @@ main(int argc, char **argv)
*/
lockfd = acquire_lock(&subj, flags | O_NONBLOCK, silent);
while (lockfd == -1 && !timed_out && waitsec != 0) {
- if (keep || fdlock)
+ if (keep || fdlock) {
lockfd = acquire_lock(&subj, flags, silent);
- else {
+ } else {
wait_for_lock(lockname);
lockfd = acquire_lock(&subj, flags | O_NONBLOCK,
silent);
}
+
+ /* timed_out */
+ atomic_signal_fence(memory_order_acquire);
}
if (waitsec > 0)
alarm(0);
@@ -234,9 +254,30 @@ main(int argc, char **argv)
if (atexit(cleanup) == -1)
err(EX_OSERR, "atexit failed");
+
+ /*
+ * Block SIGTERM while SIGCHLD is being processed, so that we can safely
+ * waitpid(2) for the child without a concurrent termination observing
+ * an invalid pid (i.e., waited-on). If our setup between here and the
+ * sigsuspend loop gets any more complicated, we should rewrite it to
+ * just use a pipe to signal the child onto execvp().
+ *
+ * We're blocking SIGCHLD and SIGTERM here so that we don't do any
+ * cleanup before we're ready to (after the pid is written out).
+ */
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGCHLD);
+ sigaddset(&mask, SIGTERM);
+ (void)sigprocmask(SIG_BLOCK, &mask, &omask);
+
+ memcpy(&sa_chld.sa_mask, &omask, sizeof(omask));
+ sigaddset(&sa_chld.sa_mask, SIGTERM);
+ (void)sigaction(SIGCHLD, &sa_chld, &sa_prev);
+
if ((child = fork()) == -1)
err(EX_OSERR, "cannot fork");
if (child == 0) { /* The child process. */
+ (void)sigprocmask(SIG_SETMASK, &omask, NULL);
close(lockfd);
execvp(argv[0], argv);
warn("%s", argv[0]);
@@ -246,11 +287,24 @@ main(int argc, char **argv)
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
signal(SIGTERM, killed);
+
fclose(stdin);
fclose(stdout);
fclose(stderr);
- if (waitpid(child, &status, 0) == -1)
- exit(EX_OSERR);
+
+ /* Write out the pid before we sleep on it. */
+ if (writepid)
+ (void)dprintf(lockfd, "%d\n", (int)child);
+
+ /* Just in case they were blocked on entry. */
+ sigdelset(&omask, SIGCHLD);
+ sigdelset(&omask, SIGTERM);
+ while (child >= 0) {
+ (void)sigsuspend(&omask);
+ /* child */
+ atomic_signal_fence(memory_order_acquire);
+ }
+
return (WIFEXITED(status) ? WEXITSTATUS(status) : EX_SOFTWARE);
}
@@ -308,13 +362,35 @@ static void
killed(int sig)
{
+ if (termchild && child >= 0)
+ kill(child, sig);
cleanup();
signal(sig, SIG_DFL);
- if (kill(getpid(), sig) == -1)
+ if (raise(sig) == -1)
_Exit(EX_OSERR);
}
/*
+ * Signal handler for SIGCHLD. Simply waits for the child and ensures that we
+ * don't end up in a sticky situation if we receive a SIGTERM around the same
+ * time.
+ */
+static void
+sigchld(int sig __unused)
+{
+ int ostatus;
+
+ while (waitpid(child, &ostatus, 0) != child) {
+ if (errno != EINTR)
+ _exit(EX_OSERR);
+ }
+
+ status = ostatus;
+ child = -1;
+ atomic_signal_fence(memory_order_release);
+}
+
+/*
* Signal handler for SIGALRM.
*/
static void
@@ -322,6 +398,7 @@ timeout(int sig __unused)
{
timed_out = 1;
+ atomic_signal_fence(memory_order_release);
}
static void
diff --git a/usr.bin/lockf/tests/lockf_test.sh b/usr.bin/lockf/tests/lockf_test.sh
index d73c7590653d..823b5673a176 100644
--- a/usr.bin/lockf/tests/lockf_test.sh
+++ b/usr.bin/lockf/tests/lockf_test.sh
@@ -31,6 +31,24 @@
: ${EX_CANTCREAT:=73}
: ${EX_TEMPFAIL:=75}
+waitlock()
+{
+ local cur lockfile tmo
+
+ lockfile="$1"
+
+ cur=0
+ tmo=20
+
+ while [ "$cur" -lt "$tmo" -a ! -f "$lockfile" ]; do
+ sleep 0.1
+ cur=$((cur + 1))
+ done
+
+ atf_check_not_equal "$cur" "$tmo"
+}
+
+
atf_test_case badargs
badargs_body()
{
@@ -62,6 +80,13 @@ basic_body()
atf_check test ! -e "testlock"
}
+atf_test_case bubble_error
+bubble_error_body()
+{
+ # Ensure that lockf bubbles up the error as expected.
+ atf_check -s exit:9 lockf testlock sh -c 'exit 9'
+}
+
atf_test_case fdlock
fdlock_body()
{
@@ -189,6 +214,52 @@ needfile_body()
atf_check test "$tpass" -lt 10
}
+atf_test_case termchild
+termchild_body()
+{
+ lockf -kp testlock sleep 30 &
+ lpid=$!
+
+ waitlock testlock
+
+ atf_check -o file:testlock pgrep -F testlock
+
+ start=$(date +"%s")
+ atf_check kill -TERM "$lpid"
+ wait "$lpid"
+ end=$(date +"%s")
+ elapsed=$((end - start))
+
+ if [ "$elapsed" -gt 5 ]; then
+ atf_fail "lockf seems to have dodged the SIGTERM ($elapsed passed)"
+ fi
+
+ # We didn't start lockf with -T this time, so the process should not
+ # have been terminated.
+ atf_check -o file:testlock pgrep -F testlock
+
+ lockf -kpT testlock sleep 30 &
+ lpid=$!
+
+ waitlock testlock
+
+ atf_check -o file:testlock pgrep -F testlock
+
+ start=$(date +"%s")
+ atf_check kill -TERM "$lpid"
+ wait "$lpid"
+ end=$(date +"%s")
+ elapsed=$((end - start))
+
+ if [ "$elapsed" -gt 5 ]; then
+ atf_fail "lockf -T seems to have dodged the SIGTERM ($elapsed passed)"
+ fi
+
+ # This time, it should have terminated (notably much earlier than our
+ # 30 second timeout).
+ atf_check -o empty -e not-empty -s not-exit:0 pgrep -F testlock
+}
+
atf_test_case timeout
timeout_body()
{
@@ -212,6 +283,34 @@ timeout_body()
wait "$lpid" || true
}
+atf_test_case writepid
+writepid_body()
+{
+ lockf -p "testlock" sleep 10 &
+ lpid=$!
+
+ waitlock "testlock"
+
+ atf_check test -s testlock
+ atf_check -o file:testlock pgrep -F testlock
+ atf_check -o file:testlock pgrep -F testlock -fx "sleep 10"
+ atf_check pkill -TERM -F testlock
+
+ wait
+
+ atf_check test ! -f testlock
+}
+
+atf_test_case writepid_keep
+writepid_keep_body()
+{
+ # Check that we'll clobber any existing contents (a pid, usually)
+ # once we acquire the lock.
+ jot -b A -s "" 64 > testlock
+ atf_check lockf -kp testlock sleep 0
+ atf_check -o not-match:"A" cat testlock
+}
+
atf_test_case wrlock
wrlock_head()
{
@@ -233,9 +332,13 @@ atf_init_test_cases()
{
atf_add_test_case badargs
atf_add_test_case basic
+ atf_add_test_case bubble_error
atf_add_test_case fdlock
atf_add_test_case keep
atf_add_test_case needfile
+ atf_add_test_case termchild
atf_add_test_case timeout
+ atf_add_test_case writepid
+ atf_add_test_case writepid_keep
atf_add_test_case wrlock
}
diff --git a/usr.bin/shar/Makefile b/usr.bin/shar/Makefile
deleted file mode 100644
index fc940c06d463..000000000000
--- a/usr.bin/shar/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-SCRIPTS=shar.sh
-MAN= shar.1
-
-.include <bsd.prog.mk>
diff --git a/usr.bin/shar/Makefile.depend b/usr.bin/shar/Makefile.depend
deleted file mode 100644
index 11aba52f82cf..000000000000
--- a/usr.bin/shar/Makefile.depend
+++ /dev/null
@@ -1,10 +0,0 @@
-# Autogenerated - do NOT edit!
-
-DIRDEPS = \
-
-
-.include <dirdeps.mk>
-
-.if ${DEP_RELDIR} == ${_DEP_RELDIR}
-# local dependencies - needed for -jN in clean tree
-.endif
diff --git a/usr.bin/shar/shar.1 b/usr.bin/shar/shar.1
deleted file mode 100644
index 6beb1e84ceab..000000000000
--- a/usr.bin/shar/shar.1
+++ /dev/null
@@ -1,121 +0,0 @@
-.\" Copyright (c) 1990, 1993
-.\" The Regents of the University of California. All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\" 3. Neither the name of the University nor the names of its contributors
-.\" may be used to endorse or promote products derived from this software
-.\" without specific prior written permission.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-.\" SUCH DAMAGE.
-.\"
-.Dd January 1, 2025
-.Dt SHAR 1
-.Os
-.Sh NAME
-.Nm shar
-.Nd create a shell archive of files
-.Sh DEPRECATION NOTICE
-.Nm
-is obsolete and may not be present in
-.Fx 15
-and later.
-Because shell archives are simultaneously data and code and are typically
-interpreted by
-.Xr sh 1 ,
-they can easily be trojan-horsed and pose a significant security risk to users.
-The
-.Xr tar 1
-utility can still produce shar encodings of files if needed.
-The
-.Pa sysutils/freebsd-shar
-port has been created to maintain this version of
-.Nm
-past its deprecation in base.
-.Sh SYNOPSIS
-.Nm
-.Ar
-.Sh DESCRIPTION
-The
-.Nm
-command writes a
-.Xr sh 1
-shell script to the standard output which will recreate the file
-hierarchy specified by the command line operands.
-Directories will be recreated and must be specified before the
-files they contain (the
-.Xr find 1
-utility does this correctly).
-.Pp
-The
-.Nm
-command is normally used for distributing files by
-.Xr ftp 1
-or
-.Xr mail 1 .
-.Sh EXAMPLES
-To create a shell archive of the program
-.Xr ls 1
-and mail it to Rick:
-.Bd -literal -offset indent
-cd ls
-shar `find . -print` \&| mail -s "ls source" rick
-.Ed
-.Pp
-To recreate the program directory:
-.Bd -literal -offset indent
-mkdir ls
-cd ls
-\&...
-<delete header lines and examine mailed archive>
-\&...
-sh archive
-.Ed
-.Sh SEE ALSO
-.Xr compress 1 ,
-.Xr mail 1 ,
-.Xr tar 1 ,
-.Xr uuencode 1
-.Sh HISTORY
-The
-.Nm
-command appeared in
-.Bx 4.4 .
-.Sh BUGS
-The
-.Nm
-command makes no provisions for special types of files or files containing
-magic characters.
-The
-.Nm
-command cannot handle files without a newline ('\\n')
-as the last character.
-.Pp
-It is easy to insert trojan horses into
-.Nm
-files.
-It is strongly recommended that all shell archive files be examined
-before running them through
-.Xr sh 1 .
-Archives produced using this implementation of
-.Nm
-may be easily examined with the command:
-.Bd -literal -offset indent
-egrep -av '^[X#]' shar.file
-.Ed
diff --git a/usr.bin/shar/shar.sh b/usr.bin/shar/shar.sh
deleted file mode 100644
index 52c31b419fc4..000000000000
--- a/usr.bin/shar/shar.sh
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/bin/sh -
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-# Copyright (c) 1990, 1993
-# The Regents of the University of California. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-# 3. Neither the name of the University nor the names of its contributors
-# may be used to endorse or promote products derived from this software
-# without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-# SUCH DAMAGE.
-
-if [ $# -eq 0 ]; then
- echo 'usage: shar file ...' 1>&2
- exit 64 # EX_USAGE
-fi
-
-for i
-do
- if [ ! \( -d $i -o -r $i \) ]; then
- echo "$i inaccessible or not exist" 1>&2
- exit 66 # EX_NOINPUT
- fi
-done
-
-cat << EOF
-# This is a shell archive. Save it in a file, remove anything before
-# this line, and then unpack it by entering "sh file". Note, it may
-# create directories; files and directories will be owned by you and
-# have default permissions.
-#
-# This archive contains:
-#
-EOF
-
-for i
-do
- echo "# $i"
-done
-
-echo "#"
-
-for i
-do
- if [ -d "$i" ]; then
- echo "echo c - '$i'"
- echo "mkdir -p '$i' > /dev/null 2>&1"
- else
- md5sum=`echo -n "$i" | md5`
- echo "echo x - '$i'"
- echo "sed 's/^X//' >'$i' << '$md5sum'"
- sed 's/^/X/' "$i" || exit 1
- echo "$md5sum"
- fi
-done
-echo exit
-echo ""
-
-exit 0
diff --git a/usr.bin/truncate/truncate.1 b/usr.bin/truncate/truncate.1
index f6b8b0cc37c9..aa70943b889f 100644
--- a/usr.bin/truncate/truncate.1
+++ b/usr.bin/truncate/truncate.1
@@ -1,4 +1,6 @@
.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
.\" Copyright (c) 2000 Sheldon Hearn <sheldonh@FreeBSD.org>.
.\" All rights reserved.
.\" Copyright (c) 2021 The FreeBSD Foundation
@@ -27,12 +29,12 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd March 6, 2025
+.Dd July 9, 2025
.Dt TRUNCATE 1
.Os
.Sh NAME
.Nm truncate
-.Nd truncate, extend the length of files, or perform space management in files
+.Nd resize files or manage file space
.Sh SYNOPSIS
.Nm
.Op Fl c
@@ -132,7 +134,8 @@ file system space deallocation may be performed in the operation region.
The space management operation is performed at the given
.Ar offset
bytes in the file.
-If this option is not specified, the operation is performed at the beginning of the file.
+If this option is not specified,
+the operation is performed at the beginning of the file.
.It Fl l Ar length
The length of the operation range in bytes.
This option must always be specified if option
@@ -195,9 +198,9 @@ truncate -c -s 10M test_file
.Pp
Same as above but create the file if it does not exist:
.Bd -literal -offset indent
-truncate -s 10M test_file
-ls -l test_file
--rw-r--r-- 1 root wheel 10485760 Jul 22 18:48 test_file
+truncate -s +10M test_file
+ls -lh test_file
+-rw-r--r-- 1 root wheel 10M Jul 22 18:48 test_file
.Ed
.Pp
Adjust the size of
@@ -207,10 +210,10 @@ to the size of the kernel and create another file
with the same size:
.Bd -literal -offset indent
truncate -r /boot/kernel/kernel test_file test_file2
-ls -l /boot/kernel/kernel test_file*
--r-xr-xr-x 1 root wheel 31352552 May 15 14:18 /boot/kernel/kernel
--rw-r--r-- 1 root wheel 31352552 Jul 22 19:15 test_file
--rw-r--r-- 1 root wheel 31352552 Jul 22 19:15 test_file2
+ls -lh /boot/kernel/kernel test_file*
+-r--r--r-- 1 root wheel 30M May 15 14:18 /boot/kernel/kernel
+-rw-r--r-- 1 root wheel 30M Jul 22 19:15 test_file
+-rw-r--r-- 1 root wheel 30M Jul 22 19:15 test_file2
.Ed
.Pp
Increase the size of the file
@@ -228,9 +231,9 @@ Reduce the size of the file
by 5 megabytes:
.Bd -literal -offset indent
truncate -s -5M test_file
-ls -l test_file*
--rw-r--r-- 1 root wheel 31352552 Jul 22 19:19 test_file
--rw-r--r-- 1 root wheel 31352552 Jul 22 19:15 test_file2
+ls -lh test_file*
+-rw-r--r-- 1 root wheel 25M Jul 22 19:17 test_file
+-rw-r--r-- 1 root wheel 30M Jul 22 19:15 test_file2
.Ed
.Sh SEE ALSO
.Xr dd 1 ,
@@ -247,6 +250,7 @@ The
utility first appeared in
.Fx 4.2 .
.Sh AUTHORS
+.An -nosplit
The
.Nm
utility was written by
diff --git a/usr.sbin/crunch/examples/really-big.conf b/usr.sbin/crunch/examples/really-big.conf
index 12c08b73936f..9c227a7b8d29 100644
--- a/usr.sbin/crunch/examples/really-big.conf
+++ b/usr.sbin/crunch/examples/really-big.conf
@@ -52,7 +52,7 @@ progs tty ul uname unexpand unifdef uniq units unvis users uudecode uuencode
progs vacation vgrind vi vis vmstat w wall wc what whatis whereis who
progs whois window write xargs xinstall xstr yacc yes ypcat ypmatch ypwhich
-# shell scripts: lorder mkdep shar which
+# shell scripts: lorder mkdep which
# problems: rdist uses libcompat.a(regex.o), which conflicts with
# libedit(readline.o) over regerror().