From 57fe787cb83fe5efc51995f5a18b71c54761ae25 Mon Sep 17 00:00:00 2001 From: Lingao Meng Date: Thu, 16 Jul 2026 15:14:59 +0800 Subject: [PATCH 1/5] arch/sim: Add AF_LOCAL support to host usrsock The sim host usrsock backend only accepted INET/NETLINK domains and translated socket addresses through plain struct sockaddr. That prevents simulated applications from using POSIX AF_LOCAL sockets through the standard socket API when CONFIG_NET_USRSOCK is used. Add AF_LOCAL address conversion for struct sockaddr_un, allow PF_LOCAL sockets through usrsock, handle NuttX socket type flags, and poll host descriptors from the sim usrsock work item so nonblocking connect/read/write readiness is reported back to NuttX. Use sockaddr_storage for native address translation so larger address structures are not truncated. Testing: - Host: Ubuntu 22.04 x86_64. - Board/config: sim:nsh with CONFIG_NET_USRSOCK=y and CONFIG_EXAMPLES_HELLO=y. - make clean && make -j16. - Ran a temporary hello example that connected to host AF_UNIX SOCK_STREAM and SOCK_SEQPACKET sockets through NuttX socket(), connect(), write(), and read(); both received pong and printed AF_LOCAL usrsock test passed. Signed-off-by: Lingao Meng --- arch/sim/src/sim/posix/sim_hostusrsock.c | 241 ++++++++++++++++++----- arch/sim/src/sim/sim_hostusrsock.h | 8 + arch/sim/src/sim/sim_usrsock.c | 1 + net/usrsock/usrsock_sockif.c | 4 +- 4 files changed, 198 insertions(+), 56 deletions(-) diff --git a/arch/sim/src/sim/posix/sim_hostusrsock.c b/arch/sim/src/sim/posix/sim_hostusrsock.c index 4ba0fb0dafa54..4ebc3eb2410a7 100644 --- a/arch/sim/src/sim/posix/sim_hostusrsock.c +++ b/arch/sim/src/sim/posix/sim_hostusrsock.c @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -39,6 +40,7 @@ #include #include +#include #include "sim_internal.h" #include "sim_hostusrsock.h" @@ -92,26 +94,93 @@ static void host_usrsock_set_fd(int fd, fd_set *fds) } } -static void sockaddr_to_native(const struct nuttx_sockaddr *addr, - const nuttx_socklen_t addrlen, - struct sockaddr *naddr, - socklen_t *naddrlen) +static int sockaddr_to_native(const struct nuttx_sockaddr *addr, + const nuttx_socklen_t addrlen, + struct sockaddr_storage *naddr, + socklen_t *naddrlen) { - naddr->sa_family = addr->sa_family; - memcpy(naddr->sa_data, addr->sa_data, sizeof(naddr->sa_data)); + if (addr == NULL || naddr == NULL || naddrlen == NULL) + { + return -EINVAL; + } + + memset(naddr, 0, sizeof(*naddr)); + + if (addr->sa_family == NUTTX_AF_LOCAL) + { + const struct nuttx_sockaddr_un *un = + (const struct nuttx_sockaddr_un *)addr; + struct sockaddr_un *native = (struct sockaddr_un *)naddr; + size_t pathlen; + if (addrlen < offsetof(struct nuttx_sockaddr_un, sun_path) + 1) + { + return -EINVAL; + } + + pathlen = strnlen(un->sun_path, sizeof(un->sun_path)); + if (pathlen >= sizeof(native->sun_path)) + { + return -ENAMETOOLONG; + } + + native->sun_family = AF_UNIX; + memcpy(native->sun_path, un->sun_path, pathlen + 1); + *naddrlen = offsetof(struct sockaddr_un, sun_path) + pathlen + 1; + + return 0; + } + + if (addrlen > sizeof(*naddr)) + { + return -ENOSPC; + } + + memcpy(naddr, addr, addrlen); *naddrlen = addrlen; + + return 0; } -static void sockaddr_to_nuttx(const struct sockaddr *naddr, - const socklen_t naddrlen, - struct nuttx_sockaddr *addr, - nuttx_socklen_t *addrlen) +static int sockaddr_to_nuttx(const struct sockaddr *naddr, + const socklen_t naddrlen, + struct nuttx_sockaddr *addr, + nuttx_socklen_t *addrlen) { - addr->sa_family = naddr->sa_family; - memcpy(addr->sa_data, naddr->sa_data, sizeof(addr->sa_data)); + if (naddr == NULL || addr == NULL || addrlen == NULL) + { + return -EINVAL; + } + if (naddr->sa_family == AF_UNIX) + { + const struct sockaddr_un *native = (const struct sockaddr_un *)naddr; + struct nuttx_sockaddr_un *un = (struct nuttx_sockaddr_un *)addr; + size_t pathlen; + + if (*addrlen < sizeof(*un)) + { + return -ENOSPC; + } + + memset(un, 0, sizeof(*un)); + pathlen = strnlen(native->sun_path, sizeof(native->sun_path)); + un->sun_family = NUTTX_AF_LOCAL; + memcpy(un->sun_path, native->sun_path, pathlen); + *addrlen = offsetof(struct nuttx_sockaddr_un, sun_path) + pathlen + 1; + + return 0; + } + + if (*addrlen < naddrlen) + { + return -ENOSPC; + } + + memcpy(addr, naddr, naddrlen); *addrlen = naddrlen; + + return 0; } static void sock_nonblock(int socket, int enable) @@ -248,34 +317,67 @@ static int host_usrsock_sockopt(int sockfd, int level, int optname, int host_usrsock_socket(int domain, int type, int protocol) { int opt = 1; + int sockflags = 0; int ret; if (domain == NUTTX_PF_INET) { domain = PF_INET; } +#ifdef CONFIG_NET_IPv6 + else if (domain == NUTTX_PF_INET6) + { + domain = PF_INET6; + } +#endif + else if (domain == NUTTX_PF_LOCAL) + { + domain = PF_UNIX; + } else { return -EINVAL; } - if (type == NUTTX_SOCK_STREAM) + if ((type & NUTTX_SOCK_TYPE_MASK) == NUTTX_SOCK_STREAM) { - type = SOCK_STREAM; + sockflags = SOCK_STREAM; } - else if (type == NUTTX_SOCK_DGRAM) + else if ((type & NUTTX_SOCK_TYPE_MASK) == NUTTX_SOCK_DGRAM) { - type = SOCK_DGRAM; + sockflags = SOCK_DGRAM; } - else if (type == NUTTX_SOCK_RAW) + else if ((type & NUTTX_SOCK_TYPE_MASK) == NUTTX_SOCK_RAW) { - type = SOCK_RAW; + sockflags = SOCK_RAW; + } + else if ((type & NUTTX_SOCK_TYPE_MASK) == NUTTX_SOCK_SEQPACKET) + { +#ifdef SOCK_SEQPACKET + sockflags = SOCK_SEQPACKET; +#else + return -EPROTONOSUPPORT; +#endif } else { return -EINVAL; } +#ifdef SOCK_CLOEXEC + if ((type & NUTTX_SOCK_CLOEXEC) != 0) + { + sockflags |= SOCK_CLOEXEC; + } +#endif + +#ifdef SOCK_NONBLOCK + if ((type & NUTTX_SOCK_NONBLOCK) != 0) + { + sockflags |= SOCK_NONBLOCK; + } +#endif + if (protocol == NUTTX_IPPROTO_IP) { protocol = IPPROTO_IP; @@ -297,7 +399,7 @@ int host_usrsock_socket(int domain, int type, int protocol) return -EINVAL; } - ret = socket(domain, type, protocol); + ret = socket(domain, sockflags, protocol); if (ret < 0) { return -errno; @@ -327,20 +429,37 @@ int host_usrsock_connect(int sockfd, const struct nuttx_sockaddr *addr, nuttx_socklen_t addrlen) { - struct sockaddr naddr; + struct sockaddr_storage naddr; socklen_t naddrlen; int ret; - sockaddr_to_native(addr, addrlen, &naddr, &naddrlen); + ret = sockaddr_to_native(addr, addrlen, &naddr, &naddrlen); + if (ret < 0) + { + return ret; + } - sock_nonblock(sockfd, false); - ret = connect(sockfd, &naddr, naddrlen); - sock_nonblock(sockfd, true); + ret = connect(sockfd, (struct sockaddr *)&naddr, naddrlen); if (ret < 0) { + if (errno == EISCONN) + { + host_usrsock_clear_fd(sockfd, &g_active_write_fds); + host_usrsock_set_fd(sockfd, &g_active_read_fds); + return 0; + } + + if (errno == EINPROGRESS || errno == EALREADY || errno == EWOULDBLOCK) + { + host_usrsock_set_fd(sockfd, &g_active_write_fds); + host_usrsock_set_fd(sockfd, &g_active_read_fds); + return -EINPROGRESS; + } + return -errno; } + host_usrsock_clear_fd(sockfd, &g_active_write_fds); host_usrsock_set_fd(sockfd, &g_active_read_fds); return ret; @@ -351,14 +470,20 @@ ssize_t host_usrsock_sendto(int sockfd, const void *buf, const struct nuttx_sockaddr *dest_addr, nuttx_socklen_t addrlen) { - struct sockaddr naddr; + struct sockaddr_storage naddr; socklen_t naddrlen; int ret; if (dest_addr && addrlen >= sizeof(*dest_addr)) { - sockaddr_to_native(dest_addr, addrlen, &naddr, &naddrlen); - ret = sendto(sockfd, buf, len, flags, &naddr, naddrlen); + ret = sockaddr_to_native(dest_addr, addrlen, &naddr, &naddrlen); + if (ret < 0) + { + return ret; + } + + ret = sendto(sockfd, buf, len, flags, + (struct sockaddr *)&naddr, naddrlen); } else { @@ -384,14 +509,14 @@ ssize_t host_usrsock_recvfrom(int sockfd, void *buf, size_t len, int flags, struct nuttx_sockaddr *src_addr, nuttx_socklen_t *addrlen) { - struct sockaddr naddr; - socklen_t naddrlen; + struct sockaddr_storage naddr; + socklen_t naddrlen = sizeof(naddr); int ret; - if (src_addr && addrlen && *addrlen >= sizeof(*src_addr)) + if (src_addr && addrlen) { - sockaddr_to_native(src_addr, *addrlen, &naddr, &naddrlen); - ret = recvfrom(sockfd, buf, len, flags, &naddr, &naddrlen); + ret = recvfrom(sockfd, buf, len, flags, + (struct sockaddr *)&naddr, &naddrlen); } else { @@ -408,9 +533,10 @@ ssize_t host_usrsock_recvfrom(int sockfd, void *buf, size_t len, int flags, return -errno; } - if (src_addr && addrlen && *addrlen >= sizeof(*src_addr)) + if (src_addr && addrlen) { - sockaddr_to_nuttx(&naddr, naddrlen, src_addr, addrlen); + sockaddr_to_nuttx((struct sockaddr *)&naddr, naddrlen, src_addr, + addrlen); } host_usrsock_set_fd(sockfd, &g_active_read_fds); @@ -436,19 +562,20 @@ int host_usrsock_getsockname(int sockfd, struct nuttx_sockaddr *addr, nuttx_socklen_t *addrlen) { - socklen_t naddrlen = sizeof(struct sockaddr); - struct sockaddr naddr; + socklen_t naddrlen = sizeof(struct sockaddr_storage); + struct sockaddr_storage naddr; int ret; - ret = getsockname(sockfd, &naddr, &naddrlen); + ret = getsockname(sockfd, (struct sockaddr *)&naddr, &naddrlen); if (ret < 0) { return -errno; } - if (addr && addrlen && *addrlen >= sizeof(*addr)) + if (addr && addrlen) { - sockaddr_to_nuttx(&naddr, naddrlen, addr, addrlen); + ret = sockaddr_to_nuttx((struct sockaddr *)&naddr, naddrlen, addr, + addrlen); } return ret; @@ -458,19 +585,20 @@ int host_usrsock_getpeername(int sockfd, struct nuttx_sockaddr *addr, nuttx_socklen_t *addrlen) { - socklen_t naddrlen = sizeof(struct sockaddr); - struct sockaddr naddr; + socklen_t naddrlen = sizeof(struct sockaddr_storage); + struct sockaddr_storage naddr; int ret; - ret = getpeername(sockfd, &naddr, &naddrlen); + ret = getpeername(sockfd, (struct sockaddr *)&naddr, &naddrlen); if (ret < 0) { return -errno; } - if (addr && addrlen && *addrlen >= sizeof(*addr)) + if (addr && addrlen) { - sockaddr_to_nuttx(&naddr, naddrlen, addr, addrlen); + ret = sockaddr_to_nuttx((struct sockaddr *)&naddr, naddrlen, addr, + addrlen); } return ret; @@ -480,12 +608,17 @@ int host_usrsock_bind(int sockfd, const struct nuttx_sockaddr *addr, nuttx_socklen_t addrlen) { - struct sockaddr naddr; + struct sockaddr_storage naddr; socklen_t naddrlen; + int ret; - sockaddr_to_native(addr, addrlen, &naddr, &naddrlen); + ret = sockaddr_to_native(addr, addrlen, &naddr, &naddrlen); + if (ret < 0) + { + return ret; + } - return bind(sockfd, &naddr, naddrlen) < 0 ? -errno : 0; + return bind(sockfd, (struct sockaddr *)&naddr, naddrlen) < 0 ? -errno : 0; } int host_usrsock_listen(int sockfd, int backlog) @@ -506,19 +639,19 @@ int host_usrsock_listen(int sockfd, int backlog) int host_usrsock_accept(int sockfd, struct nuttx_sockaddr *addr, nuttx_socklen_t *addrlen) { - socklen_t naddrlen = sizeof(socklen_t); - struct sockaddr naddr; + socklen_t naddrlen = sizeof(struct sockaddr_storage); + struct sockaddr_storage naddr; int ret; - ret = accept(sockfd, &naddr, &naddrlen); - if (ret <= 0) + ret = accept(sockfd, (struct sockaddr *)&naddr, &naddrlen); + if (ret < 0) { return -errno; } - if (addr && addrlen && *addrlen >= sizeof(*addr)) + if (addr && addrlen) { - sockaddr_to_nuttx(&naddr, naddrlen, addr, addrlen); + sockaddr_to_nuttx((struct sockaddr *)&naddr, naddrlen, addr, addrlen); } sock_nonblock(ret, true); @@ -562,7 +695,7 @@ void host_usrsock_loop(void) int ret; int i; - if (g_active_maxfd <= 0) + if (g_active_maxfd < 0) { return; } diff --git a/arch/sim/src/sim/sim_hostusrsock.h b/arch/sim/src/sim/sim_hostusrsock.h index e5fb2f10d3d31..34a2ce243b563 100644 --- a/arch/sim/src/sim/sim_hostusrsock.h +++ b/arch/sim/src/sim/sim_hostusrsock.h @@ -83,6 +83,8 @@ #define NUTTX_PF_PKTRADIO 64 #define NUTTX_PF_RPMSG 65 +#define NUTTX_UNIX_PATH_MAX 108 + #define NUTTX_AF_UNSPEC NUTTX_PF_UNSPEC #define NUTTX_AF_UNIX NUTTX_PF_UNIX #define NUTTX_AF_LOCAL NUTTX_PF_LOCAL @@ -219,6 +221,12 @@ struct nuttx_sockaddr char sa_data[14]; /* 14-bytes data (actually variable length) */ }; +struct nuttx_sockaddr_un +{ + sa_family_t sun_family; /* Address family: AF_LOCAL */ + char sun_path[NUTTX_UNIX_PATH_MAX]; +}; + struct nuttx_linger { int l_onoff; /* Indicates whether linger option is enabled. */ diff --git a/arch/sim/src/sim/sim_usrsock.c b/arch/sim/src/sim/sim_usrsock.c index c8210d0336149..ae41fc663b089 100644 --- a/arch/sim/src/sim/sim_usrsock.c +++ b/arch/sim/src/sim/sim_usrsock.c @@ -415,6 +415,7 @@ static const usrsock_handler_t g_usrsock_handler[] = static void sim_usrsock_work(void *arg) { + host_usrsock_loop(); work_queue_next_wq(g_work_queue, &g_usrsock.work, sim_usrsock_work, NULL, SIM_USRSOCK_PERIOD); } diff --git a/net/usrsock/usrsock_sockif.c b/net/usrsock/usrsock_sockif.c index 28079dfd38cf0..da1ea2005e32a 100644 --- a/net/usrsock/usrsock_sockif.c +++ b/net/usrsock/usrsock_sockif.c @@ -103,9 +103,9 @@ static int usrsock_sockif_setup(FAR struct socket *psock) int ret; if (psock->s_domain != PF_INET && psock->s_domain != PF_INET6 && - psock->s_domain != PF_NETLINK) + psock->s_domain != PF_NETLINK && psock->s_domain != PF_LOCAL) { - return -ENOTSUP; /* Only ipv4, ipv6 and netlink support the offload */ + return -ENOTSUP; /* Only supported families can use usrsock offload */ }; /* Let the user socket logic handle the setup... From 91de62a5b03adba8dd8b82468d25747c2ad41530 Mon Sep 17 00:00:00 2001 From: Lingao Meng Date: Thu, 16 Jul 2026 15:26:05 +0800 Subject: [PATCH 2/5] fs/hostfs: Handle POSIX byte-range locks fcntl(F_GETLK/F_SETLK/F_SETLKW) is handled by VFS and reaches file systems as private FIOC_* ioctl commands. hostfs previously forwarded those private ioctl command numbers to the host ioctl backend, which is not the POSIX file-locking interface and cannot be interpreted by the host OS. Route F_GETLK and non-blocking F_SETLK through a host_fcntl() backend operation instead. The POSIX sim backend translates the NuttX fcntl commands, open flags and struct flock ABI to host values before calling host fcntl(). Backends that cannot forward host file locks return -ENOTTY from host_fcntl(), which lets VFS fall back to NuttX internal file-lock handling. Do not forward F_SETLKW to the host. A blocking host fcntl() can stop the whole simulated OS, so hostfs returns -ENOTTY and lets VFS handle the blocking lock in NuttX. Testing: - Host: Ubuntu 22.04 x86_64. - Board/config: sim:nsh with CONFIG_FS_HOSTFS=y, CONFIG_SIM_HOSTFS=y and CONFIG_EXAMPLES_HELLO=y. - make clean && make -j16. - Ran a temporary hello example that mounted /tmp through hostfs, opened a host-backed file, then successfully executed fcntl(F_SETLK), fcntl(F_GETLK), and fcntl(F_SETLK) with F_UNLCK. The app printed "hostfs fcntl lock test passed". Signed-off-by: Lingao Meng --- arch/arm/src/common/arm_hostfs.c | 5 + arch/arm64/src/common/arm64_hostfs.c | 5 + arch/risc-v/src/common/riscv_hostfs.c | 5 + arch/sim/src/sim/posix/sim_hostfs.c | 330 ++++++++++++++++++++----- arch/sim/src/sim/win/sim_hostfs.c | 9 + arch/xtensa/src/common/xtensa_hostfs.c | 5 + fs/hostfs/hostfs.c | 24 ++ include/nuttx/fs/hostfs.h | 26 ++ 8 files changed, 344 insertions(+), 65 deletions(-) diff --git a/arch/arm/src/common/arm_hostfs.c b/arch/arm/src/common/arm_hostfs.c index fbfd9a5248545..cc208ed512097 100644 --- a/arch/arm/src/common/arm_hostfs.c +++ b/arch/arm/src/common/arm_hostfs.c @@ -235,6 +235,11 @@ int host_ioctl(int fd, int request, unsigned long arg) return -ENOSYS; } +int host_fcntl(int fd, int cmd, ...) +{ + return -ENOTTY; +} + void host_sync(int fd) { } diff --git a/arch/arm64/src/common/arm64_hostfs.c b/arch/arm64/src/common/arm64_hostfs.c index ddd064ed07d41..402733b00fe8f 100644 --- a/arch/arm64/src/common/arm64_hostfs.c +++ b/arch/arm64/src/common/arm64_hostfs.c @@ -235,6 +235,11 @@ int host_ioctl(int fd, int request, unsigned long arg) return -ENOSYS; } +int host_fcntl(int fd, int cmd, ...) +{ + return -ENOTTY; +} + void host_sync(int fd) { } diff --git a/arch/risc-v/src/common/riscv_hostfs.c b/arch/risc-v/src/common/riscv_hostfs.c index c077044054ecb..5d0566dab8e8d 100644 --- a/arch/risc-v/src/common/riscv_hostfs.c +++ b/arch/risc-v/src/common/riscv_hostfs.c @@ -235,6 +235,11 @@ int host_ioctl(int fd, int request, unsigned long arg) return -ENOSYS; } +int host_fcntl(int fd, int cmd, ...) +{ + return -ENOTTY; +} + void host_sync(int fd) { } diff --git a/arch/sim/src/sim/posix/sim_hostfs.c b/arch/sim/src/sim/posix/sim_hostfs.c index 8716e9fe5123f..7e032ebd88577 100644 --- a/arch/sim/src/sim/posix/sim_hostfs.c +++ b/arch/sim/src/sim/posix/sim_hostfs.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "hostfs.h" #include "sim_internal.h" @@ -43,6 +44,186 @@ * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: host_oflags_convert + ****************************************************************************/ + +static int host_oflags_convert(int flags) +{ + int mapflags = 0; + + switch (flags & NUTTX_O_ACCMODE) + { + case NUTTX_O_RDONLY: + mapflags = O_RDONLY; + break; + + case NUTTX_O_WRONLY: + mapflags = O_WRONLY; + break; + + case NUTTX_O_RDWR: + mapflags = O_RDWR; + break; + } + + if (flags & NUTTX_O_APPEND) + { + mapflags |= O_APPEND; + } + + if (flags & NUTTX_O_CREAT) + { + mapflags |= O_CREAT; + } + + if (flags & NUTTX_O_EXCL) + { + mapflags |= O_EXCL; + } + + if (flags & NUTTX_O_TRUNC) + { + mapflags |= O_TRUNC; + } + + if (flags & NUTTX_O_NONBLOCK) + { + mapflags |= O_NONBLOCK; + } + + if (flags & NUTTX_O_SYNC) + { + mapflags |= O_SYNC; + } + +#ifdef O_DIRECT + if (flags & NUTTX_O_DIRECT) + { + mapflags |= O_DIRECT; + } +#endif + + if (flags & NUTTX_O_CLOEXEC) + { + mapflags |= O_CLOEXEC; + } + + if (flags & NUTTX_O_DIRECTORY) + { + mapflags |= O_DIRECTORY; + } + + return mapflags; +} + +/**************************************************************************** + * Name: host_oflags_revert + ****************************************************************************/ + +static int host_oflags_revert(int flags) +{ + int mapflags = 0; + + switch (flags & O_ACCMODE) + { + case O_RDONLY: + mapflags = NUTTX_O_RDONLY; + break; + + case O_WRONLY: + mapflags = NUTTX_O_WRONLY; + break; + + case O_RDWR: + mapflags = NUTTX_O_RDWR; + break; + } + + if (flags & O_APPEND) + { + mapflags |= NUTTX_O_APPEND; + } + + if (flags & O_CREAT) + { + mapflags |= NUTTX_O_CREAT; + } + + if (flags & O_EXCL) + { + mapflags |= NUTTX_O_EXCL; + } + + if (flags & O_TRUNC) + { + mapflags |= NUTTX_O_TRUNC; + } + + if (flags & O_NONBLOCK) + { + mapflags |= NUTTX_O_NONBLOCK; + } + + if (flags & O_SYNC) + { + mapflags |= NUTTX_O_SYNC; + } + +#ifdef O_DIRECT + if (flags & O_DIRECT) + { + mapflags |= NUTTX_O_DIRECT; + } +#endif + + if (flags & O_CLOEXEC) + { + mapflags |= NUTTX_O_CLOEXEC; + } + + if (flags & O_DIRECTORY) + { + mapflags |= NUTTX_O_DIRECTORY; + } + + return mapflags; +} + +/**************************************************************************** + * Name: host_fcntl_cmd_convert + ****************************************************************************/ + +static int host_fcntl_cmd_convert(int cmd) +{ + switch (cmd) + { + case NUTTX_F_DUPFD: + return F_DUPFD; + + case NUTTX_F_GETFD: + return F_GETFD; + + case NUTTX_F_GETFL: + return F_GETFL; + + case NUTTX_F_GETLK: + return F_GETLK; + + case NUTTX_F_SETFD: + return F_SETFD; + + case NUTTX_F_SETFL: + return F_SETFL; + + case NUTTX_F_SETLK: + return F_SETLK; + + default: + return -EINVAL; + } +} + /**************************************************************************** * Name: host_stat_convert ****************************************************************************/ @@ -130,71 +311,7 @@ static void host_stat_convert(struct stat *hostbuf, struct nuttx_stat_s *buf) int host_open(const char *pathname, int flags, int mode) { - int mapflags = 0; - - /* Perform flag mapping */ - - switch (flags & NUTTX_O_ACCMODE) - { - case NUTTX_O_RDONLY: - mapflags = O_RDONLY; - break; - - case NUTTX_O_WRONLY: - mapflags = O_WRONLY; - break; - - case NUTTX_O_RDWR: - mapflags = O_RDWR; - break; - } - - if (flags & NUTTX_O_APPEND) - { - mapflags |= O_APPEND; - } - - if (flags & NUTTX_O_CREAT) - { - mapflags |= O_CREAT; - } - - if (flags & NUTTX_O_EXCL) - { - mapflags |= O_EXCL; - } - - if (flags & NUTTX_O_TRUNC) - { - mapflags |= O_TRUNC; - } - - if (flags & NUTTX_O_NONBLOCK) - { - mapflags |= O_NONBLOCK; - } - - if (flags & NUTTX_O_SYNC) - { - mapflags |= O_SYNC; - } - -#ifdef O_DIRECT - if (flags & NUTTX_O_DIRECT) - { - mapflags |= O_DIRECT; - } -#endif - - if (flags & NUTTX_O_CLOEXEC) - { - mapflags |= O_CLOEXEC; - } - - if (flags & NUTTX_O_DIRECTORY) - { - mapflags |= O_DIRECTORY; - } + int mapflags = host_oflags_convert(flags); int ret = open(pathname, mapflags, mode); if (ret == -1) @@ -274,6 +391,89 @@ nuttx_off_t host_lseek(int fd, nuttx_off_t pos, nuttx_off_t offset, return ret; } +/**************************************************************************** + * Name: host_fcntl + ****************************************************************************/ + +int host_fcntl(int fd, int cmd, ...) +{ + struct nuttx_flock_s *lock; + struct flock hostlock; + int hostcmd; + va_list ap; + int arg; + int ret; + + hostcmd = host_fcntl_cmd_convert(cmd); + if (hostcmd < 0) + { + return hostcmd; + } + + va_start(ap, cmd); + + switch (cmd) + { + case NUTTX_F_GETFD: + ret = fcntl(fd, hostcmd); + break; + + case NUTTX_F_GETFL: + ret = fcntl(fd, hostcmd); + if (ret >= 0) + { + ret = host_oflags_revert(ret); + } + + break; + + case NUTTX_F_DUPFD: + case NUTTX_F_SETFD: + case NUTTX_F_SETFL: + arg = va_arg(ap, int); + if (cmd == NUTTX_F_SETFL) + { + arg = host_oflags_convert(arg); + } + + ret = fcntl(fd, hostcmd, arg); + break; + + case NUTTX_F_GETLK: + case NUTTX_F_SETLK: + lock = va_arg(ap, struct nuttx_flock_s *); + hostlock.l_type = lock->l_type; + hostlock.l_whence = lock->l_whence; + hostlock.l_start = lock->l_start; + hostlock.l_len = lock->l_len; + hostlock.l_pid = lock->l_pid; + + ret = fcntl(fd, hostcmd, &hostlock); + if (ret >= 0) + { + lock->l_type = hostlock.l_type; + lock->l_whence = hostlock.l_whence; + lock->l_start = hostlock.l_start; + lock->l_len = hostlock.l_len; + lock->l_pid = hostlock.l_pid; + } + break; + + default: + ret = -1; + errno = EINVAL; + break; + } + + va_end(ap); + if (ret < 0) + { + ret = host_errno_convert(-errno); + } + + return ret; +} + /**************************************************************************** * Name: host_ioctl ****************************************************************************/ diff --git a/arch/sim/src/sim/win/sim_hostfs.c b/arch/sim/src/sim/win/sim_hostfs.c index 5cd0ad1ddf564..ec3fe8f5e9436 100644 --- a/arch/sim/src/sim/win/sim_hostfs.c +++ b/arch/sim/src/sim/win/sim_hostfs.c @@ -227,6 +227,15 @@ int host_ioctl(int fd, int request, unsigned long arg) return -ENOSYS; } +/**************************************************************************** + * Name: host_fcntl + ****************************************************************************/ + +int host_fcntl(int fd, int cmd, ...) +{ + return -ENOTTY; +} + /**************************************************************************** * Name: host_sync ****************************************************************************/ diff --git a/arch/xtensa/src/common/xtensa_hostfs.c b/arch/xtensa/src/common/xtensa_hostfs.c index 74b711cf2ebba..cafcecc4ecc2a 100644 --- a/arch/xtensa/src/common/xtensa_hostfs.c +++ b/arch/xtensa/src/common/xtensa_hostfs.c @@ -143,6 +143,11 @@ int host_ioctl(int fd, int request, unsigned long arg) return -ENOSYS; } +int host_fcntl(int fd, int cmd, ...) +{ + return -ENOTTY; +} + void host_sync(int fd) { } diff --git a/fs/hostfs/hostfs.c b/fs/hostfs/hostfs.c index 092655ef609ae..5fa57715cb371 100644 --- a/fs/hostfs/hostfs.c +++ b/fs/hostfs/hostfs.c @@ -609,6 +609,29 @@ static int hostfs_ioctl(FAR struct file *filep, int cmd, unsigned long arg) return ret; } + /* POSIX file locks reach filesystems as private FIOC_* commands after + * fcntl() handling in VFS. Backends that can forward non-blocking lock + * commands to the host may implement host_fcntl(). Other backends return + * -ENOTTY so VFS falls back to NuttX internal file locks. Do not forward + * F_SETLKW because a blocking host fcntl() can stop the whole sim OS. + */ + + if (cmd == FIOC_GETLK) + { + ret = host_fcntl(hf->fd, F_GETLK, (FAR struct flock *)(uintptr_t)arg); + goto out; + } + else if (cmd == FIOC_SETLK) + { + ret = host_fcntl(hf->fd, F_SETLK, (FAR struct flock *)(uintptr_t)arg); + goto out; + } + else if (cmd == FIOC_SETLKW) + { + ret = -ENOTTY; + goto out; + } + /* Call our internal routine to perform the ioctl */ ret = host_ioctl(hf->fd, cmd, arg); @@ -632,6 +655,7 @@ static int hostfs_ioctl(FAR struct file *filep, int cmd, unsigned long arg) } } +out: nxmutex_unlock(&g_lock); return ret; } diff --git a/include/nuttx/fs/hostfs.h b/include/nuttx/fs/hostfs.h index 85840d23b5e83..81494019bc763 100644 --- a/include/nuttx/fs/hostfs.h +++ b/include/nuttx/fs/hostfs.h @@ -113,6 +113,21 @@ #define NUTTX_CH_STAT_ATIME (1 << 3) #define NUTTX_CH_STAT_MTIME (1 << 4) +/* These must exactly match the definitions from include/fcntl.h: */ + +#define NUTTX_F_DUPFD 0 +#define NUTTX_F_GETFD 1 +#define NUTTX_F_GETFL 2 +#define NUTTX_F_GETLK 4 +#define NUTTX_F_SETFD 8 +#define NUTTX_F_SETFL 9 +#define NUTTX_F_SETLK 11 +#define NUTTX_F_SETLKW 12 + +#define NUTTX_F_RDLCK 0 +#define NUTTX_F_WRLCK 1 +#define NUTTX_F_UNLCK 2 + #endif /* __SIM__ */ /**************************************************************************** @@ -203,6 +218,15 @@ struct nuttx_stat_s nuttx_blkcnt_t st_blocks; /* Number of blocks allocated */ }; +struct nuttx_flock_s +{ + int16_t l_type; + int16_t l_whence; + nuttx_off_t l_start; + nuttx_off_t l_len; + int32_t l_pid; +}; + #endif /* __SIM__ */ /**************************************************************************** @@ -216,6 +240,7 @@ nuttx_ssize_t host_read(int fd, void *buf, nuttx_size_t count); nuttx_ssize_t host_write(int fd, const void *buf, nuttx_size_t count); nuttx_off_t host_lseek(int fd, nuttx_off_t pos, nuttx_off_t offset, int whence); +int host_fcntl(int fd, int cmd, ...); int host_ioctl(int fd, int request, unsigned long arg); void host_sync(int fd); int host_dup(int fd); @@ -241,6 +266,7 @@ int host_close(int fd); ssize_t host_read(int fd, void *buf, size_t count); ssize_t host_write(int fd, const void *buf, size_t count); off_t host_lseek(int fd, off_t pos, off_t offset, int whence); +int host_fcntl(int fd, int cmd, ...); int host_ioctl(int fd, int request, unsigned long arg); void host_sync(int fd); int host_dup(int fd); From f730e2b6d42d93d7f8a0d7dbe18be0eb4d65245b Mon Sep 17 00:00:00 2001 From: Lingao Meng Date: Thu, 16 Jul 2026 15:34:02 +0800 Subject: [PATCH 3/5] netdb: Add http and https service entries getaddrinfo() and getservbyname() use the built-in service table when resolving service names. The table only contained ntp, so common service names such as http and https could not be resolved without a numeric port. Add http and https entries for both TCP and UDP to match the existing service table style. Testing: - Host: Ubuntu 22.04 x86_64. - Board/config: sim:nsh with CONFIG_LIBC_NETDB=y and CONFIG_EXAMPLES_HELLO=y. - make clean && make -j16. - Ran a temporary hello example that called getservbyname("http", "tcp") and getservbyname("https", "tcp"). The app verified ports 80 and 443 and printed "getservbyname http/https test passed". Signed-off-by: Lingao Meng --- libs/libc/netdb/lib_getservbynamer.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libs/libc/netdb/lib_getservbynamer.c b/libs/libc/netdb/lib_getservbynamer.c index a1fe9fee71ce2..eaf3a26e7db45 100644 --- a/libs/libc/netdb/lib_getservbynamer.c +++ b/libs/libc/netdb/lib_getservbynamer.c @@ -46,6 +46,10 @@ const struct services_db_s g_services_db[] = { + { "http", 80, IP_PROTO_TCP }, + { "http", 80, IP_PROTO_UDP }, + { "https", 443, IP_PROTO_TCP }, + { "https", 443, IP_PROTO_UDP }, { "ntp", 123, IP_PROTO_TCP }, { "ntp", 123, IP_PROTO_UDP }, { NULL, 0, 0 } From 345d706b3fb38e24419d81f8292d3dd77176a711 Mon Sep 17 00:00:00 2001 From: Lingao Meng Date: Fri, 17 Jul 2026 16:00:00 +0800 Subject: [PATCH 4/5] fs/hostfs: Fix long root path construction hostfs_mkpath() appends a relative path to the configured host root with strlcat(). The third argument to strlcat() is the total destination buffer size, not the remaining free space. Passing pathlen - strlen(path) makes the effective limit shrink after a long host root has already been copied. With a sufficiently long root, a valid relative path can be dropped or truncated, so operations under the mount point may resolve to the host root instead of the requested child path. Pass the full destination buffer size and let strlcat() account for the current string length internally. The companion examples/hostfs_longpath app validates this regression by mounting hostfs with a long host root, writing a probe file below the mount point, and reading it back. The old size argument drops the relative component in that scenario; this fix preserves it. Signed-off-by: Lingao Meng --- fs/hostfs/hostfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/hostfs/hostfs.c b/fs/hostfs/hostfs.c index 5fa57715cb371..c569d0d586126 100644 --- a/fs/hostfs/hostfs.c +++ b/fs/hostfs/hostfs.c @@ -236,7 +236,7 @@ static void hostfs_mkpath(FAR struct hostfs_mountpt_s *fs, if (depth >= 0) { - strlcat(path, &relpath[first], pathlen - strlen(path)); + strlcat(path, &relpath[first], pathlen); } } From 1be3aa5d5715aa2a579a80b1d509f4173f5ee334 Mon Sep 17 00:00:00 2001 From: Lingao Meng Date: Fri, 17 Jul 2026 16:01:25 +0800 Subject: [PATCH 5/5] fs/hostfs: Use configured path length hostfs keeps its own HOSTFS_MAX_PATH wrapper for internal buffers, but it should not hard-code a path length separate from the system path configuration. Define HOSTFS_MAX_PATH from PATH_MAX instead. PATH_MAX is backed by CONFIG_PATH_MAX, whose default remains 256, so the default hostfs behavior does not change while configurations that choose a larger path limit are honored consistently. Signed-off-by: Lingao Meng --- fs/hostfs/hostfs.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/hostfs/hostfs.h b/fs/hostfs/hostfs.h index 096be6ae75ae6..05486aed7cf32 100644 --- a/fs/hostfs/hostfs.h +++ b/fs/hostfs/hostfs.h @@ -29,6 +29,7 @@ #include +#include #include #include #include @@ -37,7 +38,7 @@ * Pre-processor Definitions ****************************************************************************/ -#define HOSTFS_MAX_PATH 256 +#define HOSTFS_MAX_PATH PATH_MAX /**************************************************************************** * Public Types