Files
2026-07-13 13:04:25 +08:00

159 lines
4.8 KiB
C

/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief Linux target VFS host filesystem registration + init
*
* Registers the cooperative libc ops (backed by freertos_linux_coop_*)
* as a VFS filesystem using esp_vfs_register_fs_with_id, so that
* file descriptors registered against this VFS ID are dispatched
* through the cooperative syscall layer.
*
* stdin/stdout/stderr are registered with VFS here, and all other
* kernel FDs are registered by the strong POSIX overrides in vfs_linux.c.
*
* Non-blocking syscalls (lseek, fstat, ioctl, fsync) are resolved directly
* via dlsym and bypass the cooperative interposition layer because they
* complete synchronously and never return EAGAIN/EWOULDBLOCK.
*/
#include <dlfcn.h>
#include <stdarg.h>
#include <unistd.h>
#include <sys/stat.h>
#include "esp_vfs.h"
#include "esp_private/freertos_linux_coop_syscalls.h"
#include "esp_private/startup_internal.h"
/* VFS ID for the Linux host filesystem — used by vfs_linux.c to register FDs */
esp_vfs_id_t s_linux_host_vfs_id = -1;
/* Real libc entry points for non-blocking syscalls, resolved at startup */
static off_t (*real_lseek)(int, off_t, int);
static int (*real_fstat)(int, struct stat *);
static int (*real_fsync)(int);
typedef int (*real_ioctl_fn_t)(int, unsigned long, ...);
static real_ioctl_fn_t real_ioctl;
static ssize_t default_read(void *ctx, int fd, void *dst, size_t size)
{
(void)ctx;
return freertos_linux_coop_read(fd, dst, size);
}
static ssize_t default_write(void *ctx, int fd, const void *data, size_t size)
{
(void)ctx;
return freertos_linux_coop_write(fd, data, size);
}
static ssize_t default_pread(void *ctx, int fd, void *dst, size_t size, off_t offset)
{
(void)ctx;
return freertos_linux_coop_pread(fd, dst, size, offset);
}
static ssize_t default_pwrite(void *ctx, int fd, const void *src, size_t size, off_t offset)
{
(void)ctx;
return freertos_linux_coop_pwrite(fd, src, size, offset);
}
static int default_open(void *ctx, const char *path, int flags, int mode)
{
(void)ctx;
return freertos_linux_coop_open(path, flags, mode);
}
static int default_close(void *ctx, int fd)
{
(void)ctx;
return freertos_linux_coop_close(fd);
}
static int default_fcntl(void *ctx, int fd, int cmd, int arg)
{
(void)ctx;
return freertos_linux_coop_fcntl(fd, cmd, arg);
}
/* lseek never blocks — call real libc directly, no cooperative retry needed */
static off_t default_lseek(void *ctx, int fd, off_t offset, int whence)
{
(void)ctx;
return real_lseek(fd, offset, whence);
}
/* fstat never blocks — call real libc directly, no cooperative retry needed */
static int default_fstat(void *ctx, int fd, struct stat *st)
{
(void)ctx;
return real_fstat(fd, st);
}
/* ioctl never blocks — call real libc directly, no cooperative retry needed */
static int default_ioctl(void *ctx, int fd, int cmd, va_list args)
{
(void)ctx;
void *arg = va_arg(args, void *);
return real_ioctl(fd, (unsigned long)cmd, arg);
}
/* fsync never blocks — call real libc directly, no cooperative retry needed */
static int default_fsync(void *ctx, int fd)
{
(void)ctx;
return real_fsync(fd);
}
static const esp_vfs_fs_ops_t s_linux_host_ops = {
.read_p = default_read,
.write_p = default_write,
.pread_p = default_pread,
.pwrite_p = default_pwrite,
.open_p = default_open,
.close_p = default_close,
.fcntl_p = default_fcntl,
.lseek_p = default_lseek,
.fstat_p = default_fstat,
.ioctl_p = default_ioctl,
.fsync_p = default_fsync,
};
ESP_SYSTEM_INIT_FN(init_vfs_linux_coop, CORE, BIT(0), 99)
{
/* Resolve real libc symbols for non-blocking syscalls */
real_lseek = dlsym(RTLD_NEXT, "lseek");
real_fstat = dlsym(RTLD_NEXT, "fstat");
real_ioctl = dlsym(RTLD_NEXT, "ioctl");
real_fsync = dlsym(RTLD_NEXT, "fsync");
freertos_linux_coop_syscalls_init();
/* Register the Linux host FS with VFS (id-based, no path prefix) */
esp_err_t err = esp_vfs_register_fs_with_id(&s_linux_host_ops,
ESP_VFS_FLAG_CONTEXT_PTR,
NULL,
&s_linux_host_vfs_id);
if (err != ESP_OK) {
return err;
}
/* Register stdin/stdout/stderr so apps see them as VFS FDs 0, 1, 2 */
int fd;
esp_vfs_register_fd_with_local_fd(s_linux_host_vfs_id, STDIN_FILENO, true, &fd);
esp_vfs_register_fd_with_local_fd(s_linux_host_vfs_id, STDOUT_FILENO, true, &fd);
esp_vfs_register_fd_with_local_fd(s_linux_host_vfs_id, STDERR_FILENO, true, &fd);
return ESP_OK;
}
void esp_vfs_include_linux_coop_init(void)
{
// Linker hook function, exists to make the linker examine this file
}