From ccdc019b77e7a4b680e803c31fd0438293518b66 Mon Sep 17 00:00:00 2001
From: Andrew Tridgell <andrew@tridgell.net>
Date: Thu, 4 Jun 2026 14:46:38 +1000
Subject: [PATCH 66/81] build: fall back to do_mknod() when mknodat() is
 unavailable (#896)

do_mknod_at() (the symlink-race-safe variant used by a non-chrooted
daemon receiver) calls mknodat()/mkfifoat(), but the at-variant was
gated only on AT_FDCWD.  Older Darwin declares AT_FDCWD without
mknodat(), so the build failed with "mknodat undeclared".

Probe mknodat()/mkfifoat() in configure and require HAVE_MKNODAT for the
at-variant; without it do_mknod_at() falls back to do_mknod(), exactly
as it already does where AT_FDCWD is missing.  Linux keeps the mknodat
path since HAVE_MKNODAT is defined there.

Thanks to @debohman for the report (#896).

Fixes: #896
(cherry picked from commit 24d75c04e43b81d3af538002684999264f591876)
---
 configure.ac | 2 +-
 syscall.c    | 6 ++++--
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/configure.ac b/configure.ac
index 87b900c5..8fb6a992 100644
--- a/configure.ac
+++ b/configure.ac
@@ -868,7 +868,7 @@ AC_FUNC_UTIME_NULL
 AC_FUNC_ALLOCA
 AC_CHECK_FUNCS(waitpid wait4 getcwd chown chmod lchmod mknod mkfifo \
     fchmod fstat ftruncate strchr readlink link utime utimes lutimes strftime \
-    chflags getattrlist mktime innetgr linkat \
+    chflags getattrlist mktime innetgr linkat mknodat mkfifoat \
     memmove lchown vsnprintf snprintf vasprintf asprintf setsid strpbrk \
     strlcat strlcpy strtol mallinfo mallinfo2 getgroups setgroups geteuid getegid \
     setlocale setmode open64 lseek64 mkstemp64 mtrace va_copy __va_copy \
diff --git a/syscall.c b/syscall.c
index 4f456807..95be2ac4 100644
--- a/syscall.c
+++ b/syscall.c
@@ -535,7 +535,9 @@ int do_mknod(const char *pathname, mode_t mode, dev_t dev)
 */
 int do_mknod_at(const char *pathname, mode_t mode, dev_t dev)
 {
-#ifdef AT_FDCWD
+	/* HAVE_MKNODAT: older Darwin declares AT_FDCWD but not mknodat(), so
+	 * the at-variant won't build there; fall back to do_mknod() (#896). */
+#if defined(AT_FDCWD) && defined(HAVE_MKNODAT)
 	extern int am_daemon, am_chrooted;
 	char dirpath[MAXPATHLEN];
 	const char *bname;
@@ -597,7 +599,7 @@ int do_mknod_at(const char *pathname, mode_t mode, dev_t dev)
 		return ret;
 	}
 
-#if !defined MKNOD_CREATES_FIFOS && defined HAVE_MKFIFO
+#if !defined MKNOD_CREATES_FIFOS && defined HAVE_MKFIFO && defined HAVE_MKFIFOAT
 	if (S_ISFIFO(mode))
 		ret = mkfifoat(dfd, bname, mode);
 	else
-- 
2.53.0

