From c2f5ede5e0b4931820affcb7fdc57d959d02374a Mon Sep 17 00:00:00 2001 From: Jim Garlick Date: Fri, 7 Nov 2025 08:09:53 -0800 Subject: [PATCH 1/8] diodcli: fix alpine compilation issue Problem: on alpine linux, diodcli won't compile because basename(3) is undefined. Add missing include directive. --- src/cmd/diodcli.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cmd/diodcli.c b/src/cmd/diodcli.c index 67eaf20b..ab16eb65 100644 --- a/src/cmd/diodcli.c +++ b/src/cmd/diodcli.c @@ -45,6 +45,7 @@ #include #include #include +#include #if HAVE_SYS_XATTR_H #include #else From 9029fbf17f58a4d242c900d5a5abd03321b2c74e Mon Sep 17 00:00:00 2001 From: Jim Garlick Date: Fri, 7 Nov 2025 08:13:59 -0800 Subject: [PATCH 2/8] diod: fix alpine AF_UNIX getnameinfo failure Problem: diod refuses to accept AF_UNIX connections on alpine linux. The musl libc getnameinfo(3) fails with EAI_FAMILY when presented with an AF_UNIX socket, unlike glibc which looks up the name as "localhost" (NI_NUMERICHOST) or the local hostname. Just set the client ID to one of the above when accepting an AF_UNIX socket. --- src/libdiod/diod_sock.c | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/src/libdiod/diod_sock.c b/src/libdiod/diod_sock.c index 48b0bca7..12a80f8a 100644 --- a/src/libdiod/diod_sock.c +++ b/src/libdiod/diod_sock.c @@ -333,27 +333,34 @@ diod_sock_accept_one (Npsrv *srv, int fd, int lookup) err ("accept"); return; } - if ((res = getnameinfo ((struct sockaddr *)&addr, addr_size, - ip, sizeof(ip), svc, sizeof(svc), - NI_NUMERICHOST | NI_NUMERICSERV))) { - msg ("getnameinfo: %s", gai_strerror(res)); - close (fd); - return; + /* N.B. although glibc getnameinfo() sets ip to "localhost" for + * AF_UNIX, musl libc fails with EAI_FAMILY. Hence, getnameinfo() is + * only attempted for non-AF_UNIX. See also chaos/diod#160 + */ + if (addr.ss_family == AF_UNIX) { + if (!lookup || gethostname (host, sizeof (host)) < 0) + snprintf (host, sizeof (host), "localhost"); } - if (addr.ss_family != AF_UNIX) { + else { + if ((res = getnameinfo ((struct sockaddr *)&addr, addr_size, + ip, sizeof(ip), svc, sizeof(svc), + NI_NUMERICHOST | NI_NUMERICSERV))) { + msg ("getnameinfo: %s", gai_strerror(res)); + close (fd); + return; + } + if (lookup && (res = getnameinfo ((struct sockaddr *)&addr, addr_size, + host, sizeof(host), NULL, 0, 0))) { + msg ("getnameinfo: %s", gai_strerror(res)); + close (fd); + return; + } + port = strtoul (svc, NULL, 10); + if (port < IPPORT_RESERVED && port >= IPPORT_RESERVED / 2) + flags |= CONN_FLAGS_PRIVPORT; (void)_disable_nagle (fd); (void)_enable_keepalive (fd); } - host[0] = '\0'; - if (lookup && (res = getnameinfo ((struct sockaddr *)&addr, addr_size, - host, sizeof(host), NULL, 0, 0))) { - msg ("getnameinfo: %s", gai_strerror(res)); - close (fd); - return; - } - port = strtoul (svc, NULL, 10); - if (port < IPPORT_RESERVED && port >= IPPORT_RESERVED / 2) - flags |= CONN_FLAGS_PRIVPORT; diod_sock_startfd (srv, fd, fd, strlen(host) > 0 ? host : ip, flags); } From 2813a8f31653d0dc9ad89ac5cb662f69795eb1e9 Mon Sep 17 00:00:00 2001 From: Jim Garlick Date: Fri, 7 Nov 2025 08:49:31 -0800 Subject: [PATCH 3/8] sharness: set SUDO to preserve environment Problem: when test clients need to run as root, they use $SUDO -E to ensure DIOD_ environment variables pass through, which is not only tedious but makes it hard to redefine SUDO to an alternative like doas(8). Redefine $SUDO to "sudo -E". Updates tests to drop explicit -E flag. --- t/sharness.d/10-sudo.sh | 2 +- t/t0001-basic-runasuser.t | 8 ++++---- t/t0002-basic-allsquash.t | 8 ++++---- t/t0003-basic-multiuser.t | 16 ++++++++-------- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/t/sharness.d/10-sudo.sh b/t/sharness.d/10-sudo.sh index 6f13a233..4a7cfd1a 100644 --- a/t/sharness.d/10-sudo.sh +++ b/t/sharness.d/10-sudo.sh @@ -3,12 +3,12 @@ ## if sudo --non-interactive true >/dev/null 2>&1; then test_set_prereq SUDO + SUDO="sudo -E" fi ## # Fixup sudo commandline if sanitizers are enabled. # LSan doesn't work under setuid or program run under sudo ## -SUDO=sudo if test_have_prereq ASAN; then SUDO="sudo -E ASAN_OPTIONS=$ASAN_OPTIONS:detect_leaks=0" fi diff --git a/t/t0001-basic-runasuser.t b/t/t0001-basic-runasuser.t index 3484466e..153f0137 100755 --- a/t/t0001-basic-runasuser.t +++ b/t/t0001-basic-runasuser.t @@ -54,11 +54,11 @@ test_expect_success 'copy ctl:/zero to ctl:null' ' # implemented directly in libnpfs, bypassing diod_ops.c, where op_attach() # gates access to all other exports. test_expect_success SUDO 'the root user can access ctl:/version' ' - $SUDO -E $PATH_DIODCLI --aname=ctl read version + $SUDO $PATH_DIODCLI --aname=ctl read version ' test_expect_success NOBODY 'the nobody user can access ctl:/version' ' - $SUDO -E -u nobody $PATH_DIODCLI --aname=ctl read version + $SUDO -u nobody $PATH_DIODCLI --aname=ctl read version ' test_expect_success 'ls net:/ shows test files' ' @@ -87,13 +87,13 @@ test_expect_success 'cat net:/1/c produced test file content' ' ' test_expect_success SUDO 'cat net:/1/c fails as root' ' - test_must_fail $SUDO -E \ + test_must_fail $SUDO \ $PATH_DIODCLI --aname=$exportdir read /1/c 2>rootcat.err && grep "Operation not permitted" rootcat.err ' test_expect_success NOBODY 'cat net:/1/c fails as nobody' ' - test_must_fail $SUDO -E -u nobody \ + test_must_fail $SUDO -u nobody \ $PATH_DIODCLI --aname=$exportdir read /1/c \ 2>nobodycat.err && grep "Operation not permitted" nobodycat.err diff --git a/t/t0002-basic-allsquash.t b/t/t0002-basic-allsquash.t index 7cd7606c..984d3d3b 100755 --- a/t/t0002-basic-allsquash.t +++ b/t/t0002-basic-allsquash.t @@ -29,21 +29,21 @@ test_expect_success 'the squash user can access ctl:/version' ' ' test_expect_success SUDO 'the root user can access ctl:/version' ' - $SUDO -E $PATH_DIODCLI --aname=ctl read version + $SUDO $PATH_DIODCLI --aname=ctl read version ' test_expect_success NOBODY 'the nobody user can access ctl:/version' ' - $SUDO -E -u nobody $PATH_DIODCLI --aname=ctl read version + $SUDO -u nobody $PATH_DIODCLI --aname=ctl read version ' test_expect_success 'the squash user can access net:/a' ' $PATH_DIODCLI --aname=$exportdir read /a ' test_expect_success SUDO 'the root user can access net:/a' ' - $SUDO -E $PATH_DIODCLI --aname=$exportdir read /a + $SUDO $PATH_DIODCLI --aname=$exportdir read /a ' test_expect_success NOBODY 'the nobody user can access net:/a' ' - $SUDO -E -u nobody $PATH_DIODCLI --aname=$exportdir read /a + $SUDO -u nobody $PATH_DIODCLI --aname=$exportdir read /a ' test_expect_success 'stop diod' ' diff --git a/t/t0003-basic-multiuser.t b/t/t0003-basic-multiuser.t index 226d5408..ed3ea568 100755 --- a/t/t0003-basic-multiuser.t +++ b/t/t0003-basic-multiuser.t @@ -47,43 +47,43 @@ test_expect_success 'the squash user can access ctl:/version' ' $PATH_DIODCLI --aname=ctl read version ' test_expect_success 'the root user can access ctl:/version' ' - $SUDO -E $PATH_DIODCLI --aname=ctl read version + $SUDO $PATH_DIODCLI --aname=ctl read version ' test_expect_success 'the nobody user can access ctl:/version' ' - $SUDO -E -u nobody $PATH_DIODCLI --aname=ctl read version + $SUDO -u nobody $PATH_DIODCLI --aname=ctl read version ' test_expect_success 'user can access net:/user' ' $PATH_DIODCLI --aname=$exportdir read /user ' test_expect_success 'nobody cannot access net:/user' ' - test_must_fail $SUDO -E -u nobody \ + test_must_fail $SUDO -u nobody \ $PATH_DIODCLI --aname=$exportdir read /user ' test_expect_success 'root can access net:/user' ' - $SUDO -E $PATH_DIODCLI --aname=$exportdir read /user + $SUDO $PATH_DIODCLI --aname=$exportdir read /user ' test_expect_success 'user cannot access net:/nobody' ' test_must_fail $PATH_DIODCLI --aname=$exportdir read /nobody ' test_expect_success 'nobody can access net:/nobody' ' - $SUDO -E -u nobody \ + $SUDO -u nobody \ $PATH_DIODCLI --aname=$exportdir read /nobody ' test_expect_success 'root can access net:/nobody' ' - $SUDO -E $PATH_DIODCLI --aname=$exportdir read /nobody + $SUDO $PATH_DIODCLI --aname=$exportdir read /nobody ' test_expect_success 'user cannot access net:/root' ' test_must_fail $PATH_DIODCLI --aname=$exportdir read /root ' test_expect_success 'nobody cannot access net:/root' ' - test_must_fail $SUDO -E -u nobody \ + test_must_fail $SUDO -u nobody \ $PATH_DIODCLI --aname=$exportdir read /root ' test_expect_success 'root can access net:/root' ' - $SUDO -E $PATH_DIODCLI --aname=$exportdir read /root + $SUDO $PATH_DIODCLI --aname=$exportdir read /root ' test_expect_success 'stop diod' ' From 221e0ec4fed7232cf824919e78f53d98145634f0 Mon Sep 17 00:00:00 2001 From: Jim Garlick Date: Fri, 7 Nov 2025 08:59:01 -0800 Subject: [PATCH 4/8] sharness: use doas(8) if sudo(8) is unavailable Problem: on some systems like alpine linux and the BSDs, doas(8) is preferred over sudo(8). As long as doas(8) is configured for "keepenv" and "nopass", allow it to be used. --- t/sharness.d/10-sudo.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/t/sharness.d/10-sudo.sh b/t/sharness.d/10-sudo.sh index 4a7cfd1a..2e22ce25 100644 --- a/t/sharness.d/10-sudo.sh +++ b/t/sharness.d/10-sudo.sh @@ -4,11 +4,14 @@ if sudo --non-interactive true >/dev/null 2>&1; then test_set_prereq SUDO SUDO="sudo -E" +elif _probeenv=xyz doas -n printenv _probeenv >/dev/null 2>&1; then + test_set_prereq SUDO + SUDO="doas" fi ## # Fixup sudo commandline if sanitizers are enabled. # LSan doesn't work under setuid or program run under sudo ## if test_have_prereq ASAN; then - SUDO="sudo -E ASAN_OPTIONS=$ASAN_OPTIONS:detect_leaks=0" + SUDO="ASAN_OPTIONS=$ASAN_OPTIONS:detect_leaks=0 $SUDO" fi From 662e24c922f9dc37576622e02ee845a0fe15613f Mon Sep 17 00:00:00 2001 From: Jim Garlick Date: Fri, 7 Nov 2025 09:24:11 -0800 Subject: [PATCH 5/8] testsuite: fix alpine compilation issue Problem: on alpine linux, test_flock_single won't compile because open(2) is undefined. Add missing include directives. --- src/cmd/test/flock_single.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/cmd/test/flock_single.c b/src/cmd/test/flock_single.c index daa677ea..cbb01b81 100644 --- a/src/cmd/test/flock_single.c +++ b/src/cmd/test/flock_single.c @@ -13,6 +13,9 @@ #if HAVE_CONFIG_H #include "config.h" #endif +#include +#include +#include #include #include #include From 768e61d2f2e5c4e7443b8283c8e1848fa4004d4e Mon Sep 17 00:00:00 2001 From: Jim Garlick Date: Fri, 7 Nov 2025 09:48:39 -0800 Subject: [PATCH 6/8] testsuite: fix umount option portability Problem: the test suite uses umount --lazy, which fails on alpine linux. Use umount -l instead. --- t/t0010-v9fs-runasuser.t | 2 +- t/t0011-v9fs-allsquash.t | 2 +- t/t0012-v9fs-multiuser.t | 2 +- t/t0013-v9fs-acl.t | 2 +- t/t0020-dbench.t | 2 +- t/t0021-postmark.t | 2 +- t/t0022-scrub.t | 2 +- t/t0023-rsync.t | 2 +- t/t0024-selfhost.t | 2 +- t/t0025-pathwalk.t | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/t/t0010-v9fs-runasuser.t b/t/t0010-v9fs-runasuser.t index b308915d..7c513c7f 100755 --- a/t/t0010-v9fs-runasuser.t +++ b/t/t0010-v9fs-runasuser.t @@ -30,7 +30,7 @@ test_under_diod unixsocket \ # gnome probes for .Trash, autorun.inf, etc asynchronously on new mounts, # causing umount to fail with EBUSY if still in progress. Therefore --lazy. -umountcmd="$SUDO umount --lazy" +umountcmd="$SUDO umount -l" mountcmd="$SUDO mount -n -t 9p" mountopts="trans=unix,uname=$(id -un)" diff --git a/t/t0011-v9fs-allsquash.t b/t/t0011-v9fs-allsquash.t index 73ae2baa..0fb2416c 100755 --- a/t/t0011-v9fs-allsquash.t +++ b/t/t0011-v9fs-allsquash.t @@ -27,7 +27,7 @@ test_under_diod unixsocket \ # gnome probes for .Trash, autorun.inf, etc asynchronously on new mounts, # causing umount to fail with EBUSY if still in progress. Therefore --lazy. -umountcmd="$SUDO umount --lazy" +umountcmd="$SUDO umount -l" mountcmd="$SUDO mount -n -t 9p" mountopts="trans=unix,uname=$(id -un)" diff --git a/t/t0012-v9fs-multiuser.t b/t/t0012-v9fs-multiuser.t index b2cdb0ce..11dd32e9 100755 --- a/t/t0012-v9fs-multiuser.t +++ b/t/t0012-v9fs-multiuser.t @@ -38,7 +38,7 @@ fi # gnome probes for .Trash, autorun.inf, etc asynchronously on new mounts, # causing umount to fail with EBUSY if still in progress. Therefore --lazy. -umountcmd="$SUDO umount --lazy" +umountcmd="$SUDO umount -l" mountcmd="$SUDO mount -n -t 9p" mountopts="trans=unix,uname=$(id -un)" diff --git a/t/t0013-v9fs-acl.t b/t/t0013-v9fs-acl.t index 3a5d6bd8..c1f97ae5 100755 --- a/t/t0013-v9fs-acl.t +++ b/t/t0013-v9fs-acl.t @@ -34,7 +34,7 @@ test_under_diod unixsocketroot \ # gnome probes for .Trash, autorun.inf, etc asynchronously on new mounts, # causing umount to fail with EBUSY if still in progress. Therefore --lazy. -umountcmd="$SUDO umount --lazy" +umountcmd="$SUDO umount -l" test_expect_success 'create export/mount directories' ' mkdir -p exp mnt diff --git a/t/t0020-dbench.t b/t/t0020-dbench.t index a9a549dc..93b03536 100755 --- a/t/t0020-dbench.t +++ b/t/t0020-dbench.t @@ -35,7 +35,7 @@ test_under_diod unixsocket \ # gnome probes for .Trash, autorun.inf, etc asynchronously on new mounts, # causing umount to fail with EBUSY if still in progress. Therefore --lazy. -umountcmd="$SUDO umount --lazy" +umountcmd="$SUDO umount -l" mountcmd="$SUDO mount -n -t 9p" mountopts="trans=unix,uname=$(id -un)" diff --git a/t/t0021-postmark.t b/t/t0021-postmark.t index f390da95..a13673c2 100755 --- a/t/t0021-postmark.t +++ b/t/t0021-postmark.t @@ -35,7 +35,7 @@ test_under_diod unixsocket \ # gnome probes for .Trash, autorun.inf, etc asynchronously on new mounts, # causing umount to fail with EBUSY if still in progress. Therefore --lazy. -umountcmd="$SUDO umount --lazy" +umountcmd="$SUDO umount -l" mountcmd="$SUDO mount -n -t 9p" mountopts="trans=unix,uname=$(id -un)" diff --git a/t/t0022-scrub.t b/t/t0022-scrub.t index 5e8c638c..9d8b0f51 100755 --- a/t/t0022-scrub.t +++ b/t/t0022-scrub.t @@ -34,7 +34,7 @@ test_under_diod unixsocket \ # gnome probes for .Trash, autorun.inf, etc asynchronously on new mounts, # causing umount to fail with EBUSY if still in progress. Therefore --lazy. -umountcmd="$SUDO umount --lazy" +umountcmd="$SUDO umount -l" mountcmd="$SUDO mount -n -t 9p" mountopts="trans=unix,uname=$(id -un)" diff --git a/t/t0023-rsync.t b/t/t0023-rsync.t index c7bea400..6a040e68 100755 --- a/t/t0023-rsync.t +++ b/t/t0023-rsync.t @@ -35,7 +35,7 @@ test_under_diod unixsocketroot \ # gnome probes for .Trash, autorun.inf, etc asynchronously on new mounts, # causing umount to fail with EBUSY if still in progress. Therefore --lazy. -umountcmd="$SUDO umount --lazy" +umountcmd="$SUDO umount -l" test_expect_success 'create export/mount directories' ' mkdir -p exp mnt diff --git a/t/t0024-selfhost.t b/t/t0024-selfhost.t index e09cd352..8c20eaf6 100755 --- a/t/t0024-selfhost.t +++ b/t/t0024-selfhost.t @@ -38,7 +38,7 @@ test_under_diod unixsocket \ # gnome probes for .Trash, autorun.inf, etc asynchronously on new mounts, # causing umount to fail with EBUSY if still in progress. Therefore --lazy. -umountcmd="$SUDO umount --lazy" +umountcmd="$SUDO umount -l" mountcmd="$SUDO mount -n -t 9p" mountopts="trans=unix,uname=$(id -un)" diff --git a/t/t0025-pathwalk.t b/t/t0025-pathwalk.t index 6d2fadf3..0561fc84 100755 --- a/t/t0025-pathwalk.t +++ b/t/t0025-pathwalk.t @@ -26,7 +26,7 @@ test_under_diod unixsocket \ # gnome probes for .Trash, autorun.inf, etc asynchronously on new mounts, # causing umount to fail with EBUSY if still in progress. Therefore --lazy. -umountcmd="$SUDO umount --lazy" +umountcmd="$SUDO umount -l" mountcmd="$SUDO mount -n -t 9p" mountopts="trans=unix,uname=$(id -un)" From 10a39c8caca679d42e6d7f854dc636907ebb2b8a Mon Sep 17 00:00:00 2001 From: Jim Garlick Date: Fri, 7 Nov 2025 10:09:03 -0800 Subject: [PATCH 7/8] testsuite: fix alpine stat -f portability Problem: stat -f on alpine/busybox cannot decode the 9p file system type and reports UNKNOWN causing a test to fail there. Use %t instead of %T to check the undecoded value instead. --- t/t0010-v9fs-runasuser.t | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/t/t0010-v9fs-runasuser.t b/t/t0010-v9fs-runasuser.t index 7c513c7f..2e4c5590 100755 --- a/t/t0010-v9fs-runasuser.t +++ b/t/t0010-v9fs-runasuser.t @@ -83,9 +83,10 @@ test_expect_success 'mount filesystem with access= on mnt' ' $mountcmd -oaname=$exportdir,$mountopts,access=$(id -u) \ $DIOD_SOCKET mnt ' +# On alpine/busybox, %T decodes as type=UNKNOWN. Use %t instead. test_expect_success STAT 'file system type is v9fs' ' - echo v9fs >type.exp && - stat -f -c "%T" mnt >type.out && + echo 1021997 >type.exp && + stat -f -c "%t" mnt >type.out && test_cmp type.exp type.out ' test_expect_success STAT 'client/server mount point stats match' ' From 43cc75a7c3028aebcd6a389e98c3d1d336feb14d Mon Sep 17 00:00:00 2001 From: Jim Garlick Date: Fri, 7 Nov 2025 10:23:49 -0800 Subject: [PATCH 8/8] testsuite: fix allsquash mkdir test on alpine Problem: a test that calls "mkdir -m 755 dir" as root on an allsquash mount fails on alpine linux. stracing "mkdir -m 755" shows that alpine calls mkdirat(AT_FDCWD, "/tmp/yyy", 0777) = 0 fchmodat(AT_FDCWD, "/tmp/yyy", 0755) = 0 while glibc calls: mkdir("/tmp/zzz", 0755) = 0 Presumably the fchmodat is failing because, because root no longer owns the file after the mkdirat due to the squashing. In that test, perform the chmod separately as the squash user. --- t/t0011-v9fs-allsquash.t | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/t/t0011-v9fs-allsquash.t b/t/t0011-v9fs-allsquash.t index 0fb2416c..78a42a8e 100755 --- a/t/t0011-v9fs-allsquash.t +++ b/t/t0011-v9fs-allsquash.t @@ -50,8 +50,12 @@ test_expect_success SUDO,STAT 'root can create a directory, mode 755' ' $SUDO mkdir -m 755 mnt/rootdir && test "$($PATH_STAT -c "%u:%g" exp/rootdir)" = "$(id -u):$(id -g)" ' +# N.B. fails on alpine/busybox when mkdir -m 755 is used because alpine +# calls mkdir and chmod separately, so the chmod isn't allowed. +# Do the chmod as the squashuser instead. test_expect_success NOBODY,STAT 'nobody can create a directory, mode 755' ' - $SUDO -u nobody mkdir -m 755 mnt/nobodydir && + $SUDO -u nobody mkdir mnt/nobodydir && + chmod 755 mnt/nobodydir && test "$($PATH_STAT -c "%u:%g" exp/nobodydir)" = "$(id -u):$(id -g)" '