/* lib9p/tests/test_server/main.c - Main entry point for test 9P server * * Copyright (C) 2024-2025 Luke T. Shumaker * SPDX-License-Identifier: AGPL-3.0-or-later */ #include #include #include #include #include #include #include #include #include #include "static.h" /* configuration **************************************************************/ #include "config.h" #ifndef CONFIG_SRV9P_NUM_CONNS #error config.h must define CONFIG_SRV9P_NUM_CONNS #endif /* globals ********************************************************************/ static implements_lib9p_srv_file *get_root(struct lib9p_srv_ctx *, struct lib9p_s); const char *hexdig = "0123456789abcdef"; struct { struct hostnet_tcp_listener listeners[CONFIG_SRV9P_NUM_CONNS]; struct lib9p_srv srv; } globals = { .srv = (struct lib9p_srv){ .rootdir = get_root, }, }; /* api ************************************************************************/ struct api_file { implements_lib9p_srv_file; uint64_t pathnum; }; static void api_free(implements_lib9p_srv_file *) {} static uint32_t api_chio(implements_lib9p_srv_file *, struct lib9p_srv_ctx *, bool, bool, bool) { return 0; } static void api_wstat(implements_lib9p_srv_file *, struct lib9p_srv_ctx *ctx, struct lib9p_stat) { lib9p_error(&ctx->basectx, LINUX_EROFS, "cannot wstat API file"); } static void api_remove(implements_lib9p_srv_file *, struct lib9p_srv_ctx *ctx) { lib9p_error(&ctx->basectx, LINUX_EROFS, "cannot remove API file"); } static struct lib9p_qid api_qid(implements_lib9p_srv_file *_self) { struct api_file *self = VCALL_SELF(struct api_file, implements_lib9p_srv_file, _self); assert(self); return (struct lib9p_qid){ .type = LIB9P_QT_FILE, .vers = 1, .path = self->pathnum, }; } static struct lib9p_stat api_stat(implements_lib9p_srv_file *_self, struct lib9p_srv_ctx *) { struct api_file *self = VCALL_SELF(struct api_file, implements_lib9p_srv_file, _self); assert(self); return (struct lib9p_stat){ .kern_type = 0, .kern_dev = 0, .file_qid = api_qid(self), .file_mode = 0222, .file_atime = 1728337905, .file_mtime = 1728337904, .file_size = 0, .file_name = lib9p_str("shutdown"), .file_owner_uid = lib9p_str("root"), .file_owner_gid = lib9p_str("root"), .file_last_modified_uid = lib9p_str("root"), .file_extension = lib9p_str(NULL), .file_owner_n_uid = 0, .file_owner_n_gid = 0, .file_last_modified_n_uid = 0, }; } static uint32_t api_pwrite(implements_lib9p_srv_file *, struct lib9p_srv_ctx *, void *, uint32_t byte_count, uint64_t) { if (byte_count == 0) return 0; for (int i = 0; i < CONFIG_SRV9P_NUM_CONNS; i++) VCALL(&globals.listeners[i], close); return byte_count; } static struct lib9p_srv_file_vtable api_file_vtable = { .free = api_free, .qid = api_qid, .chio = api_chio, .stat = api_stat, .wstat = api_wstat, .remove = api_remove, .pread = NULL, .pwrite = api_pwrite, }; /* file tree ******************************************************************/ enum { PATH_BASE = __COUNTER__ }; #define PATH_COUNTER __COUNTER__ - PATH_BASE #define STATIC_FILE(STRNAME, SYMNAME) \ ((struct util9p_static_file){ \ ._util9p_static_common = { \ .vtable = &util9p_static_file_vtable, \ \ .u_name = "root", .u_num = 0, /* owner user */ \ .g_name = "root", .g_num = 0, /* owner group */ \ .m_name = "root", .m_num = 0, /* last-modified-by user */ \ \ .pathnum = PATH_COUNTER, \ .name = STRNAME, \ .perm = 0444, \ .atime = 1728337905, \ .mtime = 1728337904, \ }, \ .data_start = _binary_static_##SYMNAME##_start, \ .data_end = _binary_static_##SYMNAME##_end, \ }) #define STATIC_DIR(STRNAME, ...) \ ((struct util9p_static_dir){ \ ._util9p_static_common = { \ .vtable = &util9p_static_dir_vtable, \ \ .u_name = "root", .u_num = 0, /* owner user */ \ .g_name = "root", .g_num = 0, /* owner group */ \ .m_name = "root", .m_num = 0, /* last-modified-by user */ \ \ .pathnum = PATH_COUNTER, \ .name = STRNAME, \ .perm = 0555, \ .atime = 1728337905, \ .mtime = 1728337904, \ }, \ .members = { __VA_ARGS__ __VA_OPT__(,) NULL }, \ }) /* NB: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118814 */ static struct util9p_static_dir root = STATIC_DIR("", &STATIC_DIR("Documentation", &STATIC_FILE("x", Documentation_x)), &STATIC_FILE("README.md", README_md), &((struct api_file){.vtable = &api_file_vtable, .pathnum = PATH_COUNTER})); static implements_lib9p_srv_file *get_root(struct lib9p_srv_ctx *LM_UNUSED(ctx), struct lib9p_s LM_UNUSED(treename)) { return &root; } /* main ***********************************************************************/ static COROUTINE read_cr(void *_i) { int i = *((int *)_i); cr_begin(); hostnet_tcp_listener_init(&globals.listeners[i], 9000); lib9p_srv_read_cr(&globals.srv, &globals.listeners[i]); cr_end(); } static COROUTINE init_cr(void *) { cr_begin(); sleep_for_ms(1); for (int i = 0; i < CONFIG_SRV9P_NUM_CONNS; i++) { char name[] = {'r', 'e', 'a', 'd', '-', hexdig[i], '\0'}; if (!coroutine_add(name, read_cr, &i)) error(1, 0, "coroutine_add(read_cr, &i)"); } for (int i = 0; i < 2*CONFIG_SRV9P_NUM_CONNS; i++) { char name[] = {'w', 'r', 'i', 't', 'e', '-', hexdig[i], '\0'}; if (!coroutine_add(name, lib9p_srv_write_cr, &globals.srv)) error(1, 0, "coroutine_add(lib9p_srv_write_cr, &globals.srv)"); } cr_exit(); } int main() { struct hostclock clock_monotonic = { .vtable = &hostclock_vtable, .clock_id = CLOCK_MONOTONIC, }; bootclock = &clock_monotonic; coroutine_add("init", init_cr, NULL); coroutine_main(); return 0; }