diff options
124 files changed, 8190 insertions, 3937 deletions
diff --git a/.editorconfig b/.editorconfig index f907b33..c632054 100644 --- a/.editorconfig +++ b/.editorconfig @@ -15,6 +15,8 @@ indent_style = tab insert_final_newline = true trim_trailing_whitespace = true +# By well-known name ########################################################### + [*.{c,h}] _mode = c @@ -27,20 +29,6 @@ _mode = cmake [*.md] _mode = markdown -[*.9p{,.wip}] -_mode = 9p - -[{lib9p/tests/test_server/static.h.gen,build-aux/embed-sources.h.gen,build-aux/lint-{generic,unknown},lib9p/tests/test_compile.c.gen}] -_mode = sh - -[{build-aux/lint-h,build-aux/lint-bin,build-aux/get-dscname,build-aux/linux-errno.txt.gen,libusb/include/libusb/tusb_helpers.h.gen,lib9p/tests/runtest}] -_mode = bash - -[{lib9p/proto.gen,lib9p/include/lib9p/linux-errno.h.gen,build-aux/stack.c.gen}] -_mode = python3 -indent_style = space -indent_size = 4 - [*.py] _mode = python3 indent_style = space @@ -49,11 +37,43 @@ indent_size = 4 [requirements.txt] _mode = pip -[**/Documentation/**.txt] -_mode = man-cat - [{.editorconfig,.gitmodules,.pylintrc}] _mode = ini [.gitignore] _mode = gitignore + +# By specific filename (non-lib9p) ############################################# + +[{build-aux/lint-{generic,unknown},build-aux/embed-sources.h.gen}] +_mode = sh + +[{build-aux/lint-{bin,h},build-aux/get-dscname,build-aux/valgrind,libusb/include/libusb/tusb_helpers.h.gen}] +_mode = bash + +[build-aux/stack.c.gen] +_mode = python3 +indent_style = space +indent_size = 4 + +[**/Documentation/**.txt] +_mode = man-cat + +# By specific filename (lib9p) ################################################# + +[lib9p/idl/*.9p{,.wip}] +_mode = 9p-idl + +[lib9p/tests/*.explog] +_mode = 9p-log + +[{lib9p/tests/test_server/static.h.gen,lib9p/tests/test_compile.c.gen}] +_mode = sh + +[{lib9p/linux-errno.txt.gen,lib9p/tests/runtest,lib9p/tests/testclient-p9p}] +_mode = bash + +[{lib9p/core.gen,lib9p/idl/2010-9P2000.L.9p.gen}] +_mode = python3 +indent_style = space +indent_size = 4 diff --git a/3rd-party/linux-errno.txt b/3rd-party/linux-errno.txt index 839efc2..5b450f0 100644 --- a/3rd-party/linux-errno.txt +++ b/3rd-party/linux-errno.txt @@ -1,4 +1,4 @@ -# 3rd-party/linux-errno.txt - Generated from build-aux/linux-errno.txt.gen and linux.git v6.7. DO NOT EDIT! +# 3rd-party/linux-errno.txt - Generated from lib9p/linux-errno.txt.gen and linux.git v6.14. DO NOT EDIT! 1 EPERM Operation not permitted 2 ENOENT No such file or directory 3 ESRCH No such process diff --git a/CMakeLists.txt b/CMakeLists.txt index 22756c1..9fa048f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -112,7 +112,7 @@ function(add_lib_test arg_libname arg_testname) target_include_directories("${arg_testname}" PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/tests) add_test( NAME "${arg_libname}/${arg_testname}" - COMMAND valgrind --error-exitcode=2 "./${arg_testname}" + COMMAND "${CMAKE_SOURCE_DIR}/build-aux/valgrind" "./${arg_testname}" ) endif() endfunction() diff --git a/GNUmakefile b/GNUmakefile index f6ff6c3..8636973 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -34,19 +34,19 @@ generate/files += 3rd-party/COPYING.newlib.txt cp $< $@ generate/files += 3rd-party/linux-errno.txt -3rd-party/linux-errno.txt: build-aux/linux-errno.txt.gen +3rd-party/linux-errno.txt: lib9p/linux-errno.txt.gen $< $(linux.git) $@ -generate/files += lib9p/include/lib9p/linux-errno.h -lib9p/include/lib9p/linux-errno.h: %: %.gen 3rd-party/linux-errno.txt +generate/files += lib9p/idl/2010-9P2000.L.9p +lib9p/idl/2010-9P2000.L.9p: %: %.gen 3rd-party/linux-errno.txt $^ >$@ -generate/files += lib9p/9p.generated.c lib9p/include/lib9p/9p.generated.h -lib9p/9p.generated.c lib9p/include/lib9p/9p.generated.h &: lib9p/proto.gen lib9p/idl/__init__.py lib9p/protogen lib9p/protogen/*.py lib9p/idl lib9p/idl/*.9p - $< $(filter %.9p,$^) +generate/files += lib9p/core_generated.c lib9p/core_include/lib9p/_core_generated.h +lib9p/core_generated.c lib9p/core_include/lib9p/_core_generated.h &: lib9p/core.gen lib9p/idl/__init__.py lib9p/core_gen lib9p/core_gen/*.py lib9p/idl lib9p/idl/2010-9P2000.L.9p lib9p/idl/*.9p + $< $(sort $(filter %.9p,$^)) generate/files += lib9p/tests/test_compile.c -lib9p/tests/test_compile.c: %: %.gen lib9p/include/lib9p/9p.generated.h +lib9p/tests/test_compile.c: %: %.gen lib9p/core_include/lib9p/_core_generated.h $^ $@ generate/files += libusb/include/libusb/tusb_helpers.h 3rd-party/MS-LCID.pdf 3rd-party/MS-LCID.txt @@ -78,9 +78,6 @@ generate-clean: platforms := rp2040 host # $(shell sed -nE 's/if *\(PICO_PLATFORM STREQUAL "(.*)"\)/\1/p' cmd/*/CMakeLists.txt) build_types = Debug Release RelWithDebInfo MinSizeRel -export CTEST_PARALLEL_LEVEL = 0 -export CTEST_OUTPUT_ON_FAILURE = 1 - build: $(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/build)) .PHONY: build @@ -91,12 +88,12 @@ $(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/build)): build/% $(MAKE) -C $(<D) .PHONY: $(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/build)) -check: build - $(MAKE) -j1 -k INNER=t $(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/check)) +check: + $(MAKE) -k INNER=t $(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/check)) .PHONY: check -$(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/check)): build/%/check: build/%/Makefile - $(MAKE) -C $(<D) test +$(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/check)): build/%/check: build/%/build + +cd $(@D) && ctest --output-on-failure $(if $(filter --jobserver-auth=%,$(MAKEFLAGS)),--parallel) .PHONY: $(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/check)) # `lint` and `format` ########################################################## @@ -109,44 +106,47 @@ build-aux/venv: build-aux/requirements.txt $@/bin/pip install -r $< touch --no-create $@ -# `lint` ########### +# `lint` ############################### +# generic ########## lint: $(MAKE) -k INNER=t $(patsubst sources_%,lint/%,$(filter sources_%,$(.VARIABLES))) # Only lint binaries if the build scripts pass lint. $(MAKE) INNER=t lint/bin lint/bin: build build-aux/lint-bin ./build-aux/lint-bin $(foreach t,$(build_types),build/rp2040-$t/cmd/sbc_harness/sbc_harness.elf) +lint/all: lint/%: build-aux/lint-generic build-aux/get-dscname + ./build-aux/lint-generic '%s\n' $(sources_$*) +lint/unknown: lint/%: build-aux/lint-unknown + ./build-aux/lint-unknown $(sources_$*) +.PHONY: lint lint/% +# specific ######### +lint/c: lint/%: build-aux/lint-h build-aux/get-dscname + ./build-aux/lint-h $(filter %.h,$(sources_$*)) lint/sh lint/bash: lint/%: shellcheck $(sources_$*) + shfmt --diff --case-indent --simplify $(sources_$*) lint/python3: lint/%: build-aux/venv ./build-aux/venv/bin/mypy --strict --scripts-are-modules $(sources_$*) ./build-aux/venv/bin/black --check $(sources_$*) ./build-aux/venv/bin/isort --check $(sources_$*) ./build-aux/venv/bin/pylint $(sources_$*) - ! grep -nh 'SPECIAL$$' -- lib9p/proto.gen lib9p/protogen/*.py + ! grep -nh 'SPECIAL$$' -- lib9p/core.gen lib9p/core_gen/*.py ./build-aux/venv/bin/pytest $(foreach f,$(sources_python3),$(if $(filter test_%.py,$(notdir $f)),$f)) -lint/c: lint/%: build-aux/lint-h build-aux/get-dscname - ./build-aux/lint-h $(filter %.h,$(sources_$*)) -lint/make lint/cmake lint/gitignore lint/ini lint/9p lint/markdown lint/pip lint/man-cat: lint/%: - @: -lint/unknown: lint/%: build-aux/lint-unknown - ./build-aux/lint-unknown $(sources_$*) -lint/all: lint/%: build-aux/lint-generic build-aux/get-dscname - ./build-aux/lint-generic '%s\n' $(sources_$*) -.PHONY: lint lint/% +lint/make lint/cmake lint/gitignore lint/ini lint/9p-idl lint/9p-log lint/markdown lint/pip lint/man-cat: lint/%: + @: TODO: Write/adopt linters for these file types -# `format` ######### +# `format` ############################# +# generic ########## format: - $(MAKE) -k INNER=t $(patsubst sources_%,format/%,$(filter-out sources_all,$(filter sources_%,$(.VARIABLES)))) + $(MAKE) -k INNER=t $(patsubst sources_%,format/%,$(filter-out sources_all sources_unknown,$(filter sources_%,$(.VARIABLES)))) +.PHONY: format format/% +# specific ######### +format/c: format/%: + @: TODO: Adopt a C code-formatter +format/sh format/bash: format/%: + shfmt --write --case-indent --simplify $(sources_$*) format/python3: format/%: ./build-aux/venv ./build-aux/venv/bin/black $(sources_$*) ./build-aux/venv/bin/isort $(sources_$*) -format/sh format/bash: format/% - @: -format/c: format/%: - @: TODO: Adopt a C code-formatter -format/make format/cmake format/gitignore format/ini format/9p format/markdown format/pip format/man-cat: format/%: - @: -format/unknown: format/%: - @: -.PHONY: format format/% +format/make format/cmake format/gitignore format/ini format/9p-idl format/9p-log format/markdown format/pip format/man-cat: format/%: + @: TODO: Write/adopt formatters for these file types @@ -1,10 +1,20 @@ <!-- PLAN.md - Misc planning notes - Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> SPDX-License-Identifier: AGPL-3.0-or-later --> +- [ ] syslog on 9p +- [ ] better 9p-shutdown +- [ ] PIO-based USB +- [ ] wire the USB keyboard to 9P +- [ ] wire uart to 9p + +- SDcard to 9p +- PicoDVI +- solder up the bus switch + - with hardware I have: 1. [X] type "hello world" as a USB keyboard 2. [ ] get networking up (ping) @@ -19,5 +29,3 @@ 1. [ ] PicoDVI hello-world 2. [ ] "PiciDVI" to network 3. [ ] reverse the flow of PicoDVI - -https://hackaday.com/2022/08/26/bit-banged-ethernet-on-the-raspberry-pi-pico/ @@ -77,9 +77,9 @@ protocol over TCP: - `9P2000` (base protocol): Yes - `9P2000.u` (Unix extension): Yes, with Linux kernel architecture-"generic" errnos. This will match the Linux kernel - errnos on most architectures (but, as of Linux v6.7, not on - Alpha, MIPS, PA-RISC, PowerPC, or SPARC; I am unsure whether on - these platforms the kernel's v9fs filesystem driver will map the + errnos on most architectures (but, as of Linux v6.14, not on + Alpha, MIPS, PA-RISC, PowerPC, or SPARC; unfortunately on these + platforms the kernel's v9fs filesystem driver won't map the "generic" errnos to the architecture-specific errnos for you). - `9P2000.L` (Linux extension): No, it's an abomination and unlikely to ever be supported diff --git a/build-aux/embed-sources.h.gen b/build-aux/embed-sources.h.gen index 0329496..ee9eb42 100755 --- a/build-aux/embed-sources.h.gen +++ b/build-aux/embed-sources.h.gen @@ -6,5 +6,5 @@ nm --format=posix "$@" | sed -n -E \ - -e 's/(.*_(end|start)) [DR] .*/extern char \1[];/p' \ - -e 's/(.*_size) A .*/extern size_t \1;/p' + -e 's/(.*_(end|start)) [DR] .*/extern char \1[];/p' \ + -e 's/(.*_size) A .*/extern size_t \1;/p' diff --git a/build-aux/lint-bin b/build-aux/lint-bin index 78ed19f..91f1612 100755 --- a/build-aux/lint-bin +++ b/build-aux/lint-bin @@ -62,7 +62,7 @@ lint_globals() { cd "$rel_base" total=0 while read -r symbol addr size source; do - if (( addr == 0 )); then + if ((addr == 0)); then continue fi case "$source" in @@ -103,8 +103,9 @@ lint_stack() { fi done < <( comm -3 \ - <(sed -En 's/^included: (.*:)?//p' "${in_elffile%.elf}_stack.c" | sort -u) \ - <(readelf_funcs "$in_elffile" | sed -E -e 's/\.part\.[0-9]*$//' -e 's/^__(.*)_veneer$/\1/' | sort -u)) + <(sed -En 's/^included: (.*:)?//p' "${in_elffile%.elf}_stack.c" | sort -u) \ + <(readelf_funcs "$in_elffile" | sed -E -e 's/\.part\.[0-9]*$//' -e 's/^__(.*)_veneer$/\1/' | sort -u) + ) } lint_func_blocklist() { @@ -118,8 +119,8 @@ lint_func_blocklist() { while read -r func; do err "$in_elffile" "Contains blocklisted function: ${func}" done < <(readelf --syms --wide -- "$in_elffile" | - awk '$4 == "FUNC" { print $8 }' | - grep -Fx "${blocklist[@]/#/-e}") + awk '$4 == "FUNC" { print $8 }' | + grep -Fx "${blocklist[@]/#/-e}") } main() { @@ -130,8 +131,8 @@ main() { { echo 'Global variables:' lint_globals "${elf}.map" | sed 's/^/ /' - } > "${elf%.elf}.lint.globals" - (lint_stack "$elf") &> "${elf%.elf}.lint.stack" + } >"${elf%.elf}.lint.globals" + (lint_stack "$elf") &>"${elf%.elf}.lint.stack" lint_func_blocklist "$elf" done diff --git a/build-aux/lint-generic b/build-aux/lint-generic index 58a65d2..70e814a 100755 --- a/build-aux/lint-generic +++ b/build-aux/lint-generic @@ -25,12 +25,17 @@ for filename in "$@"; do if [ -x "$filename" ] && [ -z "$shebang" ]; then err "$filename" 'is executable but does not have a shebang' elif [ -n "$shebang" ] && ! [ -x "$filename" ]; then - err "$filename" 'has a shebang but is executable' + err "$filename" 'has a shebang but is not executable' fi if ! grep -E -q 'Copyright \(C\) 202[4-9]((-|, )202[5-9])* Luke T. Shumaker' "$filename"; then err "$filename" 'is missing a copyright statement' fi + if test -e .git && ! git diff --quiet milestone/2025-01-01 HEAD -- "$filename"; then + if ! grep -E -q 'Copyright \(C\) .*2025 Luke T. Shumaker' "$filename"; then + err "$filename" 'has an outdated copyright statement' + fi + fi if ! grep -q '\sSPDX-License-Identifier[:] ' "$filename"; then err "$filename" 'is missing an SPDX-License-Identifier' fi diff --git a/build-aux/lint-h b/build-aux/lint-h index 26ac13d..7459032 100755 --- a/build-aux/lint-h +++ b/build-aux/lint-h @@ -18,9 +18,9 @@ for filename in "$@"; do guard=${dscname//'/'/'_'} guard=${guard//'.'/'_'} guard="_${guard^^}_" - if ! { grep -Fxq "#ifndef ${guard}" "$filename" && - grep -Fxq "#define ${guard}" "$filename" && - grep -Fxq "#endif /* ${guard} */" "$filename"; }; then + if ! { grep -Fxq "#ifndef ${guard}" "$filename" && + grep -Fxq "#define ${guard}" "$filename" && + grep -Fxq "#endif /* ${guard} */" "$filename"; }; then err "$filename" "does not have ${guard} guard" fi done diff --git a/build-aux/measurestack/app_plugins.py b/build-aux/measurestack/app_plugins.py index 36e661b..bbb0eae 100644 --- a/build-aux/measurestack/app_plugins.py +++ b/build-aux/measurestack/app_plugins.py @@ -4,6 +4,7 @@ # SPDX-License-Identifier: AGPL-3.0-or-later import re +import subprocess import typing from . import analyze, util @@ -247,8 +248,8 @@ class LibCRIPCPlugin: return None if "/chan.c:" in loc and "front->dequeue(" in line: return [ - QName("_cr_chan_dequeue"), - QName("_cr_select_dequeue"), + QName("cr_chan_dequeue"), + QName("cr_select_dequeue"), ], False return None @@ -271,9 +272,8 @@ re_lib9p_callee = re.compile( class Lib9PPlugin: tmessage_handlers: set[QName] | None lib9p_msgs: set[str] - _CONFIG_9P_NUM_SOCKS: int | None - CONFIG_9P_SRV_MAX_REQS: int | None - CONFIG_9P_SRV_MAX_DEPTH: int | None + _CONFIG_9P_MAX_CONNS: int | None + _CONFIG_9P_MAX_REQS: int | None formatters: typing.Collection[BaseName] def __init__( @@ -305,25 +305,25 @@ class Lib9PPlugin: ) lib9p_generated_c_fname = util.get_zero_or_one( - lambda fname: fname.endswith("lib9p/9p.generated.c"), arg_c_fnames + lambda fname: fname.endswith("lib9p/_core_generated.c"), arg_c_fnames ) # Read config ########################################################## def config_h_get(varname: str) -> int | None: if config_h_fname: - with open(config_h_fname, "r", encoding="utf-8") as fh: - for line in fh: - line = line.rstrip() - if line.startswith("#define"): - parts = line.split() - if parts[1] == varname: - return int(parts[2]) + line = subprocess.run( + ["cpp"], + input=f'#include "{config_h_fname}"\n{varname}\n', + check=True, + capture_output=True, + encoding="utf-8", + ).stdout.split("\n")[-2] + return int(eval(line)) # pylint: disable=eval-used return None - self._CONFIG_9P_NUM_SOCKS = config_h_get("_CONFIG_9P_NUM_SOCKS") - self.CONFIG_9P_SRV_MAX_REQS = config_h_get("CONFIG_9P_SRV_MAX_REQS") - self.CONFIG_9P_SRV_MAX_DEPTH = config_h_get("CONFIG_9P_SRV_MAX_DEPTH") + self._CONFIG_9P_MAX_CONNS = config_h_get("_CONFIG_9P_MAX_REQS") + self._CONFIG_9P_MAX_REQS = config_h_get("_CONFIG_9P_MAX_REQS") # Read sources ######################################################### @@ -348,12 +348,12 @@ class Lib9PPlugin: self.lib9p_msgs = lib9p_msgs def thread_count(self, name: QName) -> int: - assert self._CONFIG_9P_NUM_SOCKS - assert self.CONFIG_9P_SRV_MAX_REQS + assert self._CONFIG_9P_MAX_CONNS + assert self._CONFIG_9P_MAX_REQS if "read" in str(name.base()): - return self._CONFIG_9P_NUM_SOCKS + return self._CONFIG_9P_MAX_CONNS if "write" in str(name.base()): - return self._CONFIG_9P_NUM_SOCKS * self.CONFIG_9P_SRV_MAX_REQS + return self._CONFIG_9P_MAX_REQS return 1 def is_intrhandler(self, name: QName) -> bool: @@ -405,11 +405,6 @@ class Lib9PPlugin: self.formatters, self._skipmodel__vfctprintf ), } - if isinstance(self.CONFIG_9P_SRV_MAX_DEPTH, int): - ret[BaseName("srv_util_pathfree")] = analyze.SkipModel( - self.CONFIG_9P_SRV_MAX_DEPTH, - self._skipmodel_srv_util_pathfree, - ) return ret def _skipmodel__lib9p_validate_unmarshal_marshal( @@ -423,17 +418,6 @@ class Lib9PPlugin: return False return m_caller.group("grp") != m_callee.group("grp") - def _skipmodel_srv_util_pathfree( - self, chain: typing.Sequence[QName], call: QName - ) -> bool: - assert isinstance(self.CONFIG_9P_SRV_MAX_DEPTH, int) - if call.base() == BaseName("srv_util_pathfree"): - return len(chain) >= self.CONFIG_9P_SRV_MAX_DEPTH and all( - c.base() == BaseName("srv_util_pathfree") - for c in chain[-self.CONFIG_9P_SRV_MAX_DEPTH :] - ) - return False - def _skipmodel__vfctprintf( self, chain: typing.Sequence[QName], call: QName ) -> bool: diff --git a/build-aux/valgrind b/build-aux/valgrind new file mode 100755 index 0000000..7ad2712 --- /dev/null +++ b/build-aux/valgrind @@ -0,0 +1,16 @@ +#!/bin/env bash +# build-aux/valgrind - Wrapper around valgrind to keep flags consistent +# +# Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com> +# SPDX-License-Identifier: AGPL-3.0-or-later + +exec \ + valgrind \ + --fair-sched=yes \ + --error-exitcode=2 \ + --leak-check=full \ + --show-leak-kinds=all \ + --errors-for-leak-kinds=all \ + --show-error-list=all \ + -- \ + "$@" diff --git a/cmd/sbc_harness/CMakeLists.txt b/cmd/sbc_harness/CMakeLists.txt index 678af07..6e722d7 100644 --- a/cmd/sbc_harness/CMakeLists.txt +++ b/cmd/sbc_harness/CMakeLists.txt @@ -30,7 +30,7 @@ target_link_libraries(sbc_harness_objs libusb libdhcp libhw_cr - lib9p + lib9p_srv lib9p_util ) pico_minimize_runtime(sbc_harness_objs diff --git a/cmd/sbc_harness/config/config.h b/cmd/sbc_harness/config/config.h index 5e7bc06..ca23462 100644 --- a/cmd/sbc_harness/config/config.h +++ b/cmd/sbc_harness/config/config.h @@ -11,6 +11,9 @@ #define CONFIG_FLASH_DEBUG 1 +#define _CONFIG_9P_MAX_CONNS 3 /* FIXME: bump this back up to 8 */ +#define _CONFIG_9P_MAX_REQS (2*_CONFIG_9P_MAX_CONNS) + /* RP2040 *********************************************************************/ #define CONFIG_RP2040_SPI_DEBUG 1 /* bool */ @@ -36,6 +39,18 @@ #define CONFIG_9P_MAX_ERR_SIZE 128 /* 128 is what Plan 9 4e uses */ +#define CONFIG_9P_ENABLE_9P2000 1 /* bool */ +#define CONFIG_9P_ENABLE_9P2000_u 1 /* bool */ +#define CONFIG_9P_ENABLE_9P2000_e 0 /* bool */ +#define CONFIG_9P_ENABLE_9P2000_L 0 /* bool */ +#define CONFIG_9P_ENABLE_9P2000_p9p 0 /* bool */ + +/* 9P_SRV *********************************************************************/ + +#define CONFIG_9P_SRV_DEBUG 1 /* bool */ + +#define CONFIG_9P_SRV_MAX_MSG_SIZE ((4*1024)+24) + /** * This max-msg-size is sized so that a Twrite message can return * 8KiB of data. @@ -60,15 +75,6 @@ * struct padding, (2) array pointers. */ #define CONFIG_9P_SRV_MAX_HOSTMSG_SIZE CONFIG_9P_SRV_MAX_MSG_SIZE+16 -#define CONFIG_9P_SRV_MAX_FIDS 16 -#define CONFIG_9P_SRV_MAX_REQS 2 -#define CONFIG_9P_SRV_MAX_DEPTH 3 - -#define CONFIG_9P_ENABLE_9P2000 1 /* bool */ -#define CONFIG_9P_ENABLE_9P2000_u 1 /* bool */ -#define CONFIG_9P_ENABLE_9P2000_e 0 /* bool */ -#define CONFIG_9P_ENABLE_9P2000_L 0 /* bool */ -#define CONFIG_9P_ENABLE_9P2000_p9p 0 /* bool */ /* DHCP ***********************************************************************/ @@ -92,8 +98,8 @@ extern const size_t CONFIG_COROUTINE_STACK_SIZE_dhcp_cr; extern const size_t CONFIG_COROUTINE_STACK_SIZE_init_cr; -extern const size_t CONFIG_COROUTINE_STACK_SIZE_lib9p_srv_write_cr; extern const size_t CONFIG_COROUTINE_STACK_SIZE_read9p_cr; +extern const size_t CONFIG_COROUTINE_STACK_SIZE_write9p_cr; extern const size_t CONFIG_COROUTINE_STACK_SIZE_usb_common_cr; extern const size_t CONFIG_COROUTINE_STACK_SIZE_usb_keyboard_cr; extern const size_t CONFIG_COROUTINE_STACK_SIZE_w5500_irq_cr; @@ -104,12 +110,11 @@ extern const size_t CONFIG_COROUTINE_STACK_SIZE_w5500_irq_cr; #define CONFIG_COROUTINE_VALGRIND 0 /* bool */ #define CONFIG_COROUTINE_GDB 1 /* bool */ -#define _CONFIG_9P_NUM_SOCKS 3 /* FIXME: bump this back up to 8 */ -#define CONFIG_COROUTINE_NUM ( \ - 1 /* usb_common */ + \ - 1 /* usb_keyboard */ + \ - 1 /* W5500 irq handler */ + \ - _CONFIG_9P_NUM_SOCKS /* 9P accept()+read() */ + \ - (CONFIG_9P_SRV_MAX_REQS*_CONFIG_9P_NUM_SOCKS) /* 9P work+write() */ ) +#define CONFIG_COROUTINE_NUM ( \ + 1 /* usb_common */ + \ + 1 /* usb_keyboard */ + \ + 1 /* W5500 irq handler */ + \ + _CONFIG_9P_MAX_CONNS /* 9P accept()+read() */ + \ + _CONFIG_9P_MAX_REQS /* 9P work+write() */ ) #endif /* _CONFIG_H_ */ diff --git a/cmd/sbc_harness/config/tusb_config.h b/cmd/sbc_harness/config/tusb_config.h index 0a6d3e4..5240311 100644 --- a/cmd/sbc_harness/config/tusb_config.h +++ b/cmd/sbc_harness/config/tusb_config.h @@ -1,6 +1,6 @@ /* tusb_config.h - Compile-time configuration for the TinyUSB library * - * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later * * SPDX-License-Identifier: MIT @@ -61,7 +61,7 @@ extern "C" { TU_BREAKPOINT(); \ return _ret; \ } \ - } while(0) + } while (0) void _libmisc_tu_mess_failed(const char *expr, const char *file, unsigned int line, const char *func); diff --git a/cmd/sbc_harness/fs_harness_flash_bin.c b/cmd/sbc_harness/fs_harness_flash_bin.c index bdb8da4..5920b85 100644 --- a/cmd/sbc_harness/fs_harness_flash_bin.c +++ b/cmd/sbc_harness/fs_harness_flash_bin.c @@ -4,6 +4,8 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ +#include <string.h> + #include <hardware/flash.h> #include <hardware/watchdog.h> @@ -146,40 +148,35 @@ static struct lib9p_qid flash_file_qid(struct flash_file *self) { }; } -static struct lib9p_stat flash_file_stat(struct flash_file *self, struct lib9p_srv_ctx *ctx) { +static struct lib9p_srv_stat flash_file_stat(struct flash_file *self, struct lib9p_srv_ctx *ctx) { assert(self); assert(ctx); - return (struct lib9p_stat){ - .kern_type = 0, - .kern_dev = 0, - .file_qid = flash_file_qid(self), - .file_mode = LIB9P_DM_EXCL|0666, - .file_atime = UTIL9P_ATIME, - .file_mtime = UTIL9P_MTIME, - .file_size = DATA_SIZE, - .file_name = lib9p_str(self->name), - .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, + return (struct lib9p_srv_stat){ + .qid = flash_file_qid(self), + .mode = LIB9P_DM_EXCL|0666, + .atime_sec = UTIL9P_ATIME, + .mtime_sec = UTIL9P_MTIME, + .size = DATA_SIZE, + .name = lib9p_str(self->name), + .owner_uid = { .name = lib9p_str("root"), .num = 0 }, + .owner_gid = { .name = lib9p_str("root"), .num = 0 }, + .last_modifier_uid = { .name = lib9p_str("root"), .num = 0 }, + .extension = lib9p_str(NULL), }; } static void flash_file_wstat(struct flash_file *self, struct lib9p_srv_ctx *ctx, - struct lib9p_stat) { + struct lib9p_srv_stat) { assert(self); assert(ctx); - lib9p_error(&ctx->basectx, LINUX_EROFS, "read-only part of filesystem"); + lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "read-only part of filesystem"); } static void flash_file_remove(struct flash_file *self, struct lib9p_srv_ctx *ctx) { assert(self); assert(ctx); - lib9p_error(&ctx->basectx, LINUX_EROFS, "read-only part of filesystem"); + lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "read-only part of filesystem"); } LIB9P_SRV_NOTDIR(struct flash_file, flash_file); @@ -233,7 +230,7 @@ static void flash_file_pread(struct flash_file *self, struct lib9p_srv_ctx *ctx, if (byte_offset > DATA_SIZE) { lib9p_error(&ctx->basectx, - LINUX_EINVAL, "offset is past the chip size"); + LIB9P_ERRNO_L_EINVAL, "offset is past the chip size"); return; } @@ -279,14 +276,14 @@ static uint32_t flash_file_pwrite(struct flash_file *self, struct lib9p_srv_ctx if (byte_offset > DATA_HSIZE) { lib9p_error(&ctx->basectx, - LINUX_EINVAL, "offset is past half the chip size"); + LIB9P_ERRNO_L_EINVAL, "offset is past half the chip size"); return 0; } if (byte_count == 0) return 0; if (byte_offset == DATA_HSIZE) { lib9p_error(&ctx->basectx, - LINUX_EINVAL, "offset is at half the chip size"); + LIB9P_ERRNO_L_EINVAL, "offset is at half the chip size"); return 0; } diff --git a/cmd/sbc_harness/fs_harness_uptime_txt.c b/cmd/sbc_harness/fs_harness_uptime_txt.c index 9216986..f7b755f 100644 --- a/cmd/sbc_harness/fs_harness_uptime_txt.c +++ b/cmd/sbc_harness/fs_harness_uptime_txt.c @@ -5,10 +5,10 @@ */ #include <stdio.h> /* for snprintf() */ -#include <stdlib.h> /* for malloc(), free() */ #include <libhw/generic/alarmclock.h> #include <util9p/static.h> +#include <libmisc/alloc.h> /* for heap_alloc(), free() */ #include "fs_harness_uptime_txt.h" @@ -38,7 +38,7 @@ static struct lib9p_qid uptime_file_qid(struct uptime_file *self) { }; } -static struct lib9p_stat uptime_file_stat(struct uptime_file *self, struct lib9p_srv_ctx *ctx) { +static struct lib9p_srv_stat uptime_file_stat(struct uptime_file *self, struct lib9p_srv_ctx *ctx) { assert(self); assert(ctx); @@ -52,36 +52,31 @@ static struct lib9p_stat uptime_file_stat(struct uptime_file *self, struct lib9p size++; size += 3; - return (struct lib9p_stat){ - .kern_type = 0, - .kern_dev = 0, - .file_qid = uptime_file_qid(self), - .file_mode = 0444, - .file_atime = UTIL9P_ATIME, - .file_mtime = UTIL9P_MTIME, - .file_size = size, - .file_name = lib9p_str(self->name), - .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, + return (struct lib9p_srv_stat){ + .qid = uptime_file_qid(self), + .mode = 0444, + .atime_sec = UTIL9P_ATIME, + .mtime_sec = UTIL9P_MTIME, + .size = size, + .name = lib9p_str(self->name), + .owner_uid = { .name = lib9p_str("root"), .num = 0 }, + .owner_gid = { .name = lib9p_str("root"), .num = 0 }, + .last_modifier_uid = { .name = lib9p_str("root"), .num = 0 }, + .extension = lib9p_str(NULL), }; } static void uptime_file_wstat(struct uptime_file *self, struct lib9p_srv_ctx *ctx, - struct lib9p_stat) { + struct lib9p_srv_stat) { assert(self); assert(ctx); - lib9p_error(&ctx->basectx, LINUX_EROFS, "read-only part of filesystem"); + lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "read-only part of filesystem"); } static void uptime_file_remove(struct uptime_file *self, struct lib9p_srv_ctx *ctx) { assert(self); assert(ctx); - lib9p_error(&ctx->basectx, LINUX_EROFS, "read-only part of filesystem"); + lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "read-only part of filesystem"); } LIB9P_SRV_NOTDIR(struct uptime_file, uptime_file); @@ -91,7 +86,7 @@ static lo_interface lib9p_srv_fio uptime_file_fopen(struct uptime_file *self, st assert(self); assert(ctx); - struct uptime_fio *ret = malloc(sizeof(struct uptime_fio)); + struct uptime_fio *ret = heap_alloc(1, struct uptime_fio); ret->parent = self; ret->buf_len = 0; @@ -130,7 +125,7 @@ static void uptime_fio_pread(struct uptime_fio *self, struct lib9p_srv_ctx *ctx, if (byte_offset > (uint64_t)self->buf_len) { lib9p_error(&ctx->basectx, - LINUX_EINVAL, "offset is past end-of-file length"); + LIB9P_ERRNO_L_EINVAL, "offset is past end-of-file length"); return; } @@ -151,6 +146,6 @@ static uint32_t uptime_fio_pwrite(struct uptime_fio *self, struct lib9p_srv_ctx assert(self); assert(ctx); - lib9p_error(&ctx->basectx, LINUX_EROFS, "read-only part of filesystem"); + lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "read-only part of filesystem"); return 0; } diff --git a/cmd/sbc_harness/main.c b/cmd/sbc_harness/main.c index 25b122c..5630e83 100644 --- a/cmd/sbc_harness/main.c +++ b/cmd/sbc_harness/main.c @@ -39,6 +39,13 @@ #include "config.h" +#ifndef _CONFIG_9P_MAX_CONNS + #error config.h must define _CONFIG_9P_MAX_CONNS +#endif +#ifndef _CONFIG_9P_MAX_REQS + #error config.h must define _CONFIG_9P_MAX_REQS +#endif + /* file tree ******************************************************************/ enum { PATH_BASE = __COUNTER__ }; @@ -153,13 +160,21 @@ static COROUTINE read9p_cr(void *) { lo_interface net_iface iface = lo_box_w5500_if_as_net_iface(&globals.dev_w5500); lo_interface net_stream_listener listener = LO_CALL(iface, tcp_listen, LIB9P_DEFAULT_PORT_9FS); - lib9p_srv_read_cr(&globals.srv, listener); + lib9p_srv_accept_and_read_loop(&globals.srv, listener); + + cr_end(); +} + +static COROUTINE write9p_cr(void *) { + cr_begin(); + + lib9p_srv_worker_loop(&globals.srv); cr_end(); } const char *const hexdig = "0123456789ABCDEF"; -static_assert(CONFIG_9P_SRV_MAX_REQS*_CONFIG_9P_NUM_SOCKS <= 16); +static_assert(_CONFIG_9P_MAX_REQS <= 16); COROUTINE init_cr(void *) { cr_begin(); @@ -215,13 +230,13 @@ COROUTINE init_cr(void *) { coroutine_add("usb_keyboard", usb_keyboard_cr, &globals.keyboard_chan); //coroutine_add("hello_world", hello_world_cr, &globals.keyboard_chan); coroutine_add("dhcp", dhcp_cr, NULL); - for (int i = 0; i < _CONFIG_9P_NUM_SOCKS; i++) { + for (int i = 0; i < _CONFIG_9P_MAX_CONNS; i++) { char name[] = {'r', 'e', 'a', 'd', '-', hexdig[i], '\0'}; coroutine_add(name, read9p_cr, NULL); } - for (int i = 0; i < CONFIG_9P_SRV_MAX_REQS*_CONFIG_9P_NUM_SOCKS; i++) { + for (int i = 0; i < _CONFIG_9P_MAX_REQS; i++) { char name[] = {'w', 'r', 'i', 't', 'e', '-', hexdig[i], '\0'}; - coroutine_add(name, lib9p_srv_write_cr, &globals.srv); + coroutine_add(name, write9p_cr, NULL); } cr_exit(); @@ -234,4 +249,5 @@ int main() { infof("==================================================================="); coroutine_add("init", init_cr, NULL); coroutine_main(); + assert_notreached("all coroutines exited"); } diff --git a/cmd/sbc_harness/usb_keyboard.c b/cmd/sbc_harness/usb_keyboard.c index f3cb42d..7dd8a24 100644 --- a/cmd/sbc_harness/usb_keyboard.c +++ b/cmd/sbc_harness/usb_keyboard.c @@ -54,8 +54,8 @@ COROUTINE usb_keyboard_cr(void *_chan) { while (!tud_hid_n_ready(kbd_ifc)) cr_yield(); - if (usb_keyboard_rpc_can_recv_req(chan)) { - usb_keyboard_rpc_req_t req = usb_keyboard_rpc_recv_req(chan); + if (cr_rpc_can_recv_req(chan)) { + usb_keyboard_rpc_req_t req = cr_rpc_recv_req(chan); uint32_t rune = req.req; modifier = ascii2keycode[rune][0] ? KEYBOARD_MODIFIER_LEFTSHIFT : 0; @@ -69,7 +69,7 @@ COROUTINE usb_keyboard_cr(void *_chan) { keycodes[0] = 0; tud_hid_n_keyboard_report(kbd_ifc, report_id, modifier, keycodes); - usb_keyboard_rpc_send_resp(req, 1); + cr_rpc_send_resp(req, 1); } else { modifier = 0; keycodes[0] = 0; diff --git a/cmd/sbc_harness/usb_keyboard.h b/cmd/sbc_harness/usb_keyboard.h index 210014d..cf8483b 100644 --- a/cmd/sbc_harness/usb_keyboard.h +++ b/cmd/sbc_harness/usb_keyboard.h @@ -1,6 +1,6 @@ /* sbc_harness/usb_keyboard.h - Implementation of a USB keyboard device * - * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later */ @@ -12,7 +12,7 @@ #include <libcr/coroutine.h> /* for COROUTINE */ #include <libcr_ipc/rpc.h> /* for CR_RPC_DECLARE */ -CR_RPC_DECLARE(usb_keyboard_rpc, uint32_t, int) +CR_RPC_DECLARE(usb_keyboard_rpc, uint32_t, int); void usb_keyboard_init(void); COROUTINE usb_keyboard_cr(void *arg); diff --git a/gdb-helpers/libcr.py b/gdb-helpers/libcr.py index fcfd86e..6f95a81 100644 --- a/gdb-helpers/libcr.py +++ b/gdb-helpers/libcr.py @@ -89,6 +89,7 @@ def gdb_longjmp(buf: gdb_JmpBuf) -> None: class CrGlobals: + main: "CrMain" coroutines: list["CrCoroutine"] _breakpoint: "CrBreakpoint" _known_threads: set[gdb.InferiorThread] @@ -98,6 +99,7 @@ class CrGlobals: gdb.parse_and_eval("sizeof(coroutine_table)/sizeof(coroutine_table[0])") ) + self.main = CrMain(self) self.coroutines = [CrCoroutine(self, i + 1) for i in range(num)] self._breakpoint = CrBreakpoint() @@ -126,35 +128,37 @@ class CrGlobals: # Ignore thread creation events. self._known_threads = cur_threads return - if self.coroutine_running: - if not self.coroutine_running.is_selected(): - if gdb_bug_32428: - print("Must return to running coroutine before continuing.") - print("Hit ^C twice then run:") - print(f" cr select {self.coroutine_running.id}") - while True: - time.sleep(1) - assert self.coroutine_running.cont_env - gdb_longjmp(self.coroutine_running.cont_env) + if not self.coroutine_running.is_selected(): + if gdb_bug_32428: + print("Must return to running coroutine before continuing.") + print("Hit ^C twice then run:") + print(f" cr select {self.coroutine_running.cid}") + while True: + time.sleep(1) + assert self.coroutine_running.cont_env + gdb_longjmp(self.coroutine_running.cont_env) + self.main.cont_env = None for cr in self.coroutines: cr.cont_env = None def is_valid_cid(self, cid: int) -> bool: - return 0 < cid <= len(self.coroutines) + return (0 < cid <= len(self.coroutines)) and ( + self.coroutines[cid - 1].state != self.CR_NONE + ) @property - def coroutine_running(self) -> "CrCoroutine | None": + def coroutine_running(self) -> "CrMain | CrCoroutine": cid = int(gdb.parse_and_eval("coroutine_running")) if not self.is_valid_cid(cid): - return None + return self.main return self.coroutines[cid - 1] @property - def coroutine_selected(self) -> "CrCoroutine | None": + def coroutine_selected(self) -> "CrMain | CrCoroutine": for cr in self.coroutines: if cr.is_selected(): return cr - return None + return self.main @property def CR_NONE(self) -> gdb.Value: @@ -164,6 +168,35 @@ class CrGlobals: def CR_RUNNING(self) -> gdb.Value: return gdb.parse_and_eval("CR_RUNNING") + def select(self, cr: "CrMain | CrCoroutine", level: int = -1) -> None: + self.coroutine_selected.cont_env = gdb_setjmp() + + if cr.cont_env: + gdb_longjmp(cr.cont_env) + else: + env: gdb_JmpBuf + if cr == self.coroutine_running: + assert False # cr.cont_env should have been set + match cr: + case CrMain(): + env = self.readjmp("&coroutine_main_env") + case CrCoroutine(): + if cr.state == self.CR_RUNNING: + env = self.readjmp("&coroutine_add_env") + else: + env = self.readjmp(f"&coroutine_table[{cr.cid-1}].env") + gdb_longjmp(env) + cr_select_top_frame() + + @contextlib.contextmanager + def with_selected(self, cr: "CrMain | CrCoroutine") -> typing.Iterator[None]: + saved_env = gdb_setjmp() + self.select(cr) + try: + yield + finally: + gdb_longjmp(saved_env) + class CrBreakpointUnwinder(gdb.unwinder.Unwinder): """Used to temporarily disable unwinding so that @@ -245,6 +278,22 @@ def cr_select_top_frame() -> None: break +class CrMain: + cr_globals: CrGlobals + cont_env: gdb_JmpBuf | None + + def __init__(self, cr_globals: CrGlobals) -> None: + self.cr_globals = cr_globals + self.cont_env = None + + @property + def cid(self) -> int: + return 0 + + def is_selected(self) -> bool: + return not any(cr.is_selected() for cr in self.cr_globals.coroutines) + + class CrCoroutine: cr_globals: CrGlobals cid: int @@ -256,10 +305,6 @@ class CrCoroutine: self.cont_env = None @property - def id(self) -> int: - return self.cid - - @property def state(self) -> gdb.Value: return gdb.parse_and_eval(f"coroutine_table[{self.cid-1}].state") @@ -272,36 +317,10 @@ class CrCoroutine: def is_selected(self) -> bool: sp = int(gdb.parse_and_eval("$sp")) - lo = int(gdb.parse_and_eval(f"coroutine_table[{self.id-1}].stack")) - hi = lo + int(gdb.parse_and_eval(f"coroutine_table[{self.id-1}].stack_size")) + lo = int(gdb.parse_and_eval(f"coroutine_table[{self.cid-1}].stack")) + hi = lo + int(gdb.parse_and_eval(f"coroutine_table[{self.cid-1}].stack_size")) return lo <= sp < hi - def select(self, level: int = -1) -> None: - if self.cr_globals.coroutine_selected: - self.cr_globals.coroutine_selected.cont_env = gdb_setjmp() - - if self.cont_env: - gdb_longjmp(self.cont_env) - else: - env: gdb_JmpBuf - if self == self.cr_globals.coroutine_running: - assert False # self.cont_env should have been set - elif self.state == self.cr_globals.CR_RUNNING: - env = self.cr_globals.readjmp("&coroutine_add_env") - else: - env = self.cr_globals.readjmp(f"&coroutine_table[{self.id-1}].env") - gdb_longjmp(env) - cr_select_top_frame() - - @contextlib.contextmanager - def with_selected(self) -> typing.Iterator[None]: - saved_env = gdb_setjmp() - self.select() - try: - yield - finally: - gdb_longjmp(saved_env) - # User-facing commands ######################################################### @@ -342,8 +361,11 @@ class CrListCommand(gdb.Command): rows: list[tuple[str, str, str, str, str]] = [ ("", "Id", "Name", "State", "Frame") ] - for cr in self.cr_globals.coroutines: - if cr.state == self.cr_globals.CR_NONE: + for cid in range(len(self.cr_globals.coroutines) + 1): + cr: CrMain | CrCoroutine = ( + self.cr_globals.coroutines[cid - 1] if cid else self.cr_globals.main + ) + if isinstance(cr, CrCoroutine) and cr.state == self.cr_globals.CR_NONE: continue rows += [ ( @@ -353,9 +375,9 @@ class CrListCommand(gdb.Command): "G" if cr.is_selected() else " ", ] ), - str(cr.id), - repr(cr.name), - str(cr.state), + str(cr.cid), + repr(cr.name) if isinstance(cr, CrCoroutine) else "-", + str(cr.state) if isinstance(cr, CrCoroutine) else "-", self._pretty_frame(cr, from_tty), ) ] @@ -382,9 +404,9 @@ class CrListCommand(gdb.Command): l = l[:maxline] print(l) - def _pretty_frame(self, cr: CrCoroutine, from_tty: bool) -> str: + def _pretty_frame(self, cr: CrMain | CrCoroutine, from_tty: bool) -> str: try: - with cr.with_selected(): + with self.cr_globals.with_selected(cr): saved_level = gdb.selected_frame().level() cr_select_top_frame() full = gdb.execute("frame", from_tty=from_tty, to_string=True) @@ -411,16 +433,15 @@ class CrSelectCommand(gdb.Command): if len(argv) != 1: raise gdb.GdbError("Usage: cr select COROUTINE") cr = self._find(argv[0]) - cr.select() + self.cr_globals.select(cr) gdb.execute("frame") - def _find(self, name: str) -> CrCoroutine: + def _find(self, name: str) -> CrMain | CrCoroutine: if name.isnumeric(): cid = int(name) - if ( - self.cr_globals.is_valid_cid(cid) - and self.cr_globals.coroutines[cid - 1].state != self.cr_globals.CR_NONE - ): + if cid == 0: + return self.cr_globals.main + if self.cr_globals.is_valid_cid(cid): return self.cr_globals.coroutines[cid - 1] crs: list[CrCoroutine] = [] for cr in self.cr_globals.coroutines: @@ -445,6 +466,7 @@ def cr_initialize() -> None: if _cr_globals: old = _cr_globals new = CrGlobals() + new.main.cont_env = old.main.cont_env for i in range(min(len(old.coroutines), len(new.coroutines))): new.coroutines[i].cont_env = old.coroutines[i].cont_env old.delete() diff --git a/lib9p/CMakeLists.txt b/lib9p/CMakeLists.txt index d433a12..0a5ea3e 100644 --- a/lib9p/CMakeLists.txt +++ b/lib9p/CMakeLists.txt @@ -3,27 +3,67 @@ # Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> # SPDX-License-Identifier: AGPL-3.0-or-later -add_library(lib9p INTERFACE) -target_include_directories(lib9p PUBLIC INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include) -target_sources(lib9p INTERFACE - 9p.generated.c - 9p.c - tables.c - srv.c +add_library(lib9p_core INTERFACE) +target_include_directories(lib9p_core PUBLIC INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/core_include) +target_sources(lib9p_core INTERFACE + core.c + core_generated.c + core_tables.c ) -target_link_libraries(lib9p INTERFACE - libcr_ipc +target_link_libraries(lib9p_core INTERFACE libfmt libhw_generic libmisc ) +add_library(lib9p_srv INTERFACE) +target_include_directories(lib9p_srv PUBLIC INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/srv_include) +target_sources(lib9p_srv INTERFACE + srv.c +) +target_link_libraries(lib9p_srv INTERFACE + lib9p_core + libcr_ipc +) + if (ENABLE_TESTS) add_subdirectory(tests/test_server) - add_test( - NAME "lib9p/runtest" - COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/tests/runtest" + + function(add_lib9p_executable arg_testname) + add_executable("${arg_testname}" "tests/${arg_testname}.c") + target_link_libraries("${arg_testname}" lib9p_core) + target_include_directories("${arg_testname}" PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/tests + ${CMAKE_CURRENT_SOURCE_DIR}/tests/client_config + ) + endfunction() + function(add_lib9p_test arg_testscript) + get_filename_component(tmp_basename "${arg_testscript}" "NAME") + add_test( + NAME "lib9p/${tmp_basename}" + COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/tests/runtest" "${arg_testscript}" "${CMAKE_CURRENT_SOURCE_DIR}/tests/${tmp_basename}.explog" + ) + endfunction() + + add_lib9p_test("${CMAKE_CURRENT_SOURCE_DIR}/tests/testclient-p9p") + + add_lib9p_executable("testclient-sess") + add_lib9p_test("./testclient-sess") + + set(cfg_matrix + "CONFIG_9P_SRV_DEBUG;[0;1]" + "CONFIG_9P_ENABLE_9P2000;[0;1]" + "CONFIG_9P_ENABLE_9P2000_u;[0;1]" + "CONFIG_9P_ENABLE_9P2000_e;[0;1]" + "CONFIG_9P_ENABLE_9P2000_L;[0;1]" + "CONFIG_9P_ENABLE_9P2000_p9p;[0;1]" ) - add_lib_test(lib9p test_compile) - target_include_directories(test_compile PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_compile_config) + function(add_compile_test n defs) + add_executable("test_compile${n}" "tests/test_compile.c") + target_link_libraries("test_compile${n}" lib9p_srv) + target_include_directories("test_compile${n}" PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_compile_config) + target_compile_definitions("test_compile${n}" PUBLIC "${defs}") + # Don't bother running it (don't bother calling add_test()) + endfunction() + apply_matrix(add_compile_test "${cfg_matrix}") endif() diff --git a/lib9p/9p.c b/lib9p/core.c index e7b20b5..cb8ddee 100644 --- a/lib9p/9p.c +++ b/lib9p/core.c @@ -1,4 +1,4 @@ -/* lib9p/9p.c - Base 9P protocol utilities for both clients and servers +/* lib9p/core.c - Base 9P protocol utilities for both clients and servers * * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later @@ -10,7 +10,7 @@ #include <libfmt/fmt.h> /* for fmt_vsnprintf() */ -#include <lib9p/9p.h> +#include <lib9p/core.h> /* strings ********************************************************************/ @@ -47,7 +47,7 @@ bool lib9p_str_eq(struct lib9p_s a, struct lib9p_s b) { void lib9p_ctx_clear_error(struct lib9p_ctx *ctx) { assert(ctx); -#if CONFIG_9P_ENABLE_9P2000_u +#if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L ctx->err_num = 0; #endif ctx->err_msg[0] = '\0'; @@ -58,22 +58,31 @@ bool lib9p_ctx_has_error(struct lib9p_ctx *ctx) { return ctx->err_msg[0]; } -int lib9p_error(struct lib9p_ctx *ctx, lib9p_errno_t linux_errno, char const *msg) { +#undef lib9p_error +#undef lib9p_errorf + +int lib9p_error(struct lib9p_ctx *ctx, +#if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L + lib9p_errno_t linux_errno, +#endif + char const *msg) { if (lib9p_ctx_has_error(ctx)) return -1; strncpy(ctx->err_msg, msg, sizeof(ctx->err_msg)); ctx->err_msg[sizeof(ctx->err_msg)-1] = '\0'; -#if CONFIG_9P_ENABLE_9P2000_u +#if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L ctx->err_num = linux_errno; -#else - (void)(linux_errno); #endif return -1; } -int lib9p_errorf(struct lib9p_ctx *ctx, lib9p_errno_t linux_errno, char const *fmt, ...) { +int lib9p_errorf(struct lib9p_ctx *ctx, +#if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L + lib9p_errno_t linux_errno, +#endif + char const *fmt, ...) { int n; va_list args; @@ -85,10 +94,8 @@ int lib9p_errorf(struct lib9p_ctx *ctx, lib9p_errno_t linux_errno, char const *f if ((size_t)(n+1) < sizeof(ctx->err_msg)) memset(&ctx->err_msg[n+1], 0, sizeof(ctx->err_msg)-(n+1)); -#if CONFIG_9P_ENABLE_9P2000_u +#if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L ctx->err_num = linux_errno; -#else - (void)(linux_errno); #endif return -1; diff --git a/lib9p/proto.gen b/lib9p/core.gen index 60f1347..b30ec31 100755 --- a/lib9p/proto.gen +++ b/lib9p/core.gen @@ -1,6 +1,6 @@ #!/usr/bin/env python -# lib9p/proto.gen - Generate C marshalers/unmarshalers for .9p files -# defining 9P protocol variants. +# lib9p/core.gen - Generate C marshalers/unmarshalers for .9p files +# defining 9P protocol variants. # # Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> # SPDX-License-Identifier: AGPL-3.0-or-later @@ -9,7 +9,7 @@ import os.path import sys sys.path.insert(0, os.path.normpath(os.path.join(__file__, ".."))) -import protogen # pylint: disable=wrong-import-position +import core_gen # pylint: disable=wrong-import-position if __name__ == "__main__": - protogen.main() + core_gen.main() diff --git a/lib9p/protogen/__init__.py b/lib9p/core_gen/__init__.py index c2c6173..b0da237 100644 --- a/lib9p/protogen/__init__.py +++ b/lib9p/core_gen/__init__.py @@ -1,4 +1,4 @@ -# lib9p/protogen/__init__.py - Generate C marshalers/unmarshalers for +# lib9p/core_gen/__init__.py - Generate C marshalers/unmarshalers for # .9p files defining 9P protocol variants # # Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> @@ -50,8 +50,10 @@ def main() -> None: versions, typs = parser.all() outdir = os.path.normpath(os.path.join(sys.argv[0], "..")) with open( - os.path.join(outdir, "include/lib9p/9p.generated.h"), "w", encoding="utf-8" + os.path.join(outdir, "core_include/lib9p/_core_generated.h"), + "w", + encoding="utf-8", ) as fh: fh.write(h.gen_h(versions, typs)) - with open(os.path.join(outdir, "9p.generated.c"), "w", encoding="utf-8") as fh: + with open(os.path.join(outdir, "core_generated.c"), "w", encoding="utf-8") as fh: fh.write(c.gen_c(versions, typs)) diff --git a/lib9p/protogen/c.py b/lib9p/core_gen/c.py index a6824ce..a300404 100644 --- a/lib9p/protogen/c.py +++ b/lib9p/core_gen/c.py @@ -1,4 +1,4 @@ -# lib9p/protogen/c.py - Generate 9p.generated.c +# lib9p/core_gen/c.py - Generate core_generated.c # # Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> # SPDX-License-Identifier: AGPL-3.0-or-later @@ -31,10 +31,10 @@ def gen_c(versions: set[str], typs: list[idl.UserType]) -> str: #include <libmisc/assert.h> #include <libmisc/endian.h> -#include <lib9p/9p.h> +#include <lib9p/core.h> -#include "tables.h" -#include "utf8.h" +#include "core_tables.h" +#include "core_utf8.h" """ # libobj vtables ########################################################### ret += """ @@ -79,7 +79,9 @@ def gen_c(versions: set[str], typs: list[idl.UserType]) -> str: if not isinstance(typ, idl.Bitfield): continue ret += "\n" - ret += cutil.ifdef_push(1, c9util.ver_ifdef(typ.in_versions)) + ret += cutil.ifdef_push( + 1, c9util.ver_ifdef(typ.in_versions - {"unknown"}) + ) # SPECIAL (initialization) ret += f"static const {c9util.typename(typ)} {typ.typname}_masks[{c9util.ver_enum('NUM')}] = {{\n" verwidth = max(len(ver) for ver in versions) for ver in sorted(versions): @@ -121,12 +123,17 @@ def gen_c(versions: set[str], typs: list[idl.UserType]) -> str: ret += "\n" ret += f"const struct {c9util.ident('_ver_tentry')} {c9util.ident('_table_ver')}[{c9util.ver_enum('NUM')}] = {{\n" rerror = next(typ for typ in typs if typ.typname == "Rerror") - for ver in ["unknown", *sorted(versions)]: - if ver == "unknown": - min_msg_size = rerror.min_size("9P2000") # SPECIAL (initialization) - else: - ret += cutil.ifdef_push(1, c9util.ver_ifdef({ver})) - min_msg_size = rerror.min_size(ver) + for ver in sorted(versions): + # XXX: There are good arguments that min_msg_size should be + # something larger than rerror.min_size(). + # srv.c:respond_error() assumes that min_msg_size is + # rerror.min_size(); if you do change min_msg_size to + # something larger, then be sure to update respond_error(). + ret += cutil.ifdef_push(1, c9util.ver_ifdef({ver})) + min_msg_size = rerror.min_size(ver) + if ver == "9P2000.L": # SPECIAL (9P2000.L) + rlerror = next(typ for typ in typs if typ.typname == "Rlerror") + min_msg_size = rlerror.min_size(ver) ret += f'\t[{c9util.ver_enum(ver)}] = {{.name="{ver}", .min_msg_size={min_msg_size}}},\n' ret += cutil.ifdef_pop(0) ret += "};\n" @@ -135,19 +142,14 @@ def gen_c(versions: set[str], typs: list[idl.UserType]) -> str: cstruct: str, cname: str, each: str, _range: tuple[int, int, int] ) -> str: ret = f"const struct {c9util.ident(cstruct)} {c9util.ident(cname)}[{c9util.ver_enum('NUM')}][{hex(len(range(*_range)))}] = {{\n" - for ver in ["unknown", *sorted(versions)]: - if ver != "unknown": - ret += cutil.ifdef_push(1, c9util.ver_ifdef({ver})) + for ver in sorted(versions): + ret += cutil.ifdef_push(1, c9util.ver_ifdef({ver})) ret += f"\t[{c9util.ver_enum(ver)}] = {{\n" for n in range(*_range): xmsg: idl.Message | None = id2typ.get(n, None) if xmsg: - if ver == "unknown": # SPECIAL (initialization) - if xmsg.typname not in ["Tversion", "Rversion", "Rerror"]: - xmsg = None - else: - if ver not in xmsg.in_versions: - xmsg = None + if ver not in xmsg.in_versions: + xmsg = None if xmsg: ret += f"\t\t{each}({xmsg.typname}),\n" ret += "\t},\n" @@ -186,6 +188,7 @@ def gen_c(versions: set[str], typs: list[idl.UserType]) -> str: ret += msg_table("_send_tentry", "_table_Rmsg_send", "_MSG_SEND", (1, 0x100, 2)) ret += f""" +{cutil.ifdef_push(1, c9util.ver_ifdef(next(typ for typ in typs if typ.typname == 'stat').in_versions)).rstrip()} LM_FLATTEN ssize_t {c9util.ident('_stat_validate')}(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes, uint32_t *ret_net_size) {{ \treturn validate_stat(ctx, net_size, net_bytes, ret_net_size); }} @@ -195,7 +198,7 @@ LM_FLATTEN void {c9util.ident('_stat_unmarshal')}(struct lib9p_ctx *ctx, uint8_t LM_FLATTEN bool {c9util.ident('_stat_marshal')}(struct lib9p_ctx *ctx, struct {c9util.ident('stat')} *val, struct _marshal_ret *ret) {{ \treturn marshal_stat(ctx, val, ret); }} -""" +{cutil.ifdef_pop(0)}""" ############################################################################ return ret diff --git a/lib9p/protogen/c9util.py b/lib9p/core_gen/c9util.py index cf91951..84fdee4 100644 --- a/lib9p/protogen/c9util.py +++ b/lib9p/core_gen/c9util.py @@ -1,4 +1,4 @@ -# lib9p/protogen/c9util.py - Utilities for generating lib9p-specific C +# lib9p/core_gen/c9util.py - Utilities for generating lib9p-specific C # # Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> # SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib9p/protogen/c_format.py b/lib9p/core_gen/c_format.py index a1bcbf3..c633fbb 100644 --- a/lib9p/protogen/c_format.py +++ b/lib9p/core_gen/c_format.py @@ -1,4 +1,4 @@ -# lib9p/protogen/c_format.py - Generate C pretty-print functions +# lib9p/core_gen/c_format.py - Generate C pretty-print functions # # Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> # SPDX-License-Identifier: AGPL-3.0-or-later @@ -21,6 +21,19 @@ def bf_numname(typ: idl.Bitfield, num: idl.BitNum, base: str) -> str: return c9util.Ident(c9util.add_prefix(prefix, base)) +def ext_printf(line: str) -> str: + assert line.startswith("\t") + assert line.endswith("\n") + # It sucks that %v trips -Wformat and -Wformat-extra-args + # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47781 + ret = "#pragma GCC diagnostic push\n" + ret += '#pragma GCC diagnostic ignored "-Wformat"\n' + ret += '#pragma GCC diagnostic ignored "-Wformat-extra-args"\n' + ret += line + ret += "#pragma GCC diagnostic pop\n" + return ret + + def gen_c_format(versions: set[str], typs: list[idl.UserType]) -> str: ret = """ /* *_format *******************************************************************/ @@ -92,13 +105,10 @@ def gen_c_format(versions: set[str], typs: list[idl.UserType]) -> str: ret += "\tif (empty)\n" ret += "\t\tfmt_state_putchar(state, '0');\n" ret += "\tfmt_state_putchar(state, ')');\n" - case idl.Struct(typname="s"): # SPECIAL(string) - ret += "\t/* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47781 */\n" - ret += "#pragma GCC diagnostic push\n" - ret += '#pragma GCC diagnostic ignored "-Wformat"\n' - ret += '#pragma GCC diagnostic ignored "-Wformat-extra-args"\n' - ret += '\tfmt_state_printf(state, "%.*q", self->len, self->utf8);\n' - ret += "#pragma GCC diagnostic pop\n" + case idl.Struct(typname="s"): # SPECIAL (string) + ret += ext_printf( + '\tfmt_state_printf(state, "%.*q", self->len, self->utf8);\n' + ) case idl.Struct(): # and idl.Message(): if isinstance(typ, idl.Message): ret += f'\tfmt_state_puts(state, "{typ.typname} {{");\n' @@ -109,19 +119,29 @@ def gen_c_format(versions: set[str], typs: list[idl.UserType]) -> str: continue ret += cutil.ifdef_push(2, c9util.ver_ifdef(member.in_versions)) if member.cnt: - if member.typ.static_size == 1: # SPECIAL (data) - ret += f'\tfmt_state_puts(state, " {member.membname}=<bytedata>");\n' - continue if isinstance(member.cnt, int): cnt_str = str(member.cnt) cnt_typ = "size_t" else: cnt_str = f"self->{member.cnt.membname}" cnt_typ = c9util.typename(member.cnt.typ) + if member.typ.static_size == 1: # SPECIAL (data) + ret += f"\tif (is_valid_utf8_without_nul((uint8_t *)self->{member.membname}, (size_t){cnt_str})) {{\n" + ret += ext_printf( + f'\t\tfmt_state_printf(state, " {member.membname}=%.*q%s",\n' + f"\t\t\t(int)({cnt_str} < 50 ? {cnt_str} : 50),\n" + f"\t\t\t(char *)self->{member.membname},\n" + f'\t\t\t{cnt_str} < 50 ? "" : "...");\n' + ) + ret += "\t} else {\n" + ret += f'\t\tfmt_state_puts(state, " {member.membname}=<bytedata>");\n' + ret += "\t}\n" + continue ret += f'\tfmt_state_puts(state, " {member.membname}=[");\n' ret += f"\tfor ({cnt_typ} i = 0; i < {cnt_str}; i++) {{\n" ret += "\t\tif (i)\n" - ret += '\t\t\tfmt_state_puts(state, ", ");\n' + ret += "\t\t\tfmt_state_putchar(state, ',');\n" + ret += "\t\tfmt_state_putchar(state, ' ');\n" if isinstance(member.typ, idl.Primitive): ret += f'\t\tfmt_state_printf(state, "%"PRIu{member.typ.static_size*8}, self->{member.membname}[i]);\n' else: diff --git a/lib9p/protogen/c_marshal.py b/lib9p/core_gen/c_marshal.py index 4dab864..620bdea 100644 --- a/lib9p/protogen/c_marshal.py +++ b/lib9p/core_gen/c_marshal.py @@ -1,4 +1,4 @@ -# lib9p/protogen/c_marshal.py - Generate C marshal functions +# lib9p/core_gen/c_marshal.py - Generate C marshal functions # # Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> # SPDX-License-Identifier: AGPL-3.0-or-later @@ -381,7 +381,7 @@ def gen_c_marshal(versions: set[str], typs: list[idl.UserType]) -> str: ) ret += "\tif (needed_size > ctx->max_msg_size) {\n" if isinstance(typ, idl.Message): # SPECIAL (disable for stat) - ret += '\t\tlib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",\n' + ret += f'\t\tlib9p_errorf(ctx, {c9util.IDENT("ERRNO_L_ERANGE")}, "%s message too large to marshal into %s limit (limit=%"PRIu32")",\n' ret += f'\t\t\t"{typ.typname}",\n' ret += f'\t\t\tctx->version ? "negotiated" : "{'client' if typ.msgid % 2 == 0 else 'server'}",\n' ret += "\t\t\tctx->max_msg_size);\n" diff --git a/lib9p/protogen/c_unmarshal.py b/lib9p/core_gen/c_unmarshal.py index 34635f9..1afbe1d 100644 --- a/lib9p/protogen/c_unmarshal.py +++ b/lib9p/core_gen/c_unmarshal.py @@ -1,4 +1,4 @@ -# lib9p/protogen/c_unmarshal.py - Generate C unmarshal functions +# lib9p/core_gen/c_unmarshal.py - Generate C unmarshal functions # # Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> # SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib9p/protogen/c_validate.py b/lib9p/core_gen/c_validate.py index 535a750..3073ed0 100644 --- a/lib9p/protogen/c_validate.py +++ b/lib9p/core_gen/c_validate.py @@ -1,4 +1,4 @@ -# lib9p/protogen/c_validate.py - Generate C validation functions +# lib9p/core_gen/c_validate.py - Generate C validation functions # # Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> # SPDX-License-Identifier: AGPL-3.0-or-later @@ -57,9 +57,9 @@ def gen_c_validate(versions: set[str], typs: list[idl.UserType]) -> str: "\t\t/* If needed-net-size overflowed uint32_t, then\n" "\t\t * there's no way that actual-net-size will live up to\n" "\t\t * that. */\n" - '\t\treturn lib9p_error(ctx, LINUX_EBADMSG, "message is too short for content");\n' + f'\t\treturn lib9p_error(ctx, {c9util.IDENT("ERRNO_L_EBADMSG")}, "message is too short for content");\n' "\tif (net_offset > net_size)\n" - '\t\treturn lib9p_errorf(ctx, LINUX_EBADMSG, "message is too short for content (%"PRIu32" > %"PRIu32") @ %d", net_offset, net_size, __LINE__);\n' + f'\t\treturn lib9p_errorf(ctx, {c9util.IDENT("ERRNO_L_EBADMSG")}, "message is too short for content (%"PRIu32" > %"PRIu32") @ %d", net_offset, net_size, __LINE__);\n' ) ret += cutil.macro( "#define VALIDATE_NET_UTF8(n)\n" @@ -67,7 +67,7 @@ def gen_c_validate(versions: set[str], typs: list[idl.UserType]) -> str: "\t\tsize_t len = n;\n" "\t\tVALIDATE_NET_BYTES(len);\n" "\t\tif (!is_valid_utf8_without_nul(&net_bytes[net_offset-len], len))\n" - '\t\t\treturn lib9p_error(ctx, LINUX_EBADMSG, "message contains invalid UTF-8");\n' + f'\t\t\treturn lib9p_error(ctx, {c9util.IDENT("ERRNO_L_EBADMSG")}, "message contains invalid UTF-8");\n' "\t}\n" ) ret += cutil.macro( @@ -76,7 +76,7 @@ def gen_c_validate(versions: set[str], typs: list[idl.UserType]) -> str: "\t\t/* If needed-host-size overflowed ssize_t, then there's\n" "\t\t * no way that actual-net-size will live up to\n" "\t\t * that. */\n" - '\t\treturn lib9p_error(ctx, LINUX_EBADMSG, "message is too short for content");\n' + f'\t\treturn lib9p_error(ctx, {c9util.IDENT("ERRNO_L_EBADMSG")}, "message is too short for content");\n' ) ret += "#define GET_U8LE(off) (net_bytes[off])\n" @@ -193,7 +193,7 @@ def gen_c_validate(versions: set[str], typs: list[idl.UserType]) -> str: act = f"(uint{nbits}_t)GET_U{nbits}LE({lookup_sym(f'&{child.membname}')})" exp = f"(uint{nbits}_t)({c9util.idl_expr(child.val, lookup_sym)})" ret += f"{'\t'*indent_lvl()}if ({act} != {exp})\n" - ret += f'{"\t"*(indent_lvl()+1)}return lib9p_errorf(ctx, LINUX_EBADMSG, "{path} value is wrong: actual: %"PRIu{nbits}" != correct:%"PRIu{nbits},\n' + ret += f'{"\t"*(indent_lvl()+1)}return lib9p_errorf(ctx, {c9util.IDENT("ERRNO_L_EBADMSG")}, "{path} value is wrong: actual: %"PRIu{nbits}" != correct:%"PRIu{nbits},\n' ret += f"{'\t'*(indent_lvl()+2)}{act}, {exp});\n" if child.max: incr_flush() @@ -208,7 +208,7 @@ def gen_c_validate(versions: set[str], typs: list[idl.UserType]) -> str: act = f"(uint{nbits}_t)GET_U{nbits}LE({lookup_sym(f'&{child.membname}')})" exp = f"(uint{nbits}_t)({c9util.idl_expr(child.max, lookup_sym)})" ret += f"{'\t'*indent_lvl()}if ({act} > {exp})\n" - ret += f'{"\t"*(indent_lvl()+1)}return lib9p_errorf(ctx, LINUX_EBADMSG, "{path} value is too large: %"PRIu{nbits}" > %"PRIu{nbits},\n' + ret += f'{"\t"*(indent_lvl()+1)}return lib9p_errorf(ctx, {c9util.IDENT("ERRNO_L_EBADMSG")}, "{path} value is too large: %"PRIu{nbits}" > %"PRIu{nbits},\n' ret += f"{'\t'*(indent_lvl()+2)}{act}, {exp});\n" if isinstance(child.typ, idl.Bitfield): incr_flush() @@ -216,7 +216,7 @@ def gen_c_validate(versions: set[str], typs: list[idl.UserType]) -> str: nbits = nbytes * 8 act = f"GET_U{nbits}LE({lookup_sym(f'&{child.membname}')})" ret += f"{'\t'*indent_lvl()}if ({act} & ~{child.typ.typname}_masks[ctx->version])\n" - ret += f'{"\t"*(indent_lvl()+1)}return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in {child.typ.typname} bitfield: %#0{nbytes*2}"PRIx{nbits},\n' + ret += f'{"\t"*(indent_lvl()+1)}return lib9p_errorf(ctx, {c9util.IDENT("ERRNO_L_EBADMSG")}, "unknown bits in {child.typ.typname} bitfield: %#0{nbytes*2}"PRIx{nbits},\n' ret += f"{'\t'*(indent_lvl()+2)}{act} & ~{child.typ.typname}_masks[ctx->version]);\n" def handle( diff --git a/lib9p/protogen/cutil.py b/lib9p/core_gen/cutil.py index 8df6db9..9183cc4 100644 --- a/lib9p/protogen/cutil.py +++ b/lib9p/core_gen/cutil.py @@ -1,4 +1,4 @@ -# lib9p/protogen/cutil.py - Utilities for generating C code +# lib9p/core_gen/cutil.py - Utilities for generating C code # # Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> # SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/lib9p/protogen/h.py b/lib9p/core_gen/h.py index 3b33419..ff070c6 100644 --- a/lib9p/protogen/h.py +++ b/lib9p/core_gen/h.py @@ -1,4 +1,4 @@ -# lib9p/protogen/h.py - Generate 9p.generated.h +# lib9p/core_gen/h.py - Generate _core_generated.h # # Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> # SPDX-License-Identifier: AGPL-3.0-or-later @@ -159,14 +159,14 @@ def gen_h(versions: set[str], typs: list[idl.UserType]) -> str: ret = f"""/* Generated by `{' '.join(sys.argv)}`. DO NOT EDIT! */ -#ifndef _LIB9P_9P_H_ -\t#error Do not include <lib9p/9p.generated.h> directly; include <lib9p/9p.h> instead +#ifndef _LIB9P_CORE_H_ +\t#error Do not include <lib9p/_core_generated.h> directly; include <lib9p/core.h> instead #endif #include <stdint.h> /* for uint{{n}}_t types */ #include <libfmt/fmt.h> /* for fmt_formatter */ -#include <libhw/generic/net.h> /* for struct iovec */ +#include <libhw/generic/io.h> /* for struct iovec */ """ id2typ: dict[int, idl.Message] = {} @@ -192,14 +192,21 @@ def gen_h(versions: set[str], typs: list[idl.UserType]) -> str: ret += "\t#endif\n" ret += "#endif\n" + # SPECIAL (convenience) + ret += "\n" + ret += f"#define _LIB9P_ENABLE_stat {c9util.ver_ifdef(next(typ for typ in typs if typ.typname == 'stat').in_versions)}\n" + ret += f""" /* enum version ***************************************************************/ enum {c9util.ident('version')} {{ """ - fullversions = ["unknown = 0", *sorted(versions)] - verwidth = max(len(v) for v in fullversions) - for ver in fullversions: + xversions = [ + "unknown = 0", + *sorted(v for v in versions if v != "unknown"), + ] # SPECIAL (initialization) + verwidth = max(len(v) for v in xversions) + for ver in xversions: if ver in versions: ret += cutil.ifdef_push(1, c9util.ver_ifdef({ver})) ret += f"\t{c9util.ver_enum(ver)}," diff --git a/lib9p/protogen/idlutil.py b/lib9p/core_gen/idlutil.py index dc4d012..e92839a 100644 --- a/lib9p/protogen/idlutil.py +++ b/lib9p/core_gen/idlutil.py @@ -1,10 +1,9 @@ -# lib9p/protogen/idlutil.py - Utilities for working with the 9P idl package +# lib9p/core_gen/idlutil.py - Utilities for working with the 9P idl package # # Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> # SPDX-License-Identifier: AGPL-3.0-or-later import enum -import graphlib import typing import idl @@ -22,21 +21,40 @@ __all__ = [ def topo_sorted(typs: list[idl.UserType]) -> typing.Iterable[idl.UserType]: - ts: graphlib.TopologicalSorter[idl.UserType] = graphlib.TopologicalSorter() + ret: list[idl.UserType] = [] + struct_ord: dict[str, int] = {} + + def get_struct_ord(typ: idl.Struct) -> int: + nonlocal struct_ord + if typ.typname not in struct_ord: + deps = [ + get_struct_ord(member.typ) + for member in typ.members + if isinstance(member.typ, idl.Struct) + ] + if len(deps) == 0: + struct_ord[typ.typname] = 0 + else: + struct_ord[typ.typname] = 1 + max(deps) + return struct_ord[typ.typname] + for typ in typs: match typ: case idl.Number(): - ts.add(typ) + ret.append(typ) case idl.Bitfield(): - ts.add(typ) + ret.append(typ) case idl.Struct(): # and idl.Message(): - deps = [ - member.typ - for member in typ.members - if not isinstance(member.typ, idl.Primitive) - ] - ts.add(typ, *deps) - return ts.static_order() + _ = get_struct_ord(typ) + for _ord in sorted(set(struct_ord.values())): + for typ in typs: + if not isinstance(typ, idl.Struct): + continue + if struct_ord[typ.typname] != _ord: + continue + ret.append(typ) + assert len(ret) == len(typs) + return ret # walk() ####################################################################### diff --git a/lib9p/9p.generated.c b/lib9p/core_generated.c index b58a485..8539fdf 100644 --- a/lib9p/9p.generated.c +++ b/lib9p/core_generated.c @@ -1,4 +1,4 @@ -/* Generated by `lib9p/proto.gen lib9p/idl/2002-9P2000.9p lib9p/idl/2003-9P2000.p9p.9p lib9p/idl/2005-9P2000.u.9p lib9p/idl/2010-9P2000.L.9p lib9p/idl/2012-9P2000.e.9p`. DO NOT EDIT! */ +/* Generated by `lib9p/core.gen lib9p/idl/0000-uninitialized.9p lib9p/idl/2002-9P2000.9p lib9p/idl/2003-9P2000.p9p.9p lib9p/idl/2005-9P2000.u.9p lib9p/idl/2010-9P2000.L.9p lib9p/idl/2012-9P2000.e.9p`. DO NOT EDIT! */ #include <stdbool.h> #include <stddef.h> /* for size_t */ @@ -8,36 +8,42 @@ #include <libmisc/assert.h> #include <libmisc/endian.h> -#include <lib9p/9p.h> +#include <lib9p/core.h> -#include "tables.h" -#include "utf8.h" +#include "core_tables.h" +#include "core_utf8.h" /* libobj vtables *************************************************************/ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown LO_IMPLEMENTATION_C(fmt_formatter, lib9p_tag_t, lib9p_tag, static); LO_IMPLEMENTATION_C(fmt_formatter, lib9p_fid_t, lib9p_fid, static); LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_s, lib9p_s, static); -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown LO_IMPLEMENTATION_C(fmt_formatter, lib9p_dm_t, lib9p_dm, static); -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown LO_IMPLEMENTATION_C(fmt_formatter, lib9p_qt_t, lib9p_qt, static); LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_qid, lib9p_qid, static); -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_stat, lib9p_stat, static); LO_IMPLEMENTATION_C(fmt_formatter, lib9p_o_t, lib9p_o, static); #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tversion, lib9p_msg_Tversion, static); LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rversion, lib9p_msg_Rversion, static); +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tauth, lib9p_msg_Tauth, static); LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rauth, lib9p_msg_Rauth, static); LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tattach, lib9p_msg_Tattach, static); LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rattach, lib9p_msg_Rattach, static); +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rerror, lib9p_msg_Rerror, static); +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tflush, lib9p_msg_Tflush, static); LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rflush, lib9p_msg_Rflush, static); LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Twalk, lib9p_msg_Twalk, static); @@ -159,6 +165,11 @@ LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rswrite, lib9p_msg_Rswrite, #else #define _is_ver_9P2000_u(v) false #endif +#if CONFIG_9P_ENABLE_unknown + #define _is_ver_unknown(v) (v == LIB9P_VER_unknown) +#else + #define _is_ver_unknown(v) false +#endif /** * is_ver(ctx, ver) is essentially `(ctx->version == LIB9P_VER_##ver)`, but @@ -187,6 +198,9 @@ static const lib9p_dm_t dm_masks[LIB9P_VER_NUM] = { #if CONFIG_9P_ENABLE_9P2000_u [LIB9P_VER_9P2000_u] = 0b11111100101111000000000111111111, #endif /* CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_unknown + [LIB9P_VER_unknown] = 0b11111100000000000000000111111111, +#endif /* CONFIG_9P_ENABLE_unknown */ }; #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ @@ -207,6 +221,9 @@ static const lib9p_qt_t qt_masks[LIB9P_VER_NUM] = { #if CONFIG_9P_ENABLE_9P2000_u [LIB9P_VER_9P2000_u] = 0b11111110, #endif /* CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_unknown + [LIB9P_VER_unknown] = 0b11111100, +#endif /* CONFIG_9P_ENABLE_unknown */ }; #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ @@ -227,6 +244,9 @@ static const lib9p_o_t o_masks[LIB9P_VER_NUM] = { #if CONFIG_9P_ENABLE_9P2000_u [LIB9P_VER_9P2000_u] = 0b01010011, #endif /* CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_unknown + [LIB9P_VER_unknown] = 0b00000000, +#endif /* CONFIG_9P_ENABLE_unknown */ }; #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ @@ -245,6 +265,9 @@ static const lib9p_lo_t lo_masks[LIB9P_VER_NUM] = { #if CONFIG_9P_ENABLE_9P2000_u [LIB9P_VER_9P2000_u] = 0b00000000000000000000000000000000, #endif /* CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_unknown + [LIB9P_VER_unknown] = 0b00000000000000000000000000000000, +#endif /* CONFIG_9P_ENABLE_unknown */ }; static const lib9p_mode_t mode_masks[LIB9P_VER_NUM] = { @@ -261,6 +284,9 @@ static const lib9p_mode_t mode_masks[LIB9P_VER_NUM] = { #if CONFIG_9P_ENABLE_9P2000_u [LIB9P_VER_9P2000_u] = 0b00000000000000000000000000000000, #endif /* CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_unknown + [LIB9P_VER_unknown] = 0b00000000000000000000000000000000, +#endif /* CONFIG_9P_ENABLE_unknown */ }; static const lib9p_getattr_t getattr_masks[LIB9P_VER_NUM] = { @@ -277,6 +303,9 @@ static const lib9p_getattr_t getattr_masks[LIB9P_VER_NUM] = { #if CONFIG_9P_ENABLE_9P2000_u [LIB9P_VER_9P2000_u] = 0b0000000000000000000000000000000000000000000000000000000000000000, #endif /* CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_unknown + [LIB9P_VER_unknown] = 0b0000000000000000000000000000000000000000000000000000000000000000, +#endif /* CONFIG_9P_ENABLE_unknown */ }; static const lib9p_setattr_t setattr_masks[LIB9P_VER_NUM] = { @@ -293,6 +322,9 @@ static const lib9p_setattr_t setattr_masks[LIB9P_VER_NUM] = { #if CONFIG_9P_ENABLE_9P2000_u [LIB9P_VER_9P2000_u] = 0b00000000000000000000000000000000, #endif /* CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_unknown + [LIB9P_VER_unknown] = 0b00000000000000000000000000000000, +#endif /* CONFIG_9P_ENABLE_unknown */ }; static const lib9p_lock_flags_t lock_flags_masks[LIB9P_VER_NUM] = { @@ -309,32 +341,35 @@ static const lib9p_lock_flags_t lock_flags_masks[LIB9P_VER_NUM] = { #if CONFIG_9P_ENABLE_9P2000_u [LIB9P_VER_9P2000_u] = 0b00000000000000000000000000000000, #endif /* CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_unknown + [LIB9P_VER_unknown] = 0b00000000000000000000000000000000, +#endif /* CONFIG_9P_ENABLE_unknown */ }; #endif /* CONFIG_9P_ENABLE_9P2000_L */ /* validate_* *****************************************************************/ -#define VALIDATE_NET_BYTES(n) \ - if (__builtin_add_overflow(net_offset, n, &net_offset)) \ - /* If needed-net-size overflowed uint32_t, then \ - * there's no way that actual-net-size will live up to \ - * that. */ \ - return lib9p_error(ctx, LINUX_EBADMSG, "message is too short for content"); \ - if (net_offset > net_size) \ - return lib9p_errorf(ctx, LINUX_EBADMSG, "message is too short for content (%"PRIu32" > %"PRIu32") @ %d", net_offset, net_size, __LINE__); -#define VALIDATE_NET_UTF8(n) \ - { \ - size_t len = n; \ - VALIDATE_NET_BYTES(len); \ - if (!is_valid_utf8_without_nul(&net_bytes[net_offset-len], len)) \ - return lib9p_error(ctx, LINUX_EBADMSG, "message contains invalid UTF-8"); \ +#define VALIDATE_NET_BYTES(n) \ + if (__builtin_add_overflow(net_offset, n, &net_offset)) \ + /* If needed-net-size overflowed uint32_t, then \ + * there's no way that actual-net-size will live up to \ + * that. */ \ + return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "message is too short for content"); \ + if (net_offset > net_size) \ + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "message is too short for content (%"PRIu32" > %"PRIu32") @ %d", net_offset, net_size, __LINE__); +#define VALIDATE_NET_UTF8(n) \ + { \ + size_t len = n; \ + VALIDATE_NET_BYTES(len); \ + if (!is_valid_utf8_without_nul(&net_bytes[net_offset-len], len)) \ + return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "message contains invalid UTF-8"); \ } #define RESERVE_HOST_BYTES(n) \ if (__builtin_add_overflow(host_size, n, &host_size)) \ /* If needed-host-size overflowed ssize_t, then there's \ * no way that actual-net-size will live up to \ * that. */ \ - return lib9p_error(ctx, LINUX_EBADMSG, "message is too short for content"); + return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "message is too short for content"); #define GET_U8LE(off) (net_bytes[off]) #define GET_U16LE(off) uint16le_decode(&net_bytes[off]) #define GET_U32LE(off) uint32le_decode(&net_bytes[off]) @@ -348,14 +383,14 @@ static const lib9p_lock_flags_t lock_flags_masks[LIB9P_VER_NUM] = { static ssize_t validate_stat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes, uint32_t *ret_net_size) { uint32_t net_offset = 0; ssize_t host_size = sizeof(struct lib9p_stat); - uint32_t offsetof_stat_size = net_offset + 0; - uint32_t offsetof_kern_type = net_offset + 2; - uint32_t offsetof_file_qid_type = net_offset + 8; + uint32_t offsetof__stat_size = net_offset + 0; + uint32_t offsetof_fstype = net_offset + 2; + uint32_t offsetof_qid_type = net_offset + 8; VALIDATE_NET_BYTES(21); - if (GET_U8LE(offsetof_file_qid_type) & ~qt_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, - GET_U8LE(offsetof_file_qid_type) & ~qt_masks[ctx->version]); - uint32_t offsetof_file_mode = net_offset + 0; + if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]) + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, + GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]); + uint32_t offsetof_mode = net_offset + 0; VALIDATE_NET_BYTES(22); VALIDATE_NET_UTF8(LAST_U16LE()); VALIDATE_NET_BYTES(2); @@ -372,19 +407,19 @@ static ssize_t validate_stat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t * } #endif /* CONFIG_9P_ENABLE_9P2000_u */ uint32_t offsetof_end = net_offset + 0; - if ((uint32_t)GET_U32LE(offsetof_stat_size) != (uint32_t)(offsetof_end - offsetof_kern_type)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "stat->stat_size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, - (uint32_t)GET_U32LE(offsetof_stat_size), (uint32_t)(offsetof_end - offsetof_kern_type)); - if (GET_U32LE(offsetof_file_mode) & ~dm_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in dm bitfield: %#08"PRIx32, - GET_U32LE(offsetof_file_mode) & ~dm_masks[ctx->version]); + if ((uint32_t)GET_U32LE(offsetof__stat_size) != (uint32_t)(offsetof_end - offsetof_fstype)) + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "stat->_stat_size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof__stat_size), (uint32_t)(offsetof_end - offsetof_fstype)); + if (GET_U32LE(offsetof_mode) & ~dm_masks[ctx->version]) + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in dm bitfield: %#08"PRIx32, + GET_U32LE(offsetof_mode) & ~dm_masks[ctx->version]); if (ret_net_size) *ret_net_size = net_offset; return (ssize_t)host_size; } #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown static ssize_t validate_Tversion(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { uint32_t net_offset = 0; ssize_t host_size = sizeof(struct lib9p_msg_Tversion); @@ -394,10 +429,10 @@ static ssize_t validate_Tversion(struct lib9p_ctx *ctx, uint32_t net_size, uint8 VALIDATE_NET_UTF8(LAST_U16LE()); uint32_t offsetof_end = net_offset + 0; if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tversion->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tversion->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(100)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tversion->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tversion->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(100)); return (ssize_t)host_size; } @@ -411,14 +446,16 @@ static ssize_t validate_Rversion(struct lib9p_ctx *ctx, uint32_t net_size, uint8 VALIDATE_NET_UTF8(LAST_U16LE()); uint32_t offsetof_end = net_offset + 0; if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rversion->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rversion->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(101)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rversion->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rversion->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(101)); return (ssize_t)host_size; } +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u static ssize_t validate_Tauth(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { uint32_t net_offset = 0; ssize_t host_size = sizeof(struct lib9p_msg_Tauth); @@ -435,10 +472,10 @@ static ssize_t validate_Tauth(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t #endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ uint32_t offsetof_end = net_offset + 0; if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tauth->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tauth->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(102)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tauth->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tauth->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(102)); return (ssize_t)host_size; } @@ -451,14 +488,14 @@ static ssize_t validate_Rauth(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t uint32_t offsetof_aqid_type = net_offset + 7; VALIDATE_NET_BYTES(20); if (GET_U8LE(offsetof_aqid_type) & ~qt_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, GET_U8LE(offsetof_aqid_type) & ~qt_masks[ctx->version]); uint32_t offsetof_end = net_offset + 0; if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rauth->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rauth->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(103)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rauth->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rauth->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(103)); return (ssize_t)host_size; } @@ -479,10 +516,10 @@ static ssize_t validate_Tattach(struct lib9p_ctx *ctx, uint32_t net_size, uint8_ #endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ uint32_t offsetof_end = net_offset + 0; if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tattach->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tattach->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(104)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tattach->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tattach->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(104)); return (ssize_t)host_size; } @@ -495,18 +532,20 @@ static ssize_t validate_Rattach(struct lib9p_ctx *ctx, uint32_t net_size, uint8_ uint32_t offsetof_qid_type = net_offset + 7; VALIDATE_NET_BYTES(20); if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]); uint32_t offsetof_end = net_offset + 0; if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rattach->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rattach->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(105)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rattach->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rattach->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(105)); return (ssize_t)host_size; } +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown static ssize_t validate_Rerror(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { uint32_t net_offset = 0; ssize_t host_size = sizeof(struct lib9p_msg_Rerror); @@ -521,14 +560,16 @@ static ssize_t validate_Rerror(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t #endif /* CONFIG_9P_ENABLE_9P2000_u */ uint32_t offsetof_end = net_offset + 0; if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rerror->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rerror->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(107)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rerror->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rerror->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(107)); return (ssize_t)host_size; } +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u static ssize_t validate_Tflush(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) { uint32_t net_offset = 0; ssize_t host_size = sizeof(struct lib9p_msg_Tflush); @@ -537,10 +578,10 @@ static ssize_t validate_Tflush(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t uint32_t offsetof_end = net_offset + 9; VALIDATE_NET_BYTES(9); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tflush->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tflush->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(108)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tflush->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tflush->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(108)); return (ssize_t)host_size; } @@ -553,10 +594,10 @@ static ssize_t validate_Rflush(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t uint32_t offsetof_end = net_offset + 7; VALIDATE_NET_BYTES(7); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rflush->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rflush->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(109)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rflush->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rflush->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(109)); return (ssize_t)host_size; } @@ -575,13 +616,13 @@ static ssize_t validate_Twalk(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t } uint32_t offsetof_end = net_offset + 0; if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Twalk->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Twalk->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(110)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Twalk->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Twalk->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(110)); if ((uint16_t)GET_U16LE(offsetof_nwname) > (uint16_t)(16)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Twalk->nwname value is too large: %"PRIu16" > %"PRIu16, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Twalk->nwname value is too large: %"PRIu16" > %"PRIu16, (uint16_t)GET_U16LE(offsetof_nwname), (uint16_t)(16)); return (ssize_t)host_size; } @@ -598,18 +639,18 @@ static ssize_t validate_Rwalk(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t uint32_t offsetof_wqid_type = net_offset + 0; VALIDATE_NET_BYTES(13); if (GET_U8LE(offsetof_wqid_type) & ~qt_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, GET_U8LE(offsetof_wqid_type) & ~qt_masks[ctx->version]); } uint32_t offsetof_end = net_offset + 0; if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rwalk->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rwalk->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(111)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rwalk->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rwalk->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(111)); if ((uint16_t)GET_U16LE(offsetof_nwqid) > (uint16_t)(16)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rwalk->nwqid value is too large: %"PRIu16" > %"PRIu16, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rwalk->nwqid value is too large: %"PRIu16" > %"PRIu16, (uint16_t)GET_U16LE(offsetof_nwqid), (uint16_t)(16)); return (ssize_t)host_size; } @@ -625,13 +666,13 @@ static ssize_t validate_Topen(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t uint32_t offsetof_end = net_offset + 12; VALIDATE_NET_BYTES(12); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Topen->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Topen->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(112)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Topen->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Topen->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(112)); if (GET_U8LE(offsetof_mode) & ~o_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in o bitfield: %#02"PRIx8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in o bitfield: %#02"PRIx8, GET_U8LE(offsetof_mode) & ~o_masks[ctx->version]); return (ssize_t)host_size; } @@ -644,15 +685,15 @@ static ssize_t validate_Ropen(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t uint32_t offsetof_qid_type = net_offset + 7; VALIDATE_NET_BYTES(20); if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]); uint32_t offsetof_end = net_offset + 4; VALIDATE_NET_BYTES(4); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Ropen->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Ropen->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(113)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Ropen->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Ropen->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(113)); return (ssize_t)host_size; } @@ -669,16 +710,16 @@ static ssize_t validate_Tcreate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_ uint32_t offsetof_end = net_offset + 5; VALIDATE_NET_BYTES(5); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tcreate->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tcreate->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(114)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tcreate->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tcreate->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(114)); if (GET_U32LE(offsetof_perm) & ~dm_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in dm bitfield: %#08"PRIx32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in dm bitfield: %#08"PRIx32, GET_U32LE(offsetof_perm) & ~dm_masks[ctx->version]); if (GET_U8LE(offsetof_mode) & ~o_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in o bitfield: %#02"PRIx8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in o bitfield: %#02"PRIx8, GET_U8LE(offsetof_mode) & ~o_masks[ctx->version]); return (ssize_t)host_size; } @@ -691,15 +732,15 @@ static ssize_t validate_Rcreate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_ uint32_t offsetof_qid_type = net_offset + 7; VALIDATE_NET_BYTES(20); if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]); uint32_t offsetof_end = net_offset + 4; VALIDATE_NET_BYTES(4); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rcreate->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rcreate->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(115)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rcreate->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rcreate->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(115)); return (ssize_t)host_size; } @@ -716,16 +757,16 @@ static ssize_t validate_Tread(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t uint32_t offsetof_end = net_offset + 23; VALIDATE_NET_BYTES(23); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tread->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tread->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(116)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tread->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tread->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(116)); if ((uint64_t)GET_U64LE(offsetof_offset) > (uint64_t)(INT64_MAX)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tread->offset value is too large: %"PRIu64" > %"PRIu64, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tread->offset value is too large: %"PRIu64" > %"PRIu64, (uint64_t)GET_U64LE(offsetof_offset), (uint64_t)(INT64_MAX)); if ((uint32_t)GET_U32LE(offsetof_count) > (uint32_t)(INT32_MAX)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tread->count value is too large: %"PRIu32" > %"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tread->count value is too large: %"PRIu32" > %"PRIu32, (uint32_t)GET_U32LE(offsetof_count), (uint32_t)(INT32_MAX)); return (ssize_t)host_size; } @@ -740,13 +781,13 @@ static ssize_t validate_Rread(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t VALIDATE_NET_BYTES(LAST_U32LE()); uint32_t offsetof_end = net_offset + 0; if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rread->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rread->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(117)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rread->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rread->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(117)); if ((uint32_t)GET_U32LE(offsetof_count) > (uint32_t)(INT32_MAX)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rread->count value is too large: %"PRIu32" > %"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rread->count value is too large: %"PRIu32" > %"PRIu32, (uint32_t)GET_U32LE(offsetof_count), (uint32_t)(INT32_MAX)); return (ssize_t)host_size; } @@ -762,16 +803,16 @@ static ssize_t validate_Twrite(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t VALIDATE_NET_BYTES(LAST_U32LE()); uint32_t offsetof_end = net_offset + 0; if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Twrite->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Twrite->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(118)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Twrite->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Twrite->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(118)); if ((uint64_t)GET_U64LE(offsetof_offset) > (uint64_t)(INT64_MAX)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Twrite->offset value is too large: %"PRIu64" > %"PRIu64, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Twrite->offset value is too large: %"PRIu64" > %"PRIu64, (uint64_t)GET_U64LE(offsetof_offset), (uint64_t)(INT64_MAX)); if ((uint32_t)GET_U32LE(offsetof_count) > (uint32_t)(INT32_MAX)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Twrite->count value is too large: %"PRIu32" > %"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Twrite->count value is too large: %"PRIu32" > %"PRIu32, (uint32_t)GET_U32LE(offsetof_count), (uint32_t)(INT32_MAX)); return (ssize_t)host_size; } @@ -785,13 +826,13 @@ static ssize_t validate_Rwrite(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t uint32_t offsetof_end = net_offset + 11; VALIDATE_NET_BYTES(11); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rwrite->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rwrite->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(119)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rwrite->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rwrite->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(119)); if ((uint32_t)GET_U32LE(offsetof_count) > (uint32_t)(INT32_MAX)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rwrite->count value is too large: %"PRIu32" > %"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rwrite->count value is too large: %"PRIu32" > %"PRIu32, (uint32_t)GET_U32LE(offsetof_count), (uint32_t)(INT32_MAX)); return (ssize_t)host_size; } @@ -804,10 +845,10 @@ static ssize_t validate_Tclunk(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t uint32_t offsetof_end = net_offset + 11; VALIDATE_NET_BYTES(11); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tclunk->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tclunk->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(120)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tclunk->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tclunk->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(120)); return (ssize_t)host_size; } @@ -820,10 +861,10 @@ static ssize_t validate_Rclunk(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t uint32_t offsetof_end = net_offset + 7; VALIDATE_NET_BYTES(7); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rclunk->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rclunk->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(121)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rclunk->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rclunk->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(121)); return (ssize_t)host_size; } @@ -836,10 +877,10 @@ static ssize_t validate_Tremove(struct lib9p_ctx *ctx, uint32_t net_size, uint8_ uint32_t offsetof_end = net_offset + 11; VALIDATE_NET_BYTES(11); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tremove->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tremove->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(122)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tremove->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tremove->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(122)); return (ssize_t)host_size; } @@ -852,10 +893,10 @@ static ssize_t validate_Rremove(struct lib9p_ctx *ctx, uint32_t net_size, uint8_ uint32_t offsetof_end = net_offset + 7; VALIDATE_NET_BYTES(7); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rremove->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rremove->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(123)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rremove->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rremove->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(123)); return (ssize_t)host_size; } @@ -870,10 +911,10 @@ static ssize_t validate_Tstat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t uint32_t offsetof_end = net_offset + 11; VALIDATE_NET_BYTES(11); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tstat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tstat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(124)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tstat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tstat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(124)); return (ssize_t)host_size; } @@ -885,14 +926,14 @@ static ssize_t validate_Rstat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t uint32_t offsetof_typ = net_offset + 4; uint32_t offsetof_nstat = net_offset + 7; uint32_t offsetof_stat = net_offset + 9; - uint32_t offsetof_stat_stat_size = net_offset + 9; - uint32_t offsetof_stat_kern_type = net_offset + 11; - uint32_t offsetof_stat_file_qid_type = net_offset + 17; + uint32_t offsetof_stat__stat_size = net_offset + 9; + uint32_t offsetof_stat_fstype = net_offset + 11; + uint32_t offsetof_stat_qid_type = net_offset + 17; VALIDATE_NET_BYTES(30); - if (GET_U8LE(offsetof_stat_file_qid_type) & ~qt_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, - GET_U8LE(offsetof_stat_file_qid_type) & ~qt_masks[ctx->version]); - uint32_t offsetof_stat_file_mode = net_offset + 0; + if (GET_U8LE(offsetof_stat_qid_type) & ~qt_masks[ctx->version]) + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, + GET_U8LE(offsetof_stat_qid_type) & ~qt_masks[ctx->version]); + uint32_t offsetof_stat_mode = net_offset + 0; VALIDATE_NET_BYTES(22); VALIDATE_NET_UTF8(LAST_U16LE()); VALIDATE_NET_BYTES(2); @@ -909,21 +950,21 @@ static ssize_t validate_Rstat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t } #endif /* CONFIG_9P_ENABLE_9P2000_u */ uint32_t offsetof_stat_end = net_offset + 0; - if ((uint32_t)GET_U32LE(offsetof_stat_stat_size) != (uint32_t)(offsetof_stat_end - offsetof_stat_kern_type)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rstat->stat.stat_size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, - (uint32_t)GET_U32LE(offsetof_stat_stat_size), (uint32_t)(offsetof_stat_end - offsetof_stat_kern_type)); - if (GET_U32LE(offsetof_stat_file_mode) & ~dm_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in dm bitfield: %#08"PRIx32, - GET_U32LE(offsetof_stat_file_mode) & ~dm_masks[ctx->version]); + if ((uint32_t)GET_U32LE(offsetof_stat__stat_size) != (uint32_t)(offsetof_stat_end - offsetof_stat_fstype)) + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rstat->stat._stat_size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_stat__stat_size), (uint32_t)(offsetof_stat_end - offsetof_stat_fstype)); + if (GET_U32LE(offsetof_stat_mode) & ~dm_masks[ctx->version]) + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in dm bitfield: %#08"PRIx32, + GET_U32LE(offsetof_stat_mode) & ~dm_masks[ctx->version]); uint32_t offsetof_end = net_offset + 0; if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rstat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rstat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(125)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rstat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rstat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(125)); if ((uint32_t)GET_U32LE(offsetof_nstat) != (uint32_t)(offsetof_end - offsetof_stat)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rstat->nstat value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rstat->nstat value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_nstat), (uint32_t)(offsetof_end - offsetof_stat)); return (ssize_t)host_size; } @@ -935,14 +976,14 @@ static ssize_t validate_Twstat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t uint32_t offsetof_typ = net_offset + 4; uint32_t offsetof_nstat = net_offset + 11; uint32_t offsetof_stat = net_offset + 13; - uint32_t offsetof_stat_stat_size = net_offset + 13; - uint32_t offsetof_stat_kern_type = net_offset + 15; - uint32_t offsetof_stat_file_qid_type = net_offset + 21; + uint32_t offsetof_stat__stat_size = net_offset + 13; + uint32_t offsetof_stat_fstype = net_offset + 15; + uint32_t offsetof_stat_qid_type = net_offset + 21; VALIDATE_NET_BYTES(34); - if (GET_U8LE(offsetof_stat_file_qid_type) & ~qt_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, - GET_U8LE(offsetof_stat_file_qid_type) & ~qt_masks[ctx->version]); - uint32_t offsetof_stat_file_mode = net_offset + 0; + if (GET_U8LE(offsetof_stat_qid_type) & ~qt_masks[ctx->version]) + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, + GET_U8LE(offsetof_stat_qid_type) & ~qt_masks[ctx->version]); + uint32_t offsetof_stat_mode = net_offset + 0; VALIDATE_NET_BYTES(22); VALIDATE_NET_UTF8(LAST_U16LE()); VALIDATE_NET_BYTES(2); @@ -959,21 +1000,21 @@ static ssize_t validate_Twstat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t } #endif /* CONFIG_9P_ENABLE_9P2000_u */ uint32_t offsetof_stat_end = net_offset + 0; - if ((uint32_t)GET_U32LE(offsetof_stat_stat_size) != (uint32_t)(offsetof_stat_end - offsetof_stat_kern_type)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Twstat->stat.stat_size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, - (uint32_t)GET_U32LE(offsetof_stat_stat_size), (uint32_t)(offsetof_stat_end - offsetof_stat_kern_type)); - if (GET_U32LE(offsetof_stat_file_mode) & ~dm_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in dm bitfield: %#08"PRIx32, - GET_U32LE(offsetof_stat_file_mode) & ~dm_masks[ctx->version]); + if ((uint32_t)GET_U32LE(offsetof_stat__stat_size) != (uint32_t)(offsetof_stat_end - offsetof_stat_fstype)) + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Twstat->stat._stat_size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + (uint32_t)GET_U32LE(offsetof_stat__stat_size), (uint32_t)(offsetof_stat_end - offsetof_stat_fstype)); + if (GET_U32LE(offsetof_stat_mode) & ~dm_masks[ctx->version]) + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in dm bitfield: %#08"PRIx32, + GET_U32LE(offsetof_stat_mode) & ~dm_masks[ctx->version]); uint32_t offsetof_end = net_offset + 0; if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Twstat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Twstat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(126)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Twstat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Twstat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(126)); if ((uint32_t)GET_U32LE(offsetof_nstat) != (uint32_t)(offsetof_end - offsetof_stat)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Twstat->nstat value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Twstat->nstat value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_nstat), (uint32_t)(offsetof_end - offsetof_stat)); return (ssize_t)host_size; } @@ -986,10 +1027,10 @@ static ssize_t validate_Rwstat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t uint32_t offsetof_end = net_offset + 7; VALIDATE_NET_BYTES(7); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rwstat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rwstat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(127)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rwstat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rwstat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(127)); return (ssize_t)host_size; } @@ -1005,13 +1046,13 @@ static ssize_t validate_Topenfd(struct lib9p_ctx *ctx, uint32_t net_size, uint8_ uint32_t offsetof_end = net_offset + 12; VALIDATE_NET_BYTES(12); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Topenfd->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Topenfd->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(98)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Topenfd->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Topenfd->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(98)); if (GET_U8LE(offsetof_mode) & ~o_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in o bitfield: %#02"PRIx8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in o bitfield: %#02"PRIx8, GET_U8LE(offsetof_mode) & ~o_masks[ctx->version]); return (ssize_t)host_size; } @@ -1024,15 +1065,15 @@ static ssize_t validate_Ropenfd(struct lib9p_ctx *ctx, uint32_t net_size, uint8_ uint32_t offsetof_qid_type = net_offset + 7; VALIDATE_NET_BYTES(20); if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]); uint32_t offsetof_end = net_offset + 8; VALIDATE_NET_BYTES(8); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Ropenfd->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Ropenfd->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(99)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Ropenfd->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Ropenfd->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(99)); return (ssize_t)host_size; } @@ -1047,10 +1088,10 @@ static ssize_t validate_Rlerror(struct lib9p_ctx *ctx, uint32_t net_size, uint8_ uint32_t offsetof_end = net_offset + 11; VALIDATE_NET_BYTES(11); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rlerror->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rlerror->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(7)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rlerror->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rlerror->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(7)); return (ssize_t)host_size; } @@ -1063,10 +1104,10 @@ static ssize_t validate_Tstatfs(struct lib9p_ctx *ctx, uint32_t net_size, uint8_ uint32_t offsetof_end = net_offset + 11; VALIDATE_NET_BYTES(11); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tstatfs->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tstatfs->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(8)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tstatfs->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tstatfs->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(8)); return (ssize_t)host_size; } @@ -1079,10 +1120,10 @@ static ssize_t validate_Rstatfs(struct lib9p_ctx *ctx, uint32_t net_size, uint8_ uint32_t offsetof_end = net_offset + 67; VALIDATE_NET_BYTES(67); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rstatfs->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rstatfs->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(9)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rstatfs->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rstatfs->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(9)); return (ssize_t)host_size; } @@ -1096,13 +1137,13 @@ static ssize_t validate_Tlopen(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t uint32_t offsetof_end = net_offset + 15; VALIDATE_NET_BYTES(15); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tlopen->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tlopen->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(12)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tlopen->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tlopen->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(12)); if (GET_U32LE(offsetof_flags) & ~lo_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in lo bitfield: %#08"PRIx32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in lo bitfield: %#08"PRIx32, GET_U32LE(offsetof_flags) & ~lo_masks[ctx->version]); return (ssize_t)host_size; } @@ -1115,15 +1156,15 @@ static ssize_t validate_Rlopen(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t uint32_t offsetof_qid_type = net_offset + 7; VALIDATE_NET_BYTES(20); if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]); uint32_t offsetof_end = net_offset + 4; VALIDATE_NET_BYTES(4); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rlopen->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rlopen->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(13)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rlopen->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rlopen->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(13)); return (ssize_t)host_size; } @@ -1140,16 +1181,16 @@ static ssize_t validate_Tlcreate(struct lib9p_ctx *ctx, uint32_t net_size, uint8 uint32_t offsetof_end = net_offset + 12; VALIDATE_NET_BYTES(12); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tlcreate->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tlcreate->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(14)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tlcreate->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tlcreate->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(14)); if (GET_U32LE(offsetof_flags) & ~lo_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in lo bitfield: %#08"PRIx32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in lo bitfield: %#08"PRIx32, GET_U32LE(offsetof_flags) & ~lo_masks[ctx->version]); if (GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in mode bitfield: %#08"PRIx32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in mode bitfield: %#08"PRIx32, GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]); return (ssize_t)host_size; } @@ -1162,15 +1203,15 @@ static ssize_t validate_Rlcreate(struct lib9p_ctx *ctx, uint32_t net_size, uint8 uint32_t offsetof_qid_type = net_offset + 7; VALIDATE_NET_BYTES(20); if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]); uint32_t offsetof_end = net_offset + 4; VALIDATE_NET_BYTES(4); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rlcreate->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rlcreate->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(15)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rlcreate->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rlcreate->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(15)); return (ssize_t)host_size; } @@ -1187,10 +1228,10 @@ static ssize_t validate_Tsymlink(struct lib9p_ctx *ctx, uint32_t net_size, uint8 uint32_t offsetof_end = net_offset + 4; VALIDATE_NET_BYTES(4); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tsymlink->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tsymlink->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(16)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tsymlink->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tsymlink->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(16)); return (ssize_t)host_size; } @@ -1203,14 +1244,14 @@ static ssize_t validate_Rsymlink(struct lib9p_ctx *ctx, uint32_t net_size, uint8 uint32_t offsetof_qid_type = net_offset + 7; VALIDATE_NET_BYTES(20); if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]); uint32_t offsetof_end = net_offset + 0; if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rsymlink->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rsymlink->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(17)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rsymlink->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rsymlink->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(17)); return (ssize_t)host_size; } @@ -1226,13 +1267,13 @@ static ssize_t validate_Tmknod(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t uint32_t offsetof_end = net_offset + 16; VALIDATE_NET_BYTES(16); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tmknod->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tmknod->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(18)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tmknod->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tmknod->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(18)); if (GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in mode bitfield: %#08"PRIx32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in mode bitfield: %#08"PRIx32, GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]); return (ssize_t)host_size; } @@ -1245,14 +1286,14 @@ static ssize_t validate_Rmknod(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t uint32_t offsetof_qid_type = net_offset + 7; VALIDATE_NET_BYTES(20); if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]); uint32_t offsetof_end = net_offset + 0; if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rmknod->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rmknod->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(19)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rmknod->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rmknod->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(19)); return (ssize_t)host_size; } @@ -1266,10 +1307,10 @@ static ssize_t validate_Trename(struct lib9p_ctx *ctx, uint32_t net_size, uint8_ VALIDATE_NET_UTF8(LAST_U16LE()); uint32_t offsetof_end = net_offset + 0; if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Trename->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Trename->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(20)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Trename->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Trename->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(20)); return (ssize_t)host_size; } @@ -1282,10 +1323,10 @@ static ssize_t validate_Rrename(struct lib9p_ctx *ctx, uint32_t net_size, uint8_ uint32_t offsetof_end = net_offset + 7; VALIDATE_NET_BYTES(7); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rrename->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rrename->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(21)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rrename->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rrename->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(21)); return (ssize_t)host_size; } @@ -1298,10 +1339,10 @@ static ssize_t validate_Treadlink(struct lib9p_ctx *ctx, uint32_t net_size, uint uint32_t offsetof_end = net_offset + 11; VALIDATE_NET_BYTES(11); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Treadlink->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Treadlink->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(22)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Treadlink->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Treadlink->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(22)); return (ssize_t)host_size; } @@ -1315,10 +1356,10 @@ static ssize_t validate_Rreadlink(struct lib9p_ctx *ctx, uint32_t net_size, uint VALIDATE_NET_UTF8(LAST_U16LE()); uint32_t offsetof_end = net_offset + 0; if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rreadlink->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rreadlink->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(23)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rreadlink->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rreadlink->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(23)); return (ssize_t)host_size; } @@ -1332,13 +1373,13 @@ static ssize_t validate_Tgetattr(struct lib9p_ctx *ctx, uint32_t net_size, uint8 uint32_t offsetof_end = net_offset + 19; VALIDATE_NET_BYTES(19); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tgetattr->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tgetattr->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(24)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tgetattr->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tgetattr->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(24)); if (GET_U64LE(offsetof_request_mask) & ~getattr_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in getattr bitfield: %#016"PRIx64, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in getattr bitfield: %#016"PRIx64, GET_U64LE(offsetof_request_mask) & ~getattr_masks[ctx->version]); return (ssize_t)host_size; } @@ -1352,22 +1393,22 @@ static ssize_t validate_Rgetattr(struct lib9p_ctx *ctx, uint32_t net_size, uint8 uint32_t offsetof_qid_type = net_offset + 15; VALIDATE_NET_BYTES(28); if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]); uint32_t offsetof_mode = net_offset + 0; uint32_t offsetof_end = net_offset + 132; VALIDATE_NET_BYTES(132); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rgetattr->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rgetattr->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(25)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rgetattr->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rgetattr->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(25)); if (GET_U64LE(offsetof_valid) & ~getattr_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in getattr bitfield: %#016"PRIx64, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in getattr bitfield: %#016"PRIx64, GET_U64LE(offsetof_valid) & ~getattr_masks[ctx->version]); if (GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in mode bitfield: %#08"PRIx32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in mode bitfield: %#08"PRIx32, GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]); return (ssize_t)host_size; } @@ -1382,16 +1423,16 @@ static ssize_t validate_Tsetattr(struct lib9p_ctx *ctx, uint32_t net_size, uint8 uint32_t offsetof_end = net_offset + 67; VALIDATE_NET_BYTES(67); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tsetattr->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tsetattr->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(26)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tsetattr->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tsetattr->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(26)); if (GET_U32LE(offsetof_valid) & ~setattr_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in setattr bitfield: %#08"PRIx32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in setattr bitfield: %#08"PRIx32, GET_U32LE(offsetof_valid) & ~setattr_masks[ctx->version]); if (GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in mode bitfield: %#08"PRIx32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in mode bitfield: %#08"PRIx32, GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]); return (ssize_t)host_size; } @@ -1404,10 +1445,10 @@ static ssize_t validate_Rsetattr(struct lib9p_ctx *ctx, uint32_t net_size, uint8 uint32_t offsetof_end = net_offset + 7; VALIDATE_NET_BYTES(7); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rsetattr->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rsetattr->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(27)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rsetattr->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rsetattr->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(27)); return (ssize_t)host_size; } @@ -1421,10 +1462,10 @@ static ssize_t validate_Txattrwalk(struct lib9p_ctx *ctx, uint32_t net_size, uin VALIDATE_NET_UTF8(LAST_U16LE()); uint32_t offsetof_end = net_offset + 0; if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Txattrwalk->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Txattrwalk->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(30)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Txattrwalk->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Txattrwalk->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(30)); return (ssize_t)host_size; } @@ -1437,10 +1478,10 @@ static ssize_t validate_Rxattrwalk(struct lib9p_ctx *ctx, uint32_t net_size, uin uint32_t offsetof_end = net_offset + 15; VALIDATE_NET_BYTES(15); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rxattrwalk->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rxattrwalk->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(31)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rxattrwalk->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rxattrwalk->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(31)); return (ssize_t)host_size; } @@ -1455,10 +1496,10 @@ static ssize_t validate_Txattrcreate(struct lib9p_ctx *ctx, uint32_t net_size, u uint32_t offsetof_end = net_offset + 12; VALIDATE_NET_BYTES(12); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Txattrcreate->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Txattrcreate->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(32)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Txattrcreate->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Txattrcreate->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(32)); return (ssize_t)host_size; } @@ -1471,10 +1512,10 @@ static ssize_t validate_Rxattrcreate(struct lib9p_ctx *ctx, uint32_t net_size, u uint32_t offsetof_end = net_offset + 7; VALIDATE_NET_BYTES(7); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rxattrcreate->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rxattrcreate->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(33)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rxattrcreate->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rxattrcreate->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(33)); return (ssize_t)host_size; } @@ -1487,10 +1528,10 @@ static ssize_t validate_Treaddir(struct lib9p_ctx *ctx, uint32_t net_size, uint8 uint32_t offsetof_end = net_offset + 23; VALIDATE_NET_BYTES(23); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Treaddir->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Treaddir->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(40)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Treaddir->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Treaddir->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(40)); return (ssize_t)host_size; } @@ -1504,10 +1545,10 @@ static ssize_t validate_Rreaddir(struct lib9p_ctx *ctx, uint32_t net_size, uint8 VALIDATE_NET_BYTES(LAST_U32LE()); uint32_t offsetof_end = net_offset + 0; if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rreaddir->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rreaddir->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(41)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rreaddir->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rreaddir->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(41)); return (ssize_t)host_size; } @@ -1520,10 +1561,10 @@ static ssize_t validate_Tfsync(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t uint32_t offsetof_end = net_offset + 15; VALIDATE_NET_BYTES(15); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tfsync->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tfsync->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(50)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tfsync->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tfsync->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(50)); return (ssize_t)host_size; } @@ -1536,10 +1577,10 @@ static ssize_t validate_Rfsync(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t uint32_t offsetof_end = net_offset + 7; VALIDATE_NET_BYTES(7); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rfsync->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rfsync->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(51)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rfsync->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rfsync->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(51)); return (ssize_t)host_size; } @@ -1554,13 +1595,13 @@ static ssize_t validate_Tlock(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t VALIDATE_NET_UTF8(LAST_U16LE()); uint32_t offsetof_end = net_offset + 0; if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tlock->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tlock->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(52)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tlock->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tlock->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(52)); if (GET_U32LE(offsetof_flags) & ~lock_flags_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in lock_flags bitfield: %#08"PRIx32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in lock_flags bitfield: %#08"PRIx32, GET_U32LE(offsetof_flags) & ~lock_flags_masks[ctx->version]); return (ssize_t)host_size; } @@ -1573,10 +1614,10 @@ static ssize_t validate_Rlock(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t uint32_t offsetof_end = net_offset + 8; VALIDATE_NET_BYTES(8); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rlock->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rlock->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(53)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rlock->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rlock->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(53)); return (ssize_t)host_size; } @@ -1590,10 +1631,10 @@ static ssize_t validate_Tgetlock(struct lib9p_ctx *ctx, uint32_t net_size, uint8 VALIDATE_NET_UTF8(LAST_U16LE()); uint32_t offsetof_end = net_offset + 0; if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tgetlock->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tgetlock->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(54)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tgetlock->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tgetlock->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(54)); return (ssize_t)host_size; } @@ -1607,10 +1648,10 @@ static ssize_t validate_Rgetlock(struct lib9p_ctx *ctx, uint32_t net_size, uint8 VALIDATE_NET_UTF8(LAST_U16LE()); uint32_t offsetof_end = net_offset + 0; if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rgetlock->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rgetlock->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(55)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rgetlock->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rgetlock->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(55)); return (ssize_t)host_size; } @@ -1624,10 +1665,10 @@ static ssize_t validate_Tlink(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t VALIDATE_NET_UTF8(LAST_U16LE()); uint32_t offsetof_end = net_offset + 0; if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tlink->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tlink->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(70)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tlink->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tlink->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(70)); return (ssize_t)host_size; } @@ -1640,10 +1681,10 @@ static ssize_t validate_Rlink(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t uint32_t offsetof_end = net_offset + 7; VALIDATE_NET_BYTES(7); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rlink->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rlink->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(71)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rlink->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rlink->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(71)); return (ssize_t)host_size; } @@ -1659,13 +1700,13 @@ static ssize_t validate_Tmkdir(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t uint32_t offsetof_end = net_offset + 8; VALIDATE_NET_BYTES(8); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tmkdir->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tmkdir->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(72)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tmkdir->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tmkdir->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(72)); if (GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in mode bitfield: %#08"PRIx32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in mode bitfield: %#08"PRIx32, GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]); return (ssize_t)host_size; } @@ -1678,14 +1719,14 @@ static ssize_t validate_Rmkdir(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t uint32_t offsetof_qid_type = net_offset + 7; VALIDATE_NET_BYTES(20); if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]) - return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8, GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]); uint32_t offsetof_end = net_offset + 0; if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rmkdir->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rmkdir->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(73)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rmkdir->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rmkdir->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(73)); return (ssize_t)host_size; } @@ -1701,10 +1742,10 @@ static ssize_t validate_Trenameat(struct lib9p_ctx *ctx, uint32_t net_size, uint VALIDATE_NET_UTF8(LAST_U16LE()); uint32_t offsetof_end = net_offset + 0; if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Trenameat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Trenameat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(74)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Trenameat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Trenameat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(74)); return (ssize_t)host_size; } @@ -1717,10 +1758,10 @@ static ssize_t validate_Rrenameat(struct lib9p_ctx *ctx, uint32_t net_size, uint uint32_t offsetof_end = net_offset + 7; VALIDATE_NET_BYTES(7); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rrenameat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rrenameat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(75)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rrenameat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rrenameat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(75)); return (ssize_t)host_size; } @@ -1735,10 +1776,10 @@ static ssize_t validate_Tunlinkat(struct lib9p_ctx *ctx, uint32_t net_size, uint uint32_t offsetof_end = net_offset + 4; VALIDATE_NET_BYTES(4); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tunlinkat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tunlinkat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(76)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tunlinkat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tunlinkat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(76)); return (ssize_t)host_size; } @@ -1751,10 +1792,10 @@ static ssize_t validate_Runlinkat(struct lib9p_ctx *ctx, uint32_t net_size, uint uint32_t offsetof_end = net_offset + 7; VALIDATE_NET_BYTES(7); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Runlinkat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Runlinkat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(77)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Runlinkat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Runlinkat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(77)); return (ssize_t)host_size; } @@ -1769,10 +1810,10 @@ static ssize_t validate_Tsession(struct lib9p_ctx *ctx, uint32_t net_size, uint8 uint32_t offsetof_end = net_offset + 15; VALIDATE_NET_BYTES(15); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tsession->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tsession->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(150)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tsession->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tsession->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(150)); return (ssize_t)host_size; } @@ -1785,10 +1826,10 @@ static ssize_t validate_Rsession(struct lib9p_ctx *ctx, uint32_t net_size, uint8 uint32_t offsetof_end = net_offset + 7; VALIDATE_NET_BYTES(7); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rsession->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rsession->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(151)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rsession->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rsession->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(151)); return (ssize_t)host_size; } @@ -1806,10 +1847,10 @@ static ssize_t validate_Tsread(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t } uint32_t offsetof_end = net_offset + 0; if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tsread->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tsread->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(152)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tsread->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tsread->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(152)); return (ssize_t)host_size; } @@ -1823,10 +1864,10 @@ static ssize_t validate_Rsread(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t VALIDATE_NET_BYTES(LAST_U32LE()); uint32_t offsetof_end = net_offset + 0; if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rsread->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rsread->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(153)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rsread->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rsread->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(153)); return (ssize_t)host_size; } @@ -1846,10 +1887,10 @@ static ssize_t validate_Tswrite(struct lib9p_ctx *ctx, uint32_t net_size, uint8_ VALIDATE_NET_BYTES(LAST_U32LE()); uint32_t offsetof_end = net_offset + 0; if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tswrite->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tswrite->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(154)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Tswrite->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tswrite->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(154)); return (ssize_t)host_size; } @@ -1862,10 +1903,10 @@ static ssize_t validate_Rswrite(struct lib9p_ctx *ctx, uint32_t net_size, uint8_ uint32_t offsetof_end = net_offset + 11; VALIDATE_NET_BYTES(11); if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rswrite->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rswrite->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32, (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size)); if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(155)) - return lib9p_errorf(ctx, LINUX_EBADMSG, "Rswrite->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rswrite->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8, (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(155)); return (ssize_t)host_size; } @@ -1895,36 +1936,36 @@ static void unmarshal_stat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_b [[gnu::unused]] void *extra = &out[1]; uint32_t net_offset = 0; net_offset += 2; - UNMARSHAL_U16LE(ctx, out->kern_type); - UNMARSHAL_U32LE(ctx, out->kern_dev); - UNMARSHAL_U8LE(ctx, out->file_qid.type); - UNMARSHAL_U32LE(ctx, out->file_qid.vers); - UNMARSHAL_U64LE(ctx, out->file_qid.path); - UNMARSHAL_U32LE(ctx, out->file_mode); - UNMARSHAL_U32LE(ctx, out->file_atime); - UNMARSHAL_U32LE(ctx, out->file_mtime); - UNMARSHAL_U64LE(ctx, out->file_size); - UNMARSHAL_U16LE(ctx, out->file_name.len); - UNMARSHAL_BYTES(ctx, out->file_name.utf8, out->file_name.len); - UNMARSHAL_U16LE(ctx, out->file_owner_uid.len); - UNMARSHAL_BYTES(ctx, out->file_owner_uid.utf8, out->file_owner_uid.len); - UNMARSHAL_U16LE(ctx, out->file_owner_gid.len); - UNMARSHAL_BYTES(ctx, out->file_owner_gid.utf8, out->file_owner_gid.len); - UNMARSHAL_U16LE(ctx, out->file_last_modified_uid.len); - UNMARSHAL_BYTES(ctx, out->file_last_modified_uid.utf8, out->file_last_modified_uid.len); + UNMARSHAL_U16LE(ctx, out->fstype); + UNMARSHAL_U32LE(ctx, out->fsdev); + UNMARSHAL_U8LE(ctx, out->qid.type); + UNMARSHAL_U32LE(ctx, out->qid.vers); + UNMARSHAL_U64LE(ctx, out->qid.path); + UNMARSHAL_U32LE(ctx, out->mode); + UNMARSHAL_U32LE(ctx, out->atime); + UNMARSHAL_U32LE(ctx, out->mtime); + UNMARSHAL_U64LE(ctx, out->length); + UNMARSHAL_U16LE(ctx, out->name.len); + UNMARSHAL_BYTES(ctx, out->name.utf8, out->name.len); + UNMARSHAL_U16LE(ctx, out->owner_uname.len); + UNMARSHAL_BYTES(ctx, out->owner_uname.utf8, out->owner_uname.len); + UNMARSHAL_U16LE(ctx, out->owner_gname.len); + UNMARSHAL_BYTES(ctx, out->owner_gname.utf8, out->owner_gname.len); + UNMARSHAL_U16LE(ctx, out->last_modifier_uname.len); + UNMARSHAL_BYTES(ctx, out->last_modifier_uname.utf8, out->last_modifier_uname.len); #if CONFIG_9P_ENABLE_9P2000_u if (is_ver(ctx, 9P2000_u)) { - UNMARSHAL_U16LE(ctx, out->file_extension.len); - UNMARSHAL_BYTES(ctx, out->file_extension.utf8, out->file_extension.len); - UNMARSHAL_U32LE(ctx, out->file_owner_n_uid); - UNMARSHAL_U32LE(ctx, out->file_owner_n_gid); - UNMARSHAL_U32LE(ctx, out->file_last_modified_n_uid); + UNMARSHAL_U16LE(ctx, out->extension.len); + UNMARSHAL_BYTES(ctx, out->extension.utf8, out->extension.len); + UNMARSHAL_U32LE(ctx, out->owner_unum); + UNMARSHAL_U32LE(ctx, out->owner_gnum); + UNMARSHAL_U32LE(ctx, out->last_modifier_unum); } #endif /* CONFIG_9P_ENABLE_9P2000_u */ } #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown static void unmarshal_Tversion([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { struct lib9p_msg_Tversion *out = out_buf; [[gnu::unused]] void *extra = &out[1]; @@ -1949,6 +1990,8 @@ static void unmarshal_Rversion([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *n UNMARSHAL_BYTES(ctx, out->version.utf8, out->version.len); } +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u static void unmarshal_Tauth([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { struct lib9p_msg_Tauth *out = out_buf; [[gnu::unused]] void *extra = &out[1]; @@ -1963,7 +2006,7 @@ static void unmarshal_Tauth([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_ UNMARSHAL_BYTES(ctx, out->aname.utf8, out->aname.len); #if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u if (( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) )) { - UNMARSHAL_U32LE(ctx, out->n_uid); + UNMARSHAL_U32LE(ctx, out->unum); } #endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ } @@ -1995,7 +2038,7 @@ static void unmarshal_Tattach([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *ne UNMARSHAL_BYTES(ctx, out->aname.utf8, out->aname.len); #if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u if (( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) )) { - UNMARSHAL_U32LE(ctx, out->n_uid); + UNMARSHAL_U32LE(ctx, out->unum); } #endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ } @@ -2012,6 +2055,8 @@ static void unmarshal_Rattach([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *ne UNMARSHAL_U64LE(ctx, out->qid.path); } +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown static void unmarshal_Rerror([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { struct lib9p_msg_Rerror *out = out_buf; [[gnu::unused]] void *extra = &out[1]; @@ -2019,15 +2064,17 @@ static void unmarshal_Rerror([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net net_offset += 4; net_offset += 1; UNMARSHAL_U16LE(ctx, out->tag); - UNMARSHAL_U16LE(ctx, out->ename.len); - UNMARSHAL_BYTES(ctx, out->ename.utf8, out->ename.len); + UNMARSHAL_U16LE(ctx, out->errstr.len); + UNMARSHAL_BYTES(ctx, out->errstr.utf8, out->errstr.len); #if CONFIG_9P_ENABLE_9P2000_u if (is_ver(ctx, 9P2000_u)) { - UNMARSHAL_U32LE(ctx, out->errno); + UNMARSHAL_U32LE(ctx, out->errnum); } #endif /* CONFIG_9P_ENABLE_9P2000_u */ } +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u static void unmarshal_Tflush([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { struct lib9p_msg_Tflush *out = out_buf; [[gnu::unused]] void *extra = &out[1]; @@ -2242,30 +2289,30 @@ static void unmarshal_Rstat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_ UNMARSHAL_U16LE(ctx, out->tag); net_offset += 2; net_offset += 2; - UNMARSHAL_U16LE(ctx, out->stat.kern_type); - UNMARSHAL_U32LE(ctx, out->stat.kern_dev); - UNMARSHAL_U8LE(ctx, out->stat.file_qid.type); - UNMARSHAL_U32LE(ctx, out->stat.file_qid.vers); - UNMARSHAL_U64LE(ctx, out->stat.file_qid.path); - UNMARSHAL_U32LE(ctx, out->stat.file_mode); - UNMARSHAL_U32LE(ctx, out->stat.file_atime); - UNMARSHAL_U32LE(ctx, out->stat.file_mtime); - UNMARSHAL_U64LE(ctx, out->stat.file_size); - UNMARSHAL_U16LE(ctx, out->stat.file_name.len); - UNMARSHAL_BYTES(ctx, out->stat.file_name.utf8, out->stat.file_name.len); - UNMARSHAL_U16LE(ctx, out->stat.file_owner_uid.len); - UNMARSHAL_BYTES(ctx, out->stat.file_owner_uid.utf8, out->stat.file_owner_uid.len); - UNMARSHAL_U16LE(ctx, out->stat.file_owner_gid.len); - UNMARSHAL_BYTES(ctx, out->stat.file_owner_gid.utf8, out->stat.file_owner_gid.len); - UNMARSHAL_U16LE(ctx, out->stat.file_last_modified_uid.len); - UNMARSHAL_BYTES(ctx, out->stat.file_last_modified_uid.utf8, out->stat.file_last_modified_uid.len); + UNMARSHAL_U16LE(ctx, out->stat.fstype); + UNMARSHAL_U32LE(ctx, out->stat.fsdev); + UNMARSHAL_U8LE(ctx, out->stat.qid.type); + UNMARSHAL_U32LE(ctx, out->stat.qid.vers); + UNMARSHAL_U64LE(ctx, out->stat.qid.path); + UNMARSHAL_U32LE(ctx, out->stat.mode); + UNMARSHAL_U32LE(ctx, out->stat.atime); + UNMARSHAL_U32LE(ctx, out->stat.mtime); + UNMARSHAL_U64LE(ctx, out->stat.length); + UNMARSHAL_U16LE(ctx, out->stat.name.len); + UNMARSHAL_BYTES(ctx, out->stat.name.utf8, out->stat.name.len); + UNMARSHAL_U16LE(ctx, out->stat.owner_uname.len); + UNMARSHAL_BYTES(ctx, out->stat.owner_uname.utf8, out->stat.owner_uname.len); + UNMARSHAL_U16LE(ctx, out->stat.owner_gname.len); + UNMARSHAL_BYTES(ctx, out->stat.owner_gname.utf8, out->stat.owner_gname.len); + UNMARSHAL_U16LE(ctx, out->stat.last_modifier_uname.len); + UNMARSHAL_BYTES(ctx, out->stat.last_modifier_uname.utf8, out->stat.last_modifier_uname.len); #if CONFIG_9P_ENABLE_9P2000_u if (is_ver(ctx, 9P2000_u)) { - UNMARSHAL_U16LE(ctx, out->stat.file_extension.len); - UNMARSHAL_BYTES(ctx, out->stat.file_extension.utf8, out->stat.file_extension.len); - UNMARSHAL_U32LE(ctx, out->stat.file_owner_n_uid); - UNMARSHAL_U32LE(ctx, out->stat.file_owner_n_gid); - UNMARSHAL_U32LE(ctx, out->stat.file_last_modified_n_uid); + UNMARSHAL_U16LE(ctx, out->stat.extension.len); + UNMARSHAL_BYTES(ctx, out->stat.extension.utf8, out->stat.extension.len); + UNMARSHAL_U32LE(ctx, out->stat.owner_unum); + UNMARSHAL_U32LE(ctx, out->stat.owner_gnum); + UNMARSHAL_U32LE(ctx, out->stat.last_modifier_unum); } #endif /* CONFIG_9P_ENABLE_9P2000_u */ } @@ -2280,30 +2327,30 @@ static void unmarshal_Twstat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net UNMARSHAL_U32LE(ctx, out->fid); net_offset += 2; net_offset += 2; - UNMARSHAL_U16LE(ctx, out->stat.kern_type); - UNMARSHAL_U32LE(ctx, out->stat.kern_dev); - UNMARSHAL_U8LE(ctx, out->stat.file_qid.type); - UNMARSHAL_U32LE(ctx, out->stat.file_qid.vers); - UNMARSHAL_U64LE(ctx, out->stat.file_qid.path); - UNMARSHAL_U32LE(ctx, out->stat.file_mode); - UNMARSHAL_U32LE(ctx, out->stat.file_atime); - UNMARSHAL_U32LE(ctx, out->stat.file_mtime); - UNMARSHAL_U64LE(ctx, out->stat.file_size); - UNMARSHAL_U16LE(ctx, out->stat.file_name.len); - UNMARSHAL_BYTES(ctx, out->stat.file_name.utf8, out->stat.file_name.len); - UNMARSHAL_U16LE(ctx, out->stat.file_owner_uid.len); - UNMARSHAL_BYTES(ctx, out->stat.file_owner_uid.utf8, out->stat.file_owner_uid.len); - UNMARSHAL_U16LE(ctx, out->stat.file_owner_gid.len); - UNMARSHAL_BYTES(ctx, out->stat.file_owner_gid.utf8, out->stat.file_owner_gid.len); - UNMARSHAL_U16LE(ctx, out->stat.file_last_modified_uid.len); - UNMARSHAL_BYTES(ctx, out->stat.file_last_modified_uid.utf8, out->stat.file_last_modified_uid.len); + UNMARSHAL_U16LE(ctx, out->stat.fstype); + UNMARSHAL_U32LE(ctx, out->stat.fsdev); + UNMARSHAL_U8LE(ctx, out->stat.qid.type); + UNMARSHAL_U32LE(ctx, out->stat.qid.vers); + UNMARSHAL_U64LE(ctx, out->stat.qid.path); + UNMARSHAL_U32LE(ctx, out->stat.mode); + UNMARSHAL_U32LE(ctx, out->stat.atime); + UNMARSHAL_U32LE(ctx, out->stat.mtime); + UNMARSHAL_U64LE(ctx, out->stat.length); + UNMARSHAL_U16LE(ctx, out->stat.name.len); + UNMARSHAL_BYTES(ctx, out->stat.name.utf8, out->stat.name.len); + UNMARSHAL_U16LE(ctx, out->stat.owner_uname.len); + UNMARSHAL_BYTES(ctx, out->stat.owner_uname.utf8, out->stat.owner_uname.len); + UNMARSHAL_U16LE(ctx, out->stat.owner_gname.len); + UNMARSHAL_BYTES(ctx, out->stat.owner_gname.utf8, out->stat.owner_gname.len); + UNMARSHAL_U16LE(ctx, out->stat.last_modifier_uname.len); + UNMARSHAL_BYTES(ctx, out->stat.last_modifier_uname.utf8, out->stat.last_modifier_uname.len); #if CONFIG_9P_ENABLE_9P2000_u if (is_ver(ctx, 9P2000_u)) { - UNMARSHAL_U16LE(ctx, out->stat.file_extension.len); - UNMARSHAL_BYTES(ctx, out->stat.file_extension.utf8, out->stat.file_extension.len); - UNMARSHAL_U32LE(ctx, out->stat.file_owner_n_uid); - UNMARSHAL_U32LE(ctx, out->stat.file_owner_n_gid); - UNMARSHAL_U32LE(ctx, out->stat.file_last_modified_n_uid); + UNMARSHAL_U16LE(ctx, out->stat.extension.len); + UNMARSHAL_BYTES(ctx, out->stat.extension.utf8, out->stat.extension.len); + UNMARSHAL_U32LE(ctx, out->stat.owner_unum); + UNMARSHAL_U32LE(ctx, out->stat.owner_gnum); + UNMARSHAL_U32LE(ctx, out->stat.last_modifier_unum); } #endif /* CONFIG_9P_ENABLE_9P2000_u */ } @@ -2353,7 +2400,7 @@ static void unmarshal_Rlerror([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *ne net_offset += 4; net_offset += 1; UNMARSHAL_U16LE(ctx, out->tag); - UNMARSHAL_U32LE(ctx, out->ecode); + UNMARSHAL_U32LE(ctx, out->errnum); } static void unmarshal_Tstatfs([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) { @@ -2965,53 +3012,53 @@ static void unmarshal_Rswrite([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *ne #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u static bool marshal_stat(struct lib9p_ctx *ctx, struct lib9p_stat *val, struct _marshal_ret *ret) { - uint32_t needed_size = 49 + val->file_name.len + val->file_owner_uid.len + val->file_owner_gid.len + val->file_last_modified_uid.len; + uint32_t needed_size = 49 + val->name.len + val->owner_uname.len + val->owner_gname.len + val->last_modifier_uname.len; #if CONFIG_9P_ENABLE_9P2000_u if is_ver(ctx, 9P2000_u) { - needed_size += 14 + val->file_extension.len; + needed_size += 14 + val->extension.len; } #endif /* CONFIG_9P_ENABLE_9P2000_u */ if (needed_size > ctx->max_msg_size) { return true; } uint32_t offsetof_end = needed_size; - uint32_t offsetof_kern_type = 2; - MARSHAL_U16LE(ctx, offsetof_end - offsetof_kern_type); - MARSHAL_U16LE(ctx, val->kern_type); - MARSHAL_U32LE(ctx, val->kern_dev); - MARSHAL_U8LE(ctx, val->file_qid.type & qt_masks[ctx->version]); - MARSHAL_U32LE(ctx, val->file_qid.vers); - MARSHAL_U64LE(ctx, val->file_qid.path); - MARSHAL_U32LE(ctx, val->file_mode & dm_masks[ctx->version]); - MARSHAL_U32LE(ctx, val->file_atime); - MARSHAL_U32LE(ctx, val->file_mtime); - MARSHAL_U64LE(ctx, val->file_size); - MARSHAL_U16LE(ctx, val->file_name.len); - MARSHAL_BYTES(ctx, val->file_name.utf8, val->file_name.len); - MARSHAL_U16LE(ctx, val->file_owner_uid.len); - MARSHAL_BYTES(ctx, val->file_owner_uid.utf8, val->file_owner_uid.len); - MARSHAL_U16LE(ctx, val->file_owner_gid.len); - MARSHAL_BYTES(ctx, val->file_owner_gid.utf8, val->file_owner_gid.len); - MARSHAL_U16LE(ctx, val->file_last_modified_uid.len); - MARSHAL_BYTES(ctx, val->file_last_modified_uid.utf8, val->file_last_modified_uid.len); + uint32_t offsetof_fstype = 2; + MARSHAL_U16LE(ctx, offsetof_end - offsetof_fstype); + MARSHAL_U16LE(ctx, val->fstype); + MARSHAL_U32LE(ctx, val->fsdev); + MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->version]); + MARSHAL_U32LE(ctx, val->qid.vers); + MARSHAL_U64LE(ctx, val->qid.path); + MARSHAL_U32LE(ctx, val->mode & dm_masks[ctx->version]); + MARSHAL_U32LE(ctx, val->atime); + MARSHAL_U32LE(ctx, val->mtime); + MARSHAL_U64LE(ctx, val->length); + MARSHAL_U16LE(ctx, val->name.len); + MARSHAL_BYTES(ctx, val->name.utf8, val->name.len); + MARSHAL_U16LE(ctx, val->owner_uname.len); + MARSHAL_BYTES(ctx, val->owner_uname.utf8, val->owner_uname.len); + MARSHAL_U16LE(ctx, val->owner_gname.len); + MARSHAL_BYTES(ctx, val->owner_gname.utf8, val->owner_gname.len); + MARSHAL_U16LE(ctx, val->last_modifier_uname.len); + MARSHAL_BYTES(ctx, val->last_modifier_uname.utf8, val->last_modifier_uname.len); #if CONFIG_9P_ENABLE_9P2000_u if (is_ver(ctx, 9P2000_u)) { - MARSHAL_U16LE(ctx, val->file_extension.len); - MARSHAL_BYTES(ctx, val->file_extension.utf8, val->file_extension.len); - MARSHAL_U32LE(ctx, val->file_owner_n_uid); - MARSHAL_U32LE(ctx, val->file_owner_n_gid); - MARSHAL_U32LE(ctx, val->file_last_modified_n_uid); + MARSHAL_U16LE(ctx, val->extension.len); + MARSHAL_BYTES(ctx, val->extension.utf8, val->extension.len); + MARSHAL_U32LE(ctx, val->owner_unum); + MARSHAL_U32LE(ctx, val->owner_gnum); + MARSHAL_U32LE(ctx, val->last_modifier_unum); } #endif /* CONFIG_9P_ENABLE_9P2000_u */ return false; } #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown static bool marshal_Tversion(struct lib9p_ctx *ctx, struct lib9p_msg_Tversion *val, struct _marshal_ret *ret) { uint32_t needed_size = 13 + val->version.len; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tversion", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -3031,7 +3078,7 @@ static bool marshal_Tversion(struct lib9p_ctx *ctx, struct lib9p_msg_Tversion *v static bool marshal_Rversion(struct lib9p_ctx *ctx, struct lib9p_msg_Rversion *val, struct _marshal_ret *ret) { uint32_t needed_size = 13 + val->version.len; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rversion", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -3048,6 +3095,8 @@ static bool marshal_Rversion(struct lib9p_ctx *ctx, struct lib9p_msg_Rversion *v return false; } +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u static bool marshal_Tauth(struct lib9p_ctx *ctx, struct lib9p_msg_Tauth *val, struct _marshal_ret *ret) { uint32_t needed_size = 15 + val->uname.len + val->aname.len; #if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u @@ -3056,7 +3105,7 @@ static bool marshal_Tauth(struct lib9p_ctx *ctx, struct lib9p_msg_Tauth *val, st } #endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tauth", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -3074,7 +3123,7 @@ static bool marshal_Tauth(struct lib9p_ctx *ctx, struct lib9p_msg_Tauth *val, st MARSHAL_BYTES_ZEROCOPY(ctx, val->aname.utf8, val->aname.len); #if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u if (( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) )) { - MARSHAL_U32LE(ctx, val->n_uid); + MARSHAL_U32LE(ctx, val->unum); } #endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ return false; @@ -3083,7 +3132,7 @@ static bool marshal_Tauth(struct lib9p_ctx *ctx, struct lib9p_msg_Tauth *val, st static bool marshal_Rauth(struct lib9p_ctx *ctx, struct lib9p_msg_Rauth *val, struct _marshal_ret *ret) { uint32_t needed_size = 20; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rauth", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -3108,7 +3157,7 @@ static bool marshal_Tattach(struct lib9p_ctx *ctx, struct lib9p_msg_Tattach *val } #endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tattach", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -3127,7 +3176,7 @@ static bool marshal_Tattach(struct lib9p_ctx *ctx, struct lib9p_msg_Tattach *val MARSHAL_BYTES_ZEROCOPY(ctx, val->aname.utf8, val->aname.len); #if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u if (( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) )) { - MARSHAL_U32LE(ctx, val->n_uid); + MARSHAL_U32LE(ctx, val->unum); } #endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ return false; @@ -3136,7 +3185,7 @@ static bool marshal_Tattach(struct lib9p_ctx *ctx, struct lib9p_msg_Tattach *val static bool marshal_Rattach(struct lib9p_ctx *ctx, struct lib9p_msg_Rattach *val, struct _marshal_ret *ret) { uint32_t needed_size = 20; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rattach", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -3153,15 +3202,17 @@ static bool marshal_Rattach(struct lib9p_ctx *ctx, struct lib9p_msg_Rattach *val return false; } +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown static bool marshal_Rerror(struct lib9p_ctx *ctx, struct lib9p_msg_Rerror *val, struct _marshal_ret *ret) { - uint32_t needed_size = 9 + val->ename.len; + uint32_t needed_size = 9 + val->errstr.len; #if CONFIG_9P_ENABLE_9P2000_u if is_ver(ctx, 9P2000_u) { needed_size += 4; } #endif /* CONFIG_9P_ENABLE_9P2000_u */ if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rerror", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -3172,20 +3223,22 @@ static bool marshal_Rerror(struct lib9p_ctx *ctx, struct lib9p_msg_Rerror *val, MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); MARSHAL_U8LE(ctx, 107); MARSHAL_U16LE(ctx, val->tag); - MARSHAL_U16LE(ctx, val->ename.len); - MARSHAL_BYTES_ZEROCOPY(ctx, val->ename.utf8, val->ename.len); + MARSHAL_U16LE(ctx, val->errstr.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->errstr.utf8, val->errstr.len); #if CONFIG_9P_ENABLE_9P2000_u if (is_ver(ctx, 9P2000_u)) { - MARSHAL_U32LE(ctx, val->errno); + MARSHAL_U32LE(ctx, val->errnum); } #endif /* CONFIG_9P_ENABLE_9P2000_u */ return false; } +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u static bool marshal_Tflush(struct lib9p_ctx *ctx, struct lib9p_msg_Tflush *val, struct _marshal_ret *ret) { uint32_t needed_size = 9; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tflush", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -3203,7 +3256,7 @@ static bool marshal_Tflush(struct lib9p_ctx *ctx, struct lib9p_msg_Tflush *val, static bool marshal_Rflush(struct lib9p_ctx *ctx, struct lib9p_msg_Rflush *val, struct _marshal_ret *ret) { uint32_t needed_size = 7; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rflush", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -3223,7 +3276,7 @@ static bool marshal_Twalk(struct lib9p_ctx *ctx, struct lib9p_msg_Twalk *val, st needed_size += 2 + val->wname[i].len; } if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Twalk", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -3247,7 +3300,7 @@ static bool marshal_Twalk(struct lib9p_ctx *ctx, struct lib9p_msg_Twalk *val, st static bool marshal_Rwalk(struct lib9p_ctx *ctx, struct lib9p_msg_Rwalk *val, struct _marshal_ret *ret) { uint32_t needed_size = 9 + (val->nwqid)*13; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rwalk", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -3272,7 +3325,7 @@ static bool marshal_Rwalk(struct lib9p_ctx *ctx, struct lib9p_msg_Rwalk *val, st static bool marshal_Topen(struct lib9p_ctx *ctx, struct lib9p_msg_Topen *val, struct _marshal_ret *ret) { uint32_t needed_size = 12; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Topen", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -3291,7 +3344,7 @@ static bool marshal_Topen(struct lib9p_ctx *ctx, struct lib9p_msg_Topen *val, st static bool marshal_Ropen(struct lib9p_ctx *ctx, struct lib9p_msg_Ropen *val, struct _marshal_ret *ret) { uint32_t needed_size = 24; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Ropen", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -3312,7 +3365,7 @@ static bool marshal_Ropen(struct lib9p_ctx *ctx, struct lib9p_msg_Ropen *val, st static bool marshal_Tcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Tcreate *val, struct _marshal_ret *ret) { uint32_t needed_size = 18 + val->name.len; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tcreate", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -3334,7 +3387,7 @@ static bool marshal_Tcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Tcreate *val static bool marshal_Rcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Rcreate *val, struct _marshal_ret *ret) { uint32_t needed_size = 24; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rcreate", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -3357,7 +3410,7 @@ static bool marshal_Rcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Rcreate *val static bool marshal_Tread(struct lib9p_ctx *ctx, struct lib9p_msg_Tread *val, struct _marshal_ret *ret) { uint32_t needed_size = 23; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tread", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -3377,7 +3430,7 @@ static bool marshal_Tread(struct lib9p_ctx *ctx, struct lib9p_msg_Tread *val, st static bool marshal_Rread(struct lib9p_ctx *ctx, struct lib9p_msg_Rread *val, struct _marshal_ret *ret) { uint32_t needed_size = 11 + val->count; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rread", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -3396,7 +3449,7 @@ static bool marshal_Rread(struct lib9p_ctx *ctx, struct lib9p_msg_Rread *val, st static bool marshal_Twrite(struct lib9p_ctx *ctx, struct lib9p_msg_Twrite *val, struct _marshal_ret *ret) { uint32_t needed_size = 23 + val->count; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Twrite", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -3417,7 +3470,7 @@ static bool marshal_Twrite(struct lib9p_ctx *ctx, struct lib9p_msg_Twrite *val, static bool marshal_Rwrite(struct lib9p_ctx *ctx, struct lib9p_msg_Rwrite *val, struct _marshal_ret *ret) { uint32_t needed_size = 11; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rwrite", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -3435,7 +3488,7 @@ static bool marshal_Rwrite(struct lib9p_ctx *ctx, struct lib9p_msg_Rwrite *val, static bool marshal_Tclunk(struct lib9p_ctx *ctx, struct lib9p_msg_Tclunk *val, struct _marshal_ret *ret) { uint32_t needed_size = 11; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tclunk", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -3453,7 +3506,7 @@ static bool marshal_Tclunk(struct lib9p_ctx *ctx, struct lib9p_msg_Tclunk *val, static bool marshal_Rclunk(struct lib9p_ctx *ctx, struct lib9p_msg_Rclunk *val, struct _marshal_ret *ret) { uint32_t needed_size = 7; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rclunk", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -3470,7 +3523,7 @@ static bool marshal_Rclunk(struct lib9p_ctx *ctx, struct lib9p_msg_Rclunk *val, static bool marshal_Tremove(struct lib9p_ctx *ctx, struct lib9p_msg_Tremove *val, struct _marshal_ret *ret) { uint32_t needed_size = 11; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tremove", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -3488,7 +3541,7 @@ static bool marshal_Tremove(struct lib9p_ctx *ctx, struct lib9p_msg_Tremove *val static bool marshal_Rremove(struct lib9p_ctx *ctx, struct lib9p_msg_Rremove *val, struct _marshal_ret *ret) { uint32_t needed_size = 7; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rremove", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -3507,7 +3560,7 @@ static bool marshal_Rremove(struct lib9p_ctx *ctx, struct lib9p_msg_Rremove *val static bool marshal_Tstat(struct lib9p_ctx *ctx, struct lib9p_msg_Tstat *val, struct _marshal_ret *ret) { uint32_t needed_size = 11; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tstat", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -3523,14 +3576,14 @@ static bool marshal_Tstat(struct lib9p_ctx *ctx, struct lib9p_msg_Tstat *val, st } static bool marshal_Rstat(struct lib9p_ctx *ctx, struct lib9p_msg_Rstat *val, struct _marshal_ret *ret) { - uint32_t needed_size = 58 + val->stat.file_name.len + val->stat.file_owner_uid.len + val->stat.file_owner_gid.len + val->stat.file_last_modified_uid.len; + uint32_t needed_size = 58 + val->stat.name.len + val->stat.owner_uname.len + val->stat.owner_gname.len + val->stat.last_modifier_uname.len; #if CONFIG_9P_ENABLE_9P2000_u if is_ver(ctx, 9P2000_u) { - needed_size += 14 + val->stat.file_extension.len; + needed_size += 14 + val->stat.extension.len; } #endif /* CONFIG_9P_ENABLE_9P2000_u */ if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rstat", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -3543,52 +3596,52 @@ static bool marshal_Rstat(struct lib9p_ctx *ctx, struct lib9p_msg_Rstat *val, st MARSHAL_U8LE(ctx, 125); MARSHAL_U16LE(ctx, val->tag); MARSHAL_U16LE(ctx, offsetof_end - offsetof_stat); - uint32_t offsetof_stat_end = 49 + val->stat.file_name.len + val->stat.file_owner_uid.len + val->stat.file_owner_gid.len + val->stat.file_last_modified_uid.len; + uint32_t offsetof_stat_end = 49 + val->stat.name.len + val->stat.owner_uname.len + val->stat.owner_gname.len + val->stat.last_modifier_uname.len; #if CONFIG_9P_ENABLE_9P2000_u if is_ver(ctx, 9P2000_u) { - offsetof_stat_end += 14 + val->stat.file_extension.len; + offsetof_stat_end += 14 + val->stat.extension.len; } #endif /* CONFIG_9P_ENABLE_9P2000_u */ - uint32_t offsetof_stat_kern_type = 2; - MARSHAL_U16LE(ctx, offsetof_stat_end - offsetof_stat_kern_type); - MARSHAL_U16LE(ctx, val->stat.kern_type); - MARSHAL_U32LE(ctx, val->stat.kern_dev); - MARSHAL_U8LE(ctx, val->stat.file_qid.type & qt_masks[ctx->version]); - MARSHAL_U32LE(ctx, val->stat.file_qid.vers); - MARSHAL_U64LE(ctx, val->stat.file_qid.path); - MARSHAL_U32LE(ctx, val->stat.file_mode & dm_masks[ctx->version]); - MARSHAL_U32LE(ctx, val->stat.file_atime); - MARSHAL_U32LE(ctx, val->stat.file_mtime); - MARSHAL_U64LE(ctx, val->stat.file_size); - MARSHAL_U16LE(ctx, val->stat.file_name.len); - MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_name.utf8, val->stat.file_name.len); - MARSHAL_U16LE(ctx, val->stat.file_owner_uid.len); - MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_owner_uid.utf8, val->stat.file_owner_uid.len); - MARSHAL_U16LE(ctx, val->stat.file_owner_gid.len); - MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_owner_gid.utf8, val->stat.file_owner_gid.len); - MARSHAL_U16LE(ctx, val->stat.file_last_modified_uid.len); - MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_last_modified_uid.utf8, val->stat.file_last_modified_uid.len); + uint32_t offsetof_stat_fstype = 2; + MARSHAL_U16LE(ctx, offsetof_stat_end - offsetof_stat_fstype); + MARSHAL_U16LE(ctx, val->stat.fstype); + MARSHAL_U32LE(ctx, val->stat.fsdev); + MARSHAL_U8LE(ctx, val->stat.qid.type & qt_masks[ctx->version]); + MARSHAL_U32LE(ctx, val->stat.qid.vers); + MARSHAL_U64LE(ctx, val->stat.qid.path); + MARSHAL_U32LE(ctx, val->stat.mode & dm_masks[ctx->version]); + MARSHAL_U32LE(ctx, val->stat.atime); + MARSHAL_U32LE(ctx, val->stat.mtime); + MARSHAL_U64LE(ctx, val->stat.length); + MARSHAL_U16LE(ctx, val->stat.name.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.name.utf8, val->stat.name.len); + MARSHAL_U16LE(ctx, val->stat.owner_uname.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.owner_uname.utf8, val->stat.owner_uname.len); + MARSHAL_U16LE(ctx, val->stat.owner_gname.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.owner_gname.utf8, val->stat.owner_gname.len); + MARSHAL_U16LE(ctx, val->stat.last_modifier_uname.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.last_modifier_uname.utf8, val->stat.last_modifier_uname.len); #if CONFIG_9P_ENABLE_9P2000_u if (is_ver(ctx, 9P2000_u)) { - MARSHAL_U16LE(ctx, val->stat.file_extension.len); - MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_extension.utf8, val->stat.file_extension.len); - MARSHAL_U32LE(ctx, val->stat.file_owner_n_uid); - MARSHAL_U32LE(ctx, val->stat.file_owner_n_gid); - MARSHAL_U32LE(ctx, val->stat.file_last_modified_n_uid); + MARSHAL_U16LE(ctx, val->stat.extension.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.extension.utf8, val->stat.extension.len); + MARSHAL_U32LE(ctx, val->stat.owner_unum); + MARSHAL_U32LE(ctx, val->stat.owner_gnum); + MARSHAL_U32LE(ctx, val->stat.last_modifier_unum); } #endif /* CONFIG_9P_ENABLE_9P2000_u */ return false; } static bool marshal_Twstat(struct lib9p_ctx *ctx, struct lib9p_msg_Twstat *val, struct _marshal_ret *ret) { - uint32_t needed_size = 62 + val->stat.file_name.len + val->stat.file_owner_uid.len + val->stat.file_owner_gid.len + val->stat.file_last_modified_uid.len; + uint32_t needed_size = 62 + val->stat.name.len + val->stat.owner_uname.len + val->stat.owner_gname.len + val->stat.last_modifier_uname.len; #if CONFIG_9P_ENABLE_9P2000_u if is_ver(ctx, 9P2000_u) { - needed_size += 14 + val->stat.file_extension.len; + needed_size += 14 + val->stat.extension.len; } #endif /* CONFIG_9P_ENABLE_9P2000_u */ if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Twstat", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -3602,38 +3655,38 @@ static bool marshal_Twstat(struct lib9p_ctx *ctx, struct lib9p_msg_Twstat *val, MARSHAL_U16LE(ctx, val->tag); MARSHAL_U32LE(ctx, val->fid); MARSHAL_U16LE(ctx, offsetof_end - offsetof_stat); - uint32_t offsetof_stat_end = 49 + val->stat.file_name.len + val->stat.file_owner_uid.len + val->stat.file_owner_gid.len + val->stat.file_last_modified_uid.len; + uint32_t offsetof_stat_end = 49 + val->stat.name.len + val->stat.owner_uname.len + val->stat.owner_gname.len + val->stat.last_modifier_uname.len; #if CONFIG_9P_ENABLE_9P2000_u if is_ver(ctx, 9P2000_u) { - offsetof_stat_end += 14 + val->stat.file_extension.len; + offsetof_stat_end += 14 + val->stat.extension.len; } #endif /* CONFIG_9P_ENABLE_9P2000_u */ - uint32_t offsetof_stat_kern_type = 2; - MARSHAL_U16LE(ctx, offsetof_stat_end - offsetof_stat_kern_type); - MARSHAL_U16LE(ctx, val->stat.kern_type); - MARSHAL_U32LE(ctx, val->stat.kern_dev); - MARSHAL_U8LE(ctx, val->stat.file_qid.type & qt_masks[ctx->version]); - MARSHAL_U32LE(ctx, val->stat.file_qid.vers); - MARSHAL_U64LE(ctx, val->stat.file_qid.path); - MARSHAL_U32LE(ctx, val->stat.file_mode & dm_masks[ctx->version]); - MARSHAL_U32LE(ctx, val->stat.file_atime); - MARSHAL_U32LE(ctx, val->stat.file_mtime); - MARSHAL_U64LE(ctx, val->stat.file_size); - MARSHAL_U16LE(ctx, val->stat.file_name.len); - MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_name.utf8, val->stat.file_name.len); - MARSHAL_U16LE(ctx, val->stat.file_owner_uid.len); - MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_owner_uid.utf8, val->stat.file_owner_uid.len); - MARSHAL_U16LE(ctx, val->stat.file_owner_gid.len); - MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_owner_gid.utf8, val->stat.file_owner_gid.len); - MARSHAL_U16LE(ctx, val->stat.file_last_modified_uid.len); - MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_last_modified_uid.utf8, val->stat.file_last_modified_uid.len); + uint32_t offsetof_stat_fstype = 2; + MARSHAL_U16LE(ctx, offsetof_stat_end - offsetof_stat_fstype); + MARSHAL_U16LE(ctx, val->stat.fstype); + MARSHAL_U32LE(ctx, val->stat.fsdev); + MARSHAL_U8LE(ctx, val->stat.qid.type & qt_masks[ctx->version]); + MARSHAL_U32LE(ctx, val->stat.qid.vers); + MARSHAL_U64LE(ctx, val->stat.qid.path); + MARSHAL_U32LE(ctx, val->stat.mode & dm_masks[ctx->version]); + MARSHAL_U32LE(ctx, val->stat.atime); + MARSHAL_U32LE(ctx, val->stat.mtime); + MARSHAL_U64LE(ctx, val->stat.length); + MARSHAL_U16LE(ctx, val->stat.name.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.name.utf8, val->stat.name.len); + MARSHAL_U16LE(ctx, val->stat.owner_uname.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.owner_uname.utf8, val->stat.owner_uname.len); + MARSHAL_U16LE(ctx, val->stat.owner_gname.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.owner_gname.utf8, val->stat.owner_gname.len); + MARSHAL_U16LE(ctx, val->stat.last_modifier_uname.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.last_modifier_uname.utf8, val->stat.last_modifier_uname.len); #if CONFIG_9P_ENABLE_9P2000_u if (is_ver(ctx, 9P2000_u)) { - MARSHAL_U16LE(ctx, val->stat.file_extension.len); - MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_extension.utf8, val->stat.file_extension.len); - MARSHAL_U32LE(ctx, val->stat.file_owner_n_uid); - MARSHAL_U32LE(ctx, val->stat.file_owner_n_gid); - MARSHAL_U32LE(ctx, val->stat.file_last_modified_n_uid); + MARSHAL_U16LE(ctx, val->stat.extension.len); + MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.extension.utf8, val->stat.extension.len); + MARSHAL_U32LE(ctx, val->stat.owner_unum); + MARSHAL_U32LE(ctx, val->stat.owner_gnum); + MARSHAL_U32LE(ctx, val->stat.last_modifier_unum); } #endif /* CONFIG_9P_ENABLE_9P2000_u */ return false; @@ -3642,7 +3695,7 @@ static bool marshal_Twstat(struct lib9p_ctx *ctx, struct lib9p_msg_Twstat *val, static bool marshal_Rwstat(struct lib9p_ctx *ctx, struct lib9p_msg_Rwstat *val, struct _marshal_ret *ret) { uint32_t needed_size = 7; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rwstat", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -3661,7 +3714,7 @@ static bool marshal_Rwstat(struct lib9p_ctx *ctx, struct lib9p_msg_Rwstat *val, static bool marshal_Topenfd(struct lib9p_ctx *ctx, struct lib9p_msg_Topenfd *val, struct _marshal_ret *ret) { uint32_t needed_size = 12; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Topenfd", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -3680,7 +3733,7 @@ static bool marshal_Topenfd(struct lib9p_ctx *ctx, struct lib9p_msg_Topenfd *val static bool marshal_Ropenfd(struct lib9p_ctx *ctx, struct lib9p_msg_Ropenfd *val, struct _marshal_ret *ret) { uint32_t needed_size = 28; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Ropenfd", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -3704,7 +3757,7 @@ static bool marshal_Ropenfd(struct lib9p_ctx *ctx, struct lib9p_msg_Ropenfd *val static bool marshal_Rlerror(struct lib9p_ctx *ctx, struct lib9p_msg_Rlerror *val, struct _marshal_ret *ret) { uint32_t needed_size = 11; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rlerror", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -3715,14 +3768,14 @@ static bool marshal_Rlerror(struct lib9p_ctx *ctx, struct lib9p_msg_Rlerror *val MARSHAL_U32LE(ctx, offsetof_end - offsetof_size); MARSHAL_U8LE(ctx, 7); MARSHAL_U16LE(ctx, val->tag); - MARSHAL_U32LE(ctx, val->ecode); + MARSHAL_U32LE(ctx, val->errnum); return false; } static bool marshal_Tstatfs(struct lib9p_ctx *ctx, struct lib9p_msg_Tstatfs *val, struct _marshal_ret *ret) { uint32_t needed_size = 11; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tstatfs", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -3740,7 +3793,7 @@ static bool marshal_Tstatfs(struct lib9p_ctx *ctx, struct lib9p_msg_Tstatfs *val static bool marshal_Rstatfs(struct lib9p_ctx *ctx, struct lib9p_msg_Rstatfs *val, struct _marshal_ret *ret) { uint32_t needed_size = 67; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rstatfs", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -3766,7 +3819,7 @@ static bool marshal_Rstatfs(struct lib9p_ctx *ctx, struct lib9p_msg_Rstatfs *val static bool marshal_Tlopen(struct lib9p_ctx *ctx, struct lib9p_msg_Tlopen *val, struct _marshal_ret *ret) { uint32_t needed_size = 15; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tlopen", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -3785,7 +3838,7 @@ static bool marshal_Tlopen(struct lib9p_ctx *ctx, struct lib9p_msg_Tlopen *val, static bool marshal_Rlopen(struct lib9p_ctx *ctx, struct lib9p_msg_Rlopen *val, struct _marshal_ret *ret) { uint32_t needed_size = 24; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rlopen", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -3806,7 +3859,7 @@ static bool marshal_Rlopen(struct lib9p_ctx *ctx, struct lib9p_msg_Rlopen *val, static bool marshal_Tlcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Tlcreate *val, struct _marshal_ret *ret) { uint32_t needed_size = 25 + val->name.len; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tlcreate", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -3829,7 +3882,7 @@ static bool marshal_Tlcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Tlcreate *v static bool marshal_Rlcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Rlcreate *val, struct _marshal_ret *ret) { uint32_t needed_size = 24; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rlcreate", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -3850,7 +3903,7 @@ static bool marshal_Rlcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Rlcreate *v static bool marshal_Tsymlink(struct lib9p_ctx *ctx, struct lib9p_msg_Tsymlink *val, struct _marshal_ret *ret) { uint32_t needed_size = 19 + val->name.len + val->symtgt.len; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tsymlink", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -3873,7 +3926,7 @@ static bool marshal_Tsymlink(struct lib9p_ctx *ctx, struct lib9p_msg_Tsymlink *v static bool marshal_Rsymlink(struct lib9p_ctx *ctx, struct lib9p_msg_Rsymlink *val, struct _marshal_ret *ret) { uint32_t needed_size = 20; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rsymlink", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -3893,7 +3946,7 @@ static bool marshal_Rsymlink(struct lib9p_ctx *ctx, struct lib9p_msg_Rsymlink *v static bool marshal_Tmknod(struct lib9p_ctx *ctx, struct lib9p_msg_Tmknod *val, struct _marshal_ret *ret) { uint32_t needed_size = 29 + val->name.len; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tmknod", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -3917,7 +3970,7 @@ static bool marshal_Tmknod(struct lib9p_ctx *ctx, struct lib9p_msg_Tmknod *val, static bool marshal_Rmknod(struct lib9p_ctx *ctx, struct lib9p_msg_Rmknod *val, struct _marshal_ret *ret) { uint32_t needed_size = 20; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rmknod", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -3937,7 +3990,7 @@ static bool marshal_Rmknod(struct lib9p_ctx *ctx, struct lib9p_msg_Rmknod *val, static bool marshal_Trename(struct lib9p_ctx *ctx, struct lib9p_msg_Trename *val, struct _marshal_ret *ret) { uint32_t needed_size = 17 + val->name.len; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Trename", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -3958,7 +4011,7 @@ static bool marshal_Trename(struct lib9p_ctx *ctx, struct lib9p_msg_Trename *val static bool marshal_Rrename(struct lib9p_ctx *ctx, struct lib9p_msg_Rrename *val, struct _marshal_ret *ret) { uint32_t needed_size = 7; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rrename", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -3975,7 +4028,7 @@ static bool marshal_Rrename(struct lib9p_ctx *ctx, struct lib9p_msg_Rrename *val static bool marshal_Treadlink(struct lib9p_ctx *ctx, struct lib9p_msg_Treadlink *val, struct _marshal_ret *ret) { uint32_t needed_size = 11; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Treadlink", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -3993,7 +4046,7 @@ static bool marshal_Treadlink(struct lib9p_ctx *ctx, struct lib9p_msg_Treadlink static bool marshal_Rreadlink(struct lib9p_ctx *ctx, struct lib9p_msg_Rreadlink *val, struct _marshal_ret *ret) { uint32_t needed_size = 9 + val->target.len; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rreadlink", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -4012,7 +4065,7 @@ static bool marshal_Rreadlink(struct lib9p_ctx *ctx, struct lib9p_msg_Rreadlink static bool marshal_Tgetattr(struct lib9p_ctx *ctx, struct lib9p_msg_Tgetattr *val, struct _marshal_ret *ret) { uint32_t needed_size = 19; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tgetattr", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -4031,7 +4084,7 @@ static bool marshal_Tgetattr(struct lib9p_ctx *ctx, struct lib9p_msg_Tgetattr *v static bool marshal_Rgetattr(struct lib9p_ctx *ctx, struct lib9p_msg_Rgetattr *val, struct _marshal_ret *ret) { uint32_t needed_size = 160; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rgetattr", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -4070,7 +4123,7 @@ static bool marshal_Rgetattr(struct lib9p_ctx *ctx, struct lib9p_msg_Rgetattr *v static bool marshal_Tsetattr(struct lib9p_ctx *ctx, struct lib9p_msg_Tsetattr *val, struct _marshal_ret *ret) { uint32_t needed_size = 67; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tsetattr", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -4097,7 +4150,7 @@ static bool marshal_Tsetattr(struct lib9p_ctx *ctx, struct lib9p_msg_Tsetattr *v static bool marshal_Rsetattr(struct lib9p_ctx *ctx, struct lib9p_msg_Rsetattr *val, struct _marshal_ret *ret) { uint32_t needed_size = 7; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rsetattr", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -4114,7 +4167,7 @@ static bool marshal_Rsetattr(struct lib9p_ctx *ctx, struct lib9p_msg_Rsetattr *v static bool marshal_Txattrwalk(struct lib9p_ctx *ctx, struct lib9p_msg_Txattrwalk *val, struct _marshal_ret *ret) { uint32_t needed_size = 17 + val->name.len; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Txattrwalk", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -4135,7 +4188,7 @@ static bool marshal_Txattrwalk(struct lib9p_ctx *ctx, struct lib9p_msg_Txattrwal static bool marshal_Rxattrwalk(struct lib9p_ctx *ctx, struct lib9p_msg_Rxattrwalk *val, struct _marshal_ret *ret) { uint32_t needed_size = 15; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rxattrwalk", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -4153,7 +4206,7 @@ static bool marshal_Rxattrwalk(struct lib9p_ctx *ctx, struct lib9p_msg_Rxattrwal static bool marshal_Txattrcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Txattrcreate *val, struct _marshal_ret *ret) { uint32_t needed_size = 25 + val->name.len; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Txattrcreate", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -4175,7 +4228,7 @@ static bool marshal_Txattrcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Txattrc static bool marshal_Rxattrcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Rxattrcreate *val, struct _marshal_ret *ret) { uint32_t needed_size = 7; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rxattrcreate", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -4192,7 +4245,7 @@ static bool marshal_Rxattrcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Rxattrc static bool marshal_Treaddir(struct lib9p_ctx *ctx, struct lib9p_msg_Treaddir *val, struct _marshal_ret *ret) { uint32_t needed_size = 23; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Treaddir", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -4212,7 +4265,7 @@ static bool marshal_Treaddir(struct lib9p_ctx *ctx, struct lib9p_msg_Treaddir *v static bool marshal_Rreaddir(struct lib9p_ctx *ctx, struct lib9p_msg_Rreaddir *val, struct _marshal_ret *ret) { uint64_t needed_size = 11 + val->count; if (needed_size > (uint64_t)(ctx->max_msg_size)) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rreaddir", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -4231,7 +4284,7 @@ static bool marshal_Rreaddir(struct lib9p_ctx *ctx, struct lib9p_msg_Rreaddir *v static bool marshal_Tfsync(struct lib9p_ctx *ctx, struct lib9p_msg_Tfsync *val, struct _marshal_ret *ret) { uint32_t needed_size = 15; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tfsync", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -4250,7 +4303,7 @@ static bool marshal_Tfsync(struct lib9p_ctx *ctx, struct lib9p_msg_Tfsync *val, static bool marshal_Rfsync(struct lib9p_ctx *ctx, struct lib9p_msg_Rfsync *val, struct _marshal_ret *ret) { uint32_t needed_size = 7; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rfsync", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -4267,7 +4320,7 @@ static bool marshal_Rfsync(struct lib9p_ctx *ctx, struct lib9p_msg_Rfsync *val, static bool marshal_Tlock(struct lib9p_ctx *ctx, struct lib9p_msg_Tlock *val, struct _marshal_ret *ret) { uint32_t needed_size = 38 + val->client_id.len; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tlock", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -4292,7 +4345,7 @@ static bool marshal_Tlock(struct lib9p_ctx *ctx, struct lib9p_msg_Tlock *val, st static bool marshal_Rlock(struct lib9p_ctx *ctx, struct lib9p_msg_Rlock *val, struct _marshal_ret *ret) { uint32_t needed_size = 8; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rlock", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -4310,7 +4363,7 @@ static bool marshal_Rlock(struct lib9p_ctx *ctx, struct lib9p_msg_Rlock *val, st static bool marshal_Tgetlock(struct lib9p_ctx *ctx, struct lib9p_msg_Tgetlock *val, struct _marshal_ret *ret) { uint32_t needed_size = 34 + val->client_id.len; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tgetlock", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -4334,7 +4387,7 @@ static bool marshal_Tgetlock(struct lib9p_ctx *ctx, struct lib9p_msg_Tgetlock *v static bool marshal_Rgetlock(struct lib9p_ctx *ctx, struct lib9p_msg_Rgetlock *val, struct _marshal_ret *ret) { uint32_t needed_size = 30 + val->client_id.len; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rgetlock", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -4357,7 +4410,7 @@ static bool marshal_Rgetlock(struct lib9p_ctx *ctx, struct lib9p_msg_Rgetlock *v static bool marshal_Tlink(struct lib9p_ctx *ctx, struct lib9p_msg_Tlink *val, struct _marshal_ret *ret) { uint32_t needed_size = 17 + val->name.len; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tlink", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -4378,7 +4431,7 @@ static bool marshal_Tlink(struct lib9p_ctx *ctx, struct lib9p_msg_Tlink *val, st static bool marshal_Rlink(struct lib9p_ctx *ctx, struct lib9p_msg_Rlink *val, struct _marshal_ret *ret) { uint32_t needed_size = 7; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rlink", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -4395,7 +4448,7 @@ static bool marshal_Rlink(struct lib9p_ctx *ctx, struct lib9p_msg_Rlink *val, st static bool marshal_Tmkdir(struct lib9p_ctx *ctx, struct lib9p_msg_Tmkdir *val, struct _marshal_ret *ret) { uint32_t needed_size = 21 + val->name.len; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tmkdir", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -4417,7 +4470,7 @@ static bool marshal_Tmkdir(struct lib9p_ctx *ctx, struct lib9p_msg_Tmkdir *val, static bool marshal_Rmkdir(struct lib9p_ctx *ctx, struct lib9p_msg_Rmkdir *val, struct _marshal_ret *ret) { uint32_t needed_size = 20; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rmkdir", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -4437,7 +4490,7 @@ static bool marshal_Rmkdir(struct lib9p_ctx *ctx, struct lib9p_msg_Rmkdir *val, static bool marshal_Trenameat(struct lib9p_ctx *ctx, struct lib9p_msg_Trenameat *val, struct _marshal_ret *ret) { uint32_t needed_size = 19 + val->oldname.len + val->newname.len; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Trenameat", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -4460,7 +4513,7 @@ static bool marshal_Trenameat(struct lib9p_ctx *ctx, struct lib9p_msg_Trenameat static bool marshal_Rrenameat(struct lib9p_ctx *ctx, struct lib9p_msg_Rrenameat *val, struct _marshal_ret *ret) { uint32_t needed_size = 7; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rrenameat", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -4477,7 +4530,7 @@ static bool marshal_Rrenameat(struct lib9p_ctx *ctx, struct lib9p_msg_Rrenameat static bool marshal_Tunlinkat(struct lib9p_ctx *ctx, struct lib9p_msg_Tunlinkat *val, struct _marshal_ret *ret) { uint32_t needed_size = 17 + val->name.len; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tunlinkat", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -4498,7 +4551,7 @@ static bool marshal_Tunlinkat(struct lib9p_ctx *ctx, struct lib9p_msg_Tunlinkat static bool marshal_Runlinkat(struct lib9p_ctx *ctx, struct lib9p_msg_Runlinkat *val, struct _marshal_ret *ret) { uint32_t needed_size = 7; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Runlinkat", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -4517,7 +4570,7 @@ static bool marshal_Runlinkat(struct lib9p_ctx *ctx, struct lib9p_msg_Runlinkat static bool marshal_Tsession(struct lib9p_ctx *ctx, struct lib9p_msg_Tsession *val, struct _marshal_ret *ret) { uint32_t needed_size = 15; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tsession", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -4535,7 +4588,7 @@ static bool marshal_Tsession(struct lib9p_ctx *ctx, struct lib9p_msg_Tsession *v static bool marshal_Rsession(struct lib9p_ctx *ctx, struct lib9p_msg_Rsession *val, struct _marshal_ret *ret) { uint32_t needed_size = 7; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rsession", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -4555,7 +4608,7 @@ static bool marshal_Tsread(struct lib9p_ctx *ctx, struct lib9p_msg_Tsread *val, needed_size += 2 + val->wname[i].len; } if (needed_size > (uint64_t)(ctx->max_msg_size)) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tsread", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -4578,7 +4631,7 @@ static bool marshal_Tsread(struct lib9p_ctx *ctx, struct lib9p_msg_Tsread *val, static bool marshal_Rsread(struct lib9p_ctx *ctx, struct lib9p_msg_Rsread *val, struct _marshal_ret *ret) { uint64_t needed_size = 11 + val->count; if (needed_size > (uint64_t)(ctx->max_msg_size)) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rsread", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -4600,7 +4653,7 @@ static bool marshal_Tswrite(struct lib9p_ctx *ctx, struct lib9p_msg_Tswrite *val needed_size += 2 + val->wname[i].len; } if (needed_size > (uint64_t)(ctx->max_msg_size)) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Tswrite", ctx->version ? "negotiated" : "client", ctx->max_msg_size); @@ -4625,7 +4678,7 @@ static bool marshal_Tswrite(struct lib9p_ctx *ctx, struct lib9p_msg_Tswrite *val static bool marshal_Rswrite(struct lib9p_ctx *ctx, struct lib9p_msg_Rswrite *val, struct _marshal_ret *ret) { uint32_t needed_size = 11; if (needed_size > ctx->max_msg_size) { - lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", + lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")", "Rswrite", ctx->version ? "negotiated" : "server", ctx->max_msg_size); @@ -4643,7 +4696,7 @@ static bool marshal_Rswrite(struct lib9p_ctx *ctx, struct lib9p_msg_Rswrite *val /* *_format *******************************************************************/ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown static void lib9p_tag_format(lib9p_tag_t *self, struct fmt_state *state) { switch (*self) { case LIB9P_TAG_NOTAG: @@ -4665,7 +4718,6 @@ static void lib9p_fid_format(lib9p_fid_t *self, struct fmt_state *state) { } static void lib9p_s_format(struct lib9p_s *self, struct fmt_state *state) { - /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47781 */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat" #pragma GCC diagnostic ignored "-Wformat-extra-args" @@ -4673,8 +4725,8 @@ static void lib9p_s_format(struct lib9p_s *self, struct fmt_state *state) { #pragma GCC diagnostic pop } -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown static void lib9p_dm_format(lib9p_dm_t *self, struct fmt_state *state) { bool empty = true; fmt_state_putchar(state, '('); @@ -4876,8 +4928,8 @@ static void lib9p_dm_format(lib9p_dm_t *self, struct fmt_state *state) { fmt_state_putchar(state, ')'); } -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown static void lib9p_qt_format(lib9p_qt_t *self, struct fmt_state *state) { bool empty = true; fmt_state_putchar(state, '('); @@ -4945,41 +4997,41 @@ static void lib9p_qid_format(struct lib9p_qid *self, struct fmt_state *state) { fmt_state_puts(state, " }"); } -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u static void lib9p_stat_format(struct lib9p_stat *self, struct fmt_state *state) { fmt_state_putchar(state, '{'); - fmt_state_puts(state, " kern_type="); - fmt_state_printf(state, "%"PRIu16, self->kern_type); - fmt_state_puts(state, " kern_dev="); - fmt_state_printf(state, "%"PRIu32, self->kern_dev); - fmt_state_puts(state, " file_qid="); - lib9p_qid_format(&self->file_qid, state); - fmt_state_puts(state, " file_mode="); - lib9p_dm_format(&self->file_mode, state); - fmt_state_puts(state, " file_atime="); - fmt_state_printf(state, "%"PRIu32, self->file_atime); - fmt_state_puts(state, " file_mtime="); - fmt_state_printf(state, "%"PRIu32, self->file_mtime); - fmt_state_puts(state, " file_size="); - fmt_state_printf(state, "%"PRIu64, self->file_size); - fmt_state_puts(state, " file_name="); - lib9p_s_format(&self->file_name, state); - fmt_state_puts(state, " file_owner_uid="); - lib9p_s_format(&self->file_owner_uid, state); - fmt_state_puts(state, " file_owner_gid="); - lib9p_s_format(&self->file_owner_gid, state); - fmt_state_puts(state, " file_last_modified_uid="); - lib9p_s_format(&self->file_last_modified_uid, state); + fmt_state_puts(state, " fstype="); + fmt_state_printf(state, "%"PRIu16, self->fstype); + fmt_state_puts(state, " fsdev="); + fmt_state_printf(state, "%"PRIu32, self->fsdev); + fmt_state_puts(state, " qid="); + lib9p_qid_format(&self->qid, state); + fmt_state_puts(state, " mode="); + lib9p_dm_format(&self->mode, state); + fmt_state_puts(state, " atime="); + fmt_state_printf(state, "%"PRIu32, self->atime); + fmt_state_puts(state, " mtime="); + fmt_state_printf(state, "%"PRIu32, self->mtime); + fmt_state_puts(state, " length="); + fmt_state_printf(state, "%"PRIu64, self->length); + fmt_state_puts(state, " name="); + lib9p_s_format(&self->name, state); + fmt_state_puts(state, " owner_uname="); + lib9p_s_format(&self->owner_uname, state); + fmt_state_puts(state, " owner_gname="); + lib9p_s_format(&self->owner_gname, state); + fmt_state_puts(state, " last_modifier_uname="); + lib9p_s_format(&self->last_modifier_uname, state); #if CONFIG_9P_ENABLE_9P2000_u - fmt_state_puts(state, " file_extension="); - lib9p_s_format(&self->file_extension, state); - fmt_state_puts(state, " file_owner_n_uid="); - lib9p_nuid_format(&self->file_owner_n_uid, state); - fmt_state_puts(state, " file_owner_n_gid="); - lib9p_nuid_format(&self->file_owner_n_gid, state); - fmt_state_puts(state, " file_last_modified_n_uid="); - lib9p_nuid_format(&self->file_last_modified_n_uid, state); + fmt_state_puts(state, " extension="); + lib9p_s_format(&self->extension, state); + fmt_state_puts(state, " owner_unum="); + lib9p_nuid_format(&self->owner_unum, state); + fmt_state_puts(state, " owner_gnum="); + lib9p_nuid_format(&self->owner_gnum, state); + fmt_state_puts(state, " last_modifier_unum="); + lib9p_nuid_format(&self->last_modifier_unum, state); #endif /* CONFIG_9P_ENABLE_9P2000_u */ fmt_state_puts(state, " }"); } @@ -5060,7 +5112,7 @@ static void lib9p_o_format(lib9p_o_t *self, struct fmt_state *state) { } #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown static void lib9p_msg_Tversion_format(struct lib9p_msg_Tversion *self, struct fmt_state *state) { fmt_state_puts(state, "Tversion {"); fmt_state_puts(state, " tag="); @@ -5083,6 +5135,8 @@ static void lib9p_msg_Rversion_format(struct lib9p_msg_Rversion *self, struct fm fmt_state_puts(state, " }"); } +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u static void lib9p_msg_Tauth_format(struct lib9p_msg_Tauth *self, struct fmt_state *state) { fmt_state_puts(state, "Tauth {"); fmt_state_puts(state, " tag="); @@ -5094,8 +5148,8 @@ static void lib9p_msg_Tauth_format(struct lib9p_msg_Tauth *self, struct fmt_stat fmt_state_puts(state, " aname="); lib9p_s_format(&self->aname, state); #if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u - fmt_state_puts(state, " n_uid="); - lib9p_nuid_format(&self->n_uid, state); + fmt_state_puts(state, " unum="); + lib9p_nuid_format(&self->unum, state); #endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ fmt_state_puts(state, " }"); } @@ -5122,8 +5176,8 @@ static void lib9p_msg_Tattach_format(struct lib9p_msg_Tattach *self, struct fmt_ fmt_state_puts(state, " aname="); lib9p_s_format(&self->aname, state); #if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u - fmt_state_puts(state, " n_uid="); - lib9p_nuid_format(&self->n_uid, state); + fmt_state_puts(state, " unum="); + lib9p_nuid_format(&self->unum, state); #endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ fmt_state_puts(state, " }"); } @@ -5137,19 +5191,23 @@ static void lib9p_msg_Rattach_format(struct lib9p_msg_Rattach *self, struct fmt_ fmt_state_puts(state, " }"); } +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown static void lib9p_msg_Rerror_format(struct lib9p_msg_Rerror *self, struct fmt_state *state) { fmt_state_puts(state, "Rerror {"); fmt_state_puts(state, " tag="); lib9p_tag_format(&self->tag, state); - fmt_state_puts(state, " ename="); - lib9p_s_format(&self->ename, state); + fmt_state_puts(state, " errstr="); + lib9p_s_format(&self->errstr, state); #if CONFIG_9P_ENABLE_9P2000_u - fmt_state_puts(state, " errno="); - lib9p_errno_format(&self->errno, state); + fmt_state_puts(state, " errnum="); + lib9p_errno_format(&self->errnum, state); #endif /* CONFIG_9P_ENABLE_9P2000_u */ fmt_state_puts(state, " }"); } +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u static void lib9p_msg_Tflush_format(struct lib9p_msg_Tflush *self, struct fmt_state *state) { fmt_state_puts(state, "Tflush {"); fmt_state_puts(state, " tag="); @@ -5179,7 +5237,8 @@ static void lib9p_msg_Twalk_format(struct lib9p_msg_Twalk *self, struct fmt_stat fmt_state_puts(state, " wname=["); for (uint16_t i = 0; i < self->nwname; i++) { if (i) - fmt_state_puts(state, ", "); + fmt_state_putchar(state, ','); + fmt_state_putchar(state, ' '); lib9p_s_format(&self->wname[i], state); } fmt_state_puts(state, " ]"); @@ -5195,7 +5254,8 @@ static void lib9p_msg_Rwalk_format(struct lib9p_msg_Rwalk *self, struct fmt_stat fmt_state_puts(state, " wqid=["); for (uint16_t i = 0; i < self->nwqid; i++) { if (i) - fmt_state_puts(state, ", "); + fmt_state_putchar(state, ','); + fmt_state_putchar(state, ' '); lib9p_qid_format(&self->wqid[i], state); } fmt_state_puts(state, " ]"); @@ -5273,7 +5333,18 @@ static void lib9p_msg_Rread_format(struct lib9p_msg_Rread *self, struct fmt_stat lib9p_tag_format(&self->tag, state); fmt_state_puts(state, " count="); fmt_state_printf(state, "%"PRIu32, self->count); - fmt_state_puts(state, " data=<bytedata>"); + if (is_valid_utf8_without_nul((uint8_t *)self->data, (size_t)self->count)) { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" +#pragma GCC diagnostic ignored "-Wformat-extra-args" + fmt_state_printf(state, " data=%.*q%s", + (int)(self->count < 50 ? self->count : 50), + (char *)self->data, + self->count < 50 ? "" : "..."); +#pragma GCC diagnostic pop + } else { + fmt_state_puts(state, " data=<bytedata>"); + } fmt_state_puts(state, " }"); } @@ -5287,7 +5358,18 @@ static void lib9p_msg_Twrite_format(struct lib9p_msg_Twrite *self, struct fmt_st fmt_state_printf(state, "%"PRIu64, self->offset); fmt_state_puts(state, " count="); fmt_state_printf(state, "%"PRIu32, self->count); - fmt_state_puts(state, " data=<bytedata>"); + if (is_valid_utf8_without_nul((uint8_t *)self->data, (size_t)self->count)) { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" +#pragma GCC diagnostic ignored "-Wformat-extra-args" + fmt_state_printf(state, " data=%.*q%s", + (int)(self->count < 50 ? self->count : 50), + (char *)self->data, + self->count < 50 ? "" : "..."); +#pragma GCC diagnostic pop + } else { + fmt_state_puts(state, " data=<bytedata>"); + } fmt_state_puts(state, " }"); } @@ -5413,6 +5495,399 @@ static void lib9p_errno_format(lib9p_errno_t *self, struct fmt_state *state) { case LIB9P_ERRNO_NOERROR: fmt_state_puts(state, "NOERROR"); break; + case LIB9P_ERRNO_L_EPERM: + fmt_state_puts(state, "L_EPERM"); + break; + case LIB9P_ERRNO_L_ENOENT: + fmt_state_puts(state, "L_ENOENT"); + break; + case LIB9P_ERRNO_L_ESRCH: + fmt_state_puts(state, "L_ESRCH"); + break; + case LIB9P_ERRNO_L_EINTR: + fmt_state_puts(state, "L_EINTR"); + break; + case LIB9P_ERRNO_L_EIO: + fmt_state_puts(state, "L_EIO"); + break; + case LIB9P_ERRNO_L_ENXIO: + fmt_state_puts(state, "L_ENXIO"); + break; + case LIB9P_ERRNO_L_E2BIG: + fmt_state_puts(state, "L_E2BIG"); + break; + case LIB9P_ERRNO_L_ENOEXEC: + fmt_state_puts(state, "L_ENOEXEC"); + break; + case LIB9P_ERRNO_L_EBADF: + fmt_state_puts(state, "L_EBADF"); + break; + case LIB9P_ERRNO_L_ECHILD: + fmt_state_puts(state, "L_ECHILD"); + break; + case LIB9P_ERRNO_L_EAGAIN: + fmt_state_puts(state, "L_EAGAIN"); + break; + case LIB9P_ERRNO_L_ENOMEM: + fmt_state_puts(state, "L_ENOMEM"); + break; + case LIB9P_ERRNO_L_EACCES: + fmt_state_puts(state, "L_EACCES"); + break; + case LIB9P_ERRNO_L_EFAULT: + fmt_state_puts(state, "L_EFAULT"); + break; + case LIB9P_ERRNO_L_ENOTBLK: + fmt_state_puts(state, "L_ENOTBLK"); + break; + case LIB9P_ERRNO_L_EBUSY: + fmt_state_puts(state, "L_EBUSY"); + break; + case LIB9P_ERRNO_L_EEXIST: + fmt_state_puts(state, "L_EEXIST"); + break; + case LIB9P_ERRNO_L_EXDEV: + fmt_state_puts(state, "L_EXDEV"); + break; + case LIB9P_ERRNO_L_ENODEV: + fmt_state_puts(state, "L_ENODEV"); + break; + case LIB9P_ERRNO_L_ENOTDIR: + fmt_state_puts(state, "L_ENOTDIR"); + break; + case LIB9P_ERRNO_L_EISDIR: + fmt_state_puts(state, "L_EISDIR"); + break; + case LIB9P_ERRNO_L_EINVAL: + fmt_state_puts(state, "L_EINVAL"); + break; + case LIB9P_ERRNO_L_ENFILE: + fmt_state_puts(state, "L_ENFILE"); + break; + case LIB9P_ERRNO_L_EMFILE: + fmt_state_puts(state, "L_EMFILE"); + break; + case LIB9P_ERRNO_L_ENOTTY: + fmt_state_puts(state, "L_ENOTTY"); + break; + case LIB9P_ERRNO_L_ETXTBSY: + fmt_state_puts(state, "L_ETXTBSY"); + break; + case LIB9P_ERRNO_L_EFBIG: + fmt_state_puts(state, "L_EFBIG"); + break; + case LIB9P_ERRNO_L_ENOSPC: + fmt_state_puts(state, "L_ENOSPC"); + break; + case LIB9P_ERRNO_L_ESPIPE: + fmt_state_puts(state, "L_ESPIPE"); + break; + case LIB9P_ERRNO_L_EROFS: + fmt_state_puts(state, "L_EROFS"); + break; + case LIB9P_ERRNO_L_EMLINK: + fmt_state_puts(state, "L_EMLINK"); + break; + case LIB9P_ERRNO_L_EPIPE: + fmt_state_puts(state, "L_EPIPE"); + break; + case LIB9P_ERRNO_L_EDOM: + fmt_state_puts(state, "L_EDOM"); + break; + case LIB9P_ERRNO_L_ERANGE: + fmt_state_puts(state, "L_ERANGE"); + break; + case LIB9P_ERRNO_L_EDEADLK: + fmt_state_puts(state, "L_EDEADLK"); + break; + case LIB9P_ERRNO_L_ENAMETOOLONG: + fmt_state_puts(state, "L_ENAMETOOLONG"); + break; + case LIB9P_ERRNO_L_ENOLCK: + fmt_state_puts(state, "L_ENOLCK"); + break; + case LIB9P_ERRNO_L_ENOSYS: + fmt_state_puts(state, "L_ENOSYS"); + break; + case LIB9P_ERRNO_L_ENOTEMPTY: + fmt_state_puts(state, "L_ENOTEMPTY"); + break; + case LIB9P_ERRNO_L_ELOOP: + fmt_state_puts(state, "L_ELOOP"); + break; + case LIB9P_ERRNO_L_ENOMSG: + fmt_state_puts(state, "L_ENOMSG"); + break; + case LIB9P_ERRNO_L_EIDRM: + fmt_state_puts(state, "L_EIDRM"); + break; + case LIB9P_ERRNO_L_ECHRNG: + fmt_state_puts(state, "L_ECHRNG"); + break; + case LIB9P_ERRNO_L_EL2NSYNC: + fmt_state_puts(state, "L_EL2NSYNC"); + break; + case LIB9P_ERRNO_L_EL3HLT: + fmt_state_puts(state, "L_EL3HLT"); + break; + case LIB9P_ERRNO_L_EL3RST: + fmt_state_puts(state, "L_EL3RST"); + break; + case LIB9P_ERRNO_L_ELNRNG: + fmt_state_puts(state, "L_ELNRNG"); + break; + case LIB9P_ERRNO_L_EUNATCH: + fmt_state_puts(state, "L_EUNATCH"); + break; + case LIB9P_ERRNO_L_ENOCSI: + fmt_state_puts(state, "L_ENOCSI"); + break; + case LIB9P_ERRNO_L_EL2HLT: + fmt_state_puts(state, "L_EL2HLT"); + break; + case LIB9P_ERRNO_L_EBADE: + fmt_state_puts(state, "L_EBADE"); + break; + case LIB9P_ERRNO_L_EBADR: + fmt_state_puts(state, "L_EBADR"); + break; + case LIB9P_ERRNO_L_EXFULL: + fmt_state_puts(state, "L_EXFULL"); + break; + case LIB9P_ERRNO_L_ENOANO: + fmt_state_puts(state, "L_ENOANO"); + break; + case LIB9P_ERRNO_L_EBADRQC: + fmt_state_puts(state, "L_EBADRQC"); + break; + case LIB9P_ERRNO_L_EBADSLT: + fmt_state_puts(state, "L_EBADSLT"); + break; + case LIB9P_ERRNO_L_EBFONT: + fmt_state_puts(state, "L_EBFONT"); + break; + case LIB9P_ERRNO_L_ENOSTR: + fmt_state_puts(state, "L_ENOSTR"); + break; + case LIB9P_ERRNO_L_ENODATA: + fmt_state_puts(state, "L_ENODATA"); + break; + case LIB9P_ERRNO_L_ETIME: + fmt_state_puts(state, "L_ETIME"); + break; + case LIB9P_ERRNO_L_ENOSR: + fmt_state_puts(state, "L_ENOSR"); + break; + case LIB9P_ERRNO_L_ENONET: + fmt_state_puts(state, "L_ENONET"); + break; + case LIB9P_ERRNO_L_ENOPKG: + fmt_state_puts(state, "L_ENOPKG"); + break; + case LIB9P_ERRNO_L_EREMOTE: + fmt_state_puts(state, "L_EREMOTE"); + break; + case LIB9P_ERRNO_L_ENOLINK: + fmt_state_puts(state, "L_ENOLINK"); + break; + case LIB9P_ERRNO_L_EADV: + fmt_state_puts(state, "L_EADV"); + break; + case LIB9P_ERRNO_L_ESRMNT: + fmt_state_puts(state, "L_ESRMNT"); + break; + case LIB9P_ERRNO_L_ECOMM: + fmt_state_puts(state, "L_ECOMM"); + break; + case LIB9P_ERRNO_L_EPROTO: + fmt_state_puts(state, "L_EPROTO"); + break; + case LIB9P_ERRNO_L_EMULTIHOP: + fmt_state_puts(state, "L_EMULTIHOP"); + break; + case LIB9P_ERRNO_L_EDOTDOT: + fmt_state_puts(state, "L_EDOTDOT"); + break; + case LIB9P_ERRNO_L_EBADMSG: + fmt_state_puts(state, "L_EBADMSG"); + break; + case LIB9P_ERRNO_L_EOVERFLOW: + fmt_state_puts(state, "L_EOVERFLOW"); + break; + case LIB9P_ERRNO_L_ENOTUNIQ: + fmt_state_puts(state, "L_ENOTUNIQ"); + break; + case LIB9P_ERRNO_L_EBADFD: + fmt_state_puts(state, "L_EBADFD"); + break; + case LIB9P_ERRNO_L_EREMCHG: + fmt_state_puts(state, "L_EREMCHG"); + break; + case LIB9P_ERRNO_L_ELIBACC: + fmt_state_puts(state, "L_ELIBACC"); + break; + case LIB9P_ERRNO_L_ELIBBAD: + fmt_state_puts(state, "L_ELIBBAD"); + break; + case LIB9P_ERRNO_L_ELIBSCN: + fmt_state_puts(state, "L_ELIBSCN"); + break; + case LIB9P_ERRNO_L_ELIBMAX: + fmt_state_puts(state, "L_ELIBMAX"); + break; + case LIB9P_ERRNO_L_ELIBEXEC: + fmt_state_puts(state, "L_ELIBEXEC"); + break; + case LIB9P_ERRNO_L_EILSEQ: + fmt_state_puts(state, "L_EILSEQ"); + break; + case LIB9P_ERRNO_L_ERESTART: + fmt_state_puts(state, "L_ERESTART"); + break; + case LIB9P_ERRNO_L_ESTRPIPE: + fmt_state_puts(state, "L_ESTRPIPE"); + break; + case LIB9P_ERRNO_L_EUSERS: + fmt_state_puts(state, "L_EUSERS"); + break; + case LIB9P_ERRNO_L_ENOTSOCK: + fmt_state_puts(state, "L_ENOTSOCK"); + break; + case LIB9P_ERRNO_L_EDESTADDRREQ: + fmt_state_puts(state, "L_EDESTADDRREQ"); + break; + case LIB9P_ERRNO_L_EMSGSIZE: + fmt_state_puts(state, "L_EMSGSIZE"); + break; + case LIB9P_ERRNO_L_EPROTOTYPE: + fmt_state_puts(state, "L_EPROTOTYPE"); + break; + case LIB9P_ERRNO_L_ENOPROTOOPT: + fmt_state_puts(state, "L_ENOPROTOOPT"); + break; + case LIB9P_ERRNO_L_EPROTONOSUPPORT: + fmt_state_puts(state, "L_EPROTONOSUPPORT"); + break; + case LIB9P_ERRNO_L_ESOCKTNOSUPPORT: + fmt_state_puts(state, "L_ESOCKTNOSUPPORT"); + break; + case LIB9P_ERRNO_L_EOPNOTSUPP: + fmt_state_puts(state, "L_EOPNOTSUPP"); + break; + case LIB9P_ERRNO_L_EPFNOSUPPORT: + fmt_state_puts(state, "L_EPFNOSUPPORT"); + break; + case LIB9P_ERRNO_L_EAFNOSUPPORT: + fmt_state_puts(state, "L_EAFNOSUPPORT"); + break; + case LIB9P_ERRNO_L_EADDRINUSE: + fmt_state_puts(state, "L_EADDRINUSE"); + break; + case LIB9P_ERRNO_L_EADDRNOTAVAIL: + fmt_state_puts(state, "L_EADDRNOTAVAIL"); + break; + case LIB9P_ERRNO_L_ENETDOWN: + fmt_state_puts(state, "L_ENETDOWN"); + break; + case LIB9P_ERRNO_L_ENETUNREACH: + fmt_state_puts(state, "L_ENETUNREACH"); + break; + case LIB9P_ERRNO_L_ENETRESET: + fmt_state_puts(state, "L_ENETRESET"); + break; + case LIB9P_ERRNO_L_ECONNABORTED: + fmt_state_puts(state, "L_ECONNABORTED"); + break; + case LIB9P_ERRNO_L_ECONNRESET: + fmt_state_puts(state, "L_ECONNRESET"); + break; + case LIB9P_ERRNO_L_ENOBUFS: + fmt_state_puts(state, "L_ENOBUFS"); + break; + case LIB9P_ERRNO_L_EISCONN: + fmt_state_puts(state, "L_EISCONN"); + break; + case LIB9P_ERRNO_L_ENOTCONN: + fmt_state_puts(state, "L_ENOTCONN"); + break; + case LIB9P_ERRNO_L_ESHUTDOWN: + fmt_state_puts(state, "L_ESHUTDOWN"); + break; + case LIB9P_ERRNO_L_ETOOMANYREFS: + fmt_state_puts(state, "L_ETOOMANYREFS"); + break; + case LIB9P_ERRNO_L_ETIMEDOUT: + fmt_state_puts(state, "L_ETIMEDOUT"); + break; + case LIB9P_ERRNO_L_ECONNREFUSED: + fmt_state_puts(state, "L_ECONNREFUSED"); + break; + case LIB9P_ERRNO_L_EHOSTDOWN: + fmt_state_puts(state, "L_EHOSTDOWN"); + break; + case LIB9P_ERRNO_L_EHOSTUNREACH: + fmt_state_puts(state, "L_EHOSTUNREACH"); + break; + case LIB9P_ERRNO_L_EALREADY: + fmt_state_puts(state, "L_EALREADY"); + break; + case LIB9P_ERRNO_L_EINPROGRESS: + fmt_state_puts(state, "L_EINPROGRESS"); + break; + case LIB9P_ERRNO_L_ESTALE: + fmt_state_puts(state, "L_ESTALE"); + break; + case LIB9P_ERRNO_L_EUCLEAN: + fmt_state_puts(state, "L_EUCLEAN"); + break; + case LIB9P_ERRNO_L_ENOTNAM: + fmt_state_puts(state, "L_ENOTNAM"); + break; + case LIB9P_ERRNO_L_ENAVAIL: + fmt_state_puts(state, "L_ENAVAIL"); + break; + case LIB9P_ERRNO_L_EISNAM: + fmt_state_puts(state, "L_EISNAM"); + break; + case LIB9P_ERRNO_L_EREMOTEIO: + fmt_state_puts(state, "L_EREMOTEIO"); + break; + case LIB9P_ERRNO_L_EDQUOT: + fmt_state_puts(state, "L_EDQUOT"); + break; + case LIB9P_ERRNO_L_ENOMEDIUM: + fmt_state_puts(state, "L_ENOMEDIUM"); + break; + case LIB9P_ERRNO_L_EMEDIUMTYPE: + fmt_state_puts(state, "L_EMEDIUMTYPE"); + break; + case LIB9P_ERRNO_L_ECANCELED: + fmt_state_puts(state, "L_ECANCELED"); + break; + case LIB9P_ERRNO_L_ENOKEY: + fmt_state_puts(state, "L_ENOKEY"); + break; + case LIB9P_ERRNO_L_EKEYEXPIRED: + fmt_state_puts(state, "L_EKEYEXPIRED"); + break; + case LIB9P_ERRNO_L_EKEYREVOKED: + fmt_state_puts(state, "L_EKEYREVOKED"); + break; + case LIB9P_ERRNO_L_EKEYREJECTED: + fmt_state_puts(state, "L_EKEYREJECTED"); + break; + case LIB9P_ERRNO_L_EOWNERDEAD: + fmt_state_puts(state, "L_EOWNERDEAD"); + break; + case LIB9P_ERRNO_L_ENOTRECOVERABLE: + fmt_state_puts(state, "L_ENOTRECOVERABLE"); + break; + case LIB9P_ERRNO_L_ERFKILL: + fmt_state_puts(state, "L_ERFKILL"); + break; + case LIB9P_ERRNO_L_EHWPOISON: + fmt_state_puts(state, "L_EHWPOISON"); + break; default: fmt_state_printf(state, "%"PRIu32, *self); } @@ -6752,8 +7227,8 @@ static void lib9p_msg_Rlerror_format(struct lib9p_msg_Rlerror *self, struct fmt_ fmt_state_puts(state, "Rlerror {"); fmt_state_puts(state, " tag="); lib9p_tag_format(&self->tag, state); - fmt_state_puts(state, " ecode="); - lib9p_errno_format(&self->ecode, state); + fmt_state_puts(state, " errnum="); + lib9p_errno_format(&self->errnum, state); fmt_state_puts(state, " }"); } @@ -7086,7 +7561,18 @@ static void lib9p_msg_Rreaddir_format(struct lib9p_msg_Rreaddir *self, struct fm lib9p_tag_format(&self->tag, state); fmt_state_puts(state, " count="); fmt_state_printf(state, "%"PRIu32, self->count); - fmt_state_puts(state, " data=<bytedata>"); + if (is_valid_utf8_without_nul((uint8_t *)self->data, (size_t)self->count)) { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" +#pragma GCC diagnostic ignored "-Wformat-extra-args" + fmt_state_printf(state, " data=%.*q%s", + (int)(self->count < 50 ? self->count : 50), + (char *)self->data, + self->count < 50 ? "" : "..."); +#pragma GCC diagnostic pop + } else { + fmt_state_puts(state, " data=<bytedata>"); + } fmt_state_puts(state, " }"); } @@ -7289,7 +7775,8 @@ static void lib9p_msg_Tsread_format(struct lib9p_msg_Tsread *self, struct fmt_st fmt_state_puts(state, " wname=["); for (uint16_t i = 0; i < self->nwname; i++) { if (i) - fmt_state_puts(state, ", "); + fmt_state_putchar(state, ','); + fmt_state_putchar(state, ' '); lib9p_s_format(&self->wname[i], state); } fmt_state_puts(state, " ]"); @@ -7302,7 +7789,18 @@ static void lib9p_msg_Rsread_format(struct lib9p_msg_Rsread *self, struct fmt_st lib9p_tag_format(&self->tag, state); fmt_state_puts(state, " count="); fmt_state_printf(state, "%"PRIu32, self->count); - fmt_state_puts(state, " data=<bytedata>"); + if (is_valid_utf8_without_nul((uint8_t *)self->data, (size_t)self->count)) { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" +#pragma GCC diagnostic ignored "-Wformat-extra-args" + fmt_state_printf(state, " data=%.*q%s", + (int)(self->count < 50 ? self->count : 50), + (char *)self->data, + self->count < 50 ? "" : "..."); +#pragma GCC diagnostic pop + } else { + fmt_state_puts(state, " data=<bytedata>"); + } fmt_state_puts(state, " }"); } @@ -7317,13 +7815,25 @@ static void lib9p_msg_Tswrite_format(struct lib9p_msg_Tswrite *self, struct fmt_ fmt_state_puts(state, " wname=["); for (uint16_t i = 0; i < self->nwname; i++) { if (i) - fmt_state_puts(state, ", "); + fmt_state_putchar(state, ','); + fmt_state_putchar(state, ' '); lib9p_s_format(&self->wname[i], state); } fmt_state_puts(state, " ]"); fmt_state_puts(state, " count="); fmt_state_printf(state, "%"PRIu32, self->count); - fmt_state_puts(state, " data=<bytedata>"); + if (is_valid_utf8_without_nul((uint8_t *)self->data, (size_t)self->count)) { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" +#pragma GCC diagnostic ignored "-Wformat-extra-args" + fmt_state_printf(state, " data=%.*q%s", + (int)(self->count < 50 ? self->count : 50), + (char *)self->data, + self->count < 50 ? "" : "..."); +#pragma GCC diagnostic pop + } else { + fmt_state_puts(state, " data=<bytedata>"); + } fmt_state_puts(state, " }"); } @@ -7340,12 +7850,11 @@ static void lib9p_msg_Rswrite_format(struct lib9p_msg_Rswrite *self, struct fmt_ /* tables.h *******************************************************************/ const struct _lib9p_ver_tentry _lib9p_table_ver[LIB9P_VER_NUM] = { - [LIB9P_VER_unknown] = {.name="unknown", .min_msg_size=9}, #if CONFIG_9P_ENABLE_9P2000 [LIB9P_VER_9P2000] = {.name="9P2000", .min_msg_size=9}, #endif /* CONFIG_9P_ENABLE_9P2000 */ #if CONFIG_9P_ENABLE_9P2000_L - [LIB9P_VER_9P2000_L] = {.name="9P2000.L", .min_msg_size=9}, + [LIB9P_VER_9P2000_L] = {.name="9P2000.L", .min_msg_size=11}, #endif /* CONFIG_9P_ENABLE_9P2000_L */ #if CONFIG_9P_ENABLE_9P2000_e [LIB9P_VER_9P2000_e] = {.name="9P2000.e", .min_msg_size=9}, @@ -7356,6 +7865,9 @@ const struct _lib9p_ver_tentry _lib9p_table_ver[LIB9P_VER_NUM] = { #if CONFIG_9P_ENABLE_9P2000_u [LIB9P_VER_9P2000_u] = {.name="9P2000.u", .min_msg_size=13}, #endif /* CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_unknown + [LIB9P_VER_unknown] = {.name="unknown", .min_msg_size=9}, +#endif /* CONFIG_9P_ENABLE_unknown */ }; #define _MSG(typ) [LIB9P_TYP_##typ] = { \ @@ -7363,11 +7875,6 @@ const struct _lib9p_ver_tentry _lib9p_table_ver[LIB9P_VER_NUM] = { .box_as_fmt_formatter = (_box_as_fmt_formatter_fn_t)lo_box_lib9p_msg_##typ##_as_fmt_formatter, \ } const struct _lib9p_msg_tentry _lib9p_table_msg[LIB9P_VER_NUM][0x100] = { - [LIB9P_VER_unknown] = { - _MSG(Tversion), - _MSG(Rversion), - _MSG(Rerror), - }, #if CONFIG_9P_ENABLE_9P2000 [LIB9P_VER_9P2000] = { _MSG(Tversion), @@ -7446,7 +7953,6 @@ const struct _lib9p_msg_tentry _lib9p_table_msg[LIB9P_VER_NUM][0x100] = { _MSG(Rauth), _MSG(Tattach), _MSG(Rattach), - _MSG(Rerror), _MSG(Tflush), _MSG(Rflush), _MSG(Twalk), @@ -7562,6 +8068,13 @@ const struct _lib9p_msg_tentry _lib9p_table_msg[LIB9P_VER_NUM][0x100] = { _MSG(Rwstat), }, #endif /* CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_unknown + [LIB9P_VER_unknown] = { + _MSG(Tversion), + _MSG(Rversion), + _MSG(Rerror), + }, +#endif /* CONFIG_9P_ENABLE_unknown */ }; #define _MSG_RECV(typ) [LIB9P_TYP_##typ/2] = { \ @@ -7573,9 +8086,6 @@ const struct _lib9p_msg_tentry _lib9p_table_msg[LIB9P_VER_NUM][0x100] = { } const struct _lib9p_recv_tentry _lib9p_table_Tmsg_recv[LIB9P_VER_NUM][0x80] = { - [LIB9P_VER_unknown] = { - _MSG_RECV(Tversion), - }, #if CONFIG_9P_ENABLE_9P2000 [LIB9P_VER_9P2000] = { _MSG_RECV(Tversion), @@ -7680,13 +8190,14 @@ const struct _lib9p_recv_tentry _lib9p_table_Tmsg_recv[LIB9P_VER_NUM][0x80] = { _MSG_RECV(Twstat), }, #endif /* CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_unknown + [LIB9P_VER_unknown] = { + _MSG_RECV(Tversion), + }, +#endif /* CONFIG_9P_ENABLE_unknown */ }; const struct _lib9p_recv_tentry _lib9p_table_Rmsg_recv[LIB9P_VER_NUM][0x80] = { - [LIB9P_VER_unknown] = { - _MSG_RECV(Rversion), - _MSG_RECV(Rerror), - }, #if CONFIG_9P_ENABLE_9P2000 [LIB9P_VER_9P2000] = { _MSG_RECV(Rversion), @@ -7730,7 +8241,6 @@ const struct _lib9p_recv_tentry _lib9p_table_Rmsg_recv[LIB9P_VER_NUM][0x80] = { _MSG_RECV(Rversion), _MSG_RECV(Rauth), _MSG_RECV(Rattach), - _MSG_RECV(Rerror), _MSG_RECV(Rflush), _MSG_RECV(Rwalk), _MSG_RECV(Rread), @@ -7797,12 +8307,15 @@ const struct _lib9p_recv_tentry _lib9p_table_Rmsg_recv[LIB9P_VER_NUM][0x80] = { _MSG_RECV(Rwstat), }, #endif /* CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_unknown + [LIB9P_VER_unknown] = { + _MSG_RECV(Rversion), + _MSG_RECV(Rerror), + }, +#endif /* CONFIG_9P_ENABLE_unknown */ }; const struct _lib9p_send_tentry _lib9p_table_Tmsg_send[LIB9P_VER_NUM][0x80] = { - [LIB9P_VER_unknown] = { - _MSG_SEND(Tversion), - }, #if CONFIG_9P_ENABLE_9P2000 [LIB9P_VER_9P2000] = { _MSG_SEND(Tversion), @@ -7907,13 +8420,14 @@ const struct _lib9p_send_tentry _lib9p_table_Tmsg_send[LIB9P_VER_NUM][0x80] = { _MSG_SEND(Twstat), }, #endif /* CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_unknown + [LIB9P_VER_unknown] = { + _MSG_SEND(Tversion), + }, +#endif /* CONFIG_9P_ENABLE_unknown */ }; const struct _lib9p_send_tentry _lib9p_table_Rmsg_send[LIB9P_VER_NUM][0x80] = { - [LIB9P_VER_unknown] = { - _MSG_SEND(Rversion), - _MSG_SEND(Rerror), - }, #if CONFIG_9P_ENABLE_9P2000 [LIB9P_VER_9P2000] = { _MSG_SEND(Rversion), @@ -7957,7 +8471,6 @@ const struct _lib9p_send_tentry _lib9p_table_Rmsg_send[LIB9P_VER_NUM][0x80] = { _MSG_SEND(Rversion), _MSG_SEND(Rauth), _MSG_SEND(Rattach), - _MSG_SEND(Rerror), _MSG_SEND(Rflush), _MSG_SEND(Rwalk), _MSG_SEND(Rread), @@ -8024,8 +8537,15 @@ const struct _lib9p_send_tentry _lib9p_table_Rmsg_send[LIB9P_VER_NUM][0x80] = { _MSG_SEND(Rwstat), }, #endif /* CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_unknown + [LIB9P_VER_unknown] = { + _MSG_SEND(Rversion), + _MSG_SEND(Rerror), + }, +#endif /* CONFIG_9P_ENABLE_unknown */ }; +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u LM_FLATTEN ssize_t _lib9p_stat_validate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes, uint32_t *ret_net_size) { return validate_stat(ctx, net_size, net_bytes, ret_net_size); } @@ -8035,3 +8555,4 @@ LM_FLATTEN void _lib9p_stat_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes, LM_FLATTEN bool _lib9p_stat_marshal(struct lib9p_ctx *ctx, struct lib9p_stat *val, struct _marshal_ret *ret) { return marshal_stat(ctx, val, ret); } +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ diff --git a/lib9p/include/lib9p/9p.generated.h b/lib9p/core_include/lib9p/_core_generated.h index 7e901a3..4c45b58 100644 --- a/lib9p/include/lib9p/9p.generated.h +++ b/lib9p/core_include/lib9p/_core_generated.h @@ -1,13 +1,13 @@ -/* Generated by `lib9p/proto.gen lib9p/idl/2002-9P2000.9p lib9p/idl/2003-9P2000.p9p.9p lib9p/idl/2005-9P2000.u.9p lib9p/idl/2010-9P2000.L.9p lib9p/idl/2012-9P2000.e.9p`. DO NOT EDIT! */ +/* Generated by `lib9p/core.gen lib9p/idl/0000-uninitialized.9p lib9p/idl/2002-9P2000.9p lib9p/idl/2003-9P2000.p9p.9p lib9p/idl/2005-9P2000.u.9p lib9p/idl/2010-9P2000.L.9p lib9p/idl/2012-9P2000.e.9p`. DO NOT EDIT! */ -#ifndef _LIB9P_9P_H_ - #error Do not include <lib9p/9p.generated.h> directly; include <lib9p/9p.h> instead +#ifndef _LIB9P_CORE_H_ + #error Do not include <lib9p/_core_generated.h> directly; include <lib9p/core.h> instead #endif #include <stdint.h> /* for uint{n}_t types */ #include <libfmt/fmt.h> /* for fmt_formatter */ -#include <libhw/generic/net.h> /* for struct iovec */ +#include <libhw/generic/io.h> /* for struct iovec */ /* config *********************************************************************/ @@ -40,6 +40,12 @@ #error config.h must define CONFIG_9P_ENABLE_9P2000_u #endif +#ifndef CONFIG_9P_ENABLE_unknown + #error config.h must define CONFIG_9P_ENABLE_unknown +#endif + +#define _LIB9P_ENABLE_stat CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u + /* enum version ***************************************************************/ enum lib9p_version { @@ -111,14 +117,20 @@ enum lib9p_msg_type { /* uint8_t */ LIB9P_TYP_Topenfd = 98, LIB9P_TYP_Ropenfd = 99, #endif /* CONFIG_9P_ENABLE_9P2000_p9p */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown LIB9P_TYP_Tversion = 100, LIB9P_TYP_Rversion = 101, +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u LIB9P_TYP_Tauth = 102, LIB9P_TYP_Rauth = 103, LIB9P_TYP_Tattach = 104, LIB9P_TYP_Rattach = 105, +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown LIB9P_TYP_Rerror = 107, +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u LIB9P_TYP_Tflush = 108, LIB9P_TYP_Rflush = 109, LIB9P_TYP_Twalk = 110, @@ -159,7 +171,7 @@ LO_IMPLEMENTATION_H(fmt_formatter, enum lib9p_msg_type, lib9p_msg_type); /* payload types **************************************************************/ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown /* size = 2 ; max_iov = 1 ; max_copy = 2 */ typedef uint16_t lib9p_tag_t; LO_IMPLEMENTATION_H(fmt_formatter, lib9p_tag_t, lib9p_tag); @@ -170,15 +182,8 @@ typedef uint32_t lib9p_fid_t; LO_IMPLEMENTATION_H(fmt_formatter, lib9p_fid_t, lib9p_fid); #define LIB9P_FID_NOFID ((lib9p_fid_t)(UINT32_MAX)) -/* min_size = 2 ; exp_size = 29 ; max_size = 65,537 ; max_iov = 2 ; max_copy = 2 */ -struct lib9p_s { - uint16_t len; - [[gnu::nonstring]] char *utf8; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_s, lib9p_s); - -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown /* size = 4 ; max_iov = 1 ; max_copy = 4 */ typedef uint32_t lib9p_dm_t; LO_IMPLEMENTATION_H(fmt_formatter, lib9p_dm_t, lib9p_dm); @@ -222,8 +227,8 @@ LO_IMPLEMENTATION_H(fmt_formatter, lib9p_dm_t, lib9p_dm); /* masks */ #define LIB9P_DM_PERM_MASK ((lib9p_dm_t)(0b000000000000000000000111111111)) -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown /* size = 1 ; max_iov = 1 ; max_copy = 1 */ typedef uint8_t lib9p_qt_t; LO_IMPLEMENTATION_H(fmt_formatter, lib9p_qt_t, lib9p_qt); @@ -241,14 +246,7 @@ LO_IMPLEMENTATION_H(fmt_formatter, lib9p_qt_t, lib9p_qt); /* aliases */ #define LIB9P_QT_FILE ((lib9p_qt_t)(0)) -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u -/* size = 4 ; max_iov = 1 ; max_copy = 4 */ -typedef uint32_t lib9p_nuid_t; -LO_IMPLEMENTATION_H(fmt_formatter, lib9p_nuid_t, lib9p_nuid); -#define LIB9P_NUID_NONUID ((lib9p_nuid_t)(UINT32_MAX)) - -#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u /* size = 1 ; max_iov = 1 ; max_copy = 1 */ typedef uint8_t lib9p_o_t; @@ -274,9 +272,145 @@ LO_IMPLEMENTATION_H(fmt_formatter, lib9p_o_t, lib9p_o); #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u /* size = 4 ; max_iov = 1 ; max_copy = 4 */ +typedef uint32_t lib9p_nuid_t; +LO_IMPLEMENTATION_H(fmt_formatter, lib9p_nuid_t, lib9p_nuid); +#define LIB9P_NUID_NONUID ((lib9p_nuid_t)(UINT32_MAX)) + +/* size = 4 ; max_iov = 1 ; max_copy = 4 */ typedef uint32_t lib9p_errno_t; LO_IMPLEMENTATION_H(fmt_formatter, lib9p_errno_t, lib9p_errno); -#define LIB9P_ERRNO_NOERROR ((lib9p_errno_t)(0)) +#define LIB9P_ERRNO_NOERROR ((lib9p_errno_t)(0)) +#define LIB9P_ERRNO_L_EPERM ((lib9p_errno_t)(1)) +#define LIB9P_ERRNO_L_ENOENT ((lib9p_errno_t)(2)) +#define LIB9P_ERRNO_L_ESRCH ((lib9p_errno_t)(3)) +#define LIB9P_ERRNO_L_EINTR ((lib9p_errno_t)(4)) +#define LIB9P_ERRNO_L_EIO ((lib9p_errno_t)(5)) +#define LIB9P_ERRNO_L_ENXIO ((lib9p_errno_t)(6)) +#define LIB9P_ERRNO_L_E2BIG ((lib9p_errno_t)(7)) +#define LIB9P_ERRNO_L_ENOEXEC ((lib9p_errno_t)(8)) +#define LIB9P_ERRNO_L_EBADF ((lib9p_errno_t)(9)) +#define LIB9P_ERRNO_L_ECHILD ((lib9p_errno_t)(10)) +#define LIB9P_ERRNO_L_EAGAIN ((lib9p_errno_t)(11)) +#define LIB9P_ERRNO_L_ENOMEM ((lib9p_errno_t)(12)) +#define LIB9P_ERRNO_L_EACCES ((lib9p_errno_t)(13)) +#define LIB9P_ERRNO_L_EFAULT ((lib9p_errno_t)(14)) +#define LIB9P_ERRNO_L_ENOTBLK ((lib9p_errno_t)(15)) +#define LIB9P_ERRNO_L_EBUSY ((lib9p_errno_t)(16)) +#define LIB9P_ERRNO_L_EEXIST ((lib9p_errno_t)(17)) +#define LIB9P_ERRNO_L_EXDEV ((lib9p_errno_t)(18)) +#define LIB9P_ERRNO_L_ENODEV ((lib9p_errno_t)(19)) +#define LIB9P_ERRNO_L_ENOTDIR ((lib9p_errno_t)(20)) +#define LIB9P_ERRNO_L_EISDIR ((lib9p_errno_t)(21)) +#define LIB9P_ERRNO_L_EINVAL ((lib9p_errno_t)(22)) +#define LIB9P_ERRNO_L_ENFILE ((lib9p_errno_t)(23)) +#define LIB9P_ERRNO_L_EMFILE ((lib9p_errno_t)(24)) +#define LIB9P_ERRNO_L_ENOTTY ((lib9p_errno_t)(25)) +#define LIB9P_ERRNO_L_ETXTBSY ((lib9p_errno_t)(26)) +#define LIB9P_ERRNO_L_EFBIG ((lib9p_errno_t)(27)) +#define LIB9P_ERRNO_L_ENOSPC ((lib9p_errno_t)(28)) +#define LIB9P_ERRNO_L_ESPIPE ((lib9p_errno_t)(29)) +#define LIB9P_ERRNO_L_EROFS ((lib9p_errno_t)(30)) +#define LIB9P_ERRNO_L_EMLINK ((lib9p_errno_t)(31)) +#define LIB9P_ERRNO_L_EPIPE ((lib9p_errno_t)(32)) +#define LIB9P_ERRNO_L_EDOM ((lib9p_errno_t)(33)) +#define LIB9P_ERRNO_L_ERANGE ((lib9p_errno_t)(34)) +#define LIB9P_ERRNO_L_EDEADLK ((lib9p_errno_t)(35)) +#define LIB9P_ERRNO_L_ENAMETOOLONG ((lib9p_errno_t)(36)) +#define LIB9P_ERRNO_L_ENOLCK ((lib9p_errno_t)(37)) +#define LIB9P_ERRNO_L_ENOSYS ((lib9p_errno_t)(38)) +#define LIB9P_ERRNO_L_ENOTEMPTY ((lib9p_errno_t)(39)) +#define LIB9P_ERRNO_L_ELOOP ((lib9p_errno_t)(40)) +#define LIB9P_ERRNO_L_ENOMSG ((lib9p_errno_t)(42)) +#define LIB9P_ERRNO_L_EIDRM ((lib9p_errno_t)(43)) +#define LIB9P_ERRNO_L_ECHRNG ((lib9p_errno_t)(44)) +#define LIB9P_ERRNO_L_EL2NSYNC ((lib9p_errno_t)(45)) +#define LIB9P_ERRNO_L_EL3HLT ((lib9p_errno_t)(46)) +#define LIB9P_ERRNO_L_EL3RST ((lib9p_errno_t)(47)) +#define LIB9P_ERRNO_L_ELNRNG ((lib9p_errno_t)(48)) +#define LIB9P_ERRNO_L_EUNATCH ((lib9p_errno_t)(49)) +#define LIB9P_ERRNO_L_ENOCSI ((lib9p_errno_t)(50)) +#define LIB9P_ERRNO_L_EL2HLT ((lib9p_errno_t)(51)) +#define LIB9P_ERRNO_L_EBADE ((lib9p_errno_t)(52)) +#define LIB9P_ERRNO_L_EBADR ((lib9p_errno_t)(53)) +#define LIB9P_ERRNO_L_EXFULL ((lib9p_errno_t)(54)) +#define LIB9P_ERRNO_L_ENOANO ((lib9p_errno_t)(55)) +#define LIB9P_ERRNO_L_EBADRQC ((lib9p_errno_t)(56)) +#define LIB9P_ERRNO_L_EBADSLT ((lib9p_errno_t)(57)) +#define LIB9P_ERRNO_L_EBFONT ((lib9p_errno_t)(59)) +#define LIB9P_ERRNO_L_ENOSTR ((lib9p_errno_t)(60)) +#define LIB9P_ERRNO_L_ENODATA ((lib9p_errno_t)(61)) +#define LIB9P_ERRNO_L_ETIME ((lib9p_errno_t)(62)) +#define LIB9P_ERRNO_L_ENOSR ((lib9p_errno_t)(63)) +#define LIB9P_ERRNO_L_ENONET ((lib9p_errno_t)(64)) +#define LIB9P_ERRNO_L_ENOPKG ((lib9p_errno_t)(65)) +#define LIB9P_ERRNO_L_EREMOTE ((lib9p_errno_t)(66)) +#define LIB9P_ERRNO_L_ENOLINK ((lib9p_errno_t)(67)) +#define LIB9P_ERRNO_L_EADV ((lib9p_errno_t)(68)) +#define LIB9P_ERRNO_L_ESRMNT ((lib9p_errno_t)(69)) +#define LIB9P_ERRNO_L_ECOMM ((lib9p_errno_t)(70)) +#define LIB9P_ERRNO_L_EPROTO ((lib9p_errno_t)(71)) +#define LIB9P_ERRNO_L_EMULTIHOP ((lib9p_errno_t)(72)) +#define LIB9P_ERRNO_L_EDOTDOT ((lib9p_errno_t)(73)) +#define LIB9P_ERRNO_L_EBADMSG ((lib9p_errno_t)(74)) +#define LIB9P_ERRNO_L_EOVERFLOW ((lib9p_errno_t)(75)) +#define LIB9P_ERRNO_L_ENOTUNIQ ((lib9p_errno_t)(76)) +#define LIB9P_ERRNO_L_EBADFD ((lib9p_errno_t)(77)) +#define LIB9P_ERRNO_L_EREMCHG ((lib9p_errno_t)(78)) +#define LIB9P_ERRNO_L_ELIBACC ((lib9p_errno_t)(79)) +#define LIB9P_ERRNO_L_ELIBBAD ((lib9p_errno_t)(80)) +#define LIB9P_ERRNO_L_ELIBSCN ((lib9p_errno_t)(81)) +#define LIB9P_ERRNO_L_ELIBMAX ((lib9p_errno_t)(82)) +#define LIB9P_ERRNO_L_ELIBEXEC ((lib9p_errno_t)(83)) +#define LIB9P_ERRNO_L_EILSEQ ((lib9p_errno_t)(84)) +#define LIB9P_ERRNO_L_ERESTART ((lib9p_errno_t)(85)) +#define LIB9P_ERRNO_L_ESTRPIPE ((lib9p_errno_t)(86)) +#define LIB9P_ERRNO_L_EUSERS ((lib9p_errno_t)(87)) +#define LIB9P_ERRNO_L_ENOTSOCK ((lib9p_errno_t)(88)) +#define LIB9P_ERRNO_L_EDESTADDRREQ ((lib9p_errno_t)(89)) +#define LIB9P_ERRNO_L_EMSGSIZE ((lib9p_errno_t)(90)) +#define LIB9P_ERRNO_L_EPROTOTYPE ((lib9p_errno_t)(91)) +#define LIB9P_ERRNO_L_ENOPROTOOPT ((lib9p_errno_t)(92)) +#define LIB9P_ERRNO_L_EPROTONOSUPPORT ((lib9p_errno_t)(93)) +#define LIB9P_ERRNO_L_ESOCKTNOSUPPORT ((lib9p_errno_t)(94)) +#define LIB9P_ERRNO_L_EOPNOTSUPP ((lib9p_errno_t)(95)) +#define LIB9P_ERRNO_L_EPFNOSUPPORT ((lib9p_errno_t)(96)) +#define LIB9P_ERRNO_L_EAFNOSUPPORT ((lib9p_errno_t)(97)) +#define LIB9P_ERRNO_L_EADDRINUSE ((lib9p_errno_t)(98)) +#define LIB9P_ERRNO_L_EADDRNOTAVAIL ((lib9p_errno_t)(99)) +#define LIB9P_ERRNO_L_ENETDOWN ((lib9p_errno_t)(100)) +#define LIB9P_ERRNO_L_ENETUNREACH ((lib9p_errno_t)(101)) +#define LIB9P_ERRNO_L_ENETRESET ((lib9p_errno_t)(102)) +#define LIB9P_ERRNO_L_ECONNABORTED ((lib9p_errno_t)(103)) +#define LIB9P_ERRNO_L_ECONNRESET ((lib9p_errno_t)(104)) +#define LIB9P_ERRNO_L_ENOBUFS ((lib9p_errno_t)(105)) +#define LIB9P_ERRNO_L_EISCONN ((lib9p_errno_t)(106)) +#define LIB9P_ERRNO_L_ENOTCONN ((lib9p_errno_t)(107)) +#define LIB9P_ERRNO_L_ESHUTDOWN ((lib9p_errno_t)(108)) +#define LIB9P_ERRNO_L_ETOOMANYREFS ((lib9p_errno_t)(109)) +#define LIB9P_ERRNO_L_ETIMEDOUT ((lib9p_errno_t)(110)) +#define LIB9P_ERRNO_L_ECONNREFUSED ((lib9p_errno_t)(111)) +#define LIB9P_ERRNO_L_EHOSTDOWN ((lib9p_errno_t)(112)) +#define LIB9P_ERRNO_L_EHOSTUNREACH ((lib9p_errno_t)(113)) +#define LIB9P_ERRNO_L_EALREADY ((lib9p_errno_t)(114)) +#define LIB9P_ERRNO_L_EINPROGRESS ((lib9p_errno_t)(115)) +#define LIB9P_ERRNO_L_ESTALE ((lib9p_errno_t)(116)) +#define LIB9P_ERRNO_L_EUCLEAN ((lib9p_errno_t)(117)) +#define LIB9P_ERRNO_L_ENOTNAM ((lib9p_errno_t)(118)) +#define LIB9P_ERRNO_L_ENAVAIL ((lib9p_errno_t)(119)) +#define LIB9P_ERRNO_L_EISNAM ((lib9p_errno_t)(120)) +#define LIB9P_ERRNO_L_EREMOTEIO ((lib9p_errno_t)(121)) +#define LIB9P_ERRNO_L_EDQUOT ((lib9p_errno_t)(122)) +#define LIB9P_ERRNO_L_ENOMEDIUM ((lib9p_errno_t)(123)) +#define LIB9P_ERRNO_L_EMEDIUMTYPE ((lib9p_errno_t)(124)) +#define LIB9P_ERRNO_L_ECANCELED ((lib9p_errno_t)(125)) +#define LIB9P_ERRNO_L_ENOKEY ((lib9p_errno_t)(126)) +#define LIB9P_ERRNO_L_EKEYEXPIRED ((lib9p_errno_t)(127)) +#define LIB9P_ERRNO_L_EKEYREVOKED ((lib9p_errno_t)(128)) +#define LIB9P_ERRNO_L_EKEYREJECTED ((lib9p_errno_t)(129)) +#define LIB9P_ERRNO_L_EOWNERDEAD ((lib9p_errno_t)(130)) +#define LIB9P_ERRNO_L_ENOTRECOVERABLE ((lib9p_errno_t)(131)) +#define LIB9P_ERRNO_L_ERFKILL ((lib9p_errno_t)(132)) +#define LIB9P_ERRNO_L_EHWPOISON ((lib9p_errno_t)(133)) #endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000_L @@ -559,6 +693,23 @@ LO_IMPLEMENTATION_H(fmt_formatter, lib9p_lock_status_t, lib9p_lock_status); #define LIB9P_LOCK_STATUS_GRACE ((lib9p_lock_status_t)(3)) #endif /* CONFIG_9P_ENABLE_9P2000_L */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown +/* min_size = 2 ; exp_size = 29 ; max_size = 65,537 ; max_iov = 2 ; max_copy = 2 */ +struct lib9p_s { + uint16_t len; + [[gnu::nonstring]] char *utf8; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_s, lib9p_s); + +/* size = 13 ; max_iov = 1 ; max_copy = 13 */ +struct lib9p_qid { + lib9p_qt_t type; + uint32_t vers; + uint64_t path; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_qid, lib9p_qid); + +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u /* size = 9 ; max_iov = 1 ; max_copy = 9 */ struct lib9p_msg_Tflush { @@ -573,6 +724,27 @@ struct lib9p_msg_Rflush { }; LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rflush, lib9p_msg_Rflush); +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u +/* size = 12 ; max_iov = 1 ; max_copy = 12 */ +struct lib9p_msg_Topen { + lib9p_tag_t tag; + lib9p_fid_t fid; + lib9p_o_t mode; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Topen, lib9p_msg_Topen); + +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u +/* size = 23 ; max_iov = 1 ; max_copy = 23 */ +struct lib9p_msg_Tread { + lib9p_tag_t tag; + lib9p_fid_t fid; + uint64_t offset; + uint32_t count; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tread, lib9p_msg_Tread); + /* min_size = 11 ; exp_size = 8,203 ; max_size = 2,147,483,658 ; max_iov = 2 ; max_copy = 11 */ struct lib9p_msg_Rread { lib9p_tag_t tag; @@ -581,6 +753,16 @@ struct lib9p_msg_Rread { }; LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rread, lib9p_msg_Rread); +/* min_size = 23 ; exp_size = 8,215 ; max_size = 2,147,483,670 ; max_iov = 2 ; max_copy = 23 */ +struct lib9p_msg_Twrite { + lib9p_tag_t tag; + lib9p_fid_t fid; + uint64_t offset; + uint32_t count; + [[gnu::nonstring]] char *data; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Twrite, lib9p_msg_Twrite); + /* size = 11 ; max_iov = 1 ; max_copy = 11 */ struct lib9p_msg_Rwrite { lib9p_tag_t tag; @@ -588,12 +770,26 @@ struct lib9p_msg_Rwrite { }; LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rwrite, lib9p_msg_Rwrite); +/* size = 11 ; max_iov = 1 ; max_copy = 11 */ +struct lib9p_msg_Tclunk { + lib9p_tag_t tag; + lib9p_fid_t fid; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tclunk, lib9p_msg_Tclunk); + /* size = 7 ; max_iov = 1 ; max_copy = 7 */ struct lib9p_msg_Rclunk { lib9p_tag_t tag; }; LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rclunk, lib9p_msg_Rclunk); +/* size = 11 ; max_iov = 1 ; max_copy = 11 */ +struct lib9p_msg_Tremove { + lib9p_tag_t tag; + lib9p_fid_t fid; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tremove, lib9p_msg_Tremove); + /* size = 7 ; max_iov = 1 ; max_copy = 7 */ struct lib9p_msg_Rremove { lib9p_tag_t tag; @@ -602,6 +798,13 @@ LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rremove, lib9p_msg_Rremove); #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u +/* size = 11 ; max_iov = 1 ; max_copy = 11 */ +struct lib9p_msg_Tstat { + lib9p_tag_t tag; + lib9p_fid_t fid; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tstat, lib9p_msg_Tstat); + /* size = 7 ; max_iov = 1 ; max_copy = 7 */ struct lib9p_msg_Rwstat { lib9p_tag_t tag; @@ -609,13 +812,91 @@ struct lib9p_msg_Rwstat { LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rwstat, lib9p_msg_Rwstat); #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_9P2000_p9p +/* size = 12 ; max_iov = 1 ; max_copy = 12 */ +struct lib9p_msg_Topenfd { + lib9p_tag_t tag; + lib9p_fid_t fid; + lib9p_o_t mode; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Topenfd, lib9p_msg_Topenfd); + +#endif /* CONFIG_9P_ENABLE_9P2000_p9p */ #if CONFIG_9P_ENABLE_9P2000_L +/* size = 11 ; max_iov = 1 ; max_copy = 11 */ +struct lib9p_msg_Rlerror { + lib9p_tag_t tag; + lib9p_errno_t errnum; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rlerror, lib9p_msg_Rlerror); + +/* size = 11 ; max_iov = 1 ; max_copy = 11 */ +struct lib9p_msg_Tstatfs { + lib9p_tag_t tag; + lib9p_fid_t fid; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tstatfs, lib9p_msg_Tstatfs); + +/* size = 67 ; max_iov = 1 ; max_copy = 67 */ +struct lib9p_msg_Rstatfs { + lib9p_tag_t tag; + lib9p_super_magic_t type; + uint32_t bsize; + uint64_t blocks; + uint64_t bfree; + uint64_t bavail; + uint64_t files; + uint64_t ffree; + uint64_t fsid; + uint32_t namelen; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rstatfs, lib9p_msg_Rstatfs); + +/* size = 15 ; max_iov = 1 ; max_copy = 15 */ +struct lib9p_msg_Tlopen { + lib9p_tag_t tag; + lib9p_fid_t fid; + lib9p_lo_t flags; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tlopen, lib9p_msg_Tlopen); + /* size = 7 ; max_iov = 1 ; max_copy = 7 */ struct lib9p_msg_Rrename { lib9p_tag_t tag; }; LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rrename, lib9p_msg_Rrename); +/* size = 11 ; max_iov = 1 ; max_copy = 11 */ +struct lib9p_msg_Treadlink { + lib9p_tag_t tag; + lib9p_fid_t fid; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Treadlink, lib9p_msg_Treadlink); + +/* size = 19 ; max_iov = 1 ; max_copy = 19 */ +struct lib9p_msg_Tgetattr { + lib9p_tag_t tag; + lib9p_fid_t fid; + lib9p_getattr_t request_mask; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tgetattr, lib9p_msg_Tgetattr); + +/* size = 67 ; max_iov = 1 ; max_copy = 67 */ +struct lib9p_msg_Tsetattr { + lib9p_tag_t tag; + lib9p_fid_t fid; + lib9p_setattr_t valid; + lib9p_mode_t mode; + lib9p_nuid_t uid; + lib9p_nuid_t gid; + uint64_t filesize; + uint64_t atime_sec; + uint64_t atime_nsec; + uint64_t mtime_sec; + uint64_t mtime_nsec; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tsetattr, lib9p_msg_Tsetattr); + /* size = 7 ; max_iov = 1 ; max_copy = 7 */ struct lib9p_msg_Rsetattr { lib9p_tag_t tag; @@ -635,6 +916,15 @@ struct lib9p_msg_Rxattrcreate { }; LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rxattrcreate, lib9p_msg_Rxattrcreate); +/* size = 23 ; max_iov = 1 ; max_copy = 23 */ +struct lib9p_msg_Treaddir { + lib9p_tag_t tag; + lib9p_fid_t fid; + uint64_t offset; + uint32_t count; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Treaddir, lib9p_msg_Treaddir); + /* min_size = 11 ; exp_size = 8,203 ; max_size = 4,294,967,306 (warning: >UINT32_MAX) ; max_iov = 2 ; max_copy = 11 */ struct lib9p_msg_Rreaddir { lib9p_tag_t tag; @@ -643,12 +933,27 @@ struct lib9p_msg_Rreaddir { }; LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rreaddir, lib9p_msg_Rreaddir); +/* size = 15 ; max_iov = 1 ; max_copy = 15 */ +struct lib9p_msg_Tfsync { + lib9p_tag_t tag; + lib9p_fid_t fid; + lib9p_b4_t datasync; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tfsync, lib9p_msg_Tfsync); + /* size = 7 ; max_iov = 1 ; max_copy = 7 */ struct lib9p_msg_Rfsync { lib9p_tag_t tag; }; LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rfsync, lib9p_msg_Rfsync); +/* size = 8 ; max_iov = 1 ; max_copy = 8 */ +struct lib9p_msg_Rlock { + lib9p_tag_t tag; + lib9p_lock_status_t status; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rlock, lib9p_msg_Rlock); + /* size = 7 ; max_iov = 1 ; max_copy = 7 */ struct lib9p_msg_Rlink { lib9p_tag_t tag; @@ -698,76 +1003,34 @@ struct lib9p_msg_Rswrite { LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rswrite, lib9p_msg_Rswrite); #endif /* CONFIG_9P_ENABLE_9P2000_e */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -/* size = 23 ; max_iov = 1 ; max_copy = 23 */ -struct lib9p_msg_Tread { - lib9p_tag_t tag; - lib9p_fid_t fid; - uint64_t offset; - uint32_t count; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tread, lib9p_msg_Tread); - -/* min_size = 23 ; exp_size = 8,215 ; max_size = 2,147,483,670 ; max_iov = 2 ; max_copy = 23 */ -struct lib9p_msg_Twrite { - lib9p_tag_t tag; - lib9p_fid_t fid; - uint64_t offset; - uint32_t count; - [[gnu::nonstring]] char *data; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Twrite, lib9p_msg_Twrite); - -/* size = 11 ; max_iov = 1 ; max_copy = 11 */ -struct lib9p_msg_Tclunk { - lib9p_tag_t tag; - lib9p_fid_t fid; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tclunk, lib9p_msg_Tclunk); - -/* size = 11 ; max_iov = 1 ; max_copy = 11 */ -struct lib9p_msg_Tremove { - lib9p_tag_t tag; - lib9p_fid_t fid; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tremove, lib9p_msg_Tremove); - -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -/* size = 11 ; max_iov = 1 ; max_copy = 11 */ -struct lib9p_msg_Tstat { - lib9p_tag_t tag; - lib9p_fid_t fid; +/* LIB9P_VER_9P2000 : min_size = 49 ; exp_size = 157 ; max_size = 262,189 ; max_iov = 8 ; max_copy = 49 */ +/* LIB9P_VER_9P2000_e : min_size = 49 ; exp_size = 157 ; max_size = 262,189 ; max_iov = 8 ; max_copy = 49 */ +/* LIB9P_VER_9P2000_p9p: min_size = 49 ; exp_size = 157 ; max_size = 262,189 ; max_iov = 8 ; max_copy = 49 */ +/* LIB9P_VER_9P2000_u : min_size = 63 ; exp_size = 198 ; max_size = 327,738 ; max_iov = 11 ; max_copy = 63 */ +struct lib9p_stat { + uint16_t fstype; + uint32_t fsdev; + struct lib9p_qid qid; + lib9p_dm_t mode; + uint32_t atime; + uint32_t mtime; + uint64_t length; + struct lib9p_s name; + struct lib9p_s owner_uname; + struct lib9p_s owner_gname; + struct lib9p_s last_modifier_uname; +#if CONFIG_9P_ENABLE_9P2000_u + struct lib9p_s extension; + lib9p_nuid_t owner_unum; + lib9p_nuid_t owner_gnum; + lib9p_nuid_t last_modifier_unum; +#endif /* CONFIG_9P_ENABLE_9P2000_u */ }; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tstat, lib9p_msg_Tstat); +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_stat, lib9p_stat); #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_L -/* size = 11 ; max_iov = 1 ; max_copy = 11 */ -struct lib9p_msg_Tstatfs { - lib9p_tag_t tag; - lib9p_fid_t fid; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tstatfs, lib9p_msg_Tstatfs); - -/* size = 11 ; max_iov = 1 ; max_copy = 11 */ -struct lib9p_msg_Treadlink { - lib9p_tag_t tag; - lib9p_fid_t fid; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Treadlink, lib9p_msg_Treadlink); - -/* size = 23 ; max_iov = 1 ; max_copy = 23 */ -struct lib9p_msg_Treaddir { - lib9p_tag_t tag; - lib9p_fid_t fid; - uint64_t offset; - uint32_t count; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Treaddir, lib9p_msg_Treaddir); - -#endif /* CONFIG_9P_ENABLE_9P2000_L */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown /* min_size = 13 ; exp_size = 40 ; max_size = 65,548 ; max_iov = 2 ; max_copy = 13 */ struct lib9p_msg_Tversion { lib9p_tag_t tag; @@ -784,113 +1047,8 @@ struct lib9p_msg_Rversion { }; LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rversion, lib9p_msg_Rversion); -/* min_size = 17 ; exp_size = 481 ; max_size = 1,048,609 ; max_iov = 32 ; max_copy = 49 */ -struct lib9p_msg_Twalk { - lib9p_tag_t tag; - lib9p_fid_t fid; - lib9p_fid_t newfid; - uint16_t nwname; - struct lib9p_s *wname; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Twalk, lib9p_msg_Twalk); - -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_L -/* min_size = 17 ; exp_size = 44 ; max_size = 65,552 ; max_iov = 2 ; max_copy = 17 */ -struct lib9p_msg_Trename { - lib9p_tag_t tag; - lib9p_fid_t fid; - lib9p_fid_t dfid; - struct lib9p_s name; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Trename, lib9p_msg_Trename); - -/* min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */ -struct lib9p_msg_Rreadlink { - lib9p_tag_t tag; - struct lib9p_s target; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rreadlink, lib9p_msg_Rreadlink); - -/* min_size = 17 ; exp_size = 44 ; max_size = 65,552 ; max_iov = 2 ; max_copy = 17 */ -struct lib9p_msg_Txattrwalk { - lib9p_tag_t tag; - lib9p_fid_t fid; - lib9p_fid_t newfid; - struct lib9p_s name; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Txattrwalk, lib9p_msg_Txattrwalk); - -/* min_size = 25 ; exp_size = 52 ; max_size = 65,560 ; max_iov = 3 ; max_copy = 25 */ -struct lib9p_msg_Txattrcreate { - lib9p_tag_t tag; - lib9p_fid_t fid; - struct lib9p_s name; - uint64_t attr_size; - uint32_t flags; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Txattrcreate, lib9p_msg_Txattrcreate); - -/* min_size = 17 ; exp_size = 44 ; max_size = 65,552 ; max_iov = 2 ; max_copy = 17 */ -struct lib9p_msg_Tlink { - lib9p_tag_t tag; - lib9p_fid_t dfid; - lib9p_fid_t fid; - struct lib9p_s name; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tlink, lib9p_msg_Tlink); - -/* min_size = 19 ; exp_size = 73 ; max_size = 131,089 ; max_iov = 4 ; max_copy = 19 */ -struct lib9p_msg_Trenameat { - lib9p_tag_t tag; - lib9p_fid_t olddirfid; - struct lib9p_s oldname; - lib9p_fid_t newdirfid; - struct lib9p_s newname; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Trenameat, lib9p_msg_Trenameat); - -/* min_size = 17 ; exp_size = 44 ; max_size = 65,552 ; max_iov = 3 ; max_copy = 17 */ -struct lib9p_msg_Tunlinkat { - lib9p_tag_t tag; - lib9p_fid_t dirfd; - struct lib9p_s name; - uint32_t flags; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tunlinkat, lib9p_msg_Tunlinkat); - -#endif /* CONFIG_9P_ENABLE_9P2000_L */ -#if CONFIG_9P_ENABLE_9P2000_e -/* min_size = 13 ; exp_size = 477 ; max_size = 4,294,967,308 (warning: >UINT32_MAX) ; max_iov = 0 + (CONFIG_9P_MAX_9P2000_e_WELEM * 2) ; max_copy = 13 + (CONFIG_9P_MAX_9P2000_e_WELEM * 2) */ -struct lib9p_msg_Tsread { - lib9p_tag_t tag; - uint32_t fid; - uint16_t nwname; - struct lib9p_s *wname; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tsread, lib9p_msg_Tsread); - -/* min_size = 17 ; exp_size = 8,673 ; max_size = 8,589,934,607 (warning: >UINT32_MAX) ; max_iov = 2 + (CONFIG_9P_MAX_9P2000_e_WELEM * 2) ; max_copy = 17 + (CONFIG_9P_MAX_9P2000_e_WELEM * 2) */ -struct lib9p_msg_Tswrite { - lib9p_tag_t tag; - uint32_t fid; - uint16_t nwname; - struct lib9p_s *wname; - uint32_t count; - [[gnu::nonstring]] char *data; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tswrite, lib9p_msg_Tswrite); - -#endif /* CONFIG_9P_ENABLE_9P2000_e */ +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -/* size = 13 ; max_iov = 1 ; max_copy = 13 */ -struct lib9p_qid { - lib9p_qt_t type; - uint32_t vers; - uint64_t path; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_qid, lib9p_qid); - /* LIB9P_VER_9P2000 : min_size = 15 ; exp_size = 69 ; max_size = 131,085 ; max_iov = 4 ; max_copy = 15 */ /* LIB9P_VER_9P2000_L : min_size = 19 ; exp_size = 73 ; max_size = 131,089 ; max_iov = 5 ; max_copy = 19 */ /* LIB9P_VER_9P2000_e : min_size = 15 ; exp_size = 69 ; max_size = 131,085 ; max_iov = 4 ; max_copy = 15 */ @@ -902,11 +1060,18 @@ struct lib9p_msg_Tauth { struct lib9p_s uname; struct lib9p_s aname; #if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u - lib9p_nuid_t n_uid; + lib9p_nuid_t unum; #endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ }; LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tauth, lib9p_msg_Tauth); +/* size = 20 ; max_iov = 1 ; max_copy = 20 */ +struct lib9p_msg_Rauth { + lib9p_tag_t tag; + struct lib9p_qid aqid; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rauth, lib9p_msg_Rauth); + /* LIB9P_VER_9P2000 : min_size = 19 ; exp_size = 73 ; max_size = 131,089 ; max_iov = 4 ; max_copy = 19 */ /* LIB9P_VER_9P2000_L : min_size = 23 ; exp_size = 77 ; max_size = 131,093 ; max_iov = 5 ; max_copy = 23 */ /* LIB9P_VER_9P2000_e : min_size = 19 ; exp_size = 73 ; max_size = 131,089 ; max_iov = 4 ; max_copy = 19 */ @@ -919,251 +1084,45 @@ struct lib9p_msg_Tattach { struct lib9p_s uname; struct lib9p_s aname; #if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u - lib9p_nuid_t n_uid; + lib9p_nuid_t unum; #endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */ }; LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tattach, lib9p_msg_Tattach); -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_L -/* min_size = 19 ; exp_size = 73 ; max_size = 131,089 ; max_iov = 5 ; max_copy = 19 */ -struct lib9p_msg_Tsymlink { - lib9p_tag_t tag; - lib9p_fid_t fid; - struct lib9p_s name; - struct lib9p_s symtgt; - lib9p_nuid_t gid; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tsymlink, lib9p_msg_Tsymlink); - -#endif /* CONFIG_9P_ENABLE_9P2000_L */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -/* size = 12 ; max_iov = 1 ; max_copy = 12 */ -struct lib9p_msg_Topen { - lib9p_tag_t tag; - lib9p_fid_t fid; - lib9p_o_t mode; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Topen, lib9p_msg_Topen); - -/* min_size = 18 ; exp_size = 45 ; max_size = 65,553 ; max_iov = 3 ; max_copy = 18 */ -struct lib9p_msg_Tcreate { - lib9p_tag_t tag; - lib9p_fid_t fid; - struct lib9p_s name; - lib9p_dm_t perm; - lib9p_o_t mode; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tcreate, lib9p_msg_Tcreate); - -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_p9p -/* size = 12 ; max_iov = 1 ; max_copy = 12 */ -struct lib9p_msg_Topenfd { - lib9p_tag_t tag; - lib9p_fid_t fid; - lib9p_o_t mode; +/* size = 20 ; max_iov = 1 ; max_copy = 20 */ +struct lib9p_msg_Rattach { + lib9p_tag_t tag; + struct lib9p_qid qid; }; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Topenfd, lib9p_msg_Topenfd); +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rattach, lib9p_msg_Rattach); -#endif /* CONFIG_9P_ENABLE_9P2000_p9p */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown /* LIB9P_VER_9P2000 : min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */ -/* LIB9P_VER_9P2000_L : min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */ /* LIB9P_VER_9P2000_e : min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */ /* LIB9P_VER_9P2000_p9p: min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */ /* LIB9P_VER_9P2000_u : min_size = 13 ; exp_size = 40 ; max_size = 65,548 ; max_iov = 3 ; max_copy = 13 */ +/* LIB9P_VER_unknown : min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */ struct lib9p_msg_Rerror { lib9p_tag_t tag; - struct lib9p_s ename; + struct lib9p_s errstr; #if CONFIG_9P_ENABLE_9P2000_u - lib9p_errno_t errno; + lib9p_errno_t errnum; #endif /* CONFIG_9P_ENABLE_9P2000_u */ }; LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rerror, lib9p_msg_Rerror); -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000_L -/* size = 11 ; max_iov = 1 ; max_copy = 11 */ -struct lib9p_msg_Rlerror { - lib9p_tag_t tag; - lib9p_errno_t ecode; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rlerror, lib9p_msg_Rlerror); - -/* size = 67 ; max_iov = 1 ; max_copy = 67 */ -struct lib9p_msg_Rstatfs { - lib9p_tag_t tag; - lib9p_super_magic_t type; - uint32_t bsize; - uint64_t blocks; - uint64_t bfree; - uint64_t bavail; - uint64_t files; - uint64_t ffree; - uint64_t fsid; - uint32_t namelen; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rstatfs, lib9p_msg_Rstatfs); - -/* size = 15 ; max_iov = 1 ; max_copy = 15 */ -struct lib9p_msg_Tlopen { - lib9p_tag_t tag; - lib9p_fid_t fid; - lib9p_lo_t flags; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tlopen, lib9p_msg_Tlopen); - -/* min_size = 25 ; exp_size = 52 ; max_size = 65,560 ; max_iov = 3 ; max_copy = 25 */ -struct lib9p_msg_Tlcreate { +#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_unknown */ +#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u +/* min_size = 17 ; exp_size = 481 ; max_size = 1,048,609 ; max_iov = 32 ; max_copy = 49 */ +struct lib9p_msg_Twalk { lib9p_tag_t tag; lib9p_fid_t fid; - struct lib9p_s name; - lib9p_lo_t flags; - lib9p_mode_t mode; - lib9p_nuid_t gid; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tlcreate, lib9p_msg_Tlcreate); - -/* min_size = 29 ; exp_size = 56 ; max_size = 65,564 ; max_iov = 3 ; max_copy = 29 */ -struct lib9p_msg_Tmknod { - lib9p_tag_t tag; - lib9p_fid_t dfid; - struct lib9p_s name; - lib9p_mode_t mode; - uint32_t major; - uint32_t minor; - lib9p_nuid_t gid; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tmknod, lib9p_msg_Tmknod); - -/* min_size = 21 ; exp_size = 48 ; max_size = 65,556 ; max_iov = 3 ; max_copy = 21 */ -struct lib9p_msg_Tmkdir { - lib9p_tag_t tag; - lib9p_fid_t dfid; - struct lib9p_s name; - lib9p_mode_t mode; - lib9p_nuid_t gid; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tmkdir, lib9p_msg_Tmkdir); - -/* size = 15 ; max_iov = 1 ; max_copy = 15 */ -struct lib9p_msg_Tfsync { - lib9p_tag_t tag; - lib9p_fid_t fid; - lib9p_b4_t datasync; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tfsync, lib9p_msg_Tfsync); - -/* size = 19 ; max_iov = 1 ; max_copy = 19 */ -struct lib9p_msg_Tgetattr { - lib9p_tag_t tag; - lib9p_fid_t fid; - lib9p_getattr_t request_mask; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tgetattr, lib9p_msg_Tgetattr); - -/* size = 67 ; max_iov = 1 ; max_copy = 67 */ -struct lib9p_msg_Tsetattr { - lib9p_tag_t tag; - lib9p_fid_t fid; - lib9p_setattr_t valid; - lib9p_mode_t mode; - lib9p_nuid_t uid; - lib9p_nuid_t gid; - uint64_t filesize; - uint64_t atime_sec; - uint64_t atime_nsec; - uint64_t mtime_sec; - uint64_t mtime_nsec; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tsetattr, lib9p_msg_Tsetattr); - -/* min_size = 34 ; exp_size = 61 ; max_size = 65,569 ; max_iov = 2 ; max_copy = 34 */ -struct lib9p_msg_Tgetlock { - lib9p_tag_t tag; - lib9p_fid_t fid; - lib9p_lock_type_t type; - uint64_t start; - uint64_t length; - uint32_t proc_id; - struct lib9p_s client_id; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tgetlock, lib9p_msg_Tgetlock); - -/* min_size = 30 ; exp_size = 57 ; max_size = 65,565 ; max_iov = 2 ; max_copy = 30 */ -struct lib9p_msg_Rgetlock { - lib9p_tag_t tag; - lib9p_lock_type_t type; - uint64_t start; - uint64_t length; - uint32_t proc_id; - struct lib9p_s client_id; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rgetlock, lib9p_msg_Rgetlock); - -/* min_size = 38 ; exp_size = 65 ; max_size = 65,573 ; max_iov = 2 ; max_copy = 38 */ -struct lib9p_msg_Tlock { - lib9p_tag_t tag; - lib9p_fid_t fid; - lib9p_lock_type_t type; - lib9p_lock_flags_t flags; - uint64_t start; - uint64_t length; - uint32_t proc_id; - struct lib9p_s client_id; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tlock, lib9p_msg_Tlock); - -/* size = 8 ; max_iov = 1 ; max_copy = 8 */ -struct lib9p_msg_Rlock { - lib9p_tag_t tag; - lib9p_lock_status_t status; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rlock, lib9p_msg_Rlock); - -#endif /* CONFIG_9P_ENABLE_9P2000_L */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -/* LIB9P_VER_9P2000 : min_size = 49 ; exp_size = 157 ; max_size = 262,189 ; max_iov = 8 ; max_copy = 49 */ -/* LIB9P_VER_9P2000_e : min_size = 49 ; exp_size = 157 ; max_size = 262,189 ; max_iov = 8 ; max_copy = 49 */ -/* LIB9P_VER_9P2000_p9p: min_size = 49 ; exp_size = 157 ; max_size = 262,189 ; max_iov = 8 ; max_copy = 49 */ -/* LIB9P_VER_9P2000_u : min_size = 63 ; exp_size = 198 ; max_size = 327,738 ; max_iov = 11 ; max_copy = 63 */ -struct lib9p_stat { - uint16_t kern_type; - uint32_t kern_dev; - struct lib9p_qid file_qid; - lib9p_dm_t file_mode; - uint32_t file_atime; - uint32_t file_mtime; - uint64_t file_size; - struct lib9p_s file_name; - struct lib9p_s file_owner_uid; - struct lib9p_s file_owner_gid; - struct lib9p_s file_last_modified_uid; -#if CONFIG_9P_ENABLE_9P2000_u - struct lib9p_s file_extension; - lib9p_nuid_t file_owner_n_uid; - lib9p_nuid_t file_owner_n_gid; - lib9p_nuid_t file_last_modified_n_uid; -#endif /* CONFIG_9P_ENABLE_9P2000_u */ -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_stat, lib9p_stat); - -#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */ -#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u -/* size = 20 ; max_iov = 1 ; max_copy = 20 */ -struct lib9p_msg_Rauth { - lib9p_tag_t tag; - struct lib9p_qid aqid; -}; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rauth, lib9p_msg_Rauth); - -/* size = 20 ; max_iov = 1 ; max_copy = 20 */ -struct lib9p_msg_Rattach { - lib9p_tag_t tag; - struct lib9p_qid qid; + lib9p_fid_t newfid; + uint16_t nwname; + struct lib9p_s *wname; }; -LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rattach, lib9p_msg_Rattach); +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Twalk, lib9p_msg_Twalk); /* min_size = 9 ; exp_size = 217 ; max_size = 217 ; max_iov = 1 ; max_copy = 217 */ struct lib9p_msg_Rwalk { @@ -1183,6 +1142,16 @@ struct lib9p_msg_Ropen { }; LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Ropen, lib9p_msg_Ropen); +/* min_size = 18 ; exp_size = 45 ; max_size = 65,553 ; max_iov = 3 ; max_copy = 18 */ +struct lib9p_msg_Tcreate { + lib9p_tag_t tag; + lib9p_fid_t fid; + struct lib9p_s name; + lib9p_dm_t perm; + lib9p_o_t mode; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tcreate, lib9p_msg_Tcreate); + /* size = 24 ; max_iov = 1 ; max_copy = 24 */ struct lib9p_msg_Rcreate { lib9p_tag_t tag; @@ -1212,6 +1181,17 @@ struct lib9p_msg_Rlopen { }; LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rlopen, lib9p_msg_Rlopen); +/* min_size = 25 ; exp_size = 52 ; max_size = 65,560 ; max_iov = 3 ; max_copy = 25 */ +struct lib9p_msg_Tlcreate { + lib9p_tag_t tag; + lib9p_fid_t fid; + struct lib9p_s name; + lib9p_lo_t flags; + lib9p_mode_t mode; + lib9p_nuid_t gid; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tlcreate, lib9p_msg_Tlcreate); + /* size = 24 ; max_iov = 1 ; max_copy = 24 */ struct lib9p_msg_Rlcreate { lib9p_tag_t tag; @@ -1220,6 +1200,16 @@ struct lib9p_msg_Rlcreate { }; LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rlcreate, lib9p_msg_Rlcreate); +/* min_size = 19 ; exp_size = 73 ; max_size = 131,089 ; max_iov = 5 ; max_copy = 19 */ +struct lib9p_msg_Tsymlink { + lib9p_tag_t tag; + lib9p_fid_t fid; + struct lib9p_s name; + struct lib9p_s symtgt; + lib9p_nuid_t gid; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tsymlink, lib9p_msg_Tsymlink); + /* size = 20 ; max_iov = 1 ; max_copy = 20 */ struct lib9p_msg_Rsymlink { lib9p_tag_t tag; @@ -1227,6 +1217,18 @@ struct lib9p_msg_Rsymlink { }; LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rsymlink, lib9p_msg_Rsymlink); +/* min_size = 29 ; exp_size = 56 ; max_size = 65,564 ; max_iov = 3 ; max_copy = 29 */ +struct lib9p_msg_Tmknod { + lib9p_tag_t tag; + lib9p_fid_t dfid; + struct lib9p_s name; + lib9p_mode_t mode; + uint32_t major; + uint32_t minor; + lib9p_nuid_t gid; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tmknod, lib9p_msg_Tmknod); + /* size = 20 ; max_iov = 1 ; max_copy = 20 */ struct lib9p_msg_Rmknod { lib9p_tag_t tag; @@ -1234,6 +1236,22 @@ struct lib9p_msg_Rmknod { }; LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rmknod, lib9p_msg_Rmknod); +/* min_size = 17 ; exp_size = 44 ; max_size = 65,552 ; max_iov = 2 ; max_copy = 17 */ +struct lib9p_msg_Trename { + lib9p_tag_t tag; + lib9p_fid_t fid; + lib9p_fid_t dfid; + struct lib9p_s name; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Trename, lib9p_msg_Trename); + +/* min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */ +struct lib9p_msg_Rreadlink { + lib9p_tag_t tag; + struct lib9p_s target; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rreadlink, lib9p_msg_Rreadlink); + /* size = 160 ; max_iov = 1 ; max_copy = 160 */ struct lib9p_msg_Rgetattr { lib9p_tag_t tag; @@ -1260,6 +1278,80 @@ struct lib9p_msg_Rgetattr { }; LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rgetattr, lib9p_msg_Rgetattr); +/* min_size = 17 ; exp_size = 44 ; max_size = 65,552 ; max_iov = 2 ; max_copy = 17 */ +struct lib9p_msg_Txattrwalk { + lib9p_tag_t tag; + lib9p_fid_t fid; + lib9p_fid_t newfid; + struct lib9p_s name; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Txattrwalk, lib9p_msg_Txattrwalk); + +/* min_size = 25 ; exp_size = 52 ; max_size = 65,560 ; max_iov = 3 ; max_copy = 25 */ +struct lib9p_msg_Txattrcreate { + lib9p_tag_t tag; + lib9p_fid_t fid; + struct lib9p_s name; + uint64_t attr_size; + uint32_t flags; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Txattrcreate, lib9p_msg_Txattrcreate); + +/* min_size = 38 ; exp_size = 65 ; max_size = 65,573 ; max_iov = 2 ; max_copy = 38 */ +struct lib9p_msg_Tlock { + lib9p_tag_t tag; + lib9p_fid_t fid; + lib9p_lock_type_t type; + lib9p_lock_flags_t flags; + uint64_t start; + uint64_t length; + uint32_t proc_id; + struct lib9p_s client_id; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tlock, lib9p_msg_Tlock); + +/* min_size = 34 ; exp_size = 61 ; max_size = 65,569 ; max_iov = 2 ; max_copy = 34 */ +struct lib9p_msg_Tgetlock { + lib9p_tag_t tag; + lib9p_fid_t fid; + lib9p_lock_type_t type; + uint64_t start; + uint64_t length; + uint32_t proc_id; + struct lib9p_s client_id; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tgetlock, lib9p_msg_Tgetlock); + +/* min_size = 30 ; exp_size = 57 ; max_size = 65,565 ; max_iov = 2 ; max_copy = 30 */ +struct lib9p_msg_Rgetlock { + lib9p_tag_t tag; + lib9p_lock_type_t type; + uint64_t start; + uint64_t length; + uint32_t proc_id; + struct lib9p_s client_id; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rgetlock, lib9p_msg_Rgetlock); + +/* min_size = 17 ; exp_size = 44 ; max_size = 65,552 ; max_iov = 2 ; max_copy = 17 */ +struct lib9p_msg_Tlink { + lib9p_tag_t tag; + lib9p_fid_t dfid; + lib9p_fid_t fid; + struct lib9p_s name; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tlink, lib9p_msg_Tlink); + +/* min_size = 21 ; exp_size = 48 ; max_size = 65,556 ; max_iov = 3 ; max_copy = 21 */ +struct lib9p_msg_Tmkdir { + lib9p_tag_t tag; + lib9p_fid_t dfid; + struct lib9p_s name; + lib9p_mode_t mode; + lib9p_nuid_t gid; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tmkdir, lib9p_msg_Tmkdir); + /* size = 20 ; max_iov = 1 ; max_copy = 20 */ struct lib9p_msg_Rmkdir { lib9p_tag_t tag; @@ -1267,7 +1359,48 @@ struct lib9p_msg_Rmkdir { }; LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rmkdir, lib9p_msg_Rmkdir); +/* min_size = 19 ; exp_size = 73 ; max_size = 131,089 ; max_iov = 4 ; max_copy = 19 */ +struct lib9p_msg_Trenameat { + lib9p_tag_t tag; + lib9p_fid_t olddirfid; + struct lib9p_s oldname; + lib9p_fid_t newdirfid; + struct lib9p_s newname; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Trenameat, lib9p_msg_Trenameat); + +/* min_size = 17 ; exp_size = 44 ; max_size = 65,552 ; max_iov = 3 ; max_copy = 17 */ +struct lib9p_msg_Tunlinkat { + lib9p_tag_t tag; + lib9p_fid_t dirfd; + struct lib9p_s name; + uint32_t flags; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tunlinkat, lib9p_msg_Tunlinkat); + #endif /* CONFIG_9P_ENABLE_9P2000_L */ +#if CONFIG_9P_ENABLE_9P2000_e +/* min_size = 13 ; exp_size = 477 ; max_size = 4,294,967,308 (warning: >UINT32_MAX) ; max_iov = 0 + (CONFIG_9P_MAX_9P2000_e_WELEM * 2) ; max_copy = 13 + (CONFIG_9P_MAX_9P2000_e_WELEM * 2) */ +struct lib9p_msg_Tsread { + lib9p_tag_t tag; + uint32_t fid; + uint16_t nwname; + struct lib9p_s *wname; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tsread, lib9p_msg_Tsread); + +/* min_size = 17 ; exp_size = 8,673 ; max_size = 8,589,934,607 (warning: >UINT32_MAX) ; max_iov = 2 + (CONFIG_9P_MAX_9P2000_e_WELEM * 2) ; max_copy = 17 + (CONFIG_9P_MAX_9P2000_e_WELEM * 2) */ +struct lib9p_msg_Tswrite { + lib9p_tag_t tag; + uint32_t fid; + uint16_t nwname; + struct lib9p_s *wname; + uint32_t count; + [[gnu::nonstring]] char *data; +}; +LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tswrite, lib9p_msg_Tswrite); + +#endif /* CONFIG_9P_ENABLE_9P2000_e */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u /* LIB9P_VER_9P2000 : min_size = 58 ; exp_size = 166 ; max_size = 262,198 ; max_iov = 8 ; max_copy = 58 */ /* LIB9P_VER_9P2000_e : min_size = 58 ; exp_size = 166 ; max_size = 262,198 ; max_iov = 8 ; max_copy = 58 */ @@ -1301,6 +1434,8 @@ LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Twstat, lib9p_msg_Twstat); #else #define LIB9P_TMSG_MAX_IOV 32 #endif +#elif CONFIG_9P_ENABLE_unknown + #define LIB9P_TMSG_MAX_IOV 2 #endif #if CONFIG_9P_ENABLE_9P2000_u @@ -1321,18 +1456,22 @@ LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Twstat, lib9p_msg_Twstat); #else #define LIB9P_TMSG_MAX_COPY 62 #endif +#elif CONFIG_9P_ENABLE_unknown + #define LIB9P_TMSG_MAX_COPY 13 #endif #if CONFIG_9P_ENABLE_9P2000_u #define LIB9P_RMSG_MAX_IOV 11 #elif CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p #define LIB9P_RMSG_MAX_IOV 8 -#elif CONFIG_9P_ENABLE_9P2000_L +#elif CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_unknown #define LIB9P_RMSG_MAX_IOV 2 #endif #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u #define LIB9P_RMSG_MAX_COPY 217 +#elif CONFIG_9P_ENABLE_unknown + #define LIB9P_RMSG_MAX_COPY 13 #endif struct lib9p_Tmsg_send_buf { diff --git a/lib9p/include/lib9p/9p.h b/lib9p/core_include/lib9p/core.h index 5919260..38f3934 100644 --- a/lib9p/include/lib9p/9p.h +++ b/lib9p/core_include/lib9p/core.h @@ -1,19 +1,19 @@ -/* lib9p/9p.h - Base 9P protocol definitions for both clients and servers +/* lib9p/core.h - Base 9P protocol definitions for both clients and servers * * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later */ -#ifndef _LIB9P_9P_H_ -#define _LIB9P_9P_H_ +#ifndef _LIB9P_CORE_H_ +#define _LIB9P_CORE_H_ #include <stdbool.h> #include <sys/types.h> /* for ssize_t */ #include <libmisc/assert.h> -#include <lib9p/linux-errno.h> -#include <lib9p/9p.generated.h> +#define CONFIG_9P_ENABLE_unknown 1 +#include <lib9p/_core_generated.h> #ifndef CONFIG_9P_MAX_ERR_SIZE #error config.h must define CONFIG_9P_MAX_ERR_SIZE @@ -46,7 +46,7 @@ struct lib9p_ctx { uint32_t max_msg_size; /* state */ -#ifdef CONFIG_9P_ENABLE_9P2000_u +#if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L lib9p_errno_t err_num; #endif [[gnu::nonstring]] char err_msg[CONFIG_9P_MAX_ERR_SIZE]; @@ -57,9 +57,31 @@ void lib9p_ctx_clear_error(struct lib9p_ctx *ctx); bool lib9p_ctx_has_error(struct lib9p_ctx *ctx); /** Write an static error into ctx, return -1. */ -int lib9p_error(struct lib9p_ctx *ctx, lib9p_errno_t linux_errno, char const *msg); +int lib9p_error(struct lib9p_ctx *ctx, +#if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L + lib9p_errno_t linux_errno, +#endif + char const *msg); /** Write a printf-style error into ctx, return -1. */ -int lib9p_errorf(struct lib9p_ctx *ctx, lib9p_errno_t linux_errno, char const *fmt, ...) [[gnu::format(printf, 3, 4)]]; +int lib9p_errorf(struct lib9p_ctx *ctx, +#if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L + lib9p_errno_t linux_errno, +#endif + char const *fmt, ...) +#if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L + [[gnu::format(printf, 3, 4)]] +#else + [[gnu::format(printf, 2, 3)]] +#endif + ; + +#if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L +/* Detect things that should be just lib9p_error() */ +#define lib9p_errorf(ctx, errnum, fmt, ...) lib9p_errorf(ctx, errnum, fmt, __VA_ARGS__) +#else +#define lib9p_errorf(ctx, errnum, fmt, ...) lib9p_errorf(ctx, fmt, __VA_ARGS__) +#define lib9p_error(ctx, errnum, errmsg) lib9p_error(ctx, errmsg) +#endif /* misc utilities *************************************************************/ @@ -86,12 +108,12 @@ lo_interface fmt_formatter lo_box_lib9p_msg_as_fmt_formatter(struct lib9p_ctx *c * * @return required size, or -1 on error * - * @errno LINUX_EOPNOTSUPP: message is an R-message - * @errno LINUX_EOPNOTSUPP: message has unknown type - * @errno LINUX_EBADMSG: message is wrong size for content - * @errno LINUX_EBADMSG: message contains invalid UTF-8 - * @errno LINUX_EBADMSG: message contains a bitfield with unknown bits - * @errno LINUX_EMSGSIZE: would-be return value overflows SSIZE_MAX + * @errno L_EOPNOTSUPP: message is an R-message + * @errno L_EOPNOTSUPP: message has unknown type + * @errno L_EBADMSG: message is wrong size for content + * @errno L_EBADMSG: message contains invalid UTF-8 + * @errno L_EBADMSG: message contains a bitfield with unknown bits + * @errno L_EMSGSIZE: would-be return value overflows SSIZE_MAX */ ssize_t lib9p_Tmsg_validate(struct lib9p_ctx *ctx, uint8_t *net_bytes); @@ -126,7 +148,7 @@ void lib9p_Tmsg_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes, * @return ret_bytes : the buffer to encode to, must be at be at least ctx->max_msg_size bytes * @return whether there was an error (false=success, true=error) * - * @errno LINUX_ERANGE: reply does not fit in ctx->max_msg_size + * @errno L_ERANGE: reply does not fit in ctx->max_msg_size */ bool lib9p_Tmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body, struct lib9p_Tmsg_send_buf *ret); @@ -144,16 +166,7 @@ bool lib9p_Rmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *bo /* `struct lib9p_stat` helpers ************************************************/ -/** Assert that a `struct lib9p_stat` object looks valid. */ -static inline void lib9p_stat_assert(struct lib9p_stat stat) { - assert( ((bool)(stat.file_mode & LIB9P_DM_DIR )) == ((bool)(stat.file_qid.type & LIB9P_QT_DIR )) ); - assert( ((bool)(stat.file_mode & LIB9P_DM_APPEND)) == ((bool)(stat.file_qid.type & LIB9P_QT_APPEND)) ); - assert( ((bool)(stat.file_mode & LIB9P_DM_EXCL )) == ((bool)(stat.file_qid.type & LIB9P_QT_EXCL )) ); - assert( ((bool)(stat.file_mode & LIB9P_DM_AUTH )) == ((bool)(stat.file_qid.type & LIB9P_QT_AUTH )) ); - assert( ((bool)(stat.file_mode & LIB9P_DM_TMP )) == ((bool)(stat.file_qid.type & LIB9P_QT_TMP )) ); - assert( (stat.file_size == 0) || !(stat.file_mode & LIB9P_DM_DIR) ); -} - +#if _LIB9P_ENABLE_stat /** * Validate a message's `stat` structure. * @@ -166,7 +179,7 @@ static inline void lib9p_stat_assert(struct lib9p_stat stat) { * @return whether there was an error */ bool lib9p_stat_validate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes, - uint32_t *ret_net_size, ssize_t *ret_host_size); + uint32_t *ret_net_size, size_t *ret_host_size); /** * Unmarshal the 9P `net_bytes` into the C struct `ret_obj`. @@ -198,9 +211,10 @@ void lib9p_stat_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes, * @return ret_bytes: the buffer to encode into * @return the number of bytes written, or 0 if the stat object does not fit in max_net_size * - * @errno LINUX_ERANGE: reply does not fit in max_net_size + * @errno L_ERANGE: reply does not fit in max_net_size */ uint32_t lib9p_stat_marshal(struct lib9p_ctx *ctx, uint32_t max_net_size, struct lib9p_stat *obj, uint8_t *ret_bytes); +#endif -#endif /* _LIB9P_9P_H_ */ +#endif /* _LIB9P_CORE_H_ */ diff --git a/lib9p/tables.c b/lib9p/core_tables.c index 271b17b..bc452c7 100644 --- a/lib9p/tables.c +++ b/lib9p/core_tables.c @@ -1,4 +1,4 @@ -/* lib9p/tables.c - Access tables of version and message information +/* lib9p/core_tables.c - Access tables of version and message information * * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later @@ -9,7 +9,7 @@ #include <libmisc/endian.h> #include <libmisc/log.h> /* for const_byte_str() */ -#include "tables.h" +#include "core_tables.h" /* bounds checks **************************************************************/ @@ -64,14 +64,14 @@ ssize_t _lib9p_validate(uint8_t xxx_low_typ_bit, /* Inspect the first 5 bytes ourselves. */ uint32_t net_size = uint32le_decode(net_bytes); if (net_size < 5) - return lib9p_error(ctx, LINUX_EBADMSG, "message is impossibly short"); + return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "message is impossibly short"); uint8_t typ = net_bytes[4]; if (typ % 2 != xxx_low_typ_bit) - return lib9p_errorf(ctx, LINUX_EOPNOTSUPP, "%s: message_type=%s", xxx_errmsg, + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EOPNOTSUPP, "%s: message_type=%s", xxx_errmsg, lib9p_msgtype_str(ctx->version, typ)); struct _lib9p_recv_tentry tentry = xxx_table[ctx->version][typ/2]; if (!tentry.validate) - return lib9p_errorf(ctx, LINUX_EOPNOTSUPP, "unknown message type: %s (protocol_version=%s)", + return lib9p_errorf(ctx, LIB9P_ERRNO_L_EOPNOTSUPP, "unknown message type: %s (protocol_version=%s)", lib9p_msgtype_str(ctx->version, typ), lib9p_version_str(ctx->version)); /* Now use the message-type-specific tentry to process the whole thing. */ @@ -96,6 +96,7 @@ void _lib9p_unmarshal(const struct _lib9p_recv_tentry xxx_table[LIB9P_VER_NUM][0 enum lib9p_msg_type typ = net_bytes[4]; *ret_typ = typ; struct _lib9p_recv_tentry tentry = xxx_table[ctx->version][typ/2]; + assert(tentry.unmarshal); tentry.unmarshal(ctx, net_bytes, ret_body); } @@ -124,8 +125,9 @@ bool _lib9p_marshal(const struct _lib9p_send_tentry xxx_table[LIB9P_VER_NUM][0x8 .net_copied_size = 0, .net_copied = ret_copied, }; - struct _lib9p_send_tentry tentry = xxx_table[ctx->version][typ/2]; + assert(tentry.marshal); + bool ret_erred = tentry.marshal(ctx, body, &ret); if (ret_iov[ret.net_iov_cnt-1].iov_len == 0) ret.net_iov_cnt--; @@ -153,13 +155,14 @@ bool lib9p_Rmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *bo /* `struct lib9p_stat` helpers ************************************************/ +#if _LIB9P_ENABLE_stat bool lib9p_stat_validate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes, - uint32_t *ret_net_size, ssize_t *ret_host_size) { + uint32_t *ret_net_size, size_t *ret_host_size) { ssize_t host_size = _lib9p_stat_validate(ctx, net_size, net_bytes, ret_net_size); if (host_size < 0) return true; if (ret_host_size) - *ret_host_size = host_size; + *ret_host_size = (size_t)host_size; return false; } @@ -184,3 +187,4 @@ uint32_t lib9p_stat_marshal(struct lib9p_ctx *ctx, uint32_t max_net_size, struct return 0; return ret.net_iov[0].iov_len; } +#endif diff --git a/lib9p/tables.h b/lib9p/core_tables.h index edb402a..17e9398 100644 --- a/lib9p/tables.h +++ b/lib9p/core_tables.h @@ -1,13 +1,13 @@ -/* lib9p/tables.h - Declare tables of version and message information +/* lib9p/core_tables.h - Declare tables of version and message information * * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later */ -#ifndef _LIB9P_TABLES_H_ -#define _LIB9P_TABLES_H_ +#ifndef _LIB9P_CORE_TABLES_H_ +#define _LIB9P_CORE_TABLES_H_ -#include <lib9p/9p.h> +#include <lib9p/core.h> /* version ********************************************************************/ @@ -52,8 +52,10 @@ extern const struct _lib9p_send_tentry _lib9p_table_Rmsg_send[LIB9P_VER_NUM][0x8 /* stat ***********************************************************************/ +#if _LIB9P_ENABLE_stat ssize_t _lib9p_stat_validate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes, uint32_t *ret_net_size); void _lib9p_stat_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out); bool _lib9p_stat_marshal(struct lib9p_ctx *ctx, struct lib9p_stat *val, struct _marshal_ret *ret); +#endif -#endif /* _LIB9P_TABLES_H_ */ +#endif /* _LIB9P_CORE_TABLES_H_ */ diff --git a/lib9p/utf8.h b/lib9p/core_utf8.h index 5ffd674..636d4eb 100644 --- a/lib9p/utf8.h +++ b/lib9p/core_utf8.h @@ -1,11 +1,11 @@ -/* lib9p/utf8.h - Internal UTF-8 validation +/* lib9p/core_utf8.h - Internal UTF-8 validation * * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later */ -#ifndef _LIB9P_UTF8_H_ -#define _LIB9P_UTF8_H_ +#ifndef _LIB9P_CORE_UTF8_H_ +#define _LIB9P_CORE_UTF8_H_ static inline bool _is_valid_utf8(uint8_t *str, size_t len, bool forbid_nul) { uint32_t ch; @@ -31,4 +31,4 @@ static inline bool _is_valid_utf8(uint8_t *str, size_t len, bool forbid_nul) { #define is_valid_utf8(str, len) _is_valid_utf8(str, len, false) #define is_valid_utf8_without_nul(str, len) _is_valid_utf8(str, len, true) -#endif /* _LIB9P_UTF8_H_ */ +#endif /* _LIB9P_CORE_UTF8_H_ */ diff --git a/lib9p/idl/0000-uninitialized.9p b/lib9p/idl/0000-uninitialized.9p new file mode 100644 index 0000000..9319b5e --- /dev/null +++ b/lib9p/idl/0000-uninitialized.9p @@ -0,0 +1,13 @@ +# lib9p/idl/0000-uninitialized.9p - Defs for bootstrapping +# +# Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com> +# SPDX-License-Identifier: AGPL-3.0-or-later + +version "unknown" + +# For the actual protocol. +from ./2002-9P2000.9p import s, tag +from ./2002-9P2000.9p import Tversion, Rversion, Rerror + +# For srv.h +from ./2002-9P2000.9p import dm, qt, qid, fid diff --git a/lib9p/idl/1992-9P0.9p.wip b/lib9p/idl/1992-9P0.9p.wip index a434ba2..c9432c9 100644 --- a/lib9p/idl/1992-9P0.9p.wip +++ b/lib9p/idl/1992-9P0.9p.wip @@ -107,7 +107,7 @@ msg Rnop = "typ[1,val=51] tag[tag,val=0xFFFF]" msg Tsession = "typ[1,val=52] tag[tag,val=0xFFFF]" msg Rsession = "typ[1,val=53] tag[tag,val=0xFFFF]" #msg Terror = "typ[1,val=54] illegal" -msg Rerror = "typ[1,val=55] tag[tag] ename[errstr]" +msg Rerror = "typ[1,val=55] tag[tag] errstr[errstr]" msg Tflush = "typ[1,val=56] tag[tag] oldtag[tag]" msg Rflush = "typ[1,val=57] tag[tag]" msg Tattach = "typ[1,val=58] tag[tag] fid[fid] uid[name] aname[name] auth[auth_ticket] 13*(pad[1])" # Pad to allow auth_tickets up to 28 bytes. diff --git a/lib9p/idl/1996-Styx.9p.wip b/lib9p/idl/1996-Styx.9p.wip index 3cb3774..143be83 100644 --- a/lib9p/idl/1996-Styx.9p.wip +++ b/lib9p/idl/1996-Styx.9p.wip @@ -28,7 +28,7 @@ from ./1992-9P1.9p import tag, fid, qid, name, errstr, o, ch, stat msg Tnop = "typ[1,val=0] tag[tag,val=0xFFFF]" msg Rnop = "typ[1,val=1] tag[tag,val=0xFFFF]" #msg Terror = "typ[1,val=2] illegal" -msg Rerror = "typ[1,val=3] tag[tag] ename[errstr]" +msg Rerror = "typ[1,val=3] tag[tag] errstr[errstr]" msg Tflush = "typ[1,val=4] tag[tag] oldtag[tag]" msg Rflush = "typ[1,val=5] tag[tag]" msg Tclone = "typ[1,val=6] tag[tag] fid[fid] newfid[fid]" diff --git a/lib9p/idl/2002-9P2000.9p b/lib9p/idl/2002-9P2000.9p index 2b51612..712ffea 100644 --- a/lib9p/idl/2002-9P2000.9p +++ b/lib9p/idl/2002-9P2000.9p @@ -91,18 +91,26 @@ bitfield qt = 1 struct qid = "type[qt] vers[4] path[8]" # stat - file status -struct stat = "stat_size[2,val=end-&kern_type]" - "kern_type[2]" - "kern_dev[4]" - "file_qid[qid]" - "file_mode[dm]" - "file_atime[4]" - "file_mtime[4]" - "file_size[8]" - "file_name[s]" - "file_owner_uid[s]" - "file_owner_gid[s]" - "file_last_modified_uid[s]" +struct stat = "_stat_size[2,val=end-&fstype]" + # fstype and fsdev are documented simply as "for kernel + # use". The are ignored by Plan 9's in-kernel 9P + # client; mntdirfix() overwrites them with fstype='M' + # and fsdev=nonce. Processes may observe values other + # than fstype='M', as 'M' is used for actual 9P servers, + # while other values are used for in-kernel device + # servers (such as '|' for pipes, or 'I' for the IP + # stack). + "fstype[2]" # filesystem type + "fsdev[4]" # filesystem instance/subtype + "qid[qid]" + "mode[dm]" + "atime[4]" + "mtime[4]" + "length[8]" # 0 for directories + "name[s]" + "owner_uname[s]" + "owner_gname[s]" + "last_modifier_uname[s]" # "O"pen flags (flags to pass to Topen and Tcreate) # Unused bits *must* be 0. @@ -137,7 +145,7 @@ msg Rauth = "size[4,val=end-&size] typ[1,val=103] tag[tag] aqid[qid]" msg Tattach = "size[4,val=end-&size] typ[1,val=104] tag[tag] fid[fid] afid[fid] uname[s] aname[s]" msg Rattach = "size[4,val=end-&size] typ[1,val=105] tag[tag] qid[qid]" #msg Terror = "size[4,val=end-&size] typ[1,val=106] tag[tag] illegal" -msg Rerror = "size[4,val=end-&size] typ[1,val=107] tag[tag] ename[s]" +msg Rerror = "size[4,val=end-&size] typ[1,val=107] tag[tag] errstr[s]" msg Tflush = "size[4,val=end-&size] typ[1,val=108] tag[tag] oldtag[2]" msg Rflush = "size[4,val=end-&size] typ[1,val=109] tag[tag]" msg Twalk = "size[4,val=end-&size] typ[1,val=110] tag[tag] fid[fid] newfid[fid] nwname[2,max=16] nwname*(wname[s])" diff --git a/lib9p/idl/2003-9P2000.p9p.9p b/lib9p/idl/2003-9P2000.p9p.9p index 3f6a524..1d1c307 100644 --- a/lib9p/idl/2003-9P2000.p9p.9p +++ b/lib9p/idl/2003-9P2000.p9p.9p @@ -27,7 +27,7 @@ from ./2002-9P2000.9p import * # e.g. you replace syscall:`open()` with lib9pclient:`fsopen()`). # # "Unfortunately", programs in plan9port must deal both with 9P files -# and native "Unix" files; and need to turn an 9P FID into a native +# and native "Unix" files; and need to turn a 9P FID into a native # file descriptor. To do this, the `9pserve` program and lib9pclient # add an extension call to 9P2000: Topenfd/Ropenfd/fsopenfd(). # diff --git a/lib9p/idl/2005-9P2000.u.9p b/lib9p/idl/2005-9P2000.u.9p index 6c2f2dc..446385c 100644 --- a/lib9p/idl/2005-9P2000.u.9p +++ b/lib9p/idl/2005-9P2000.u.9p @@ -17,15 +17,15 @@ num nuid = 4 num errno = 4 "NOERROR = 0" -struct stat += "file_extension[s]" - "file_owner_n_uid[nuid]" - "file_owner_n_gid[nuid]" - "file_last_modified_n_uid[nuid]" +struct stat += "extension[s]" + "owner_unum[nuid]" + "owner_gnum[nuid]" + "last_modifier_unum[nuid]" -msg Tauth += "n_uid[nuid]" -msg Tattach += "n_uid[nuid]" +msg Tauth += "unum[nuid]" +msg Tattach += "unum[nuid]" -msg Rerror += "errno[errno]" +msg Rerror += "errnum[errno]" bitfield dm += "bit 23=DEVICE" "bit 21=PIPE" diff --git a/lib9p/idl/2010-9P2000.L.9p b/lib9p/idl/2010-9P2000.L.9p index d81a15b..5eb7d5c 100644 --- a/lib9p/idl/2010-9P2000.L.9p +++ b/lib9p/idl/2010-9P2000.L.9p @@ -1,3 +1,6 @@ +# lib9p/idl/2010-9P2000.L.9p - Generated by `lib9p/idl/2010-9P2000.L.9p.gen 3rd-party/linux-errno.txt`. DO NOT EDIT! +# 3rd-party/linux-errno.txt - Generated from lib9p/linux-errno.txt.gen and linux.git v6.14. DO NOT EDIT! + # lib9p/idl/2010-9P2000.L.9p - Definitions of 9P2000.L messages # # Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> @@ -8,12 +11,149 @@ # https://github.com/chaos/diod/blob/master/src/libnpfs/protocol.h version "9P2000.L" +# low-level types ############################################################## + from ./2002-9P2000.9p import tag, fid, s, qt, qid -from ./2002-9P2000.9p import Rerror -from ./2002-9P2000.9p import Tversion, Rversion, Tflush, Rflush, Twalk, Rwalk, Tread, Rread, Twrite, Rwrite, Tclunk, Rclunk, Tremove, Rremove -from ./2005-9P2000.u.9p import nuid, errno, Tauth, Rauth, Tattach, Rattach +from ./2005-9P2000.u.9p import nuid, errno -#num errno += # TODO +# BUG: The definitions of errno are not defined in the 9P2000.L +# protocol spec, and Linux kernel errno values vary by architecture. +# Most architectures share a "generic" list, but a handful (as of +# Linux v6.14, Alpha, MIPS, PA-RISC, PowerPC, and SPARC) have their +# own numbers. This IDL file lists the generic numbers. +# +# https://github.com/chaos/diod/issues/35 +num errno += "L_EPERM = 1" # Operation not permitted + "L_ENOENT = 2" # No such file or directory + "L_ESRCH = 3" # No such process + "L_EINTR = 4" # Interrupted system call + "L_EIO = 5" # I/O error + "L_ENXIO = 6" # No such device or address + "L_E2BIG = 7" # Argument list too long + "L_ENOEXEC = 8" # Exec format error + "L_EBADF = 9" # Bad file number + "L_ECHILD = 10" # No child processes + "L_EAGAIN = 11" # Try again + "L_ENOMEM = 12" # Out of memory + "L_EACCES = 13" # Permission denied + "L_EFAULT = 14" # Bad address + "L_ENOTBLK = 15" # Block device required + "L_EBUSY = 16" # Device or resource busy + "L_EEXIST = 17" # File exists + "L_EXDEV = 18" # Cross-device link + "L_ENODEV = 19" # No such device + "L_ENOTDIR = 20" # Not a directory + "L_EISDIR = 21" # Is a directory + "L_EINVAL = 22" # Invalid argument + "L_ENFILE = 23" # File table overflow + "L_EMFILE = 24" # Too many open files + "L_ENOTTY = 25" # Not a typewriter + "L_ETXTBSY = 26" # Text file busy + "L_EFBIG = 27" # File too large + "L_ENOSPC = 28" # No space left on device + "L_ESPIPE = 29" # Illegal seek + "L_EROFS = 30" # Read-only file system + "L_EMLINK = 31" # Too many links + "L_EPIPE = 32" # Broken pipe + "L_EDOM = 33" # Math argument out of domain of func + "L_ERANGE = 34" # Math result not representable + "L_EDEADLK = 35" # Resource deadlock would occur + "L_ENAMETOOLONG = 36" # File name too long + "L_ENOLCK = 37" # No record locks available + "L_ENOSYS = 38" # Invalid system call number + "L_ENOTEMPTY = 39" # Directory not empty + "L_ELOOP = 40" # Too many symbolic links encountered + "L_ENOMSG = 42" # No message of desired type + "L_EIDRM = 43" # Identifier removed + "L_ECHRNG = 44" # Channel number out of range + "L_EL2NSYNC = 45" # Level 2 not synchronized + "L_EL3HLT = 46" # Level 3 halted + "L_EL3RST = 47" # Level 3 reset + "L_ELNRNG = 48" # Link number out of range + "L_EUNATCH = 49" # Protocol driver not attached + "L_ENOCSI = 50" # No CSI structure available + "L_EL2HLT = 51" # Level 2 halted + "L_EBADE = 52" # Invalid exchange + "L_EBADR = 53" # Invalid request descriptor + "L_EXFULL = 54" # Exchange full + "L_ENOANO = 55" # No anode + "L_EBADRQC = 56" # Invalid request code + "L_EBADSLT = 57" # Invalid slot + "L_EBFONT = 59" # Bad font file format + "L_ENOSTR = 60" # Device not a stream + "L_ENODATA = 61" # No data available + "L_ETIME = 62" # Timer expired + "L_ENOSR = 63" # Out of streams resources + "L_ENONET = 64" # Machine is not on the network + "L_ENOPKG = 65" # Package not installed + "L_EREMOTE = 66" # Object is remote + "L_ENOLINK = 67" # Link has been severed + "L_EADV = 68" # Advertise error + "L_ESRMNT = 69" # Srmount error + "L_ECOMM = 70" # Communication error on send + "L_EPROTO = 71" # Protocol error + "L_EMULTIHOP = 72" # Multihop attempted + "L_EDOTDOT = 73" # RFS specific error + "L_EBADMSG = 74" # Not a data message + "L_EOVERFLOW = 75" # Value too large for defined data type + "L_ENOTUNIQ = 76" # Name not unique on network + "L_EBADFD = 77" # File descriptor in bad state + "L_EREMCHG = 78" # Remote address changed + "L_ELIBACC = 79" # Can not access a needed shared library + "L_ELIBBAD = 80" # Accessing a corrupted shared library + "L_ELIBSCN = 81" # .lib section in a.out corrupted + "L_ELIBMAX = 82" # Attempting to link in too many shared libraries + "L_ELIBEXEC = 83" # Cannot exec a shared library directly + "L_EILSEQ = 84" # Illegal byte sequence + "L_ERESTART = 85" # Interrupted system call should be restarted + "L_ESTRPIPE = 86" # Streams pipe error + "L_EUSERS = 87" # Too many users + "L_ENOTSOCK = 88" # Socket operation on non-socket + "L_EDESTADDRREQ = 89" # Destination address required + "L_EMSGSIZE = 90" # Message too long + "L_EPROTOTYPE = 91" # Protocol wrong type for socket + "L_ENOPROTOOPT = 92" # Protocol not available + "L_EPROTONOSUPPORT = 93" # Protocol not supported + "L_ESOCKTNOSUPPORT = 94" # Socket type not supported + "L_EOPNOTSUPP = 95" # Operation not supported on transport endpoint + "L_EPFNOSUPPORT = 96" # Protocol family not supported + "L_EAFNOSUPPORT = 97" # Address family not supported by protocol + "L_EADDRINUSE = 98" # Address already in use + "L_EADDRNOTAVAIL = 99" # Cannot assign requested address + "L_ENETDOWN = 100" # Network is down + "L_ENETUNREACH = 101" # Network is unreachable + "L_ENETRESET = 102" # Network dropped connection because of reset + "L_ECONNABORTED = 103" # Software caused connection abort + "L_ECONNRESET = 104" # Connection reset by peer + "L_ENOBUFS = 105" # No buffer space available + "L_EISCONN = 106" # Transport endpoint is already connected + "L_ENOTCONN = 107" # Transport endpoint is not connected + "L_ESHUTDOWN = 108" # Cannot send after transport endpoint shutdown + "L_ETOOMANYREFS = 109" # Too many references: cannot splice + "L_ETIMEDOUT = 110" # Connection timed out + "L_ECONNREFUSED = 111" # Connection refused + "L_EHOSTDOWN = 112" # Host is down + "L_EHOSTUNREACH = 113" # No route to host + "L_EALREADY = 114" # Operation already in progress + "L_EINPROGRESS = 115" # Operation now in progress + "L_ESTALE = 116" # Stale file handle + "L_EUCLEAN = 117" # Structure needs cleaning + "L_ENOTNAM = 118" # Not a XENIX named type file + "L_ENAVAIL = 119" # No XENIX semaphores available + "L_EISNAM = 120" # Is a named type file + "L_EREMOTEIO = 121" # Remote I/O error + "L_EDQUOT = 122" # Quota exceeded + "L_ENOMEDIUM = 123" # No medium found + "L_EMEDIUMTYPE = 124" # Wrong medium type + "L_ECANCELED = 125" # Operation Canceled + "L_ENOKEY = 126" # Required key not available + "L_EKEYEXPIRED = 127" # Key has expired + "L_EKEYREVOKED = 128" # Key has been revoked + "L_EKEYREJECTED = 129" # Key was rejected by service + "L_EOWNERDEAD = 130" # Owner died + "L_ENOTRECOVERABLE = 131" # State not recoverable + "L_ERFKILL = 132" # Operation not possible due to RF-kill + "L_EHWPOISON = 133" # Memory page has hardware error num super_magic = 4 # See <linux/magic.h> (linux.git include/uapi/linux/magic.h). @@ -168,8 +308,23 @@ num lock_status = 1 "ERROR=2" "GRACE=3" +# 9P2000 Operations (.L subset) ################################################ + +from ./2002-9P2000.9p import Tversion, Rversion +from ./2002-9P2000.9p import Tflush, Rflush +from ./2002-9P2000.9p import Twalk, Rwalk +from ./2002-9P2000.9p import Tread, Rread, Twrite, Rwrite +from ./2002-9P2000.9p import Tclunk, Rclunk +from ./2002-9P2000.9p import Tremove, Rremove + +# 9P2000.u Operations (.L subset) ############################################## + +from ./2005-9P2000.u.9p import Tattach, Rattach, Tauth, Rauth + +# 9P2000.L Operations ########################################################## + #msg Tlerror = "size[4,val=end-&size] typ[1,val=6] tag[tag] illegal" # analogous to 106/Terror -msg Rlerror = "size[4,val=end-&size] typ[1,val=7] tag[tag] ecode[errno]" # analogous to 107/Rerror +msg Rlerror = "size[4,val=end-&size] typ[1,val=7] tag[tag] errnum[errno]" # analogous to 107/Rerror msg Tstatfs = "size[4,val=end-&size] typ[1,val=8] tag[tag] fid[fid]" msg Rstatfs = "size[4,val=end-&size] typ[1,val=9] tag[tag]" # Description | statfs | statvfs "type[super_magic]" # Type of filesystem | f_type | - diff --git a/lib9p/idl/2010-9P2000.L.9p.gen b/lib9p/idl/2010-9P2000.L.9p.gen new file mode 100755 index 0000000..cb32585 --- /dev/null +++ b/lib9p/idl/2010-9P2000.L.9p.gen @@ -0,0 +1,282 @@ +#!/usr/bin/env python +# lib9p/idl/2010-9P2000.L.9p.gen - Generate definitions of 9P2000.L messages +import sys + +print( + f"# lib9p/idl/2010-9P2000.L.9p - Generated by `{' '.join(sys.argv)}`. DO NOT EDIT!" +) +errnos: dict[str, tuple[int, str]] = {} +with open(sys.argv[1], "r", encoding="utf-8") as fh: + for line in fh: + if line.startswith("#"): + print(line) + continue + _num, _name, _desc = line.split(maxsplit=2) + errnos[_name] = (int(_num), _desc.strip()) +print( + """ +# lib9p/idl/2010-9P2000.L.9p - Definitions of 9P2000.L messages +# +# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> +# SPDX-License-Identifier: AGPL-3.0-or-later + +# "9P2000.L" Linux extension +# https://github.com/chaos/diod/blob/master/protocol.md +# https://github.com/chaos/diod/blob/master/src/libnpfs/protocol.h +version "9P2000.L" + +# low-level types ############################################################## + +from ./2002-9P2000.9p import tag, fid, s, qt, qid +from ./2005-9P2000.u.9p import nuid, errno + +# BUG: The definitions of errno are not defined in the 9P2000.L +# protocol spec, and Linux kernel errno values vary by architecture. +# Most architectures share a "generic" list, but a handful (as of +# Linux v6.14, Alpha, MIPS, PA-RISC, PowerPC, and SPARC) have their +# own numbers. This IDL file lists the generic numbers. +# +# https://github.com/chaos/diod/issues/35 +""".strip() +) + +prefix = "num errno += " +namelen = max(len(name) for name in errnos) +numlen = max(len(str(num)) for (num, desc) in errnos.values()) +for name, (num, desc) in errnos.items(): + print(f'{prefix}"L_{name:<{namelen}} = {num:>{numlen}}" # {desc}') + prefix = " " * len(prefix) +print() + +print( + """ +num super_magic = 4 + # See <linux/magic.h> (linux.git include/uapi/linux/magic.h). + # + # To quote `util-linux.git:include/statfs_magic.h`: + # "Unfortunately, Linux kernel header file <linux/magic.h> is + # incomplete mess and kernel returns by statfs f_type many numbers + # that are nowhere specified (in API)." + # + # util-linux <statfs_magic.h> is also incomplete. As is the + # statfs(2) man-page. + # + # I'm working on a patchset to the kernel to get <linux/magic.h> + # to be complete, but in the mean-time I'm just not going to + # bother with putting a list here. + # + # TODO + "V9FS_MAGIC=0x01021997" + +# "L"inux "O"pen flags (flags to pass to Tlopen and Tlcreate) +# +# The values are not specified in in protocol.md, but are specified in +# protocol.h (and are different than the Linux kernel's values, which +# vary by architecture). +bitfield lo = 4 + "bit 0=num(MODE)" # low bit of the 2-bit RDONLY/WRONLY/RDWR/NOACCESS enum + "bit 1=num(MODE)" # high bit of the 2-bit RDONLY/WRONLY/RDWR/NOACCESS enum + #"bit 2=unused" + #"bit 3=unused" + #"bit 4=unused" + #"bit 5=unused" + "bit 6=CREATE" + "bit 7=EXCL" + "bit 8=NOCTTY" + "bit 9=TRUNC" + "bit 10=APPEND" + "bit 11=NONBLOCK" + "bit 12=DSYNC" + "bit 13=BSD_FASYNC" + "bit 14=DIRECT" + "bit 15=LARGEFILE" + "bit 16=DIRECTORY" + "bit 17=NOFOLLOW" + "bit 18=NOATIME" + "bit 19=CLOEXEC" + "bit 20=SYNC" + + "num(MODE) RDONLY = 0" + "num(MODE) WRONLY = 1" + "num(MODE) RDWR = 2" + "num(MODE) NOACCESS = 3" + + "mask FLAG = 0b111111111111111000000" + +# "D"irentry "T"ype +# +# These match the Linux kernel's values. +num dt = 1 + "UNKNOWN = 0" + "PIPE = 1" + "CHAR_DEV = 2" + "DIRECTORY = 4" + "BLOCK_DEV = 6" # proof it's not a bitfield + "REGULAR = 8" + "SYMLINK = 10" # proof it's not a bitfield + "SOCKET = 12" # proof it's not a bitfield + "_WHITEOUT = 14" # proof it's not a bitfield + +# Mode +# +# These match the Linux kernel's values. Why is this 32-bits wide +# instead of just 16? Who knows? +bitfield mode = 4 + #... + "bit 15=num(FMT)" # bit of the 4-bit FMT_ enum + "bit 14=num(FMT)" # bit of the 4-bit FMT_ enum + "bit 13=num(FMT)" # bit of the 4-bit FMT_ enum + "bit 12=num(FMT)" # bit of the 4-bit FMT_ enum + #... + "bit 11=PERM_SETGROUP" + "bit 10=PERM_SETUSER" + "bit 9=PERM_STICKY" + "bit 8=PERM_OWNER_R" + "bit 7=PERM_OWNER_W" + "bit 6=PERM_OWNER_X" + "bit 5=PERM_GROUP_R" + "bit 4=PERM_GROUP_W" + "bit 3=PERM_GROUP_X" + "bit 2=PERM_OTHER_R" + "bit 1=PERM_OTHER_W" + "bit 0=PERM_OTHER_X" + + "num(FMT) PIPE = dt.PIPE<<12" + "num(FMT) CHAR_DEV = dt.CHAR_DEV<<12" + "num(FMT) DIRECTORY = dt.DIRECTORY<<12" + "num(FMT) BLOCK_DEV = dt.BLOCK_DEV<<12" + "num(FMT) REGULAR = dt.REGULAR<<12" + "num(FMT) SYMLINK = dt.SYMLINK<<12" + "num(FMT) SOCKET = dt.SOCKET<<12" + + "mask PERM = 07777" # PERM_* + +# A boolean value that is for some reason 4 bytes wide. +num b4 = 4 + "FALSE=0" + "TRUE=1" + # all other values are true also + +bitfield getattr = 8 + "bit 0=MODE" + "bit 1=NLINK" + "bit 2=UID" + "bit 3=GID" + "bit 4=RDEV" + "bit 5=ATIME" + "bit 6=MTIME" + "bit 7=CTIME" + "bit 8=INO" + "bit 9=SIZE" + "bit 10=BLOCKS" + + "bit 11=BTIME" + "bit 12=GEN" + "bit 13=DATA_VERSION" + + "alias BASIC=0x000007ff" # Mask for fields up to BLOCKS + "alias ALL =0x00003fff" # Mask for All fields above + +bitfield setattr = 4 + "bit 0=MODE" + "bit 1=UID" + "bit 2=GID" + "bit 3=SIZE" + "bit 4=ATIME" + "bit 5=MTIME" + "bit 6=CTIME" + "bit 7=ATIME_SET" + "bit 8=MTIME_SET" + +num lock_type = 1 + "RDLCK=0" + "WRLCK=1" + "UNLCK=2" + +bitfield lock_flags = 4 + "bit 0=BLOCK" + "bit 1=RECLAIM" + +num lock_status = 1 + "SUCCESS=0" + "BLOCKED=1" + "ERROR=2" + "GRACE=3" + +# 9P2000 Operations (.L subset) ################################################ + +from ./2002-9P2000.9p import Tversion, Rversion +from ./2002-9P2000.9p import Tflush, Rflush +from ./2002-9P2000.9p import Twalk, Rwalk +from ./2002-9P2000.9p import Tread, Rread, Twrite, Rwrite +from ./2002-9P2000.9p import Tclunk, Rclunk +from ./2002-9P2000.9p import Tremove, Rremove + +# 9P2000.u Operations (.L subset) ############################################## + +from ./2005-9P2000.u.9p import Tattach, Rattach, Tauth, Rauth + +# 9P2000.L Operations ########################################################## + +#msg Tlerror = "size[4,val=end-&size] typ[1,val=6] tag[tag] illegal" # analogous to 106/Terror +msg Rlerror = "size[4,val=end-&size] typ[1,val=7] tag[tag] errnum[errno]" # analogous to 107/Rerror +msg Tstatfs = "size[4,val=end-&size] typ[1,val=8] tag[tag] fid[fid]" +msg Rstatfs = "size[4,val=end-&size] typ[1,val=9] tag[tag]" # Description | statfs | statvfs + "type[super_magic]" # Type of filesystem | f_type | - + "bsize[4]" # Block size in bytes | f_bsize | f_bsize + # - # Fragment size in bytes | f_frsize (since Linux 2.6) | f_frsize + "blocks[8]" # Size of FS in f_frsize units | f_blocks | f_blocks + "bfree[8]" # Number of free blocks | f_bfree | f_bfree + "bavail[8]" # Number of free blocks for unprivileged users | f_bavail | b_avail + "files[8]" # Number of inodes | f_files | f_files + "ffree[8]" # Number of free inodes | f_ffree | f_ffree + # - # Number of free inodes for unprivileged users | - | f_favail + "fsid[8]" # Filesystem instance ID | f_fsid | f_fsid + # - # Mount flags | f_flags (since Linux 2.6.36) | f_flag + "namelen[4]" # Maximum filename length | f_namemax | f_namemax +msg Tlopen = "size[4,val=end-&size] typ[1,val=12] tag[tag] fid[fid] flags[lo]" # analogous to 112/Topen +msg Rlopen = "size[4,val=end-&size] typ[1,val=13] tag[tag] qid[qid] iounit[4]" # analogous to 113/Ropen +msg Tlcreate = "size[4,val=end-&size] typ[1,val=14] tag[tag] fid[fid] name[s] flags[lo] mode[mode] gid[nuid]" # analogous to 114/Tcreate +msg Rlcreate = "size[4,val=end-&size] typ[1,val=15] tag[tag] qid[qid] iounit[4]" # analogous to 115/Rcreate +msg Tsymlink = "size[4,val=end-&size] typ[1,val=16] tag[tag] fid[fid] name[s] symtgt[s] gid[nuid]" +msg Rsymlink = "size[4,val=end-&size] typ[1,val=17] tag[tag] qid[qid]" +msg Tmknod = "size[4,val=end-&size] typ[1,val=18] tag[tag] dfid[fid] name[s] mode[mode] major[4] minor[4] gid[nuid]" +msg Rmknod = "size[4,val=end-&size] typ[1,val=19] tag[tag] qid[qid]" +msg Trename = "size[4,val=end-&size] typ[1,val=20] tag[tag] fid[fid] dfid[fid] name[s]" +msg Rrename = "size[4,val=end-&size] typ[1,val=21] tag[tag]" +msg Treadlink = "size[4,val=end-&size] typ[1,val=22] tag[tag] fid[fid]" +msg Rreadlink = "size[4,val=end-&size] typ[1,val=23] tag[tag] target[s]" +msg Tgetattr = "size[4,val=end-&size] typ[1,val=24] tag[tag] fid[fid] request_mask[getattr]" +msg Rgetattr = "size[4,val=end-&size] typ[1,val=25] tag[tag] valid[getattr] qid[qid] mode[mode] uid[nuid] gid[nuid] nlink[8]" + "rdev[8] filesize[8] blksize[8] blocks[8]" + "atime_sec[8] atime_nsec[8] mtime_sec[8] mtime_nsec[8]" + "ctime_sec[8] ctime_nsec[8] btime_sec[8] btime_nsec[8]" + "gen[8] data_version[8]" +msg Tsetattr = "size[4,val=end-&size] typ[1,val=26] tag[tag] fid[fid] valid[setattr] mode[mode] uid[nuid] gid[nuid] filesize[8] atime_sec[8] atime_nsec[8] mtime_sec[8] mtime_nsec[8]" +msg Rsetattr = "size[4,val=end-&size] typ[1,val=27] tag[tag]" +#... +msg Txattrwalk = "size[4,val=end-&size] typ[1,val=30] tag[tag] fid[fid] newfid[fid] name[s]" +msg Rxattrwalk = "size[4,val=end-&size] typ[1,val=31] tag[tag] attr_size[8]" +msg Txattrcreate = "size[4,val=end-&size] typ[1,val=32] tag[tag] fid[fid] name[s] attr_size[8] flags[4]" +msg Rxattrcreate = "size[4,val=end-&size] typ[1,val=33] tag[tag]" +#... +msg Treaddir = "size[4,val=end-&size] typ[1,val=40] tag[tag] fid[fid] offset[8] count[4]" +msg Rreaddir = "size[4,val=end-&size] typ[1,val=41] tag[tag] count[4] count*(data[1])" # data is "qid[qid] offset[8] type[dt] name[s]" +#... +msg Tfsync = "size[4,val=end-&size] typ[1,val=50] tag[tag] fid[fid] datasync[b4]" +msg Rfsync = "size[4,val=end-&size] typ[1,val=51] tag[tag]" +msg Tlock = "size[4,val=end-&size] typ[1,val=52] tag[tag] fid[fid] type[lock_type] flags[lock_flags] start[8] length[8] proc_id[4] client_id[s]" +msg Rlock = "size[4,val=end-&size] typ[1,val=53] tag[tag] status[lock_status]" +msg Tgetlock = "size[4,val=end-&size] typ[1,val=54] tag[tag] fid[fid] type[lock_type] start[8] length[8] proc_id[4] client_id[s]" +msg Rgetlock = "size[4,val=end-&size] typ[1,val=55] tag[tag] type[lock_type] start[8] length[8] proc_id[4] client_id[s]" +# ... +msg Tlink = "size[4,val=end-&size] typ[1,val=70] tag[tag] dfid[fid] fid[fid] name[s]" +msg Rlink = "size[4,val=end-&size] typ[1,val=71] tag[tag]" +msg Tmkdir = "size[4,val=end-&size] typ[1,val=72] tag[tag] dfid[fid] name[s] mode[mode] gid[nuid]" +msg Rmkdir = "size[4,val=end-&size] typ[1,val=73] tag[tag] qid[qid]" +msg Trenameat = "size[4,val=end-&size] typ[1,val=74] tag[tag] olddirfid[fid] oldname[s] newdirfid[fid] newname[s]" +msg Rrenameat = "size[4,val=end-&size] typ[1,val=75] tag[tag]" +msg Tunlinkat = "size[4,val=end-&size] typ[1,val=76] tag[tag] dirfd[fid] name[s] flags[4]" +msg Runlinkat = "size[4,val=end-&size] typ[1,val=77] tag[tag]" +""".strip() +) diff --git a/lib9p/idl/__init__.py b/lib9p/idl/__init__.py index 2d09217..3133cc4 100644 --- a/lib9p/idl/__init__.py +++ b/lib9p/idl/__init__.py @@ -647,17 +647,16 @@ def re_string(grpname: str) -> str: re_line_version = f"version\\s+{re_string('version')}" re_line_import = f"from\\s+(?P<file>\\S+)\\s+import\\s+(?P<syms>{re_impname}(?:\\s*,\\s*{re_impname})*)" re_line_num = f"num\\s+(?P<name>{re_symname})\\s*=\\s*(?P<prim>{re_priname})" +re_line_num_ = f"num\\s+(?P<name>{re_symname})\\s*\\+=\\s*{re_string('spec')}" re_line_bitfield = f"bitfield\\s+(?P<name>{re_symname})\\s*=\\s*(?P<prim>{re_priname})" -re_line_bitfield_ = ( - f"bitfield\\s+(?P<name>{re_symname})\\s*\\+=\\s*{re_string('member')}" -) +re_line_bitfield_ = f"bitfield\\s+(?P<name>{re_symname})\\s*\\+=\\s*{re_string('spec')}" re_line_struct = ( f"struct\\s+(?P<name>{re_symname})\\s*(?P<op>\\+?=)\\s*{re_string('members')}" ) re_line_msg = ( f"msg\\s+(?P<name>{re_msgname})\\s*(?P<op>\\+?=)\\s*{re_string('members')}" ) -re_line_cont = f"\\s+{re_string('specs')}" # could be bitfield/struct/msg +re_line_cont = f"\\s+{re_string('spec')}" # could be bitfield/struct/msg def parse_file( @@ -741,6 +740,11 @@ def parse_file( raise ValueError(f"duplicate type name {num.typname!r}") env[num.typname] = num prev = num + elif m := re.fullmatch(re_line_num_, line): + num = get_type(env, m.group("name"), Number) + parse_numspec(env, version, num, m.group("spec")) + + prev = num elif m := re.fullmatch(re_line_bitfield, line): prim = env[m.group("prim")] assert isinstance(prim, Primitive) @@ -754,7 +758,7 @@ def parse_file( prev = bf elif m := re.fullmatch(re_line_bitfield_, line): bf = get_type(env, m.group("name"), Bitfield) - parse_bitspec(env, version, bf, m.group("member")) + parse_bitspec(env, version, bf, m.group("spec")) prev = bf elif m := re.fullmatch(re_line_struct, line): @@ -798,11 +802,11 @@ def parse_file( elif m := re.fullmatch(re_line_cont, line): match prev: case Bitfield(): - parse_bitspec(env, version, prev, m.group("specs")) + parse_bitspec(env, version, prev, m.group("spec")) case Number(): - parse_numspec(env, version, prev, m.group("specs")) + parse_numspec(env, version, prev, m.group("spec")) case Struct(): # and Message() - parse_members(version, env, prev, m.group("specs")) + parse_members(version, env, prev, m.group("spec")) case _: raise SyntaxError( "continuation line must come after a bitfield, struct, or msg line" diff --git a/lib9p/include/lib9p/linux-errno.h b/lib9p/include/lib9p/linux-errno.h deleted file mode 100644 index e7c74f5..0000000 --- a/lib9p/include/lib9p/linux-errno.h +++ /dev/null @@ -1,139 +0,0 @@ -/* lib9p/linux-errno.h - Generated by `lib9p/include/lib9p/linux-errno.h.gen 3rd-party/linux-errno.txt`. DO NOT EDIT! */ -/* 3rd-party/linux-errno.txt - Generated from build-aux/linux-errno.txt.gen and linux.git v6.7. DO NOT EDIT! */ - -#ifndef _LIB9P_LINUX_ERRNO_H_ -#define _LIB9P_LINUX_ERRNO_H_ - -#define LINUX_EPERM 1 /* Operation not permitted */ -#define LINUX_ENOENT 2 /* No such file or directory */ -#define LINUX_ESRCH 3 /* No such process */ -#define LINUX_EINTR 4 /* Interrupted system call */ -#define LINUX_EIO 5 /* I/O error */ -#define LINUX_ENXIO 6 /* No such device or address */ -#define LINUX_E2BIG 7 /* Argument list too long */ -#define LINUX_ENOEXEC 8 /* Exec format error */ -#define LINUX_EBADF 9 /* Bad file number */ -#define LINUX_ECHILD 10 /* No child processes */ -#define LINUX_EAGAIN 11 /* Try again */ -#define LINUX_ENOMEM 12 /* Out of memory */ -#define LINUX_EACCES 13 /* Permission denied */ -#define LINUX_EFAULT 14 /* Bad address */ -#define LINUX_ENOTBLK 15 /* Block device required */ -#define LINUX_EBUSY 16 /* Device or resource busy */ -#define LINUX_EEXIST 17 /* File exists */ -#define LINUX_EXDEV 18 /* Cross-device link */ -#define LINUX_ENODEV 19 /* No such device */ -#define LINUX_ENOTDIR 20 /* Not a directory */ -#define LINUX_EISDIR 21 /* Is a directory */ -#define LINUX_EINVAL 22 /* Invalid argument */ -#define LINUX_ENFILE 23 /* File table overflow */ -#define LINUX_EMFILE 24 /* Too many open files */ -#define LINUX_ENOTTY 25 /* Not a typewriter */ -#define LINUX_ETXTBSY 26 /* Text file busy */ -#define LINUX_EFBIG 27 /* File too large */ -#define LINUX_ENOSPC 28 /* No space left on device */ -#define LINUX_ESPIPE 29 /* Illegal seek */ -#define LINUX_EROFS 30 /* Read-only file system */ -#define LINUX_EMLINK 31 /* Too many links */ -#define LINUX_EPIPE 32 /* Broken pipe */ -#define LINUX_EDOM 33 /* Math argument out of domain of func */ -#define LINUX_ERANGE 34 /* Math result not representable */ -#define LINUX_EDEADLK 35 /* Resource deadlock would occur */ -#define LINUX_ENAMETOOLONG 36 /* File name too long */ -#define LINUX_ENOLCK 37 /* No record locks available */ -#define LINUX_ENOSYS 38 /* Invalid system call number */ -#define LINUX_ENOTEMPTY 39 /* Directory not empty */ -#define LINUX_ELOOP 40 /* Too many symbolic links encountered */ -#define LINUX_ENOMSG 42 /* No message of desired type */ -#define LINUX_EIDRM 43 /* Identifier removed */ -#define LINUX_ECHRNG 44 /* Channel number out of range */ -#define LINUX_EL2NSYNC 45 /* Level 2 not synchronized */ -#define LINUX_EL3HLT 46 /* Level 3 halted */ -#define LINUX_EL3RST 47 /* Level 3 reset */ -#define LINUX_ELNRNG 48 /* Link number out of range */ -#define LINUX_EUNATCH 49 /* Protocol driver not attached */ -#define LINUX_ENOCSI 50 /* No CSI structure available */ -#define LINUX_EL2HLT 51 /* Level 2 halted */ -#define LINUX_EBADE 52 /* Invalid exchange */ -#define LINUX_EBADR 53 /* Invalid request descriptor */ -#define LINUX_EXFULL 54 /* Exchange full */ -#define LINUX_ENOANO 55 /* No anode */ -#define LINUX_EBADRQC 56 /* Invalid request code */ -#define LINUX_EBADSLT 57 /* Invalid slot */ -#define LINUX_EBFONT 59 /* Bad font file format */ -#define LINUX_ENOSTR 60 /* Device not a stream */ -#define LINUX_ENODATA 61 /* No data available */ -#define LINUX_ETIME 62 /* Timer expired */ -#define LINUX_ENOSR 63 /* Out of streams resources */ -#define LINUX_ENONET 64 /* Machine is not on the network */ -#define LINUX_ENOPKG 65 /* Package not installed */ -#define LINUX_EREMOTE 66 /* Object is remote */ -#define LINUX_ENOLINK 67 /* Link has been severed */ -#define LINUX_EADV 68 /* Advertise error */ -#define LINUX_ESRMNT 69 /* Srmount error */ -#define LINUX_ECOMM 70 /* Communication error on send */ -#define LINUX_EPROTO 71 /* Protocol error */ -#define LINUX_EMULTIHOP 72 /* Multihop attempted */ -#define LINUX_EDOTDOT 73 /* RFS specific error */ -#define LINUX_EBADMSG 74 /* Not a data message */ -#define LINUX_EOVERFLOW 75 /* Value too large for defined data type */ -#define LINUX_ENOTUNIQ 76 /* Name not unique on network */ -#define LINUX_EBADFD 77 /* File descriptor in bad state */ -#define LINUX_EREMCHG 78 /* Remote address changed */ -#define LINUX_ELIBACC 79 /* Can not access a needed shared library */ -#define LINUX_ELIBBAD 80 /* Accessing a corrupted shared library */ -#define LINUX_ELIBSCN 81 /* .lib section in a.out corrupted */ -#define LINUX_ELIBMAX 82 /* Attempting to link in too many shared libraries */ -#define LINUX_ELIBEXEC 83 /* Cannot exec a shared library directly */ -#define LINUX_EILSEQ 84 /* Illegal byte sequence */ -#define LINUX_ERESTART 85 /* Interrupted system call should be restarted */ -#define LINUX_ESTRPIPE 86 /* Streams pipe error */ -#define LINUX_EUSERS 87 /* Too many users */ -#define LINUX_ENOTSOCK 88 /* Socket operation on non-socket */ -#define LINUX_EDESTADDRREQ 89 /* Destination address required */ -#define LINUX_EMSGSIZE 90 /* Message too long */ -#define LINUX_EPROTOTYPE 91 /* Protocol wrong type for socket */ -#define LINUX_ENOPROTOOPT 92 /* Protocol not available */ -#define LINUX_EPROTONOSUPPORT 93 /* Protocol not supported */ -#define LINUX_ESOCKTNOSUPPORT 94 /* Socket type not supported */ -#define LINUX_EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ -#define LINUX_EPFNOSUPPORT 96 /* Protocol family not supported */ -#define LINUX_EAFNOSUPPORT 97 /* Address family not supported by protocol */ -#define LINUX_EADDRINUSE 98 /* Address already in use */ -#define LINUX_EADDRNOTAVAIL 99 /* Cannot assign requested address */ -#define LINUX_ENETDOWN 100 /* Network is down */ -#define LINUX_ENETUNREACH 101 /* Network is unreachable */ -#define LINUX_ENETRESET 102 /* Network dropped connection because of reset */ -#define LINUX_ECONNABORTED 103 /* Software caused connection abort */ -#define LINUX_ECONNRESET 104 /* Connection reset by peer */ -#define LINUX_ENOBUFS 105 /* No buffer space available */ -#define LINUX_EISCONN 106 /* Transport endpoint is already connected */ -#define LINUX_ENOTCONN 107 /* Transport endpoint is not connected */ -#define LINUX_ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ -#define LINUX_ETOOMANYREFS 109 /* Too many references: cannot splice */ -#define LINUX_ETIMEDOUT 110 /* Connection timed out */ -#define LINUX_ECONNREFUSED 111 /* Connection refused */ -#define LINUX_EHOSTDOWN 112 /* Host is down */ -#define LINUX_EHOSTUNREACH 113 /* No route to host */ -#define LINUX_EALREADY 114 /* Operation already in progress */ -#define LINUX_EINPROGRESS 115 /* Operation now in progress */ -#define LINUX_ESTALE 116 /* Stale file handle */ -#define LINUX_EUCLEAN 117 /* Structure needs cleaning */ -#define LINUX_ENOTNAM 118 /* Not a XENIX named type file */ -#define LINUX_ENAVAIL 119 /* No XENIX semaphores available */ -#define LINUX_EISNAM 120 /* Is a named type file */ -#define LINUX_EREMOTEIO 121 /* Remote I/O error */ -#define LINUX_EDQUOT 122 /* Quota exceeded */ -#define LINUX_ENOMEDIUM 123 /* No medium found */ -#define LINUX_EMEDIUMTYPE 124 /* Wrong medium type */ -#define LINUX_ECANCELED 125 /* Operation Canceled */ -#define LINUX_ENOKEY 126 /* Required key not available */ -#define LINUX_EKEYEXPIRED 127 /* Key has expired */ -#define LINUX_EKEYREVOKED 128 /* Key has been revoked */ -#define LINUX_EKEYREJECTED 129 /* Key was rejected by service */ -#define LINUX_EOWNERDEAD 130 /* Owner died */ -#define LINUX_ENOTRECOVERABLE 131 /* State not recoverable */ -#define LINUX_ERFKILL 132 /* Operation not possible due to RF-kill */ -#define LINUX_EHWPOISON 133 /* Memory page has hardware error */ - -#endif /* _LIB9P_LINUX_ERRNO_H_ */ diff --git a/lib9p/include/lib9p/linux-errno.h.gen b/lib9p/include/lib9p/linux-errno.h.gen deleted file mode 100755 index 2c736a2..0000000 --- a/lib9p/include/lib9p/linux-errno.h.gen +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python -# lib9p/linux-errno.h.gen - Generate a C header from a list of errno numbers -# -# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> -# SPDX-License-Identifier: AGPL-3.0-or-later - -import sys - - -def print_errnos() -> None: - print( - f"/* lib9p/linux-errno.h - Generated by `{' '.join(sys.argv)}`. DO NOT EDIT! */" - ) - errnos: dict[str, tuple[int, str]] = {} - for txtlist in sys.argv[1:]: - with open(txtlist, "r", encoding="utf-8") as fh: - for line in fh: - if line.startswith("#"): - print(f"/* {line[1:].strip()} */") - continue - _num, name, desc = line.split(maxsplit=2) - num = int(_num) - desc = desc.strip() - errnos[name] = (num, desc) - print() - print("#ifndef _LIB9P_LINUX_ERRNO_H_") - print("#define _LIB9P_LINUX_ERRNO_H_") - print() - namelen = max(len(name) for name in errnos) - numlen = max(len(str(num)) for (num, desc) in errnos.values()) - for name, [num, msg] in errnos.items(): - print(f"#define LINUX_{name:<{namelen}} {num:>{numlen}} /* {msg} */") - print() - print("#endif /* _LIB9P_LINUX_ERRNO_H_ */") - - -if __name__ == "__main__": - print_errnos() diff --git a/lib9p/include/lib9p/srv.h b/lib9p/include/lib9p/srv.h deleted file mode 100644 index 070cf5a..0000000 --- a/lib9p/include/lib9p/srv.h +++ /dev/null @@ -1,179 +0,0 @@ -/* lib9p/srv.h - 9P server - * - * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -#ifndef _LIB9P_SRV_H_ -#define _LIB9P_SRV_H_ - -#include <libcr/coroutine.h> -#include <libcr_ipc/rpc.h> -#include <libcr_ipc/chan.h> -#include <libhw/generic/net.h> -#include <libmisc/assert.h> -#include <libmisc/private.h> -#include <libobj/obj.h> - -#include <lib9p/9p.h> - -/* context ********************************************************************/ - -CR_CHAN_DECLARE(_lib9p_srv_flushch, bool) - -struct lib9p_srv_ctx { - struct lib9p_ctx basectx; - uint32_t uid; - struct lib9p_s uname; - - BEGIN_PRIVATE(LIB9P_SRV_H); - _lib9p_srv_flushch_t _flushch; - END_PRIVATE(LIB9P_SRV_H); -}; - -bool lib9p_srv_flush_requested(struct lib9p_srv_ctx *ctx); - -int lib9p_srv_acknowledge_flush(struct lib9p_srv_ctx *ctx); - -/* interface definitions ******************************************************/ - -lo_interface lib9p_srv_fio; -lo_interface lib9p_srv_dio; - -/* FIXME: I don't like that the pointers returned by stat() and - * pread() have to remain live after they return. Perhaps a - * `respond()`-callback? But that just reads as gross in C. - * - * FIXME: It would be nice if pread() could return more than 1 iovec. - */ -#define lib9p_srv_file_LO_IFACE \ - /* resource management **********************************************/ \ - \ - /** \ - * free() is be called when all FIDs associated with the file are \ - * clunked. \ - * \ - * free() MUST NOT error. \ - */ \ - LO_FUNC(void , free ) \ - \ - /** \ - * qid() is called frequently and returns the current QID of the file. \ - * The .path field MUST never change, the .type field may change in \ - * response to wstat() calls (but the QT_DIR bit MUST NOT change), and \ - * the .vers field may change frequently in response to any number of \ - * things (wstat(), write(), or non-9P events). \ - * \ - * qid() MUST NOT error. \ - */ \ - LO_FUNC(struct lib9p_qid , qid ) \ - \ - /* non-"opened" generic I/O *****************************************/ \ - \ - LO_FUNC(struct lib9p_stat , stat , struct lib9p_srv_ctx *) \ - LO_FUNC(void , wstat , struct lib9p_srv_ctx *, \ - struct lib9p_stat new) \ - LO_FUNC(void , remove , struct lib9p_srv_ctx *) \ - \ - /* non-"opened" directory I/O ***************************************/ \ - \ - LO_FUNC(lo_interface lib9p_srv_file, dwalk , struct lib9p_srv_ctx *, \ - struct lib9p_s childname) \ - LO_FUNC(lo_interface lib9p_srv_file, dcreate, struct lib9p_srv_ctx *, \ - struct lib9p_s childname, \ - lib9p_dm_t perm, \ - lib9p_o_t flags) \ - \ - /* open() for I/O ***************************************************/ \ - \ - LO_FUNC(lo_interface lib9p_srv_fio , fopen , struct lib9p_srv_ctx *, \ - bool rd, bool wr, \ - bool trunc) \ - LO_FUNC(lo_interface lib9p_srv_dio , dopen , struct lib9p_srv_ctx *) -LO_INTERFACE(lib9p_srv_file); - -#define lib9p_srv_fio_LO_IFACE \ - LO_FUNC(struct lib9p_qid , qid ) \ - LO_FUNC(void , iofree ) \ - LO_FUNC(uint32_t , iounit ) \ - LO_FUNC(void , pread , struct lib9p_srv_ctx *, \ - uint32_t byte_count, \ - uint64_t byte_offset, \ - struct iovec *ret) \ - LO_FUNC(uint32_t , pwrite , struct lib9p_srv_ctx *, \ - void *buf, \ - uint32_t byte_count, \ - uint64_t byte_offset) -LO_INTERFACE(lib9p_srv_fio); - -/* FIXME: The dio interface just feels clunky. I'm not in a rush to - * change it because util9p_static_dir is already implemented and I - * don't anticipate the sbc-harness needing another dio - * implementation. But if I wanted lib9p to be used outside of - * sbc-harness, this is one of the first things that I'd want to - * change. - */ -#define lib9p_srv_dio_LO_IFACE \ - LO_FUNC(struct lib9p_qid , qid ) \ - LO_FUNC(void , iofree ) \ - LO_FUNC(size_t /* <- obj cnt */ , dread , struct lib9p_srv_ctx *, \ - uint8_t *buf, \ - /* num bytes -> */ uint32_t byte_count, \ - /* starting at this object -> */ size_t obj_offset) -LO_INTERFACE(lib9p_srv_dio); - -#define LIB9P_SRV_NOTDIR(TYP, NAM) \ - static lo_interface lib9p_srv_file NAM##_dwalk (TYP *, struct lib9p_srv_ctx *, struct lib9p_s) { assert_notreached("not a directory"); } \ - static lo_interface lib9p_srv_file NAM##_dcreate(TYP *, struct lib9p_srv_ctx *, struct lib9p_s, lib9p_dm_t, lib9p_o_t) { assert_notreached("not a directory"); } \ - static lo_interface lib9p_srv_dio NAM##_dopen (TYP *, struct lib9p_srv_ctx *) { assert_notreached("not a directory"); } - -#define LIB9P_SRV_NOTFILE(TYP, NAM) \ - static lo_interface lib9p_srv_fio NAM##_fopen (TYP *, struct lib9p_srv_ctx *, bool, bool, bool) { assert_notreached("not a file"); } - -/* main server entrypoints ****************************************************/ - -CR_RPC_DECLARE(_lib9p_srv_reqch, struct _lib9p_srv_req *, bool) - -struct lib9p_srv { - /* Things you provide */ - void /*TODO*/ (*auth )(struct lib9p_srv_ctx *, struct lib9p_s treename); /* optional */ - lo_interface lib9p_srv_file (*rootdir)(struct lib9p_srv_ctx *, struct lib9p_s treename); - - /* For internal use */ - BEGIN_PRIVATE(LIB9P_SRV_H); - unsigned int readers; - unsigned int writers; - _lib9p_srv_reqch_t _reqch; - END_PRIVATE(LIB9P_SRV_H); -}; - -/** - * In an infinite loop, accept a connection and read messages from it until - * close; dispatching requests to a pool of lib9p_srv_write_cr() coroutines - * with the same `srv`. - * - * Will just close the connection if a T-message has a size[4] <7. - * - * @param srv: The server configuration and state; has an associated pool of - * lib9p_srv_write_cr() coroutines. - * @param listener: The listener object to accept connections from. - * - * @errno LINUX_EMSGSIZE T-message has size[4] bigger than max_msg_size - * @errno LINUX_EDOM Tversion specified an impossibly small max_msg_size - * @errno LINUX_EOPNOTSUPP T-message has an R-message type, or an unrecognized T-message type - * @errno LINUX_EBADMSG T-message has wrong size[4] for its content, or has invalid UTF-8 - * @errno LINUX_ERANGE R-message does not fit into max_msg_size - */ -[[noreturn]] void lib9p_srv_read_cr(struct lib9p_srv *srv, lo_interface net_stream_listener listener); - -/** - * Service requests to the `struct lib9p_srv *srv` argument that have been - * read by lib9p_srv_read_cr(). - * - * @param struct lib9p_srv *srv: The server configuration and state; has an - * associated pool of lib9p_srv_read_cr() - * coroutines. - */ -COROUTINE lib9p_srv_write_cr(void *_srv); - -#endif /* _LIB9P_SRV_H_ */ diff --git a/build-aux/linux-errno.txt.gen b/lib9p/linux-errno.txt.gen index f94178f..687e58b 100755 --- a/build-aux/linux-errno.txt.gen +++ b/lib9p/linux-errno.txt.gen @@ -1,7 +1,7 @@ #!/usr/bin/env bash -# build-aux/linux-errno.txt.gen - Generate a listing of Linux kernel errnos +# lib9p/linux-errno.txt.gen - Generate a listing of Linux kernel errnos # -# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> +# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> # SPDX-License-Identifier: AGPL-3.0-or-later set -e diff --git a/lib9p/map.h b/lib9p/map.h deleted file mode 100644 index c5eab0f..0000000 --- a/lib9p/map.h +++ /dev/null @@ -1,114 +0,0 @@ -/* lib9p/map.h - A really dumb map/dict data structure - * - * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -/** - * `#define` `NAME`, `KEY_T`, `VAL_T`, and `CAP`; then `#include - * "map.h". - */ - -#ifndef NAME - #error NAME must be defined -#endif -#ifndef KEY_T - #error KEY_T must be defined -#endif -#ifndef VAL_T - #error VAL_T must be defined -#endif -#ifndef CAP - #error CAP must be defined -#endif - -#ifndef MAP_KEY -#define MAP_KV(TNAME) LM_CAT3(_,TNAME,_kv) -#define MAP_METHOD(TNAME, MNAME) LM_CAT3(TNAME,_,MNAME) -#define MAP_FOREACH(m, k, v) \ - for (size_t i = 0; i < LM_ARRAY_LEN((m)->items); i++) \ - if ( ({ k = (m)->items[i].key; v = &(m)->items[i].val; (m)->items[i].set; }) ) -#endif - -/* This implementation is just an array that we brute-force search - * over for a slot. I don't want to use the heap, which means - * statically-sized maps, and I'm probably going to choose a low - * static size, so this is fine. */ - -struct MAP_KV(NAME) { - bool set; - KEY_T key; - VAL_T val; -}; - -struct NAME { - size_t len; - struct MAP_KV(NAME) items[CAP]; -}; - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-function" - -/** - * Load an item from the map; return a pointer to the in-map value, or - * NULL if the item is not in the map. - */ -static VAL_T *MAP_METHOD(NAME,load)(struct NAME *m, KEY_T k) { - if (!m->len) - return NULL; - for (size_t i = 0; i < LM_ARRAY_LEN(m->items); i++) - if (m->items[i].set && m->items[i].key == k) - return &(m->items[i].val); - return NULL; -} - -/** - * Store an item into the map, perhaps replacing an existing value. - * Return a pointer to the in-map value, or NULL if the map is full. - */ -static VAL_T *MAP_METHOD(NAME,store)(struct NAME *m, KEY_T k, VAL_T v) { - VAL_T *old = MAP_METHOD(NAME,load)(m, k); - if (old) { - *old = v; - return old; - } - if (m->len == LM_ARRAY_LEN(m->items)) - return NULL; - for (size_t i = 0; i < LM_ARRAY_LEN(m->items); i++) - if (!m->items[i].set) { - m->len++; - m->items[i].set = true; - m->items[i].key = k; - m->items[i].val = v; - return &(m->items[i].val); - } - assert_notreached("should have returned from inside for() loop"); -} - -/** - * Delete an item from the map. Returns true if an item was deleted, - * false if no such item was in the map. - */ -static bool MAP_METHOD(NAME,del)(struct NAME *m, KEY_T k) { - if (!m->len) - return NULL; - for (size_t i = 0; i < LM_ARRAY_LEN(m->items); i++) - if (m->items[i].set && m->items[i].key == k) { - m->items[i].set = false; - m->len--; - return true; - } - return false; -} - -#pragma GCC diagnostic pop - -#undef NAME -#undef KEY_T -#undef VAL_T -#undef CAP - -/* Keep the linter happy. */ -#ifndef _LIB9P_MAP_H_ -#define _LIB9P_MAP_H_ -#endif /* _LIB9P_MAP_H_ */ diff --git a/lib9p/srv.c b/lib9p/srv.c index a425dc9..08ccfc3 100644 --- a/lib9p/srv.c +++ b/lib9p/srv.c @@ -4,10 +4,11 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ -#include <alloca.h> #include <inttypes.h> /* for PRI* */ -#include <stddef.h> /* for size_t */ #include <limits.h> /* for SSIZE_MAX, not set by newlib */ +#include <stddef.h> /* for size_t */ +#include <stdlib.h> /* for malloc() */ +#include <string.h> /* for memcpy() */ #ifndef SSIZE_MAX #define SSIZE_MAX (SIZE_MAX >> 1) #endif @@ -15,9 +16,10 @@ #include <libcr/coroutine.h> #include <libcr_ipc/chan.h> #include <libcr_ipc/mutex.h> -#include <libcr_ipc/select.h> +#include <libmisc/alloc.h> #include <libmisc/assert.h> #include <libmisc/endian.h> +#include <libmisc/map.h> #include <libhw/generic/net.h> #define LOG_NAME 9P_SRV @@ -30,16 +32,6 @@ #include "config.h" -#ifndef CONFIG_9P_SRV_MAX_FIDS - #error config.h must define CONFIG_9P_SRV_MAX_FIDS -#endif -#ifndef CONFIG_9P_SRV_MAX_REQS - #error config.h must define CONFIG_9P_SRV_MAX_REQS -#endif -#ifndef CONFIG_9P_SRV_MAX_DEPTH - /* 1=just the root dir, 2=just files in the root dir, 3=1 subdir, ... */ - #error config.h must define CONFIG_9P_SRV_MAX_DEPTH -#endif #ifndef CONFIG_9P_SRV_MAX_MSG_SIZE #error config.h must define CONFIG_9P_SRV_MAX_MSG_SIZE #endif @@ -53,23 +45,39 @@ static_assert(CONFIG_9P_SRV_MAX_HOSTMSG_SIZE <= SSIZE_MAX); bool lib9p_srv_flush_requested(struct lib9p_srv_ctx *ctx) { assert(ctx); - return _lib9p_srv_flushch_can_send(&ctx->_flushch); + return cr_chan_can_send(&ctx->flush_ch); } -int lib9p_srv_acknowledge_flush(struct lib9p_srv_ctx *ctx) { +void lib9p_srv_acknowledge_flush(struct lib9p_srv_ctx *ctx) { assert(ctx); - assert(_lib9p_srv_flushch_can_send(&ctx->_flushch)); - lib9p_error(&ctx->basectx, LINUX_ECANCELED, "request canceled by flush"); - _lib9p_srv_flushch_send(&ctx->_flushch, true); - return -1; + assert(cr_chan_can_send(&ctx->flush_ch)); + ctx->flush_acknowledged = true; } +#define req_debugf(fmt, ...) \ + debugf("cid=%zu: %s(tag=%"PRIu16"): " fmt, \ + cr_getcid(), \ + lib9p_msgtype_str(ctx->basectx.version, ctx->net_bytes[4]), \ + ctx->tag \ + __VA_OPT__(,) __VA_ARGS__) + /* structs ********************************************************************/ +enum srv_filetype { + SRV_FILETYPE_FILE, + SRV_FILETYPE_DIR, + SRV_FILETYPE_AUTH, +}; + +/* path *****************************************/ + typedef typeof( ((struct lib9p_qid){}).path ) srv_path_t; struct srv_pathinfo { lo_interface lib9p_srv_file file; + enum srv_filetype type; + /* .parent_dir is used for (1) Twalk(".."), and (2) for checking + * permissions on the parent directory for remove(). */ srv_path_t parent_dir; /* References from other srv_pathinfos (via .parent_dir) or @@ -79,21 +87,19 @@ struct srv_pathinfo { unsigned int io_refcount; }; -#define NAME pathmap -#define KEY_T srv_path_t -#define VAL_T struct srv_pathinfo -/* ( naive ) + ( working space for walk() ) */ -#define CAP ( (CONFIG_9P_SRV_MAX_FIDS*CONFIG_9P_SRV_MAX_DEPTH) + (CONFIG_9P_SRV_MAX_REQS*2) ) -#include "map.h" +/* fid ******************************************/ #define FIDFLAG_OPEN_R (1<<0) #define FIDFLAG_OPEN_W (1<<1) #define FIDFLAG_RCLOSE (1<<2) +#define FIDFLAG_APPEND (1<<3) #define FIDFLAG_OPEN (FIDFLAG_OPEN_R|FIDFLAG_OPEN_W) -struct _srv_fidinfo { +struct srv_fidinfo { srv_path_t path; + struct lib9p_srv_userid *user; uint8_t flags; + enum srv_filetype type; union { struct { lo_interface lib9p_srv_fio io; @@ -102,31 +108,26 @@ struct _srv_fidinfo { lo_interface lib9p_srv_dio io; size_t idx; uint64_t off; + struct lib9p_srv_dirent buffered_dirent; } dir; + struct { + struct lib9p_s aname; + bool completed; + } auth; }; }; -#define NAME fidmap -#define KEY_T lib9p_fid_t -#define VAL_T struct _srv_fidinfo -#define CAP CONFIG_9P_SRV_MAX_FIDS -#include "map.h" - -#define NAME reqmap -#define KEY_T lib9p_tag_t -#define VAL_T struct _lib9p_srv_req * -#define CAP CONFIG_9P_SRV_MAX_REQS -#include "map.h" - -/* The hierarchy of concepts is: +/* contexts ************************************** + * + * The hierarchy of contexts is: * * server -> connection -> session -> request * */ -/* struct _srv_srv {} is defined in <lib9p/srv.h> */ +/* struct lib9p_srv {} is defined in <lib9p/srv.h> */ -struct _srv_conn { +struct srv_conn { /* immutable */ struct lib9p_srv *parent_srv; lo_interface net_stream_conn fd; @@ -135,34 +136,236 @@ struct _srv_conn { cr_mutex_t writelock; }; -struct _srv_sess { +#define srv_sess _lib9p_srv_sess +MAP_DECLARE(srv_pathmap, srv_path_t, struct srv_pathinfo); +MAP_DECLARE(srv_fidmap, lib9p_fid_t, struct srv_fidinfo); +MAP_DECLARE(srv_reqmap, lib9p_tag_t, struct lib9p_srv_ctx *); +struct srv_sess { /* immutable */ - struct _srv_conn *parent_conn; + struct srv_conn *parent_conn; enum lib9p_version version; uint32_t max_msg_size; - uint32_t rerror_overhead; /* mutable */ bool initialized; bool closing; - struct pathmap paths; /* srv_path_t => lib9p_srv_file + metadata */ - struct fidmap fids; /* lib9p_fid_t => lib9p_srv_{fio,dio} + metadata */ - struct reqmap reqs; /* lib9p_tag_t => *_lib9p_srv_req */ + struct srv_pathmap paths; /* srv_path_t => `lib9p_srv_file` + metadata */ + struct srv_fidmap fids; /* lib9p_fid_t => `lib9p_srv_{fio,dio}` + metadata */ + struct srv_reqmap reqs; /* lib9p_tag_t => `struct srv_req *` */ }; -struct _lib9p_srv_req { - /* immutable */ - struct _srv_sess *parent_sess; - uint16_t tag; - uint8_t *net_bytes; - /* mutable */ - struct lib9p_srv_ctx ctx; -}; +#define srv_req lib9p_srv_ctx /* struct lib9p_srv_ctx {} is defined in <lib9p/srv.h> */ + +/* utilities for the above types **********************************************/ + +static inline enum srv_filetype srv_qid_filetype(struct lib9p_qid qid) { + if (qid.type & LIB9P_QT_AUTH) + return SRV_FILETYPE_AUTH; + if (qid.type & LIB9P_QT_DIR) + return SRV_FILETYPE_DIR; + return SRV_FILETYPE_FILE; +} + +static inline bool srv_check_perm(struct srv_req *ctx, struct lib9p_srv_stat *stat, uint8_t action) { + assert(ctx); + assert(stat); + assert(action); + + /* TODO actually check user and group instead of just assuming "other". */ + uint8_t mode = (uint8_t)(stat->mode & 07); + + return mode & action; +} + +[[gnu::unused]] +static struct lib9p_srv_userid *srv_userid_new(struct lib9p_s name +#if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L + , lib9p_nuid_t num +#endif + ) { + struct lib9p_srv_userid *ret = malloc(sizeof(struct lib9p_srv_userid) + name.len); + if (!ret) + return NULL; +#if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L + ret->num = num; +#endif + ret->name.len = name.len; + ret->name.utf8 = (void *)&ret[1]; + memcpy(ret->name.utf8, name.utf8, name.len); + ret->refcount = 1; + return ret; +} +#if !(CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L) +#define srv_userid_new(name, num) srv_userid_new(name) +#endif + +static struct lib9p_srv_userid *srv_userid_decref(struct lib9p_srv_userid *userid) { + assert(userid); + assert(userid->refcount); + userid->refcount--; + if (!userid->refcount) + free(userid); + return NULL; +} + +static struct lib9p_srv_userid *srv_userid_incref(struct lib9p_srv_userid *userid) { + assert(userid); + userid->refcount++; + return userid; +} + +/** + * Ensures that `file` is saved into the pathmap, and increments the + * gc_refcount by 1 (for presumptive insertion into the fidmap). + * parent_path's gc_refcount is also incremented as appropriate. + * + * Returns a pointer to the stored pathinfo. + */ +static inline struct srv_pathinfo *srv_path_save(struct srv_req *ctx, + lo_interface lib9p_srv_file file, + srv_path_t parent_path) { + assert(ctx); + assert(!LO_IS_NULL(file)); + + struct lib9p_qid qid = LO_CALL(file, qid); + struct srv_pathinfo *pathinfo = map_load(&ctx->parent_sess->paths, qid.path); + if (pathinfo) + assert(LO_EQ(pathinfo->file, file)); + else { + pathinfo = map_store(&ctx->parent_sess->paths, qid.path, + (struct srv_pathinfo){ + .file = file, + .type = srv_qid_filetype(qid), + .parent_dir = parent_path, + .gc_refcount = 0, + .io_refcount = 0, + }); + assert(pathinfo); + if (parent_path != qid.path) { + struct srv_pathinfo *parent = map_load(&ctx->parent_sess->paths, parent_path); + assert(parent); + parent->gc_refcount++; + } + } + pathinfo->gc_refcount++; + return pathinfo; +} + +/** + * Decrement the path's gc_refcount, and trigger garbage collection as + * appropriate. + */ +static inline void srv_path_decref(struct srv_req *ctx, srv_path_t path) { + assert(ctx); + + for (;;) { + struct srv_pathinfo *pathinfo = map_load(&ctx->parent_sess->paths, path); + assert(pathinfo); + pathinfo->gc_refcount--; + if (pathinfo->gc_refcount) + break; + srv_path_t parent_path = pathinfo->parent_dir; + LO_CALL(pathinfo->file, free); + map_del(&ctx->parent_sess->paths, path); + if (parent_path == path) + break; + path = parent_path; + } +} + +static inline void srv_fid_del(struct srv_req *ctx, lib9p_fid_t fid, struct srv_fidinfo *fidinfo, bool remove) { + assert(ctx); + assert(!ctx->user); + assert(fidinfo); + + if (fidinfo->flags & FIDFLAG_RCLOSE) + remove = true; + ctx->user = srv_userid_incref(fidinfo->user); + + struct srv_pathinfo *pathinfo = map_load(&ctx->parent_sess->paths, fidinfo->path); + assert(pathinfo); + + if (remove) + LO_CALL(pathinfo->file, remove, ctx); + + if (fidinfo->flags & FIDFLAG_OPEN) { + switch (fidinfo->type) { + case SRV_FILETYPE_DIR: + LO_CALL(fidinfo->dir.io, iofree); + break; + case SRV_FILETYPE_FILE: + LO_CALL(fidinfo->file.io, iofree); + break; + case SRV_FILETYPE_AUTH: + assert_notreached("TODO: auth not yet implemented"); + break; + } + pathinfo->io_refcount--; + } + fidinfo->user = srv_userid_decref(fidinfo->user); + srv_path_decref(ctx, fidinfo->path); + map_del(&ctx->parent_sess->fids, fid); + + ctx->user = srv_userid_decref(ctx->user); +} + +/** + * Store fid as pointing to pathinfo. Assumes that + * pathinfo->gc_refcount has already been incremented; does *not* + * decrement it on failure. + */ +static inline struct srv_fidinfo *srv_fid_store(struct srv_req *ctx, lib9p_fid_t fid, struct srv_pathinfo *pathinfo, bool overwrite) { + assert(ctx); + assert(fid != LIB9P_FID_NOFID); + assert(pathinfo); + + struct lib9p_qid qid = LO_CALL(pathinfo->file, qid); + + struct srv_fidinfo *old_fidinfo = map_load(&ctx->parent_sess->fids, fid); + if (old_fidinfo) { + if (overwrite) { + /* This should only happen from Twalk; because + * directories cannot be RCLOSE and Twalk cannot walk on + * FIDs open for I/O, we can skip most of + * srv_fid_del(). */ + assert(old_fidinfo->type == SRV_FILETYPE_DIR); + assert(old_fidinfo->flags == 0); + + old_fidinfo->user = srv_userid_decref(old_fidinfo->user); + srv_path_decref(ctx, old_fidinfo->path); + map_del(&ctx->parent_sess->fids, fid); + } else { + lib9p_error(&ctx->basectx, + LIB9P_ERRNO_L_EBADF, "FID already in use"); + return NULL; + } + } + struct srv_fidinfo *fidinfo = map_store(&ctx->parent_sess->fids, fid, (struct srv_fidinfo){ + .path = qid.path, + .type = srv_qid_filetype(qid), + .user = srv_userid_incref(ctx->user), + }); + assert(fidinfo); + return fidinfo; +} /* base utilities *************************************************************/ -#define nonrespond_errorf errorf +static void srv_msglog(struct srv_req *req, enum lib9p_msg_type typ, void *hostmsg) { + struct lib9p_srv *srv = req->parent_sess->parent_conn->parent_srv; + if (srv->msglog) { + srv->msglog(req, typ, hostmsg); + return; + } + /* It sucks that %v trips -Wformat and -Wformat-extra-args + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47781 */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" +#pragma GCC diagnostic ignored "-Wformat-extra-args" + infof("%c %v", typ % 2 ? '<' : '>', lo_box_lib9p_msg_as_fmt_formatter(&req->basectx, typ, hostmsg)); +#pragma GCC diagnostic pop +} -static ssize_t write_Rmsg(struct _lib9p_srv_req *req, struct lib9p_Rmsg_send_buf *resp) { +static ssize_t srv_write_Rmsg(struct srv_req *req, struct lib9p_Rmsg_send_buf *resp) { ssize_t r; cr_mutex_lock(&req->parent_sess->parent_conn->writelock); r = io_writev(req->parent_sess->parent_conn->fd, resp->iov, resp->iov_cnt); @@ -170,59 +373,62 @@ static ssize_t write_Rmsg(struct _lib9p_srv_req *req, struct lib9p_Rmsg_send_buf return r; } -static void respond_error(struct _lib9p_srv_req *req) { -#if CONFIG_9P_ENABLE_9P2000_u - assert(req->ctx.basectx.err_num); +#define srv_nonrespond_errorf errorf + +static void srv_respond_error(struct srv_req *req) { +#if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L + assert(req->basectx.err_num); #endif - assert(req->ctx.basectx.err_msg[0]); + assert(req->basectx.err_msg[0]); ssize_t r; struct lib9p_msg_Rerror host = { .tag = req->tag, - .ename = lib9p_strn(req->ctx.basectx.err_msg, - CONFIG_9P_MAX_ERR_SIZE), + .errstr = lib9p_strn(req->basectx.err_msg, + CONFIG_9P_MAX_ERR_SIZE), #if CONFIG_9P_ENABLE_9P2000_u - .errno = req->ctx.basectx.err_num, + .errnum = req->basectx.err_num, #endif }; - struct _srv_sess *sess = req->parent_sess; + struct srv_sess *sess = req->parent_sess; + + /* XXX: This assumes that a version's min_msg_size is the + * Rerror overhead. That's true for the current + * implementation of core_gen, but is a sneaky assumption. */ + uint32_t overhead = lib9p_version_min_msg_size(sess->version); /* Truncate the error-string if necessary to avoid needing to - * return LINUX_ERANGE. */ - if (((uint32_t)host.ename.len) + sess->rerror_overhead > sess->max_msg_size) - host.ename.len = sess->max_msg_size - sess->rerror_overhead; + * return LIB9P_ERRNO_L_ERANGE. */ + if (((uint32_t)host.errstr.len) + overhead > sess->max_msg_size) + host.errstr.len = sess->max_msg_size - overhead; struct lib9p_Rmsg_send_buf net; - lib9p_Rmsg_marshal(&req->ctx.basectx, + lib9p_Rmsg_marshal(&req->basectx, LIB9P_TYP_Rerror, &host, &net); -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wformat" -#pragma GCC diagnostic ignored "-Wformat-extra-args" - infof("< %v", lo_box_lib9p_msg_Rerror_as_fmt_formatter(&host)); -#pragma GCC diagnostic pop - r = write_Rmsg(req, &net); + srv_msglog(req, LIB9P_TYP_Rerror, &host); + r = srv_write_Rmsg(req, &net); if (r < 0) - nonrespond_errorf("write: %s", net_strerror(-r)); + srv_nonrespond_errorf("write: %s", net_strerror(-r)); } /* read coroutine *************************************************************/ -static bool read_exactly(lo_interface net_stream_conn fd, uint8_t *buf, size_t goal, size_t *done) { +static inline bool srv_read_exactly(lo_interface net_stream_conn fd, uint8_t *buf, size_t goal, size_t *done) { assert(buf); assert(goal); assert(done); while (*done < goal) { ssize_t r = io_read(fd, &buf[*done], goal - *done); if (r < 0) { - nonrespond_errorf("read: %s", net_strerror(-r)); + srv_nonrespond_errorf("read: %s", net_strerror(-r)); return true; } else if (r == 0) { if (*done != 0) - nonrespond_errorf("read: unexpected EOF"); + srv_nonrespond_errorf("read: unexpected EOF"); return true; } *done += r; @@ -230,151 +436,163 @@ static bool read_exactly(lo_interface net_stream_conn fd, uint8_t *buf, size_t g return false; } -static void handle_message(struct _lib9p_srv_req *ctx); - -[[noreturn]] void lib9p_srv_read_cr(struct lib9p_srv *srv, lo_interface net_stream_listener listener) { +void lib9p_srv_accept_and_read_loop(struct lib9p_srv *srv, lo_interface net_stream_listener listener) { assert(srv); assert(srv->rootdir); assert(!LO_IS_NULL(listener)); srv->readers++; - uint32_t initial_rerror_overhead = lib9p_version_min_msg_size(LIB9P_VER_unknown); - for (;;) { - struct _srv_conn conn = { - .parent_srv = srv, - .fd = LO_CALL(listener, accept), - .reader = cr_getcid(), - }; - if (LO_IS_NULL(conn.fd)) { - nonrespond_errorf("accept: error"); + lo_interface net_stream_conn conn = LO_CALL(listener, accept); + if (LO_IS_NULL(conn)) { + srv_nonrespond_errorf("accept: error"); srv->readers--; if (srv->readers == 0) while (srv->writers > 0) - _lib9p_srv_reqch_send_req(&srv->_reqch, NULL); - cr_exit(); + cr_rpc_send_req(&srv->_reqch, NULL); + return; } + lib9p_srv_read(srv, conn); + } +} - struct _srv_sess sess = { - .parent_conn = &conn, - .version = LIB9P_VER_unknown, - .max_msg_size = CONFIG_9P_SRV_MAX_MSG_SIZE, - .rerror_overhead = initial_rerror_overhead, - .initialized = false, - }; - for (;;) { - nextmsg: - /* Read the message. */ - size_t done = 0; - uint8_t buf[7]; - if (read_exactly(conn.fd, buf, 4, &done)) - goto close; - size_t goal = uint32le_decode(buf); - if (goal < 7) { - nonrespond_errorf("T-message is impossibly small"); - goto close; - } - if (read_exactly(conn.fd, buf, 7, &done)) - goto close; - struct _lib9p_srv_req req = { - .parent_sess = &sess, - .tag = uint16le_decode(&buf[5]), - .net_bytes = buf, - .ctx = { - .basectx = { - .version = sess.version, - .max_msg_size = sess.max_msg_size, - }, - }, - }; - if (goal > sess.max_msg_size) { - lib9p_errorf(&req.ctx.basectx, - LINUX_EMSGSIZE, "T-message larger than %s limit (%zu > %"PRIu32")", - sess.initialized ? "negotiated" : "server", - goal, - sess.max_msg_size); - respond_error(&req); - goto nextmsg; - } - req.net_bytes = malloc(goal); - assert(req.net_bytes); - memcpy(req.net_bytes, buf, done); - if (read_exactly(conn.fd, req.net_bytes, goal, &done)) { - free(req.net_bytes); - goto close; - } +void lib9p_srv_read(struct lib9p_srv *srv, lo_interface net_stream_conn _conn) { + assert(srv); + assert(srv->rootdir); + assert(!LO_IS_NULL(_conn)); - /* Handle the message... */ - if (req.net_bytes[4] == LIB9P_TYP_Tversion) - /* ...in this coroutine for Tversion, */ - handle_message(&req); - else - /* ...but usually in another coroutine. */ - _lib9p_srv_reqch_send_req(&srv->_reqch, &req); + struct srv_conn conn = { + .parent_srv = srv, + .fd = _conn, + .reader = cr_getcid(), + }; + struct srv_sess sess = { + .parent_conn = &conn, + .version = LIB9P_VER_unknown, + .max_msg_size = CONFIG_9P_SRV_MAX_MSG_SIZE, + .initialized = false, + }; + for (;;) { + /* Read the message. */ + size_t done = 0; + uint8_t buf[7]; + if (srv_read_exactly(conn.fd, buf, 4, &done)) + break; + size_t goal = uint32le_decode(buf); + if (goal < 7) { + srv_nonrespond_errorf("T-message is impossibly small"); + break; + } + if (srv_read_exactly(conn.fd, buf, 7, &done)) + break; + struct srv_req req = { + .basectx = { + .version = sess.version, + .max_msg_size = sess.max_msg_size, + }, + + .parent_sess = &sess, + .tag = uint16le_decode(&buf[5]), + .net_bytes = buf, + }; + if (goal > sess.max_msg_size) { + lib9p_errorf(&req.basectx, + LIB9P_ERRNO_L_EMSGSIZE, "T-message larger than %s limit (%zu > %"PRIu32")", + sess.initialized ? "negotiated" : "server", + goal, + sess.max_msg_size); + srv_respond_error(&req); + continue; } - close: - if (sess.reqs.len == 0) - io_close(conn.fd); - else { - io_close_read(conn.fd); - sess.closing = true; - cr_pause_and_yield(); - assert(sess.reqs.len == 0); - io_close_write(conn.fd); + req.net_bytes = malloc(goal); + assert(req.net_bytes); + memcpy(req.net_bytes, buf, done); + if (srv_read_exactly(conn.fd, req.net_bytes, goal, &done)) { + free(req.net_bytes); + break; + } + + /* Handle the message... */ + if (req.net_bytes[4] == LIB9P_TYP_Tversion) + /* ...in this coroutine for Tversion, */ + lib9p_srv_worker(&req); + else + /* ...but usually in another coroutine. */ + cr_rpc_send_req(&srv->_reqch, &req); + } + if (map_len(&sess.reqs) == 0) + io_close(conn.fd); + else { + io_close_read(conn.fd); + sess.closing = true; + cr_pause_and_yield(); + assert(map_len(&sess.reqs) == 0); + io_close_write(conn.fd); + } + + assert(map_len(&sess.reqs) == 0); + map_free(&sess.reqs); + + struct srv_req pseudoreq = { + .basectx = { + .version = sess.version, + .max_msg_size = sess.max_msg_size, + }, + .parent_sess = &sess, + }; + MAP_FOREACH(&sess.fids, fid, fidinfo) { + srv_fid_del(&pseudoreq, fid, fidinfo, false); + if (lib9p_ctx_has_error(&pseudoreq.basectx)) { + srv_nonrespond_errorf("clunk: %.*s", CONFIG_9P_MAX_ERR_SIZE, pseudoreq.basectx.err_msg); + lib9p_ctx_clear_error(&pseudoreq.basectx); } } + map_free(&sess.fids); + + assert(map_len(&sess.paths) == 0); + map_free(&sess.paths); } /* write coroutine ************************************************************/ -COROUTINE lib9p_srv_write_cr(void *_srv) { - struct _lib9p_srv_req req; +void lib9p_srv_worker_loop(struct lib9p_srv *srv) { + struct srv_req req; _lib9p_srv_reqch_req_t rpc_handle; - struct lib9p_srv *srv = _srv; assert(srv); assert(srv->rootdir); - cr_begin(); srv->writers++; for (;;) { /* Receive the request from the reader coroutine. ************/ - rpc_handle = _lib9p_srv_reqch_recv_req(&srv->_reqch); + rpc_handle = cr_rpc_recv_req(&srv->_reqch); if (!rpc_handle.req) { srv->writers--; - _lib9p_srv_reqch_send_resp(rpc_handle, 0); - cr_exit(); + cr_rpc_send_resp(rpc_handle, 0); + return; } /* Copy the request from the reader coroutine's * stack to our stack. */ req = *rpc_handle.req; /* Record that we have it. */ - reqmap_store(&req.parent_sess->reqs, req.tag, &req); + struct srv_req **reqpp = map_store(&req.parent_sess->reqs, req.tag, &req); + assert(reqpp && *reqpp == &req); /* Notify the reader coroutine that we're done with * its data. */ - _lib9p_srv_reqch_send_resp(rpc_handle, 0); + cr_rpc_send_resp(rpc_handle, 0); /* Process the request. **************************************/ - handle_message(&req); - - /* Release resources. ****************************************/ - while (_lib9p_srv_flushch_can_send(&req.ctx._flushch)) - _lib9p_srv_flushch_send(&req.ctx._flushch, false); - reqmap_del(&req.parent_sess->reqs, req.tag); - if (req.parent_sess->closing && !req.parent_sess->reqs.len) - cr_unpause(req.parent_sess->parent_conn->reader); + lib9p_srv_worker(&req); } - - cr_end(); } #define _HANDLER_PROTO(typ) \ - static void handle_T##typ(struct _lib9p_srv_req *, \ - struct lib9p_msg_T##typ *, \ - struct lib9p_msg_R##typ *) + static void handle_T##typ(struct srv_req *, \ + struct lib9p_msg_T##typ *) _HANDLER_PROTO(version); +#if _LIB9P_ENABLE_stat _HANDLER_PROTO(auth); _HANDLER_PROTO(attach); _HANDLER_PROTO(flush); @@ -387,201 +605,120 @@ _HANDLER_PROTO(clunk); _HANDLER_PROTO(remove); _HANDLER_PROTO(stat); _HANDLER_PROTO(wstat); +#endif +#if CONFIG_9P_ENABLE_9P2000_p9p +_HANDLER_PROTO(openfd); +#endif #if CONFIG_9P_ENABLE_9P2000_e _HANDLER_PROTO(session); _HANDLER_PROTO(sread); _HANDLER_PROTO(swrite); #endif -typedef void (*tmessage_handler)(struct _lib9p_srv_req *, void *, void *); - -static tmessage_handler tmessage_handlers[0x100] = { - [LIB9P_TYP_Tversion] = (tmessage_handler)handle_Tversion, - [LIB9P_TYP_Tauth] = (tmessage_handler)handle_Tauth, - [LIB9P_TYP_Tattach] = (tmessage_handler)handle_Tattach, - [LIB9P_TYP_Tflush] = (tmessage_handler)handle_Tflush, - [LIB9P_TYP_Twalk] = (tmessage_handler)handle_Twalk, - [LIB9P_TYP_Topen] = (tmessage_handler)handle_Topen, - [LIB9P_TYP_Tcreate] = (tmessage_handler)handle_Tcreate, - [LIB9P_TYP_Tread] = (tmessage_handler)handle_Tread, - [LIB9P_TYP_Twrite] = (tmessage_handler)handle_Twrite, - [LIB9P_TYP_Tclunk] = (tmessage_handler)handle_Tclunk, - [LIB9P_TYP_Tremove] = (tmessage_handler)handle_Tremove, - [LIB9P_TYP_Tstat] = (tmessage_handler)handle_Tstat, - [LIB9P_TYP_Twstat] = (tmessage_handler)handle_Twstat, -#if CONFIG_9P_ENABLE_9P2000_e - [LIB9P_TYP_Tsession] = (tmessage_handler)handle_Tsession, - [LIB9P_TYP_Tsread] = (tmessage_handler)handle_Tsread, - [LIB9P_TYP_Tswrite] = (tmessage_handler)handle_Tswrite, -#endif -}; +typedef void (*tmessage_handler)(struct srv_req *, void *); -static void handle_message(struct _lib9p_srv_req *ctx) { +void lib9p_srv_worker(struct srv_req *ctx) { uint8_t *host_req = NULL; - uint8_t host_resp[CONFIG_9P_SRV_MAX_HOSTMSG_SIZE]; - /* Unmarshal it. */ - ssize_t host_size = lib9p_Tmsg_validate(&ctx->ctx.basectx, ctx->net_bytes); - if (host_size < 0) - goto write; + /* Unmarshal it. *****************************************************/ + ssize_t host_size = lib9p_Tmsg_validate(&ctx->basectx, ctx->net_bytes); + if (host_size < 0) { + srv_respond_error(ctx); + goto release; + } host_req = calloc(1, host_size); assert(host_req); enum lib9p_msg_type typ; - lib9p_Tmsg_unmarshal(&ctx->ctx.basectx, ctx->net_bytes, - &typ, host_req); -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wformat" -#pragma GCC diagnostic ignored "-Wformat-extra-args" - infof("> %v", lo_box_lib9p_msg_as_fmt_formatter(&ctx->ctx.basectx, typ, host_req)); -#pragma GCC diagnostic pop - - /* Handle it. */ - tmessage_handlers[typ](ctx, (void *)host_req, (void *)host_resp); + lib9p_Tmsg_unmarshal(&ctx->basectx, ctx->net_bytes, + &typ, host_req); + srv_msglog(ctx, typ, host_req); - write: - if (lib9p_ctx_has_error(&ctx->ctx.basectx)) - respond_error(ctx); - else { - struct lib9p_Rmsg_send_buf net_resp; - if (lib9p_Rmsg_marshal(&ctx->ctx.basectx, - typ+1, host_resp, - &net_resp)) - goto write; + /* Handle it. ********************************************************/ + tmessage_handler handler; #pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wformat" -#pragma GCC diagnostic ignored "-Wformat-extra-args" - infof("< %v", lo_box_lib9p_msg_as_fmt_formatter(&ctx->ctx.basectx, typ+1, &host_resp)); +#pragma GCC diagnostic ignored "-Wswitch-enum" + switch (typ) { + case LIB9P_TYP_Tversion: handler = (tmessage_handler)handle_Tversion; break; +#if _LIB9P_ENABLE_stat + case LIB9P_TYP_Tauth: handler = (tmessage_handler)handle_Tauth; break; + case LIB9P_TYP_Tattach: handler = (tmessage_handler)handle_Tattach; break; + case LIB9P_TYP_Tflush: handler = (tmessage_handler)handle_Tflush; break; + case LIB9P_TYP_Twalk: handler = (tmessage_handler)handle_Twalk; break; + case LIB9P_TYP_Topen: handler = (tmessage_handler)handle_Topen; break; + case LIB9P_TYP_Tcreate: handler = (tmessage_handler)handle_Tcreate; break; + case LIB9P_TYP_Tread: handler = (tmessage_handler)handle_Tread; break; + case LIB9P_TYP_Twrite: handler = (tmessage_handler)handle_Twrite; break; + case LIB9P_TYP_Tclunk: handler = (tmessage_handler)handle_Tclunk; break; + case LIB9P_TYP_Tremove: handler = (tmessage_handler)handle_Tremove; break; + case LIB9P_TYP_Tstat: handler = (tmessage_handler)handle_Tstat; break; + case LIB9P_TYP_Twstat: handler = (tmessage_handler)handle_Twstat; break; +#endif +#if CONFIG_9P_ENABLE_9P2000_p9p + case LIB9P_TYP_Topenfd: handler = (tmessage_handler)handle_Topenfd; break; +#endif +#if CONFIG_9P_ENABLE_9P2000_e + case LIB9P_TYP_Tsession: handler = (tmessage_handler)handle_Tsession; break; + case LIB9P_TYP_Tsread: handler = (tmessage_handler)handle_Tsread; break; + case LIB9P_TYP_Tswrite: handler = (tmessage_handler)handle_Tswrite; break; +#endif + default: + assert_notreached("lib9p_Tmsg_validate() should have rejected unknown typ"); + } #pragma GCC diagnostic pop - write_Rmsg(ctx, &net_resp); + handler(ctx, (void *)host_req); + assert(ctx->responded); + + /* Release resources. ************************************************/ + release: + map_del(&ctx->parent_sess->reqs, ctx->tag); + size_t nwaiters; + while ((nwaiters = cr_chan_num_waiters(&ctx->flush_ch))) { + cr_chan_send(&ctx->flush_ch, (nwaiters == 1) + ? _LIB9P_SRV_FLUSH_RFLUSH + : _LIB9P_SRV_FLUSH_SILENT); } + if (ctx->parent_sess->closing && !map_len(&ctx->parent_sess->reqs)) + cr_unpause(ctx->parent_sess->parent_conn->reader); if (host_req) free(host_req); free(ctx->net_bytes); } -#define util_handler_common(ctx, req, resp) do { \ - assert(ctx); \ - assert(req); \ - assert(resp); \ - resp->tag = req->tag; \ - } while (0) - -static inline bool srv_util_check_perm(struct _lib9p_srv_req *ctx, struct lib9p_stat *stat, uint8_t action) { - assert(ctx); - assert(stat); - assert(action); - - /* TODO actually check user and group instead of just assuming "other". */ - uint8_t mode = (uint8_t)(stat->file_mode & 07); - - return mode & action; -} - -/** - * Ensures that `file` is saved into the pathmap, and increments the - * gc_refcount by 1 (for presumptive insertion into the fidmap). - * parent_path's gc_refcount is also incremented as appropriate. - * - * Returns a pointer to the stored pathinfo. - */ -static inline struct srv_pathinfo *srv_util_pathsave(struct _lib9p_srv_req *ctx, - lo_interface lib9p_srv_file file, - srv_path_t parent_path) { - assert(ctx); - assert(!LO_IS_NULL(file)); - - struct lib9p_qid qid = LO_CALL(file, qid); - struct srv_pathinfo *pathinfo = pathmap_load(&ctx->parent_sess->paths, qid.path); - if (pathinfo) - assert(LO_EQ(pathinfo->file, file)); - else { - pathinfo = pathmap_store(&ctx->parent_sess->paths, qid.path, - (struct srv_pathinfo){ - .file = file, - .parent_dir = parent_path, - .gc_refcount = 0, - .io_refcount = 0, - }); - assert(pathinfo); - if (parent_path != qid.path) { - struct srv_pathinfo *parent = pathmap_load(&ctx->parent_sess->paths, parent_path); - assert(parent); - parent->gc_refcount++; - } - } - pathinfo->gc_refcount++; - return pathinfo; -} - -/** - * Decrement the path's gc_refcount, and trigger garbage collection as - * appropriate. - */ -static inline void srv_util_pathfree(struct _lib9p_srv_req *ctx, srv_path_t path) { - assert(ctx); - - struct srv_pathinfo *pathinfo = pathmap_load(&ctx->parent_sess->paths, path); - assert(pathinfo); - pathinfo->gc_refcount--; - if (pathinfo->gc_refcount == 0) { - if (pathinfo->parent_dir != path) - srv_util_pathfree(ctx, pathinfo->parent_dir); - LO_CALL(pathinfo->file, free); - pathmap_del(&ctx->parent_sess->paths, path); - } -} - -static inline bool srv_util_pathisdir(struct srv_pathinfo *pathinfo) { - assert(pathinfo); - return LO_CALL(pathinfo->file, qid).type & LIB9P_QT_DIR; -} - -/** - * Store fid as pointing to pathinfo. Assumes that - * pathinfo->gc_refcount has already been incremented; does *not* - * decrement it on failure. - */ -static inline struct _srv_fidinfo *srv_util_fidsave(struct _lib9p_srv_req *ctx, lib9p_fid_t fid, struct srv_pathinfo *pathinfo, bool overwrite) { - assert(ctx); - assert(fid != LIB9P_FID_NOFID); - assert(pathinfo); - - struct lib9p_qid qid = LO_CALL(pathinfo->file, qid); - - struct _srv_fidinfo *fidinfo = fidmap_load(&ctx->parent_sess->fids, fid); - if (fidinfo) { - if (overwrite) { - struct srv_pathinfo *old_pathinfo = pathmap_load(&ctx->parent_sess->paths, fidinfo->path); - assert(old_pathinfo); - if (srv_util_pathisdir(old_pathinfo)) - LO_CALL(fidinfo->dir.io, iofree); - else - LO_CALL(fidinfo->file.io, iofree); - srv_util_pathfree(ctx, fidinfo->path); - } else { - lib9p_error(&ctx->ctx.basectx, - LINUX_EBADF, "FID already in use"); - return NULL; - } +static inline void _srv_respond(struct srv_req *ctx, enum lib9p_msg_type resp_typ, void *host_resp) { + assert(!ctx->responded); + if (lib9p_ctx_has_error(&ctx->basectx)) { + error: + srv_respond_error(ctx); + } else if (ctx->flush_acknowledged) { + /* do nothing */ } else { - fidinfo = fidmap_store(&ctx->parent_sess->fids, fid, (struct _srv_fidinfo){}); - if (!fidinfo) { - lib9p_error(&ctx->ctx.basectx, - LINUX_EMFILE, "too many open files"); - return NULL; - } + assert(host_resp); + struct lib9p_Rmsg_send_buf net_resp; + if (lib9p_Rmsg_marshal(&ctx->basectx, + resp_typ, host_resp, + &net_resp)) + goto error; + srv_msglog(ctx, resp_typ, host_resp); + srv_write_Rmsg(ctx, &net_resp); } - *fidinfo = (struct _srv_fidinfo){ - .path = qid.path, - }; - return fidinfo; + ctx->responded = true; } +#define srv_respond(CTX, TYP, HOST_RESP) do { \ + struct lib9p_msg_R##TYP *_host_resp = HOST_RESP; \ + _srv_respond(CTX, LIB9P_TYP_R##TYP, _host_resp); \ +} while (0) + +/* handle_T* ******************************************************************/ +#define srv_handler_common(ctx, typ, req) \ + assert(ctx); \ + assert(req); \ + struct lib9p_msg_T##typ *_typecheck_req [[gnu::unused]] = req; \ + struct lib9p_msg_R##typ resp = { .tag = ctx->tag } -static void handle_Tversion(struct _lib9p_srv_req *ctx, - struct lib9p_msg_Tversion *req, - struct lib9p_msg_Rversion *resp) { - util_handler_common(ctx, req, resp); +static void handle_Tversion(struct srv_req *ctx, + struct lib9p_msg_Tversion *req) { + srv_handler_common(ctx, version, req); enum lib9p_version version = LIB9P_VER_unknown; @@ -593,7 +730,14 @@ static void handle_Tversion(struct _lib9p_srv_req *ctx, '0' <= req->version.utf8[4] && req->version.utf8[4] <= '9' && '0' <= req->version.utf8[5] && req->version.utf8[5] <= '9' && (req->version.len == 6 || req->version.utf8[6] == '.')) { +#if CONFIG_9P_ENABLE_9P2000 version = LIB9P_VER_9P2000; +#endif +#if CONFIG_9P_ENABLE_9P2000_p9p + struct lib9p_srv *srv = ctx->parent_sess->parent_conn->parent_srv; + if (srv->type_assert_unix && !LO_IS_NULL(srv->type_assert_unix(ctx->parent_sess->parent_conn->fd))) + version = LIB9P_VER_9P2000_p9p; +#endif #if CONFIG_9P_ENABLE_9P2000_u if (lib9p_str_eq(lib9p_str_sliceleft(req->version, 6), lib9p_str(".u"))) version = LIB9P_VER_9P2000_u; @@ -606,292 +750,321 @@ static void handle_Tversion(struct _lib9p_srv_req *ctx, uint32_t min_msg_size = lib9p_version_min_msg_size(version); if (req->max_msg_size < min_msg_size) { - lib9p_errorf(&ctx->ctx.basectx, - LINUX_EDOM, "requested max_msg_size is less than minimum for %s (%"PRIu32" < %"PRIu32")", + lib9p_errorf(&ctx->basectx, + LIB9P_ERRNO_L_EDOM, "requested max_msg_size is less than minimum for %s (%"PRIu32" < %"PRIu32")", lib9p_version_str(version), req->max_msg_size, min_msg_size); - return; + goto tversion_return; } - resp->version = lib9p_str((char *)lib9p_version_str(version)); /* cast to discard "const" qualifier */ - resp->max_msg_size = (CONFIG_9P_SRV_MAX_MSG_SIZE < req->max_msg_size) + resp.version = lib9p_str((char *)lib9p_version_str(version)); /* cast to discard "const" qualifier */ +#if CONFIG_9P_ENABLE_9P2000_p9p + if (version == LIB9P_VER_9P2000_p9p) + resp.version = lib9p_str("9P2000"); +#endif + resp.max_msg_size = (CONFIG_9P_SRV_MAX_MSG_SIZE < req->max_msg_size) ? CONFIG_9P_SRV_MAX_MSG_SIZE : req->max_msg_size; /* Close the old session. */ - if (ctx->parent_sess->reqs.len) { + if (map_len(&ctx->parent_sess->reqs)) { /* Flush all in-progress requests, and wait for them * to finish. */ - struct cr_select_arg *list = alloca(sizeof(struct cr_select_arg) * ctx->parent_sess->reqs.len); - while (ctx->parent_sess->reqs.len) { - uint16_t tag [[gnu::unused]]; - struct _lib9p_srv_req **reqpp; + struct cr_select_arg *args = stack_alloc(map_len(&ctx->parent_sess->reqs), struct cr_select_arg); + while (map_len(&ctx->parent_sess->reqs)) { size_t i = 0; - bool flushed; MAP_FOREACH(&ctx->parent_sess->reqs, tag, reqpp) { - list[i] = CR_SELECT_RECV(&((*reqpp)->ctx._flushch), &flushed); + enum _lib9p_srv_flush_result flushed; + args[i++] = CR_SELECT_RECV(&((*reqpp)->flush_ch), &flushed); } - cr_select_v(i, list); + assert(i == map_len(&ctx->parent_sess->reqs)); + cr_select_v(i, args); } } - if (ctx->parent_sess->fids.len) { - /* Close all FIDs. */ - uint32_t fid; - struct _srv_fidinfo *fidinfo [[gnu::unused]]; - MAP_FOREACH(&ctx->parent_sess->fids, fid, fidinfo) { - handle_Tclunk(ctx, - &(struct lib9p_msg_Tclunk){.fid = fid}, - &(struct lib9p_msg_Rclunk){}); + /* Close all FIDs. */ + MAP_FOREACH(&ctx->parent_sess->fids, fid, fidinfo) { + srv_fid_del(ctx, fid, fidinfo, false); + if (lib9p_ctx_has_error(&ctx->basectx)) { + srv_nonrespond_errorf("clunk: %.*s", CONFIG_9P_MAX_ERR_SIZE, ctx->basectx.err_msg); + lib9p_ctx_clear_error(&ctx->basectx); } } /* Replace the old session with the new session. */ ctx->parent_sess->version = version; - ctx->parent_sess->max_msg_size = resp->max_msg_size; - ctx->parent_sess->rerror_overhead = min_msg_size; + ctx->parent_sess->max_msg_size = resp.max_msg_size; + + tversion_return: + srv_respond(ctx, version, &resp); } -static void handle_Tauth(struct _lib9p_srv_req *ctx, - struct lib9p_msg_Tauth *req, - struct lib9p_msg_Rauth *resp) { - util_handler_common(ctx, req, resp); +#if _LIB9P_ENABLE_stat +static void handle_Tauth(struct srv_req *ctx, + struct lib9p_msg_Tauth *req) { + srv_handler_common(ctx, auth, req); - ctx->ctx.uid = req->n_uid; - ctx->ctx.uname = req->uname; struct lib9p_srv *srv = ctx->parent_sess->parent_conn->parent_srv; - if (!srv->auth) { - lib9p_error(&ctx->ctx.basectx, - LINUX_EOPNOTSUPP, "authentication not required"); - return; + lib9p_error(&ctx->basectx, + LIB9P_ERRNO_L_EOPNOTSUPP, "authentication not required"); + goto tauth_return; } - srv->auth(&ctx->ctx, req->aname); - lib9p_error(&ctx->ctx.basectx, - LINUX_EOPNOTSUPP, "TODO: auth not implemented"); + ctx->user = srv_userid_new(req->uname, req->unum); + + srv->auth(ctx, req->aname); + + lib9p_error(&ctx->basectx, + LIB9P_ERRNO_L_EOPNOTSUPP, "TODO: auth not implemented"); + + if (lib9p_ctx_has_error(&ctx->basectx)) + ctx->user = srv_userid_decref(ctx->user); + + tauth_return: + srv_respond(ctx, auth, &resp); } -static void handle_Tattach(struct _lib9p_srv_req *ctx, - struct lib9p_msg_Tattach *req, - struct lib9p_msg_Rattach *resp) { - util_handler_common(ctx, req, resp); +static void handle_Tattach(struct srv_req *ctx, + struct lib9p_msg_Tattach *req) { + srv_handler_common(ctx, attach, req); - ctx->ctx.uid = req->n_uid; - ctx->ctx.uname = req->uname; - struct lib9p_srv *srv = ctx->parent_sess->parent_conn->parent_srv; + if (req->fid == LIB9P_FID_NOFID) { + lib9p_error(&ctx->basectx, + LIB9P_ERRNO_L_EBADF, "cannot assign to NOFID"); + goto tattach_return; + } + struct lib9p_srv *srv = ctx->parent_sess->parent_conn->parent_srv; if (srv->auth) { - /* - struct lib9p_srv_filehandle *fh = fidmap_get(req->afid); - if (!fh) - lib9p_error(&ctx->ctx.basectx, - LINUX_EACCES, "FID provided as auth-file is not a valid FID"); - else if (fh->type != FH_AUTH) - lib9p_error(&ctx->ctx.basectx, - LINUX_EACCES, "FID provided as auth-file is not an auth-file"); - else if (!lib9p_str_eq(fh->data.auth.uname, req->uname)) - lib9p_errorf(&ctx->ctx.basectx, - LINUX_EACCES, "FID provided as auth-file is for user=\"%.*s\" and cannot be used for user=\"%.*s\"", - fh->data.auth.uname.len, fh->data.auth.uname.utf8, + struct srv_fidinfo *afid = map_load(&ctx->parent_sess->fids, req->afid); + if (!afid) + lib9p_error(&ctx->basectx, + LIB9P_ERRNO_L_EACCES, "FID provided as auth-file is not a valid FID"); + else if (afid->type != SRV_FILETYPE_AUTH) + lib9p_error(&ctx->basectx, + LIB9P_ERRNO_L_EACCES, "FID provided as auth-file is not an auth-file"); + else if (!lib9p_str_eq(afid->user->name, req->uname)) + lib9p_errorf(&ctx->basectx, + LIB9P_ERRNO_L_EACCES, "FID provided as auth-file is for user=\"%.*s\" and cannot be used for user=\"%.*s\"", + afid->user->name.len, afid->user->name.utf8, req->uname.len, req->uname.utf8); - else if (!lib9p_str_eq(fh->data.auth.aname, req->aname)) - lib9p_errorf(&ctx->ctx.basectx, - LINUX_EACCES, "FID provided as auth-file is for tree=\"%.*s\" and cannot be used for tree=\"%.*s\"", - fh->data.auth.aname.len, fh->data.auth.aname.utf8, +#if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L + else if (afid->user->num != req->unum) + lib9p_errorf(&ctx->basectx, + LIB9P_ERRNO_L_EACCES, "FID provided as auth-file is for user=%"PRIu32" and cannot be used for user=%"PRIu32, + afid->user->num, req->unum); +#endif + else if (!lib9p_str_eq(afid->auth.aname, req->aname)) + lib9p_errorf(&ctx->basectx, + LIB9P_ERRNO_L_EACCES, "FID provided as auth-file is for tree=\"%.*s\" and cannot be used for tree=\"%.*s\"", + afid->auth.aname.len, afid->auth.aname.utf8, req->aname.len, req->aname.utf8); - else if (!fh->data.auth.authenticated) - lib9p_error(&ctx->ctx.basectx, - LINUX_EACCES, "FID provided as auth-file has not completed authentication"); - fh->refcount--; - if (lib9p_ctx_has_error(&ctx->ctx)) - return; - */ - lib9p_error(&ctx->ctx.basectx, - LINUX_EOPNOTSUPP, "TODO: auth not (yet?) implemented"); - return; + else if (!afid->auth.completed) + lib9p_error(&ctx->basectx, + LIB9P_ERRNO_L_EACCES, "FID provided as auth-file has not completed authentication"); + if (lib9p_ctx_has_error(&ctx->basectx)) + goto tattach_return; + ctx->user = srv_userid_incref(afid->user); } else { if (req->afid != LIB9P_FID_NOFID) { - lib9p_error(&ctx->ctx.basectx, - LINUX_EACCES, "FID provided as auth-file, but no auth-file is required"); - return; + lib9p_error(&ctx->basectx, + LIB9P_ERRNO_L_EACCES, "FID provided as auth-file, but no auth-file is required"); + goto tattach_return; } - } - - if (req->fid == LIB9P_FID_NOFID) { - lib9p_error(&ctx->ctx.basectx, - LINUX_EBADF, "cannot assign to NOFID"); - return; + ctx->user = srv_userid_new(req->uname, req->unum); } /* 1. File object */ - lo_interface lib9p_srv_file root_file = srv->rootdir(&ctx->ctx, req->aname); - assert(LO_IS_NULL(root_file) == lib9p_ctx_has_error(&ctx->ctx.basectx)); - if (lib9p_ctx_has_error(&ctx->ctx.basectx)) - return; + lo_interface lib9p_srv_file root_file = srv->rootdir(ctx, req->aname); + assert(LO_IS_NULL(root_file) == lib9p_ctx_has_error(&ctx->basectx)); + if (lib9p_ctx_has_error(&ctx->basectx)) + goto tattach_return; struct lib9p_qid root_qid = LO_CALL(root_file, qid); - assert(root_qid.type & LIB9P_QT_DIR); + assert(srv_qid_filetype(root_qid) == SRV_FILETYPE_DIR); /* 2. pathinfo */ - struct srv_pathinfo *root_pathinfo = srv_util_pathsave(ctx, root_file, root_qid.path); + struct srv_pathinfo *root_pathinfo = srv_path_save(ctx, root_file, root_qid.path); /* 3. fidinfo */ - if (!srv_util_fidsave(ctx, req->fid, root_pathinfo, false)) { - srv_util_pathfree(ctx, root_qid.path); - return; + if (!srv_fid_store(ctx, req->fid, root_pathinfo, false)) { + srv_path_decref(ctx, root_qid.path); + goto tattach_return; } - resp->qid = root_qid; - return; + resp.qid = root_qid; + tattach_return: + if (ctx->user) + ctx->user = srv_userid_decref(ctx->user); + srv_respond(ctx, attach, &resp); } -static void handle_Tflush(struct _lib9p_srv_req *ctx, - struct lib9p_msg_Tflush *req, - struct lib9p_msg_Rflush *resp) { - util_handler_common(ctx, req, resp); - - struct _lib9p_srv_req **oldreqp = reqmap_load(&ctx->parent_sess->reqs, req->oldtag); - if (oldreqp) - _lib9p_srv_flushch_recv(&((*oldreqp)->ctx._flushch)); +static void handle_Tflush(struct srv_req *ctx, + struct lib9p_msg_Tflush *req) { + srv_handler_common(ctx, flush, req); + + struct srv_req **oldreqp = map_load(&ctx->parent_sess->reqs, req->oldtag); + if (oldreqp) { + struct srv_req *oldreq = *oldreqp; + enum _lib9p_srv_flush_result res = _LIB9P_SRV_FLUSH_RFLUSH; + switch (cr_select_l(CR_SELECT_RECV(&oldreq->flush_ch, &res), + CR_SELECT_SEND(&ctx->flush_ch, &res))) { + case 0: /* original request returned */ + req_debugf("original request (tag=%"PRIu16") returned", req->oldtag); + ctx->flush_acknowledged = (res == _LIB9P_SRV_FLUSH_SILENT); + break; + case 1: /* flush itself got flushed */ + req_debugf("flush itself flushed"); + ctx->flush_acknowledged = true; + break; + } + } + srv_respond(ctx, flush, &resp); } -static void handle_Twalk(struct _lib9p_srv_req *ctx, - struct lib9p_msg_Twalk *req, - struct lib9p_msg_Rwalk *resp) { - util_handler_common(ctx, req, resp); +static void handle_Twalk(struct srv_req *ctx, + struct lib9p_msg_Twalk *req) { + srv_handler_common(ctx, walk, req); if (req->newfid == LIB9P_FID_NOFID) { - lib9p_error(&ctx->ctx.basectx, - LINUX_EBADF, "cannot assign to NOFID"); - return; + lib9p_error(&ctx->basectx, + LIB9P_ERRNO_L_EBADF, "cannot assign to NOFID"); + goto twalk_return; } - struct _srv_fidinfo *fidinfo = fidmap_load(&ctx->parent_sess->fids, req->fid); + struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid); if (!fidinfo) { - lib9p_errorf(&ctx->ctx.basectx, - LINUX_EBADF, "bad file number %"PRIu32, req->fid); - return; + lib9p_errorf(&ctx->basectx, + LIB9P_ERRNO_L_EBADF, "bad file number %"PRIu32, req->fid); + goto twalk_return; + } + if (fidinfo->flags & FIDFLAG_OPEN) { + lib9p_error(&ctx->basectx, + LIB9P_ERRNO_L_EALREADY, "cannot walk on FID open for I/O"); + goto twalk_return; } + ctx->user = srv_userid_incref(fidinfo->user); - struct srv_pathinfo *pathinfo = pathmap_load(&ctx->parent_sess->paths, fidinfo->path); + struct srv_pathinfo *pathinfo = map_load(&ctx->parent_sess->paths, fidinfo->path); assert(pathinfo); pathinfo->gc_refcount++; - resp->wqid = (struct lib9p_qid *)(&resp[1]); - for (resp->nwqid = 0; resp->nwqid < req->nwname; resp->nwqid++) { + struct lib9p_qid _resp_qid[16]; + resp.wqid = _resp_qid; + for (resp.nwqid = 0; resp.nwqid < req->nwname; resp.nwqid++) { + if (pathinfo->type != SRV_FILETYPE_DIR) { + lib9p_error(&ctx->basectx, + LIB9P_ERRNO_L_ENOTDIR, "not a directory"); + break; + } + struct srv_pathinfo *new_pathinfo; - if (lib9p_str_eq(req->wname[resp->nwqid], lib9p_str(".."))) { - new_pathinfo = pathmap_load(&ctx->parent_sess->paths, pathinfo->parent_dir); + if (lib9p_str_eq(req->wname[resp.nwqid], lib9p_str(".."))) { + new_pathinfo = map_load(&ctx->parent_sess->paths, pathinfo->parent_dir); assert(new_pathinfo); new_pathinfo->gc_refcount++; } else { - if (!srv_util_pathisdir(pathinfo)) { - lib9p_error(&ctx->ctx.basectx, - LINUX_ENOTDIR, "not a directory"); - break; - } - - lo_interface lib9p_srv_file member_file = LO_CALL(pathinfo->file, dwalk, &ctx->ctx, req->wname[resp->nwqid]); - assert(LO_IS_NULL(member_file) == lib9p_ctx_has_error(&ctx->ctx.basectx)); - if (lib9p_ctx_has_error(&ctx->ctx.basectx)) + lo_interface lib9p_srv_file member_file = LO_CALL(pathinfo->file, dwalk, ctx, req->wname[resp.nwqid]); + assert(LO_IS_NULL(member_file) == lib9p_ctx_has_error(&ctx->basectx)); + if (lib9p_ctx_has_error(&ctx->basectx)) break; - new_pathinfo = srv_util_pathsave(ctx, member_file, LO_CALL(pathinfo->file, qid).path); + new_pathinfo = srv_path_save(ctx, member_file, LO_CALL(pathinfo->file, qid).path); + assert(new_pathinfo); } - if (srv_util_pathisdir(new_pathinfo)) { - struct lib9p_stat stat = LO_CALL(new_pathinfo->file, stat, &ctx->ctx); - if (lib9p_ctx_has_error(&ctx->ctx.basectx)) + if (new_pathinfo->type == SRV_FILETYPE_DIR) { + struct lib9p_srv_stat stat = LO_CALL(new_pathinfo->file, stat, ctx); + if (lib9p_ctx_has_error(&ctx->basectx)) break; - lib9p_stat_assert(stat); - if (!srv_util_check_perm(ctx, &stat, 0b001)) { - lib9p_error(&ctx->ctx.basectx, - LINUX_EACCES, "you do not have execute permission on that directory"); - srv_util_pathfree(ctx, LO_CALL(new_pathinfo->file, qid).path); + lib9p_srv_stat_assert(stat); + if (!srv_check_perm(ctx, &stat, 0b001)) { + lib9p_error(&ctx->basectx, + LIB9P_ERRNO_L_EACCES, "you do not have execute permission on that directory"); + srv_path_decref(ctx, LO_CALL(new_pathinfo->file, qid).path); break; } } - resp->wqid[resp->nwqid] = LO_CALL(new_pathinfo->file, qid); + resp.wqid[resp.nwqid] = LO_CALL(new_pathinfo->file, qid); - srv_util_pathfree(ctx, LO_CALL(pathinfo->file, qid).path); + srv_path_decref(ctx, LO_CALL(pathinfo->file, qid).path); pathinfo = new_pathinfo; } - if (resp->nwqid == req->nwname) { - if (req->newfid == req->fid) { - if (srv_util_pathisdir(pathinfo)) - LO_CALL(fidinfo->dir.io, iofree); - else - LO_CALL(fidinfo->file.io, iofree); - fidinfo->flags = 0; - } - if (!srv_util_fidsave(ctx, req->newfid, pathinfo, req->newfid == req->fid)) - srv_util_pathfree(ctx, LO_CALL(pathinfo->file, qid).path); + if (resp.nwqid == req->nwname) { + if (!srv_fid_store(ctx, req->newfid, pathinfo, req->newfid == req->fid)) + srv_path_decref(ctx, LO_CALL(pathinfo->file, qid).path); } else { - assert(lib9p_ctx_has_error(&ctx->ctx.basectx)); - srv_util_pathfree(ctx, LO_CALL(pathinfo->file, qid).path); - if (resp->nwqid > 0) - lib9p_ctx_clear_error(&ctx->ctx.basectx); + assert(lib9p_ctx_has_error(&ctx->basectx)); + srv_path_decref(ctx, LO_CALL(pathinfo->file, qid).path); + if (resp.nwqid > 0) + lib9p_ctx_clear_error(&ctx->basectx); } + twalk_return: + if (ctx->user) + ctx->user = srv_userid_decref(ctx->user); + srv_respond(ctx, walk, &resp); } -static void handle_Topen(struct _lib9p_srv_req *ctx, - struct lib9p_msg_Topen *req, - struct lib9p_msg_Ropen *resp) { - util_handler_common(ctx, req, resp); +static void handle_Topen(struct srv_req *ctx, + struct lib9p_msg_Topen *req) { + srv_handler_common(ctx, open, req); /* Check that the FID is valid for this. */ - struct _srv_fidinfo *fidinfo = fidmap_load(&ctx->parent_sess->fids, req->fid); + struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid); if (!fidinfo) { - lib9p_errorf(&ctx->ctx.basectx, - LINUX_EBADF, "bad file number %"PRIu32, req->fid); - return; + lib9p_errorf(&ctx->basectx, + LIB9P_ERRNO_L_EBADF, "bad file number %"PRIu32, req->fid); + goto topen_return; } if (fidinfo->flags & FIDFLAG_OPEN) { - lib9p_error(&ctx->ctx.basectx, - LINUX_EALREADY, "FID is already open"); - return; + lib9p_error(&ctx->basectx, + LIB9P_ERRNO_L_EALREADY, "FID is already open"); + goto topen_return; } - struct srv_pathinfo *pathinfo = pathmap_load(&ctx->parent_sess->paths, fidinfo->path); - assert(pathinfo); - if (srv_util_pathisdir(pathinfo)) { + if (fidinfo->type == SRV_FILETYPE_DIR) { if ( ((req->mode & LIB9P_O_MODE_MASK) != LIB9P_O_MODE_READ) || (req->mode & LIB9P_O_TRUNC) || (req->mode & LIB9P_O_RCLOSE) ) { - lib9p_error(&ctx->ctx.basectx, - LINUX_EISDIR, "directories cannot be written, executed, truncated, or removed-on-close"); - return; + lib9p_error(&ctx->basectx, + LIB9P_ERRNO_L_EISDIR, "directories cannot be written, executed, truncated, or removed-on-close"); + goto topen_return; } } + ctx->user = srv_userid_incref(fidinfo->user); /* Variables. */ - lib9p_o_t reqmode = req->mode; - uint8_t fidflags = fidinfo->flags; + lib9p_o_t reqmode = req->mode; + uint8_t fidflags = fidinfo->flags; + struct srv_pathinfo *pathinfo = map_load(&ctx->parent_sess->paths, fidinfo->path); + assert(pathinfo); /* Check permissions. */ if (reqmode & LIB9P_O_RCLOSE) { - struct srv_pathinfo *parent = pathmap_load(&ctx->parent_sess->paths, pathinfo->parent_dir); + struct srv_pathinfo *parent = map_load(&ctx->parent_sess->paths, pathinfo->parent_dir); assert(parent); - struct lib9p_stat parent_stat = LO_CALL(parent->file, stat, &ctx->ctx); - if (lib9p_ctx_has_error(&ctx->ctx.basectx)) - return; - lib9p_stat_assert(parent_stat); - if (!srv_util_check_perm(ctx, &parent_stat, 0b010)) { - lib9p_error(&ctx->ctx.basectx, - LINUX_EACCES, "permission denied to remove-on-close"); - return; + struct lib9p_srv_stat parent_stat = LO_CALL(parent->file, stat, ctx); + if (lib9p_ctx_has_error(&ctx->basectx)) + goto topen_return; + lib9p_srv_stat_assert(parent_stat); + if (!srv_check_perm(ctx, &parent_stat, 0b010)) { + lib9p_error(&ctx->basectx, + LIB9P_ERRNO_L_EACCES, "permission denied to remove-on-close"); + goto topen_return; } fidflags |= FIDFLAG_RCLOSE; } - struct lib9p_stat stat = LO_CALL(pathinfo->file, stat, &ctx->ctx); - if (lib9p_ctx_has_error(&ctx->ctx.basectx)) - return; - lib9p_stat_assert(stat); - if ((stat.file_mode & LIB9P_DM_EXCL) && pathinfo->io_refcount) { - lib9p_error(&ctx->ctx.basectx, - LINUX_EEXIST, "exclusive file is already opened"); - return; + struct lib9p_srv_stat stat = LO_CALL(pathinfo->file, stat, ctx); + if (lib9p_ctx_has_error(&ctx->basectx)) + goto topen_return; + lib9p_srv_stat_assert(stat); + if ((stat.mode & LIB9P_DM_EXCL) && pathinfo->io_refcount) { + lib9p_error(&ctx->basectx, + LIB9P_ERRNO_L_EEXIST, "exclusive file is already opened"); + goto topen_return; } - if (stat.file_mode & LIB9P_DM_APPEND) + if (stat.mode & LIB9P_DM_APPEND) { + fidflags |= FIDFLAG_APPEND; reqmode = reqmode & ~LIB9P_O_TRUNC; + } uint8_t perm_bits = 0; bool rd = false, wr = false; switch (reqmode & LIB9P_O_MODE_MASK) { @@ -912,33 +1085,42 @@ static void handle_Topen(struct _lib9p_srv_req *ctx, rd = true; break; } - if (!srv_util_check_perm(ctx, &stat, perm_bits)) { - lib9p_error(&ctx->ctx.basectx, - LINUX_EACCES, "permission denied"); - return; + if (!srv_check_perm(ctx, &stat, perm_bits)) { + lib9p_error(&ctx->basectx, + LIB9P_ERRNO_L_EACCES, "permission denied"); + goto topen_return; } /* Actually make the call. */ uint32_t iounit; struct lib9p_qid qid; - if (srv_util_pathisdir(pathinfo)) { - fidinfo->dir.io = LO_CALL(pathinfo->file, dopen, &ctx->ctx); - assert(LO_IS_NULL(fidinfo->dir.io) == lib9p_ctx_has_error(&ctx->ctx.basectx)); - if (lib9p_ctx_has_error(&ctx->ctx.basectx)) - return; + switch (pathinfo->type) { + case SRV_FILETYPE_DIR: + fidinfo->dir.io = LO_CALL(pathinfo->file, dopen, ctx); + assert(LO_IS_NULL(fidinfo->dir.io) == lib9p_ctx_has_error(&ctx->basectx)); + if (lib9p_ctx_has_error(&ctx->basectx)) + goto topen_return; fidinfo->dir.idx = 0; fidinfo->dir.off = 0; qid = LO_CALL(fidinfo->dir.io, qid); iounit = 0; - } else { - fidinfo->file.io = LO_CALL(pathinfo->file, fopen, &ctx->ctx, + break; + case SRV_FILETYPE_FILE: + fidinfo->file.io = LO_CALL(pathinfo->file, fopen, ctx, rd, wr, reqmode & LIB9P_O_TRUNC); - assert(LO_IS_NULL(fidinfo->file.io) == lib9p_ctx_has_error(&ctx->ctx.basectx)); - if (lib9p_ctx_has_error(&ctx->ctx.basectx)) - return; + assert(LO_IS_NULL(fidinfo->file.io) == lib9p_ctx_has_error(&ctx->basectx)); + if (lib9p_ctx_has_error(&ctx->basectx)) + goto topen_return; qid = LO_CALL(fidinfo->file.io, qid); iounit = LO_CALL(fidinfo->file.io, iounit); + break; + case SRV_FILETYPE_AUTH: + assert_notreached("TODO: auth not yet implemented"); + break; + default: + assert_notreached("invalid srv_filetype"); + break; } /* Success. */ @@ -948,222 +1130,326 @@ static void handle_Topen(struct _lib9p_srv_req *ctx, fidflags |= FIDFLAG_OPEN_W; pathinfo->io_refcount++; fidinfo->flags = fidflags; - resp->qid = qid; - resp->iounit = iounit; + resp.qid = qid; + resp.iounit = iounit; + topen_return: + if (ctx->user) + ctx->user = srv_userid_decref(ctx->user); + srv_respond(ctx, open, &resp); } -static void handle_Tcreate(struct _lib9p_srv_req *ctx, - struct lib9p_msg_Tcreate *req, - struct lib9p_msg_Rcreate *resp) { - util_handler_common(ctx, req, resp); +static void handle_Tcreate(struct srv_req *ctx, + struct lib9p_msg_Tcreate *req) { + srv_handler_common(ctx, create, req); + + lib9p_error(&ctx->basectx, + LIB9P_ERRNO_L_EOPNOTSUPP, "create not (yet?) implemented"); - lib9p_error(&ctx->ctx.basectx, - LINUX_EOPNOTSUPP, "create not (yet?) implemented"); + srv_respond(ctx, create, &resp); } -static void handle_Tread(struct _lib9p_srv_req *ctx, - struct lib9p_msg_Tread *req, - struct lib9p_msg_Rread *resp) { - util_handler_common(ctx, req, resp); +static inline struct lib9p_stat srv_stat_to_net_stat(struct lib9p_srv_stat in) { + return (struct lib9p_stat){ + .qid = in.qid, + .mode = in.mode, + .atime = in.atime_sec, + .mtime = in.mtime_sec, + .length = in.size, + .name = in.name, + .owner_uname = in.owner_uid.name, + .owner_gname = in.owner_gid.name, + .last_modifier_uname = in.last_modifier_uid.name, +#if CONFIG_9P_ENABLE_9P2000_u + .owner_unum = in.owner_uid.num, + .owner_gnum = in.owner_gid.num, + .last_modifier_unum = in.last_modifier_uid.num, + .extension = in.extension, +#endif + }; +} + +static void handle_Tread(struct srv_req *ctx, + struct lib9p_msg_Tread *req) { + srv_handler_common(ctx, read, req); + char *heap = NULL; /* TODO: serialize simultaneous reads to the same FID */ /* Check that the FID is valid for this. */ - struct _srv_fidinfo *fidinfo = fidmap_load(&ctx->parent_sess->fids, req->fid); + struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid); if (!fidinfo) { - lib9p_errorf(&ctx->ctx.basectx, - LINUX_EBADF, "bad file number %"PRIu32, req->fid); - return; + lib9p_errorf(&ctx->basectx, + LIB9P_ERRNO_L_EBADF, "bad file number %"PRIu32, req->fid); + goto tread_return; } if (!(fidinfo->flags & FIDFLAG_OPEN_R)) { - lib9p_error(&ctx->ctx.basectx, - LINUX_EINVAL, "FID not open for reading"); - return; + lib9p_error(&ctx->basectx, + LIB9P_ERRNO_L_EINVAL, "FID not open for reading"); + goto tread_return; } - /* Variables. */ - struct srv_pathinfo *pathinfo = pathmap_load(&ctx->parent_sess->paths, fidinfo->path); - assert(pathinfo); - /* Do it. */ - if (srv_util_pathisdir(pathinfo)) { - /* Translate byte-offset to object-index. */ - size_t idx; - if (req->offset == 0) - idx = 0; - else if (req->offset == fidinfo->dir.off) - idx = fidinfo->dir.idx; - else { - lib9p_errorf(&ctx->ctx.basectx, - LINUX_EINVAL, "invalid offset (must be 0 or %"PRIu64"): %"PRIu64, + ctx->user = srv_userid_incref(fidinfo->user); + switch (fidinfo->type) { + case SRV_FILETYPE_DIR: +#if _LIB9P_ENABLE_stat + /* Seek. */ + if (req->offset == 0) { + fidinfo->dir.idx = 0; + fidinfo->dir.off = 0; + fidinfo->dir.buffered_dirent = (struct lib9p_srv_dirent){}; + } else if (req->offset != fidinfo->dir.off) { + lib9p_errorf(&ctx->basectx, + LIB9P_ERRNO_L_EINVAL, "invalid offset (must be 0 or %"PRIu64"): %"PRIu64, fidinfo->dir.off, req->offset); - return; + goto tread_return; } - /* Do it. */ - resp->data = (char *)(&resp[1]); - size_t num = LO_CALL(fidinfo->dir.io, dread, &ctx->ctx, (uint8_t *)resp->data, req->count, idx); - /* Translate object-count back to byte-count. */ - uint32_t len = 0; - for (size_t i = 0; i < num; i++) { - uint32_t i_len; - lib9p_stat_validate(&ctx->ctx.basectx, req->count, &((uint8_t *)resp->data)[len], &i_len, NULL); - len += i_len; + /* Read. */ + resp.data = heap = malloc(req->count); /* TODO: cap req->count */ + resp.count = 0; + struct srv_pathinfo *dir_pathinfo = NULL; + for (;;) { + lo_interface lib9p_srv_file member_file = {}; + struct lib9p_srv_dirent member_dirent; + if (fidinfo->dir.buffered_dirent.name.len) { + member_dirent = fidinfo->dir.buffered_dirent; + } else { + member_dirent = LO_CALL(fidinfo->dir.io, dread, ctx, fidinfo->dir.idx); + if (lib9p_ctx_has_error(&ctx->basectx)) { + if (!resp.count) + goto tread_return; + lib9p_ctx_clear_error(&ctx->basectx); + break; + } + } + if (!member_dirent.name.len) + break; + struct lib9p_srv_stat member_stat; + struct srv_pathinfo *member_pathinfo = map_load(&ctx->parent_sess->paths, member_dirent.qid.path); + if (member_pathinfo) { + member_stat = LO_CALL(member_pathinfo->file, stat, ctx); + } else { + if (!dir_pathinfo) + dir_pathinfo = map_load(&ctx->parent_sess->paths, fidinfo->path); + assert(dir_pathinfo); + member_file = LO_CALL(dir_pathinfo->file, dwalk, ctx, member_dirent.name); + assert(LO_IS_NULL(member_file) == lib9p_ctx_has_error(&ctx->basectx)); + if (!lib9p_ctx_has_error(&ctx->basectx)) + member_stat = LO_CALL(member_file, stat, ctx); + } + if (lib9p_ctx_has_error(&ctx->basectx)) { + if (!LO_IS_NULL(member_file)) + LO_CALL(member_file, free); + if (!resp.count) + goto tread_return; + lib9p_ctx_clear_error(&ctx->basectx); + break; + } + lib9p_srv_stat_assert(member_stat); + struct lib9p_stat member_netstat = srv_stat_to_net_stat(member_stat); + uint32_t nbytes = lib9p_stat_marshal(&ctx->basectx, req->count-resp.count, &member_netstat, + (uint8_t *)&resp.data[resp.count]); + if (!LO_IS_NULL(member_file)) + LO_CALL(member_file, free); + if (!nbytes) { + if (!resp.count) { + lib9p_error(&ctx->basectx, + LIB9P_ERRNO_L_ERANGE, "stat object does not fit into negotiated max message size"); + goto tread_return; + } + fidinfo->dir.buffered_dirent = member_dirent; + break; + } + resp.count += nbytes; + fidinfo->dir.idx++; + fidinfo->dir.off += nbytes; + fidinfo->dir.buffered_dirent = (struct lib9p_srv_dirent){}; } - resp->count = len; - /* Remember. */ - fidinfo->dir.idx = idx+num; - fidinfo->dir.off = req->offset + len; - } else { +#else + assert_notreached("Tread for directory on protocol version without that"); +#endif + break; + case SRV_FILETYPE_FILE: struct iovec iov; - LO_CALL(fidinfo->file.io, pread, &ctx->ctx, req->count, req->offset, &iov); - if (!lib9p_ctx_has_error(&ctx->ctx.basectx)) { - resp->count = iov.iov_len; - resp->data = iov.iov_base; - if (resp->count > req->count) - resp->count = req->count; + LO_CALL(fidinfo->file.io, pread, ctx, req->count, req->offset, &iov); + if (!lib9p_ctx_has_error(&ctx->basectx) && !ctx->flush_acknowledged) { + resp.count = iov.iov_len; + resp.data = iov.iov_base; + if (resp.count > req->count) + resp.count = req->count; } + break; + case SRV_FILETYPE_AUTH: + assert_notreached("TODO: auth not yet implemented"); + break; } + tread_return: + if (ctx->user) + ctx->user = srv_userid_decref(ctx->user); + srv_respond(ctx, read, &resp); + if (heap) + free(heap); } -static void handle_Twrite(struct _lib9p_srv_req *ctx, - struct lib9p_msg_Twrite *req, - struct lib9p_msg_Rwrite *resp) { - util_handler_common(ctx, req, resp); +static void handle_Twrite(struct srv_req *ctx, + struct lib9p_msg_Twrite *req) { + srv_handler_common(ctx, write, req); /* TODO: serialize simultaneous writes to the same FID */ /* Check that the FID is valid for this. */ - struct _srv_fidinfo *fidinfo = fidmap_load(&ctx->parent_sess->fids, req->fid); + struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid); if (!fidinfo) { - lib9p_errorf(&ctx->ctx.basectx, - LINUX_EBADF, "bad file number %"PRIu32, req->fid); - return; + lib9p_errorf(&ctx->basectx, + LIB9P_ERRNO_L_EBADF, "bad file number %"PRIu32, req->fid); + goto twrite_return; } if (!(fidinfo->flags & FIDFLAG_OPEN_W)) { - lib9p_error(&ctx->ctx.basectx, - LINUX_EINVAL, "FID not open for writing"); - return; + lib9p_error(&ctx->basectx, + LIB9P_ERRNO_L_EINVAL, "FID not open for writing"); + goto twrite_return; } - - /* Variables. */ - struct srv_pathinfo *pathinfo = pathmap_load(&ctx->parent_sess->paths, fidinfo->path); - assert(pathinfo); + if (fidinfo->flags & FIDFLAG_APPEND) + req->offset = 0; /* Do it. */ - resp->count = LO_CALL(fidinfo->file.io, pwrite, &ctx->ctx, req->data, req->count, req->offset); + ctx->user = srv_userid_incref(fidinfo->user); + resp.count = LO_CALL(fidinfo->file.io, pwrite, ctx, req->data, req->count, req->offset); + twrite_return: + if (ctx->user) + ctx->user = srv_userid_decref(ctx->user); + srv_respond(ctx, write, &resp); } -static void clunkremove(struct _lib9p_srv_req *ctx, lib9p_fid_t fid, bool remove) { - struct _srv_fidinfo *fidinfo = fidmap_load(&ctx->parent_sess->fids, fid); +static void handle_Tclunk(struct srv_req *ctx, + struct lib9p_msg_Tclunk *req) { + srv_handler_common(ctx, clunk, req); + + struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid); if (!fidinfo) { - lib9p_errorf(&ctx->ctx.basectx, - LINUX_EBADF, "bad file number %"PRIu32, fid); - return; + lib9p_errorf(&ctx->basectx, + LIB9P_ERRNO_L_EBADF, "bad file number %"PRIu32, req->fid); + goto tclunk_return; } - if (fidinfo->flags & FIDFLAG_RCLOSE) - remove = true; - struct srv_pathinfo *pathinfo = pathmap_load(&ctx->parent_sess->paths, fidinfo->path); - assert(pathinfo); - if (remove) { - if (pathinfo->parent_dir == fidinfo->path) { - lib9p_errorf(&ctx->ctx.basectx, - LINUX_EBUSY, "cannot remove root"); - goto clunk; - } - struct srv_pathinfo *parent = pathmap_load(&ctx->parent_sess->paths, pathinfo->parent_dir); - assert(parent); - struct lib9p_stat parent_stat = LO_CALL(parent->file, stat, &ctx->ctx); - if (!srv_util_check_perm(ctx, &parent_stat, 0b010)) { - lib9p_error(&ctx->ctx.basectx, - LINUX_EACCES, "you do not have write permission on the parent directory"); - goto clunk; - } - LO_CALL(pathinfo->file, remove, &ctx->ctx); - } + srv_fid_del(ctx, req->fid, fidinfo, false); - clunk: - if (fidinfo->flags & FIDFLAG_OPEN) { - if (srv_util_pathisdir(pathinfo)) - LO_CALL(fidinfo->dir.io, iofree); - else - LO_CALL(fidinfo->file.io, iofree); - pathinfo->io_refcount--; - } - srv_util_pathfree(ctx, LO_CALL(pathinfo->file, qid).path); - fidmap_del(&ctx->parent_sess->fids, fid); + tclunk_return: + srv_respond(ctx, clunk, &resp); } -static void handle_Tclunk(struct _lib9p_srv_req *ctx, - struct lib9p_msg_Tclunk *req, - struct lib9p_msg_Rclunk *resp) { - util_handler_common(ctx, req, resp); - - clunkremove(ctx, req->fid, false); -} +static void handle_Tremove(struct srv_req *ctx, + struct lib9p_msg_Tremove *req) { + srv_handler_common(ctx, remove, req); + struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid); + if (!fidinfo) { + lib9p_errorf(&ctx->basectx, + LIB9P_ERRNO_L_EBADF, "bad file number %"PRIu32, req->fid); + goto tremove_return; + } -static void handle_Tremove(struct _lib9p_srv_req *ctx, - struct lib9p_msg_Tremove *req, - struct lib9p_msg_Rremove *resp) { - util_handler_common(ctx, req, resp); + bool remove = true; + struct srv_pathinfo *pathinfo = map_load(&ctx->parent_sess->paths, fidinfo->path); + assert(pathinfo); + if (pathinfo->parent_dir == fidinfo->path) { + lib9p_error(&ctx->basectx, + LIB9P_ERRNO_L_EBUSY, "cannot remove root"); + remove = false; + goto tremove_main; + } + struct srv_pathinfo *parent = map_load(&ctx->parent_sess->paths, pathinfo->parent_dir); + assert(parent); + struct lib9p_srv_stat parent_stat = LO_CALL(parent->file, stat, ctx); + if (!lib9p_ctx_has_error(&ctx->basectx) && !srv_check_perm(ctx, &parent_stat, 0b010)) { + lib9p_error(&ctx->basectx, + LIB9P_ERRNO_L_EACCES, "you do not have write permission on the parent directory"); + remove = false; + goto tremove_main; + } - clunkremove(ctx, req->fid, true); + tremove_main: + srv_fid_del(ctx, req->fid, fidinfo, remove); + tremove_return: + srv_respond(ctx, remove, &resp); } -static void handle_Tstat(struct _lib9p_srv_req *ctx, - struct lib9p_msg_Tstat *req, - struct lib9p_msg_Rstat *resp) { - util_handler_common(ctx, req, resp); +static void handle_Tstat(struct srv_req *ctx, + struct lib9p_msg_Tstat *req) { + srv_handler_common(ctx, stat, req); - struct _srv_fidinfo *fidinfo = fidmap_load(&ctx->parent_sess->fids, req->fid); + struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid); if (!fidinfo) { - lib9p_errorf(&ctx->ctx.basectx, - LINUX_EBADF, "bad file number %"PRIu32, req->fid); - return; + lib9p_errorf(&ctx->basectx, + LIB9P_ERRNO_L_EBADF, "bad file number %"PRIu32, req->fid); + goto tstat_return; } - struct srv_pathinfo *pathinfo = pathmap_load(&ctx->parent_sess->paths, fidinfo->path); + struct srv_pathinfo *pathinfo = map_load(&ctx->parent_sess->paths, fidinfo->path); assert(pathinfo); - resp->stat = LO_CALL(pathinfo->file, stat, &ctx->ctx); - if (!lib9p_ctx_has_error(&ctx->ctx.basectx)) - lib9p_stat_assert(resp->stat); + ctx->user = srv_userid_incref(fidinfo->user); + struct lib9p_srv_stat stat = LO_CALL(pathinfo->file, stat, ctx); + if (lib9p_ctx_has_error(&ctx->basectx)) + goto tstat_return; + lib9p_srv_stat_assert(stat); + resp.stat = srv_stat_to_net_stat(stat); + tstat_return: + if (ctx->user) + ctx->user = srv_userid_decref(ctx->user); + srv_respond(ctx, stat, &resp); } -static void handle_Twstat(struct _lib9p_srv_req *ctx, - struct lib9p_msg_Twstat *req, - struct lib9p_msg_Rwstat *resp) { - util_handler_common(ctx, req, resp); +static void handle_Twstat(struct srv_req *ctx, + struct lib9p_msg_Twstat *req) { + srv_handler_common(ctx, wstat, req); + + lib9p_error(&ctx->basectx, + LIB9P_ERRNO_L_EOPNOTSUPP, "wstat not (yet?) implemented"); - lib9p_error(&ctx->ctx.basectx, - LINUX_EOPNOTSUPP, "wstat not (yet?) implemented"); + srv_respond(ctx, wstat, &resp); } +#endif + +#if CONFIG_9P_ENABLE_9P2000_p9p +static void handle_Topenfd(struct srv_req *ctx, + struct lib9p_msg_Topenfd *req) { + srv_handler_common(ctx, openfd, req); + + lib9p_error(&ctx->basectx, + LIB9P_ERRNO_L_EOPNOTSUPP, "openfd not (yet?) implemented"); + + srv_respond(ctx, openfd, &resp); +} +#endif #if CONFIG_9P_ENABLE_9P2000_e -static void handle_Tsession(struct _lib9p_srv_req *ctx, - struct lib9p_msg_Tsession *req, - struct lib9p_msg_Rsession *resp) { - util_handler_common(ctx, req, resp); +static void handle_Tsession(struct srv_req *ctx, + struct lib9p_msg_Tsession *req) { + srv_handler_common(ctx, session, req); + + lib9p_error(&ctx->basectx, + LIB9P_ERRNO_L_EOPNOTSUPP, "session not (yet?) implemented"); - lib9p_error(&ctx->ctx.basectx, - LINUX_EOPNOTSUPP, "session not (yet?) implemented"); + srv_respond(ctx, session, &resp); } -static void handle_Tsread(struct _lib9p_srv_req *ctx, - struct lib9p_msg_Tsread *req, - struct lib9p_msg_Rsread *resp) { - util_handler_common(ctx, req, resp); +static void handle_Tsread(struct srv_req *ctx, + struct lib9p_msg_Tsread *req) { + srv_handler_common(ctx, sread, req); - lib9p_error(&ctx->ctx.basectx, - LINUX_EOPNOTSUPP, "sread not (yet?) implemented"); + lib9p_error(&ctx->basectx, + LIB9P_ERRNO_L_EOPNOTSUPP, "sread not (yet?) implemented"); + + srv_respond(ctx, sread, &resp); } -static void handle_Tswrite(struct _lib9p_srv_req *ctx, - struct lib9p_msg_Tswrite *req, - struct lib9p_msg_Rswrite *resp) { - util_handler_common(ctx, req, resp); +static void handle_Tswrite(struct srv_req *ctx, + struct lib9p_msg_Tswrite *req) { + srv_handler_common(ctx, swrite, req); + + lib9p_error(&ctx->basectx, + LIB9P_ERRNO_L_EOPNOTSUPP, "swrite not (yet?) implemented"); - lib9p_error(&ctx->ctx.basectx, - LINUX_EOPNOTSUPP, "swrite not (yet?) implemented"); + srv_respond(ctx, swrite, &resp); } #endif diff --git a/lib9p/srv_include/lib9p/srv.h b/lib9p/srv_include/lib9p/srv.h new file mode 100644 index 0000000..c72aff5 --- /dev/null +++ b/lib9p/srv_include/lib9p/srv.h @@ -0,0 +1,305 @@ +/* lib9p/srv.h - 9P server + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#ifndef _LIB9P_SRV_H_ +#define _LIB9P_SRV_H_ + +#include <libcr/coroutine.h> +#include <libcr_ipc/chan.h> +#include <libcr_ipc/rpc.h> +#include <libhw/generic/net.h> +#include <libmisc/assert.h> +#include <libmisc/private.h> +#include <libobj/obj.h> + +#include <lib9p/core.h> + +/* context ********************************************************************/ + +struct lib9p_srv_userid { + struct lib9p_s name; +#if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L + lib9p_nuid_t num; +#endif + + BEGIN_PRIVATE(LIB9P_SRV_H); + unsigned int refcount; + END_PRIVATE(LIB9P_SRV_H); +}; + +enum _lib9p_srv_flush_result { + _LIB9P_SRV_FLUSH_RFLUSH, + _LIB9P_SRV_FLUSH_SILENT, +}; + +CR_CHAN_DECLARE(_lib9p_srv_flush_ch, enum _lib9p_srv_flush_result); + +struct lib9p_srv_ctx { + struct lib9p_ctx basectx; + struct lib9p_srv_userid *user; + + BEGIN_PRIVATE(LIB9P_SRV_H); + struct _lib9p_srv_sess *parent_sess; + lib9p_tag_t tag; + uint8_t *net_bytes; + _lib9p_srv_flush_ch_t flush_ch; + bool flush_acknowledged; + bool responded; + END_PRIVATE(LIB9P_SRV_H); +}; + +/** + * Return whether there is an outstanding Tflush or Tversion + * cancellation of this request. After becoming true, this may go + * back to false if the Tflush itself is flushed. + */ +bool lib9p_srv_flush_requested(struct lib9p_srv_ctx *ctx); + +/** + * Acknowledge that the handler is responding to an outstanding flush; + * a non-Rerror R-message will be elided in favor of Rflush/Rversion. + * lib9p_srv_flush_requested() must be true; so do not cr_yield() + * between checking lib9p_srv_flush_requested() and calling + * lib9p_srv_acknowledge_flush(). These are separate calls to + * facilitate cases where a flush merely truncates a call, instead of + * totally canceling it. + */ +void lib9p_srv_acknowledge_flush(struct lib9p_srv_ctx *ctx); + +/* version-independent stat ***************************************************/ + +struct lib9p_srv_stat { + struct lib9p_qid qid; + lib9p_dm_t mode; + uint32_t atime_sec; /* BUG: u32 seconds means a 2106 problem */ +#if CONFIG_9P_ENABLE_9P2000_L + uint32_t atime_nsec; +#endif + uint32_t mtime_sec; /* BUG: u32 seconds means a 2106 problem */ +#if CONFIG_9P_ENABLE_9P2000_L + uint32_t mtime_nsec; + uint32_t ctime_sec; /* BUG: u32 seconds means a 2106 problem */ + uint32_t ctime_nsec; + uint32_t btime_sec; /* BUG: u32 seconds means a 2106 problem */ + uint32_t btime_nsec; +#endif + uint64_t size; + struct lib9p_s name; + struct lib9p_srv_userid owner_uid; + struct lib9p_srv_userid owner_gid; + struct lib9p_srv_userid last_modifier_uid; +#if CONFIG_9P_ENABLE_9P2000_u + struct lib9p_s extension; +#endif +}; + +static inline void lib9p_srv_stat_assert(struct lib9p_srv_stat stat) { + assert( ((bool)(stat.mode & LIB9P_DM_DIR )) == ((bool)(stat.qid.type & LIB9P_QT_DIR )) ); + assert( ((bool)(stat.mode & LIB9P_DM_APPEND)) == ((bool)(stat.qid.type & LIB9P_QT_APPEND)) ); + assert( ((bool)(stat.mode & LIB9P_DM_EXCL )) == ((bool)(stat.qid.type & LIB9P_QT_EXCL )) ); + assert( ((bool)(stat.mode & LIB9P_DM_AUTH )) == ((bool)(stat.qid.type & LIB9P_QT_AUTH )) ); + assert( ((bool)(stat.mode & LIB9P_DM_TMP )) == ((bool)(stat.qid.type & LIB9P_QT_TMP )) ); + assert( (stat.size == 0) || !(stat.mode & LIB9P_DM_DIR) ); +} + +/* interface definitions ******************************************************/ + +struct lib9p_srv_dirent { + struct lib9p_qid qid; + struct lib9p_s name; +}; + +lo_interface lib9p_srv_fio; +lo_interface lib9p_srv_dio; + +/* FIXME: I don't like that the pointer returned by pread() has to + * remain live after it returns. Perhaps a `respond()`-callback? But + * that just reads as gross in C. + * + * FIXME: It would be nice if pread() could return more than 1 iovec. + */ +#define lib9p_srv_file_LO_IFACE \ + /* resource management **********************************************/ \ + \ + /** \ + * free() is be called when all FIDs associated with the file are \ + * clunked. \ + * \ + * free() MUST NOT error. \ + */ \ + LO_FUNC(void , free ) \ + \ + /** \ + * qid() is called frequently and returns the current QID of the file. \ + * The .path field MUST never change, the .type field may change in \ + * response to wstat() calls (but the QT_DIR bit MUST NOT change), and \ + * the .vers field may change frequently in response to any number of \ + * things (wstat(), write(), or non-9P events). \ + * \ + * qid() MUST NOT error. \ + */ \ + LO_FUNC(struct lib9p_qid , qid ) \ + \ + /* non-"opened" generic I/O *****************************************/ \ + \ + /** Strings returned from stat() must remain valid until free(). */ \ + LO_FUNC(struct lib9p_srv_stat , stat , struct lib9p_srv_ctx *) \ + LO_FUNC(void , wstat , struct lib9p_srv_ctx *, \ + struct lib9p_srv_stat) \ + LO_FUNC(void , remove , struct lib9p_srv_ctx *) \ + \ + /* non-"opened" directory I/O ***************************************/ \ + \ + LO_FUNC(lo_interface lib9p_srv_file, dwalk , struct lib9p_srv_ctx *, \ + struct lib9p_s childname) \ + LO_FUNC(lo_interface lib9p_srv_file, dcreate, struct lib9p_srv_ctx *, \ + struct lib9p_s childname, \ + struct lib9p_srv_userid *user, \ + struct lib9p_srv_userid *group, \ + lib9p_dm_t perm) \ + \ + /* open() for I/O ***************************************************/ \ + \ + LO_FUNC(lo_interface lib9p_srv_fio , fopen , struct lib9p_srv_ctx *, \ + bool rd, bool wr, \ + bool trunc) \ + LO_FUNC(lo_interface lib9p_srv_dio , dopen , struct lib9p_srv_ctx *) +LO_INTERFACE(lib9p_srv_file); + +#define lib9p_srv_fio_LO_IFACE \ + LO_FUNC(struct lib9p_qid , qid ) \ + LO_FUNC(void , iofree ) \ + LO_FUNC(uint32_t , iounit ) \ + LO_FUNC(void , pread , struct lib9p_srv_ctx *, \ + uint32_t byte_count, \ + uint64_t byte_offset, \ + struct iovec *ret) \ + /** \ + * If the file was append-only when fopen()ed, then byte_offset will \ + * always be 0. \ + */ \ + LO_FUNC(uint32_t , pwrite , struct lib9p_srv_ctx *, \ + void *buf, \ + uint32_t byte_count, \ + uint64_t byte_offset) +LO_INTERFACE(lib9p_srv_fio); + +#define lib9p_srv_dio_LO_IFACE \ + LO_FUNC(struct lib9p_qid , qid ) \ + LO_FUNC(void , iofree ) \ + /** \ + * Return the idx-th dirent. idx will always be either 0 or \ + * prev_idx+1. A dirrent with an empty name signals EOF. The string + * must remain valid until the next dread() call or iofree(). \ + */ \ + LO_FUNC(struct lib9p_srv_dirent , dread , struct lib9p_srv_ctx *, \ + size_t idx) +LO_INTERFACE(lib9p_srv_dio); + +#define LIB9P_SRV_NOTDIR(TYP, NAM) \ + static lo_interface lib9p_srv_file NAM##_dwalk (TYP *, struct lib9p_srv_ctx *, struct lib9p_s) { assert_notreached("not a directory"); } \ + static lo_interface lib9p_srv_file NAM##_dcreate(TYP *, struct lib9p_srv_ctx *, struct lib9p_s, \ + struct lib9p_srv_userid *, struct lib9p_srv_userid *, lib9p_dm_t) { assert_notreached("not a directory"); } \ + static lo_interface lib9p_srv_dio NAM##_dopen (TYP *, struct lib9p_srv_ctx *) { assert_notreached("not a directory"); } + +#define LIB9P_SRV_NOTFILE(TYP, NAM) \ + static lo_interface lib9p_srv_fio NAM##_fopen (TYP *, struct lib9p_srv_ctx *, bool, bool, bool) { assert_notreached("not a file"); } + +/* main server entrypoints ****************************************************/ + +CR_RPC_DECLARE(_lib9p_srv_reqch, struct lib9p_srv_ctx *, bool); + +#if CONFIG_9P_ENABLE_9P2000_p9p +#define net_stream_conn_unix_LO_IFACE \ + LO_NEST(net_stream_conn) \ + /** Returns 0 on success, -errno on error. */ \ + LO_FUNC(int, send_unix_fd, int fd) +LO_INTERFACE(net_stream_conn_unix); +#endif + +struct lib9p_srv { + /* Things you provide */ + void /*TODO*/ (*auth )(struct lib9p_srv_ctx *, struct lib9p_s treename); /* optional */ + lo_interface lib9p_srv_file (*rootdir)(struct lib9p_srv_ctx *, struct lib9p_s treename); + void (*msglog )(struct lib9p_srv_ctx *, enum lib9p_msg_type, void *hostmsg); /* optional */ +#if CONFIG_9P_ENABLE_9P2000_p9p + lo_interface net_stream_conn_unix (*type_assert_unix)(lo_interface net_stream_conn); /* optional */ +#endif + + /* For internal use */ + BEGIN_PRIVATE(LIB9P_SRV_H); + unsigned int readers; + unsigned int writers; + _lib9p_srv_reqch_t _reqch; + END_PRIVATE(LIB9P_SRV_H); +}; + +/** + * In a loop loop, accept a connection call lib9p_srv_read() on it. + * If LO_CALL(listener, accept) fails, then the function returns. + * + * When the last lib9p_srv_accept_and_read_loop() instance for a given + * `srv` returns, it will signal all lib9p_srv_worker_loop() calls to + * return. + * + * @param srv: The server configuration and state; has an associated + * pool of lib9p_srv_worker_loop() coroutines. + * + * @param listener: The listener object to accept connections from. + */ +void lib9p_srv_accept_and_read_loop(struct lib9p_srv *srv, lo_interface net_stream_listener listener); + +/** + * You should probably not call this directly; you should probably use + * lib9p_srv_accept_and_read_loop(). + * + * Given an already-established stream connection (i.e. a TCP + * connection), service that connection; return once the connection is + * closed. Requests are dispatched to a pool of + * lib9p_srv_worker_loop() coroutines with the same `srv`. + * + * Will just close the connection if a T-message has a size[4] <7. + * + * @param srv: The server configuration and state; has an associated + * pool of lib9p_srv_worker_loop() coroutines. + * + * @param conn: The listener object to accept connections from. + * + * Errors that this function itself may send to clients: + * + * @errno L_EMSGSIZE T-message has size[4] bigger than max_msg_size + * @errno L_EDOM Tversion specified an impossibly small max_msg_size + * @errno L_EOPNOTSUPP T-message has an R-message type, or an unrecognized T-message type + * @errno L_EBADMSG T-message has wrong size[4] for its content, or has invalid UTF-8 + */ +void lib9p_srv_read(struct lib9p_srv *srv, lo_interface net_stream_conn conn); + +/** + * In a loop, call lib9p_srv_worker() to service requests to the + * `struct lib9p_srv *srv` argument that have been read by + * lib9p_srv_accept_and_read_loop() / lib9p_srv_read(). A "NULL" + * request causes the function to return. + * + * @param srv: The server configuration and state; has an associated + * pool of lib9p_srv_accept_and_read_loop() coroutines. + */ +void lib9p_srv_worker_loop(struct lib9p_srv *srv); + +/** + * You should probably not call this directly; you should probably use + * lib9p_srv_worker_loop(). + * + * Handle and send a response to a single request. + * + * @param req: The request to handle. + * + * Errors that this function itself may send to clients: + * + * @errno L_ERANGE R-message does not fit into max_msg_size + */ +void lib9p_srv_worker(struct lib9p_srv_ctx *req); + +#endif /* _LIB9P_SRV_H_ */ diff --git a/lib9p/tests/client_config/config.h b/lib9p/tests/client_config/config.h new file mode 100644 index 0000000..bcf030d --- /dev/null +++ b/lib9p/tests/client_config/config.h @@ -0,0 +1,19 @@ +/* config.h - Compile-time configuration for lib9p test clients + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +#define CONFIG_9P_MAX_ERR_SIZE 128 +#define CONFIG_9P_MAX_9P2000_e_WELEM 16 + +#define CONFIG_9P_ENABLE_9P2000 1 /* bool */ +#define CONFIG_9P_ENABLE_9P2000_u 1 /* bool */ +#define CONFIG_9P_ENABLE_9P2000_e 1 /* bool */ +#define CONFIG_9P_ENABLE_9P2000_L 1 /* bool */ +#define CONFIG_9P_ENABLE_9P2000_p9p 1 /* bool */ + +#endif /* _CONFIG_H_ */ diff --git a/lib9p/tests/runtest b/lib9p/tests/runtest index 379ea6d..6883391 100755 --- a/lib9p/tests/runtest +++ b/lib9p/tests/runtest @@ -1,65 +1,50 @@ #!/usr/bin/env bash -# lib9p/tests/runtest - Simple tests for the 9P `test_server` +# lib9p/tests/runtest - Test harness for the 9P `test_server` # # Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com> # SPDX-License-Identifier: AGPL-3.0-or-later set -euE -o pipefail -set -x -port=$(python -c 'import socket; s=socket.socket(); s.bind(("", 0)); print(s.getsockname()[1]); s.close()') -valgrind --error-exitcode=2 ./tests/test_server/test_server "$port" & -server_pid=$! -# shellcheck disable=SC2064 -trap "kill $server_pid || true; wait $server_pid || true" EXIT -server_addr="localhost:${port}" +build_aux=$(realpath --canonicalize-missing -- "${BASH_SOURCE[0]}/../../../build-aux") -client=(9p -a "$server_addr") +if [[ $# != 2 ]]; then + echo >&2 "Usage: $0 CLIENTSCRIPT EXPLOG" + exit 2 +fi +clientscript="$1" +explog="$2" -expect_lines() ( +cleanup=() +cleanup() { { set +x; } &>/dev/null - printf >&2 '+ diff -u expected.txt actual.txt\n' - diff -u <(printf '%s\n' "$@") <(printf '%s\n' "$out") -) - -while [[ -d /proc/$server_pid && "$(readlink /proc/$server_pid/fd/4 2>/dev/null)" != socket:* ]]; do sleep 0.1; done - -out=$("${client[@]}" ls -l '') -expect_lines \ - 'd-r-xr-xr-x M 0 root root 0 Oct 7 2024 Documentation' \ - '--r--r--r-- M 0 root root 166 Oct 7 2024 README.md' \ - '---w--w--w- M 0 root root 0 Oct 7 2024 shutdown' + local i + for ((i = ${#cleanup[@]} - 1; i >= 0; i--)); do + eval "set -x; ${cleanup[$i]}" + { set +x; } &>/dev/null + done +} +trap cleanup EXIT -out=$("${client[@]}" ls -l 'Documentation/') -expect_lines \ - '--r--r--r-- M 0 root root 166 Oct 7 2024 x' +logfile=$(mktemp -t lib9p-log.XXXXXXXXXX) +cleanup+=("rm -f -- ${logfile@Q}") -out=$("${client[@]}" read 'README.md') -expect_lines \ - '<!--' \ - ' README.md - test static file' \ - '' \ - ' Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>' \ - ' SPDX-License-Identifier: AGPL-3.0-or-later' \ - '-->' \ - 'Hello, world!' +port=$(python -c 'import socket; s=socket.socket(); s.bind(("", 0)); print(s.getsockname()[1]); s.close()') -out=$("${client[@]}" read 'Documentation/x') -expect_lines \ - '<!--' \ - ' Documentation/x.txt - test static file' \ - '' \ - ' Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>' \ - ' SPDX-License-Identifier: AGPL-3.0-or-later' \ - '-->' \ - 'foo' +set -x -out=$("${client[@]}" stat 'Documentation/x') -expect_lines \ - "'x' 'root' 'root' 'root' q (0000000000000001 1 ) m 0444 at 1728337905 mt 1728337904 l 166 t 0 d 0" +"${build_aux}/valgrind" ./tests/test_server/test_server "$port" "$logfile" & +server_pid=$! +cleanup+=("kill $server_pid || true; wait $server_pid || true") +while [[ -d /proc/$server_pid ]] && ! (readlink /proc/$server_pid/fd/* 2>/dev/null | grep -q ^socket:); do sleep 0.1; done -out=$("${client[@]}" write 'shutdown' <<<1) -expect_lines '' +if [[ "$(head -c2 -- "$clientscript")" == '#!' ]]; then + "$clientscript" "$port" +else + "${build_aux}/valgrind" "$clientscript" "$port" +fi wait "$server_pid" -trap - EXIT +cleanup=("${cleanup[@]::1}") + +diff -u -- <(grep -e '^[<>]' -- "$explog") "$logfile" diff --git a/lib9p/tests/test_compile.c b/lib9p/tests/test_compile.c index 8f2445d..e53b738 100644 --- a/lib9p/tests/test_compile.c +++ b/lib9p/tests/test_compile.c @@ -1,299 +1,1255 @@ /* lib9p/tests/test_compile.c - Generated by lib9p/tests/test_compile.c.gen. DO NOT EDIT! */ -#include <lib9p/9p.h> +#include <lib9p/core.h> int main(void) { [[gnu::unused]] uint64_t x; - x = LIB9P_TAG_NOTAG; - x = LIB9P_FID_NOFID; - x = LIB9P_DM_DIR; +#ifdef LIB9P_B4_FALSE + x = LIB9P_B4_FALSE; +#endif +#ifdef LIB9P_B4_TRUE + x = LIB9P_B4_TRUE; +#endif +#ifdef LIB9P_DM_APPEND x = LIB9P_DM_APPEND; - x = LIB9P_DM_EXCL; - x = _LIB9P_DM_PLAN9_MOUNT; +#endif +#ifdef LIB9P_DM_AUTH x = LIB9P_DM_AUTH; - x = LIB9P_DM_TMP; - x = _LIB9P_DM_UNUSED_25; - x = _LIB9P_DM_UNUSED_24; +#endif +#ifdef LIB9P_DM_DEVICE x = LIB9P_DM_DEVICE; - x = _LIB9P_DM_UNUSED_22; - x = LIB9P_DM_PIPE; - x = LIB9P_DM_SOCKET; - x = LIB9P_DM_SETUID; - x = LIB9P_DM_SETGID; - x = _LIB9P_DM_UNUSED_17; - x = _LIB9P_DM_UNUSED_16; - x = _LIB9P_DM_UNUSED_15; - x = _LIB9P_DM_UNUSED_14; - x = _LIB9P_DM_UNUSED_13; - x = _LIB9P_DM_UNUSED_12; - x = _LIB9P_DM_UNUSED_11; - x = _LIB9P_DM_UNUSED_10; - x = _LIB9P_DM_UNUSED_9; - x = LIB9P_DM_OWNER_R; - x = LIB9P_DM_OWNER_W; - x = LIB9P_DM_OWNER_X; +#endif +#ifdef LIB9P_DM_DIR + x = LIB9P_DM_DIR; +#endif +#ifdef LIB9P_DM_EXCL + x = LIB9P_DM_EXCL; +#endif +#ifdef LIB9P_DM_GROUP_R x = LIB9P_DM_GROUP_R; +#endif +#ifdef LIB9P_DM_GROUP_W x = LIB9P_DM_GROUP_W; +#endif +#ifdef LIB9P_DM_GROUP_X x = LIB9P_DM_GROUP_X; +#endif +#ifdef LIB9P_DM_OTHER_R x = LIB9P_DM_OTHER_R; +#endif +#ifdef LIB9P_DM_OTHER_W x = LIB9P_DM_OTHER_W; +#endif +#ifdef LIB9P_DM_OTHER_X x = LIB9P_DM_OTHER_X; +#endif +#ifdef LIB9P_DM_OWNER_R + x = LIB9P_DM_OWNER_R; +#endif +#ifdef LIB9P_DM_OWNER_W + x = LIB9P_DM_OWNER_W; +#endif +#ifdef LIB9P_DM_OWNER_X + x = LIB9P_DM_OWNER_X; +#endif +#ifdef LIB9P_DM_PERM_MASK x = LIB9P_DM_PERM_MASK; - x = LIB9P_QT_DIR; - x = LIB9P_QT_APPEND; - x = LIB9P_QT_EXCL; - x = _LIB9P_QT_PLAN9_MOUNT; - x = LIB9P_QT_AUTH; - x = LIB9P_QT_TMP; - x = LIB9P_QT_SYMLINK; - x = _LIB9P_QT_UNUSED_0; - x = LIB9P_QT_FILE; - x = LIB9P_NUID_NONUID; - x = _LIB9P_O_UNUSED_7; - x = LIB9P_O_RCLOSE; - x = _LIB9P_O_RESERVED_CEXEC; - x = LIB9P_O_TRUNC; - x = _LIB9P_O_UNUSED_3; - x = _LIB9P_O_UNUSED_2; - x = LIB9P_O_FLAG_MASK; - x = LIB9P_O_MODE_READ; - x = LIB9P_O_MODE_WRITE; - x = LIB9P_O_MODE_RDWR; - x = LIB9P_O_MODE_EXEC; - x = LIB9P_O_MODE_MASK; +#endif +#ifdef LIB9P_DM_PIPE + x = LIB9P_DM_PIPE; +#endif +#ifdef LIB9P_DM_SETGID + x = LIB9P_DM_SETGID; +#endif +#ifdef LIB9P_DM_SETUID + x = LIB9P_DM_SETUID; +#endif +#ifdef LIB9P_DM_SOCKET + x = LIB9P_DM_SOCKET; +#endif +#ifdef LIB9P_DM_TMP + x = LIB9P_DM_TMP; +#endif +#ifdef LIB9P_DT_BLOCK_DEV + x = LIB9P_DT_BLOCK_DEV; +#endif +#ifdef LIB9P_DT_CHAR_DEV + x = LIB9P_DT_CHAR_DEV; +#endif +#ifdef LIB9P_DT_DIRECTORY + x = LIB9P_DT_DIRECTORY; +#endif +#ifdef LIB9P_DT_PIPE + x = LIB9P_DT_PIPE; +#endif +#ifdef LIB9P_DT_REGULAR + x = LIB9P_DT_REGULAR; +#endif +#ifdef LIB9P_DT_SOCKET + x = LIB9P_DT_SOCKET; +#endif +#ifdef LIB9P_DT_SYMLINK + x = LIB9P_DT_SYMLINK; +#endif +#ifdef LIB9P_DT_UNKNOWN + x = LIB9P_DT_UNKNOWN; +#endif +#ifdef LIB9P_ERRNO_L_E2BIG + x = LIB9P_ERRNO_L_E2BIG; +#endif +#ifdef LIB9P_ERRNO_L_EACCES + x = LIB9P_ERRNO_L_EACCES; +#endif +#ifdef LIB9P_ERRNO_L_EADDRINUSE + x = LIB9P_ERRNO_L_EADDRINUSE; +#endif +#ifdef LIB9P_ERRNO_L_EADDRNOTAVAIL + x = LIB9P_ERRNO_L_EADDRNOTAVAIL; +#endif +#ifdef LIB9P_ERRNO_L_EADV + x = LIB9P_ERRNO_L_EADV; +#endif +#ifdef LIB9P_ERRNO_L_EAFNOSUPPORT + x = LIB9P_ERRNO_L_EAFNOSUPPORT; +#endif +#ifdef LIB9P_ERRNO_L_EAGAIN + x = LIB9P_ERRNO_L_EAGAIN; +#endif +#ifdef LIB9P_ERRNO_L_EALREADY + x = LIB9P_ERRNO_L_EALREADY; +#endif +#ifdef LIB9P_ERRNO_L_EBADE + x = LIB9P_ERRNO_L_EBADE; +#endif +#ifdef LIB9P_ERRNO_L_EBADF + x = LIB9P_ERRNO_L_EBADF; +#endif +#ifdef LIB9P_ERRNO_L_EBADFD + x = LIB9P_ERRNO_L_EBADFD; +#endif +#ifdef LIB9P_ERRNO_L_EBADMSG + x = LIB9P_ERRNO_L_EBADMSG; +#endif +#ifdef LIB9P_ERRNO_L_EBADR + x = LIB9P_ERRNO_L_EBADR; +#endif +#ifdef LIB9P_ERRNO_L_EBADRQC + x = LIB9P_ERRNO_L_EBADRQC; +#endif +#ifdef LIB9P_ERRNO_L_EBADSLT + x = LIB9P_ERRNO_L_EBADSLT; +#endif +#ifdef LIB9P_ERRNO_L_EBFONT + x = LIB9P_ERRNO_L_EBFONT; +#endif +#ifdef LIB9P_ERRNO_L_EBUSY + x = LIB9P_ERRNO_L_EBUSY; +#endif +#ifdef LIB9P_ERRNO_L_ECANCELED + x = LIB9P_ERRNO_L_ECANCELED; +#endif +#ifdef LIB9P_ERRNO_L_ECHILD + x = LIB9P_ERRNO_L_ECHILD; +#endif +#ifdef LIB9P_ERRNO_L_ECHRNG + x = LIB9P_ERRNO_L_ECHRNG; +#endif +#ifdef LIB9P_ERRNO_L_ECOMM + x = LIB9P_ERRNO_L_ECOMM; +#endif +#ifdef LIB9P_ERRNO_L_ECONNABORTED + x = LIB9P_ERRNO_L_ECONNABORTED; +#endif +#ifdef LIB9P_ERRNO_L_ECONNREFUSED + x = LIB9P_ERRNO_L_ECONNREFUSED; +#endif +#ifdef LIB9P_ERRNO_L_ECONNRESET + x = LIB9P_ERRNO_L_ECONNRESET; +#endif +#ifdef LIB9P_ERRNO_L_EDEADLK + x = LIB9P_ERRNO_L_EDEADLK; +#endif +#ifdef LIB9P_ERRNO_L_EDESTADDRREQ + x = LIB9P_ERRNO_L_EDESTADDRREQ; +#endif +#ifdef LIB9P_ERRNO_L_EDOM + x = LIB9P_ERRNO_L_EDOM; +#endif +#ifdef LIB9P_ERRNO_L_EDOTDOT + x = LIB9P_ERRNO_L_EDOTDOT; +#endif +#ifdef LIB9P_ERRNO_L_EDQUOT + x = LIB9P_ERRNO_L_EDQUOT; +#endif +#ifdef LIB9P_ERRNO_L_EEXIST + x = LIB9P_ERRNO_L_EEXIST; +#endif +#ifdef LIB9P_ERRNO_L_EFAULT + x = LIB9P_ERRNO_L_EFAULT; +#endif +#ifdef LIB9P_ERRNO_L_EFBIG + x = LIB9P_ERRNO_L_EFBIG; +#endif +#ifdef LIB9P_ERRNO_L_EHOSTDOWN + x = LIB9P_ERRNO_L_EHOSTDOWN; +#endif +#ifdef LIB9P_ERRNO_L_EHOSTUNREACH + x = LIB9P_ERRNO_L_EHOSTUNREACH; +#endif +#ifdef LIB9P_ERRNO_L_EHWPOISON + x = LIB9P_ERRNO_L_EHWPOISON; +#endif +#ifdef LIB9P_ERRNO_L_EIDRM + x = LIB9P_ERRNO_L_EIDRM; +#endif +#ifdef LIB9P_ERRNO_L_EILSEQ + x = LIB9P_ERRNO_L_EILSEQ; +#endif +#ifdef LIB9P_ERRNO_L_EINPROGRESS + x = LIB9P_ERRNO_L_EINPROGRESS; +#endif +#ifdef LIB9P_ERRNO_L_EINTR + x = LIB9P_ERRNO_L_EINTR; +#endif +#ifdef LIB9P_ERRNO_L_EINVAL + x = LIB9P_ERRNO_L_EINVAL; +#endif +#ifdef LIB9P_ERRNO_L_EIO + x = LIB9P_ERRNO_L_EIO; +#endif +#ifdef LIB9P_ERRNO_L_EISCONN + x = LIB9P_ERRNO_L_EISCONN; +#endif +#ifdef LIB9P_ERRNO_L_EISDIR + x = LIB9P_ERRNO_L_EISDIR; +#endif +#ifdef LIB9P_ERRNO_L_EISNAM + x = LIB9P_ERRNO_L_EISNAM; +#endif +#ifdef LIB9P_ERRNO_L_EKEYEXPIRED + x = LIB9P_ERRNO_L_EKEYEXPIRED; +#endif +#ifdef LIB9P_ERRNO_L_EKEYREJECTED + x = LIB9P_ERRNO_L_EKEYREJECTED; +#endif +#ifdef LIB9P_ERRNO_L_EKEYREVOKED + x = LIB9P_ERRNO_L_EKEYREVOKED; +#endif +#ifdef LIB9P_ERRNO_L_EL2HLT + x = LIB9P_ERRNO_L_EL2HLT; +#endif +#ifdef LIB9P_ERRNO_L_EL2NSYNC + x = LIB9P_ERRNO_L_EL2NSYNC; +#endif +#ifdef LIB9P_ERRNO_L_EL3HLT + x = LIB9P_ERRNO_L_EL3HLT; +#endif +#ifdef LIB9P_ERRNO_L_EL3RST + x = LIB9P_ERRNO_L_EL3RST; +#endif +#ifdef LIB9P_ERRNO_L_ELIBACC + x = LIB9P_ERRNO_L_ELIBACC; +#endif +#ifdef LIB9P_ERRNO_L_ELIBBAD + x = LIB9P_ERRNO_L_ELIBBAD; +#endif +#ifdef LIB9P_ERRNO_L_ELIBEXEC + x = LIB9P_ERRNO_L_ELIBEXEC; +#endif +#ifdef LIB9P_ERRNO_L_ELIBMAX + x = LIB9P_ERRNO_L_ELIBMAX; +#endif +#ifdef LIB9P_ERRNO_L_ELIBSCN + x = LIB9P_ERRNO_L_ELIBSCN; +#endif +#ifdef LIB9P_ERRNO_L_ELNRNG + x = LIB9P_ERRNO_L_ELNRNG; +#endif +#ifdef LIB9P_ERRNO_L_ELOOP + x = LIB9P_ERRNO_L_ELOOP; +#endif +#ifdef LIB9P_ERRNO_L_EMEDIUMTYPE + x = LIB9P_ERRNO_L_EMEDIUMTYPE; +#endif +#ifdef LIB9P_ERRNO_L_EMFILE + x = LIB9P_ERRNO_L_EMFILE; +#endif +#ifdef LIB9P_ERRNO_L_EMLINK + x = LIB9P_ERRNO_L_EMLINK; +#endif +#ifdef LIB9P_ERRNO_L_EMSGSIZE + x = LIB9P_ERRNO_L_EMSGSIZE; +#endif +#ifdef LIB9P_ERRNO_L_EMULTIHOP + x = LIB9P_ERRNO_L_EMULTIHOP; +#endif +#ifdef LIB9P_ERRNO_L_ENAMETOOLONG + x = LIB9P_ERRNO_L_ENAMETOOLONG; +#endif +#ifdef LIB9P_ERRNO_L_ENAVAIL + x = LIB9P_ERRNO_L_ENAVAIL; +#endif +#ifdef LIB9P_ERRNO_L_ENETDOWN + x = LIB9P_ERRNO_L_ENETDOWN; +#endif +#ifdef LIB9P_ERRNO_L_ENETRESET + x = LIB9P_ERRNO_L_ENETRESET; +#endif +#ifdef LIB9P_ERRNO_L_ENETUNREACH + x = LIB9P_ERRNO_L_ENETUNREACH; +#endif +#ifdef LIB9P_ERRNO_L_ENFILE + x = LIB9P_ERRNO_L_ENFILE; +#endif +#ifdef LIB9P_ERRNO_L_ENOANO + x = LIB9P_ERRNO_L_ENOANO; +#endif +#ifdef LIB9P_ERRNO_L_ENOBUFS + x = LIB9P_ERRNO_L_ENOBUFS; +#endif +#ifdef LIB9P_ERRNO_L_ENOCSI + x = LIB9P_ERRNO_L_ENOCSI; +#endif +#ifdef LIB9P_ERRNO_L_ENODATA + x = LIB9P_ERRNO_L_ENODATA; +#endif +#ifdef LIB9P_ERRNO_L_ENODEV + x = LIB9P_ERRNO_L_ENODEV; +#endif +#ifdef LIB9P_ERRNO_L_ENOENT + x = LIB9P_ERRNO_L_ENOENT; +#endif +#ifdef LIB9P_ERRNO_L_ENOEXEC + x = LIB9P_ERRNO_L_ENOEXEC; +#endif +#ifdef LIB9P_ERRNO_L_ENOKEY + x = LIB9P_ERRNO_L_ENOKEY; +#endif +#ifdef LIB9P_ERRNO_L_ENOLCK + x = LIB9P_ERRNO_L_ENOLCK; +#endif +#ifdef LIB9P_ERRNO_L_ENOLINK + x = LIB9P_ERRNO_L_ENOLINK; +#endif +#ifdef LIB9P_ERRNO_L_ENOMEDIUM + x = LIB9P_ERRNO_L_ENOMEDIUM; +#endif +#ifdef LIB9P_ERRNO_L_ENOMEM + x = LIB9P_ERRNO_L_ENOMEM; +#endif +#ifdef LIB9P_ERRNO_L_ENOMSG + x = LIB9P_ERRNO_L_ENOMSG; +#endif +#ifdef LIB9P_ERRNO_L_ENONET + x = LIB9P_ERRNO_L_ENONET; +#endif +#ifdef LIB9P_ERRNO_L_ENOPKG + x = LIB9P_ERRNO_L_ENOPKG; +#endif +#ifdef LIB9P_ERRNO_L_ENOPROTOOPT + x = LIB9P_ERRNO_L_ENOPROTOOPT; +#endif +#ifdef LIB9P_ERRNO_L_ENOSPC + x = LIB9P_ERRNO_L_ENOSPC; +#endif +#ifdef LIB9P_ERRNO_L_ENOSR + x = LIB9P_ERRNO_L_ENOSR; +#endif +#ifdef LIB9P_ERRNO_L_ENOSTR + x = LIB9P_ERRNO_L_ENOSTR; +#endif +#ifdef LIB9P_ERRNO_L_ENOSYS + x = LIB9P_ERRNO_L_ENOSYS; +#endif +#ifdef LIB9P_ERRNO_L_ENOTBLK + x = LIB9P_ERRNO_L_ENOTBLK; +#endif +#ifdef LIB9P_ERRNO_L_ENOTCONN + x = LIB9P_ERRNO_L_ENOTCONN; +#endif +#ifdef LIB9P_ERRNO_L_ENOTDIR + x = LIB9P_ERRNO_L_ENOTDIR; +#endif +#ifdef LIB9P_ERRNO_L_ENOTEMPTY + x = LIB9P_ERRNO_L_ENOTEMPTY; +#endif +#ifdef LIB9P_ERRNO_L_ENOTNAM + x = LIB9P_ERRNO_L_ENOTNAM; +#endif +#ifdef LIB9P_ERRNO_L_ENOTRECOVERABLE + x = LIB9P_ERRNO_L_ENOTRECOVERABLE; +#endif +#ifdef LIB9P_ERRNO_L_ENOTSOCK + x = LIB9P_ERRNO_L_ENOTSOCK; +#endif +#ifdef LIB9P_ERRNO_L_ENOTTY + x = LIB9P_ERRNO_L_ENOTTY; +#endif +#ifdef LIB9P_ERRNO_L_ENOTUNIQ + x = LIB9P_ERRNO_L_ENOTUNIQ; +#endif +#ifdef LIB9P_ERRNO_L_ENXIO + x = LIB9P_ERRNO_L_ENXIO; +#endif +#ifdef LIB9P_ERRNO_L_EOPNOTSUPP + x = LIB9P_ERRNO_L_EOPNOTSUPP; +#endif +#ifdef LIB9P_ERRNO_L_EOVERFLOW + x = LIB9P_ERRNO_L_EOVERFLOW; +#endif +#ifdef LIB9P_ERRNO_L_EOWNERDEAD + x = LIB9P_ERRNO_L_EOWNERDEAD; +#endif +#ifdef LIB9P_ERRNO_L_EPERM + x = LIB9P_ERRNO_L_EPERM; +#endif +#ifdef LIB9P_ERRNO_L_EPFNOSUPPORT + x = LIB9P_ERRNO_L_EPFNOSUPPORT; +#endif +#ifdef LIB9P_ERRNO_L_EPIPE + x = LIB9P_ERRNO_L_EPIPE; +#endif +#ifdef LIB9P_ERRNO_L_EPROTO + x = LIB9P_ERRNO_L_EPROTO; +#endif +#ifdef LIB9P_ERRNO_L_EPROTONOSUPPORT + x = LIB9P_ERRNO_L_EPROTONOSUPPORT; +#endif +#ifdef LIB9P_ERRNO_L_EPROTOTYPE + x = LIB9P_ERRNO_L_EPROTOTYPE; +#endif +#ifdef LIB9P_ERRNO_L_ERANGE + x = LIB9P_ERRNO_L_ERANGE; +#endif +#ifdef LIB9P_ERRNO_L_EREMCHG + x = LIB9P_ERRNO_L_EREMCHG; +#endif +#ifdef LIB9P_ERRNO_L_EREMOTE + x = LIB9P_ERRNO_L_EREMOTE; +#endif +#ifdef LIB9P_ERRNO_L_EREMOTEIO + x = LIB9P_ERRNO_L_EREMOTEIO; +#endif +#ifdef LIB9P_ERRNO_L_ERESTART + x = LIB9P_ERRNO_L_ERESTART; +#endif +#ifdef LIB9P_ERRNO_L_ERFKILL + x = LIB9P_ERRNO_L_ERFKILL; +#endif +#ifdef LIB9P_ERRNO_L_EROFS + x = LIB9P_ERRNO_L_EROFS; +#endif +#ifdef LIB9P_ERRNO_L_ESHUTDOWN + x = LIB9P_ERRNO_L_ESHUTDOWN; +#endif +#ifdef LIB9P_ERRNO_L_ESOCKTNOSUPPORT + x = LIB9P_ERRNO_L_ESOCKTNOSUPPORT; +#endif +#ifdef LIB9P_ERRNO_L_ESPIPE + x = LIB9P_ERRNO_L_ESPIPE; +#endif +#ifdef LIB9P_ERRNO_L_ESRCH + x = LIB9P_ERRNO_L_ESRCH; +#endif +#ifdef LIB9P_ERRNO_L_ESRMNT + x = LIB9P_ERRNO_L_ESRMNT; +#endif +#ifdef LIB9P_ERRNO_L_ESTALE + x = LIB9P_ERRNO_L_ESTALE; +#endif +#ifdef LIB9P_ERRNO_L_ESTRPIPE + x = LIB9P_ERRNO_L_ESTRPIPE; +#endif +#ifdef LIB9P_ERRNO_L_ETIME + x = LIB9P_ERRNO_L_ETIME; +#endif +#ifdef LIB9P_ERRNO_L_ETIMEDOUT + x = LIB9P_ERRNO_L_ETIMEDOUT; +#endif +#ifdef LIB9P_ERRNO_L_ETOOMANYREFS + x = LIB9P_ERRNO_L_ETOOMANYREFS; +#endif +#ifdef LIB9P_ERRNO_L_ETXTBSY + x = LIB9P_ERRNO_L_ETXTBSY; +#endif +#ifdef LIB9P_ERRNO_L_EUCLEAN + x = LIB9P_ERRNO_L_EUCLEAN; +#endif +#ifdef LIB9P_ERRNO_L_EUNATCH + x = LIB9P_ERRNO_L_EUNATCH; +#endif +#ifdef LIB9P_ERRNO_L_EUSERS + x = LIB9P_ERRNO_L_EUSERS; +#endif +#ifdef LIB9P_ERRNO_L_EXDEV + x = LIB9P_ERRNO_L_EXDEV; +#endif +#ifdef LIB9P_ERRNO_L_EXFULL + x = LIB9P_ERRNO_L_EXFULL; +#endif +#ifdef LIB9P_ERRNO_NOERROR x = LIB9P_ERRNO_NOERROR; - x = LIB9P_SUPER_MAGIC_V9FS_MAGIC; - x = _LIB9P_LO_UNUSED_31; - x = _LIB9P_LO_UNUSED_30; - x = _LIB9P_LO_UNUSED_29; - x = _LIB9P_LO_UNUSED_28; - x = _LIB9P_LO_UNUSED_27; - x = _LIB9P_LO_UNUSED_26; - x = _LIB9P_LO_UNUSED_25; - x = _LIB9P_LO_UNUSED_24; - x = _LIB9P_LO_UNUSED_23; - x = _LIB9P_LO_UNUSED_22; - x = _LIB9P_LO_UNUSED_21; - x = LIB9P_LO_SYNC; +#endif +#ifdef LIB9P_FID_NOFID + x = LIB9P_FID_NOFID; +#endif +#ifdef LIB9P_GETATTR_ALL + x = LIB9P_GETATTR_ALL; +#endif +#ifdef LIB9P_GETATTR_ATIME + x = LIB9P_GETATTR_ATIME; +#endif +#ifdef LIB9P_GETATTR_BASIC + x = LIB9P_GETATTR_BASIC; +#endif +#ifdef LIB9P_GETATTR_BLOCKS + x = LIB9P_GETATTR_BLOCKS; +#endif +#ifdef LIB9P_GETATTR_BTIME + x = LIB9P_GETATTR_BTIME; +#endif +#ifdef LIB9P_GETATTR_CTIME + x = LIB9P_GETATTR_CTIME; +#endif +#ifdef LIB9P_GETATTR_DATA_VERSION + x = LIB9P_GETATTR_DATA_VERSION; +#endif +#ifdef LIB9P_GETATTR_GEN + x = LIB9P_GETATTR_GEN; +#endif +#ifdef LIB9P_GETATTR_GID + x = LIB9P_GETATTR_GID; +#endif +#ifdef LIB9P_GETATTR_INO + x = LIB9P_GETATTR_INO; +#endif +#ifdef LIB9P_GETATTR_MODE + x = LIB9P_GETATTR_MODE; +#endif +#ifdef LIB9P_GETATTR_MTIME + x = LIB9P_GETATTR_MTIME; +#endif +#ifdef LIB9P_GETATTR_NLINK + x = LIB9P_GETATTR_NLINK; +#endif +#ifdef LIB9P_GETATTR_RDEV + x = LIB9P_GETATTR_RDEV; +#endif +#ifdef LIB9P_GETATTR_SIZE + x = LIB9P_GETATTR_SIZE; +#endif +#ifdef LIB9P_GETATTR_UID + x = LIB9P_GETATTR_UID; +#endif +#ifdef LIB9P_LOCK_FLAGS_BLOCK + x = LIB9P_LOCK_FLAGS_BLOCK; +#endif +#ifdef LIB9P_LOCK_FLAGS_RECLAIM + x = LIB9P_LOCK_FLAGS_RECLAIM; +#endif +#ifdef LIB9P_LOCK_STATUS_BLOCKED + x = LIB9P_LOCK_STATUS_BLOCKED; +#endif +#ifdef LIB9P_LOCK_STATUS_ERROR + x = LIB9P_LOCK_STATUS_ERROR; +#endif +#ifdef LIB9P_LOCK_STATUS_GRACE + x = LIB9P_LOCK_STATUS_GRACE; +#endif +#ifdef LIB9P_LOCK_STATUS_SUCCESS + x = LIB9P_LOCK_STATUS_SUCCESS; +#endif +#ifdef LIB9P_LOCK_TYPE_RDLCK + x = LIB9P_LOCK_TYPE_RDLCK; +#endif +#ifdef LIB9P_LOCK_TYPE_UNLCK + x = LIB9P_LOCK_TYPE_UNLCK; +#endif +#ifdef LIB9P_LOCK_TYPE_WRLCK + x = LIB9P_LOCK_TYPE_WRLCK; +#endif +#ifdef LIB9P_LO_APPEND + x = LIB9P_LO_APPEND; +#endif +#ifdef LIB9P_LO_BSD_FASYNC + x = LIB9P_LO_BSD_FASYNC; +#endif +#ifdef LIB9P_LO_CLOEXEC x = LIB9P_LO_CLOEXEC; - x = LIB9P_LO_NOATIME; - x = LIB9P_LO_NOFOLLOW; - x = LIB9P_LO_DIRECTORY; - x = LIB9P_LO_LARGEFILE; +#endif +#ifdef LIB9P_LO_CREATE + x = LIB9P_LO_CREATE; +#endif +#ifdef LIB9P_LO_DIRECT x = LIB9P_LO_DIRECT; - x = LIB9P_LO_BSD_FASYNC; +#endif +#ifdef LIB9P_LO_DIRECTORY + x = LIB9P_LO_DIRECTORY; +#endif +#ifdef LIB9P_LO_DSYNC x = LIB9P_LO_DSYNC; - x = LIB9P_LO_NONBLOCK; - x = LIB9P_LO_APPEND; - x = LIB9P_LO_TRUNC; - x = LIB9P_LO_NOCTTY; +#endif +#ifdef LIB9P_LO_EXCL x = LIB9P_LO_EXCL; - x = LIB9P_LO_CREATE; - x = _LIB9P_LO_UNUSED_5; - x = _LIB9P_LO_UNUSED_4; - x = _LIB9P_LO_UNUSED_3; - x = _LIB9P_LO_UNUSED_2; +#endif +#ifdef LIB9P_LO_FLAG_MASK x = LIB9P_LO_FLAG_MASK; +#endif +#ifdef LIB9P_LO_LARGEFILE + x = LIB9P_LO_LARGEFILE; +#endif +#ifdef LIB9P_LO_MODE_MASK + x = LIB9P_LO_MODE_MASK; +#endif +#ifdef LIB9P_LO_MODE_NOACCESS + x = LIB9P_LO_MODE_NOACCESS; +#endif +#ifdef LIB9P_LO_MODE_RDONLY x = LIB9P_LO_MODE_RDONLY; - x = LIB9P_LO_MODE_WRONLY; +#endif +#ifdef LIB9P_LO_MODE_RDWR x = LIB9P_LO_MODE_RDWR; - x = LIB9P_LO_MODE_NOACCESS; - x = LIB9P_LO_MODE_MASK; - x = LIB9P_DT_UNKNOWN; - x = LIB9P_DT_PIPE; - x = LIB9P_DT_CHAR_DEV; - x = LIB9P_DT_DIRECTORY; - x = LIB9P_DT_BLOCK_DEV; - x = LIB9P_DT_REGULAR; - x = LIB9P_DT_SYMLINK; - x = LIB9P_DT_SOCKET; - x = _LIB9P_DT_WHITEOUT; - x = _LIB9P_MODE_UNUSED_31; - x = _LIB9P_MODE_UNUSED_30; - x = _LIB9P_MODE_UNUSED_29; - x = _LIB9P_MODE_UNUSED_28; - x = _LIB9P_MODE_UNUSED_27; - x = _LIB9P_MODE_UNUSED_26; - x = _LIB9P_MODE_UNUSED_25; - x = _LIB9P_MODE_UNUSED_24; - x = _LIB9P_MODE_UNUSED_23; - x = _LIB9P_MODE_UNUSED_22; - x = _LIB9P_MODE_UNUSED_21; - x = _LIB9P_MODE_UNUSED_20; - x = _LIB9P_MODE_UNUSED_19; - x = _LIB9P_MODE_UNUSED_18; - x = _LIB9P_MODE_UNUSED_17; - x = _LIB9P_MODE_UNUSED_16; - x = LIB9P_MODE_PERM_SETGROUP; - x = LIB9P_MODE_PERM_SETUSER; - x = LIB9P_MODE_PERM_STICKY; - x = LIB9P_MODE_PERM_OWNER_R; - x = LIB9P_MODE_PERM_OWNER_W; - x = LIB9P_MODE_PERM_OWNER_X; +#endif +#ifdef LIB9P_LO_MODE_WRONLY + x = LIB9P_LO_MODE_WRONLY; +#endif +#ifdef LIB9P_LO_NOATIME + x = LIB9P_LO_NOATIME; +#endif +#ifdef LIB9P_LO_NOCTTY + x = LIB9P_LO_NOCTTY; +#endif +#ifdef LIB9P_LO_NOFOLLOW + x = LIB9P_LO_NOFOLLOW; +#endif +#ifdef LIB9P_LO_NONBLOCK + x = LIB9P_LO_NONBLOCK; +#endif +#ifdef LIB9P_LO_SYNC + x = LIB9P_LO_SYNC; +#endif +#ifdef LIB9P_LO_TRUNC + x = LIB9P_LO_TRUNC; +#endif +#ifdef LIB9P_MODE_FMT_BLOCK_DEV + x = LIB9P_MODE_FMT_BLOCK_DEV; +#endif +#ifdef LIB9P_MODE_FMT_CHAR_DEV + x = LIB9P_MODE_FMT_CHAR_DEV; +#endif +#ifdef LIB9P_MODE_FMT_DIRECTORY + x = LIB9P_MODE_FMT_DIRECTORY; +#endif +#ifdef LIB9P_MODE_FMT_MASK + x = LIB9P_MODE_FMT_MASK; +#endif +#ifdef LIB9P_MODE_FMT_PIPE + x = LIB9P_MODE_FMT_PIPE; +#endif +#ifdef LIB9P_MODE_FMT_REGULAR + x = LIB9P_MODE_FMT_REGULAR; +#endif +#ifdef LIB9P_MODE_FMT_SOCKET + x = LIB9P_MODE_FMT_SOCKET; +#endif +#ifdef LIB9P_MODE_FMT_SYMLINK + x = LIB9P_MODE_FMT_SYMLINK; +#endif +#ifdef LIB9P_MODE_PERM_GROUP_R x = LIB9P_MODE_PERM_GROUP_R; +#endif +#ifdef LIB9P_MODE_PERM_GROUP_W x = LIB9P_MODE_PERM_GROUP_W; +#endif +#ifdef LIB9P_MODE_PERM_GROUP_X x = LIB9P_MODE_PERM_GROUP_X; +#endif +#ifdef LIB9P_MODE_PERM_MASK + x = LIB9P_MODE_PERM_MASK; +#endif +#ifdef LIB9P_MODE_PERM_OTHER_R x = LIB9P_MODE_PERM_OTHER_R; +#endif +#ifdef LIB9P_MODE_PERM_OTHER_W x = LIB9P_MODE_PERM_OTHER_W; +#endif +#ifdef LIB9P_MODE_PERM_OTHER_X x = LIB9P_MODE_PERM_OTHER_X; - x = LIB9P_MODE_PERM_MASK; - x = LIB9P_MODE_FMT_PIPE; - x = LIB9P_MODE_FMT_CHAR_DEV; - x = LIB9P_MODE_FMT_DIRECTORY; - x = LIB9P_MODE_FMT_BLOCK_DEV; - x = LIB9P_MODE_FMT_REGULAR; - x = LIB9P_MODE_FMT_SYMLINK; - x = LIB9P_MODE_FMT_SOCKET; - x = LIB9P_MODE_FMT_MASK; - x = LIB9P_B4_FALSE; - x = LIB9P_B4_TRUE; - x = _LIB9P_GETATTR_UNUSED_63; - x = _LIB9P_GETATTR_UNUSED_62; - x = _LIB9P_GETATTR_UNUSED_61; - x = _LIB9P_GETATTR_UNUSED_60; - x = _LIB9P_GETATTR_UNUSED_59; - x = _LIB9P_GETATTR_UNUSED_58; - x = _LIB9P_GETATTR_UNUSED_57; - x = _LIB9P_GETATTR_UNUSED_56; - x = _LIB9P_GETATTR_UNUSED_55; - x = _LIB9P_GETATTR_UNUSED_54; - x = _LIB9P_GETATTR_UNUSED_53; - x = _LIB9P_GETATTR_UNUSED_52; - x = _LIB9P_GETATTR_UNUSED_51; - x = _LIB9P_GETATTR_UNUSED_50; - x = _LIB9P_GETATTR_UNUSED_49; - x = _LIB9P_GETATTR_UNUSED_48; - x = _LIB9P_GETATTR_UNUSED_47; - x = _LIB9P_GETATTR_UNUSED_46; - x = _LIB9P_GETATTR_UNUSED_45; - x = _LIB9P_GETATTR_UNUSED_44; - x = _LIB9P_GETATTR_UNUSED_43; - x = _LIB9P_GETATTR_UNUSED_42; - x = _LIB9P_GETATTR_UNUSED_41; - x = _LIB9P_GETATTR_UNUSED_40; - x = _LIB9P_GETATTR_UNUSED_39; - x = _LIB9P_GETATTR_UNUSED_38; - x = _LIB9P_GETATTR_UNUSED_37; - x = _LIB9P_GETATTR_UNUSED_36; - x = _LIB9P_GETATTR_UNUSED_35; - x = _LIB9P_GETATTR_UNUSED_34; - x = _LIB9P_GETATTR_UNUSED_33; - x = _LIB9P_GETATTR_UNUSED_32; - x = _LIB9P_GETATTR_UNUSED_31; - x = _LIB9P_GETATTR_UNUSED_30; - x = _LIB9P_GETATTR_UNUSED_29; - x = _LIB9P_GETATTR_UNUSED_28; - x = _LIB9P_GETATTR_UNUSED_27; - x = _LIB9P_GETATTR_UNUSED_26; - x = _LIB9P_GETATTR_UNUSED_25; - x = _LIB9P_GETATTR_UNUSED_24; - x = _LIB9P_GETATTR_UNUSED_23; - x = _LIB9P_GETATTR_UNUSED_22; - x = _LIB9P_GETATTR_UNUSED_21; - x = _LIB9P_GETATTR_UNUSED_20; - x = _LIB9P_GETATTR_UNUSED_19; - x = _LIB9P_GETATTR_UNUSED_18; - x = _LIB9P_GETATTR_UNUSED_17; - x = _LIB9P_GETATTR_UNUSED_16; - x = _LIB9P_GETATTR_UNUSED_15; - x = _LIB9P_GETATTR_UNUSED_14; - x = LIB9P_GETATTR_DATA_VERSION; - x = LIB9P_GETATTR_GEN; - x = LIB9P_GETATTR_BTIME; - x = LIB9P_GETATTR_BLOCKS; - x = LIB9P_GETATTR_SIZE; - x = LIB9P_GETATTR_INO; - x = LIB9P_GETATTR_CTIME; - x = LIB9P_GETATTR_MTIME; - x = LIB9P_GETATTR_ATIME; - x = LIB9P_GETATTR_RDEV; - x = LIB9P_GETATTR_GID; - x = LIB9P_GETATTR_UID; - x = LIB9P_GETATTR_NLINK; - x = LIB9P_GETATTR_MODE; - x = LIB9P_GETATTR_BASIC; - x = LIB9P_GETATTR_ALL; - x = _LIB9P_SETATTR_UNUSED_31; - x = _LIB9P_SETATTR_UNUSED_30; - x = _LIB9P_SETATTR_UNUSED_29; - x = _LIB9P_SETATTR_UNUSED_28; - x = _LIB9P_SETATTR_UNUSED_27; - x = _LIB9P_SETATTR_UNUSED_26; - x = _LIB9P_SETATTR_UNUSED_25; - x = _LIB9P_SETATTR_UNUSED_24; - x = _LIB9P_SETATTR_UNUSED_23; - x = _LIB9P_SETATTR_UNUSED_22; - x = _LIB9P_SETATTR_UNUSED_21; - x = _LIB9P_SETATTR_UNUSED_20; - x = _LIB9P_SETATTR_UNUSED_19; - x = _LIB9P_SETATTR_UNUSED_18; - x = _LIB9P_SETATTR_UNUSED_17; - x = _LIB9P_SETATTR_UNUSED_16; - x = _LIB9P_SETATTR_UNUSED_15; - x = _LIB9P_SETATTR_UNUSED_14; - x = _LIB9P_SETATTR_UNUSED_13; - x = _LIB9P_SETATTR_UNUSED_12; - x = _LIB9P_SETATTR_UNUSED_11; - x = _LIB9P_SETATTR_UNUSED_10; - x = _LIB9P_SETATTR_UNUSED_9; - x = LIB9P_SETATTR_MTIME_SET; +#endif +#ifdef LIB9P_MODE_PERM_OWNER_R + x = LIB9P_MODE_PERM_OWNER_R; +#endif +#ifdef LIB9P_MODE_PERM_OWNER_W + x = LIB9P_MODE_PERM_OWNER_W; +#endif +#ifdef LIB9P_MODE_PERM_OWNER_X + x = LIB9P_MODE_PERM_OWNER_X; +#endif +#ifdef LIB9P_MODE_PERM_SETGROUP + x = LIB9P_MODE_PERM_SETGROUP; +#endif +#ifdef LIB9P_MODE_PERM_SETUSER + x = LIB9P_MODE_PERM_SETUSER; +#endif +#ifdef LIB9P_MODE_PERM_STICKY + x = LIB9P_MODE_PERM_STICKY; +#endif +#ifdef LIB9P_NUID_NONUID + x = LIB9P_NUID_NONUID; +#endif +#ifdef LIB9P_O_FLAG_MASK + x = LIB9P_O_FLAG_MASK; +#endif +#ifdef LIB9P_O_MODE_EXEC + x = LIB9P_O_MODE_EXEC; +#endif +#ifdef LIB9P_O_MODE_MASK + x = LIB9P_O_MODE_MASK; +#endif +#ifdef LIB9P_O_MODE_RDWR + x = LIB9P_O_MODE_RDWR; +#endif +#ifdef LIB9P_O_MODE_READ + x = LIB9P_O_MODE_READ; +#endif +#ifdef LIB9P_O_MODE_WRITE + x = LIB9P_O_MODE_WRITE; +#endif +#ifdef LIB9P_O_RCLOSE + x = LIB9P_O_RCLOSE; +#endif +#ifdef LIB9P_O_TRUNC + x = LIB9P_O_TRUNC; +#endif +#ifdef LIB9P_QT_APPEND + x = LIB9P_QT_APPEND; +#endif +#ifdef LIB9P_QT_AUTH + x = LIB9P_QT_AUTH; +#endif +#ifdef LIB9P_QT_DIR + x = LIB9P_QT_DIR; +#endif +#ifdef LIB9P_QT_EXCL + x = LIB9P_QT_EXCL; +#endif +#ifdef LIB9P_QT_FILE + x = LIB9P_QT_FILE; +#endif +#ifdef LIB9P_QT_SYMLINK + x = LIB9P_QT_SYMLINK; +#endif +#ifdef LIB9P_QT_TMP + x = LIB9P_QT_TMP; +#endif +#ifdef LIB9P_RMSG_MAX_COPY + x = LIB9P_RMSG_MAX_COPY; +#endif +#ifdef LIB9P_RMSG_MAX_IOV + x = LIB9P_RMSG_MAX_IOV; +#endif +#ifdef LIB9P_SETATTR_ATIME + x = LIB9P_SETATTR_ATIME; +#endif +#ifdef LIB9P_SETATTR_ATIME_SET x = LIB9P_SETATTR_ATIME_SET; +#endif +#ifdef LIB9P_SETATTR_CTIME x = LIB9P_SETATTR_CTIME; +#endif +#ifdef LIB9P_SETATTR_GID + x = LIB9P_SETATTR_GID; +#endif +#ifdef LIB9P_SETATTR_MODE + x = LIB9P_SETATTR_MODE; +#endif +#ifdef LIB9P_SETATTR_MTIME x = LIB9P_SETATTR_MTIME; - x = LIB9P_SETATTR_ATIME; +#endif +#ifdef LIB9P_SETATTR_MTIME_SET + x = LIB9P_SETATTR_MTIME_SET; +#endif +#ifdef LIB9P_SETATTR_SIZE x = LIB9P_SETATTR_SIZE; - x = LIB9P_SETATTR_GID; +#endif +#ifdef LIB9P_SETATTR_UID x = LIB9P_SETATTR_UID; - x = LIB9P_SETATTR_MODE; - x = LIB9P_LOCK_TYPE_RDLCK; - x = LIB9P_LOCK_TYPE_WRLCK; - x = LIB9P_LOCK_TYPE_UNLCK; - x = _LIB9P_LOCK_FLAGS_UNUSED_31; - x = _LIB9P_LOCK_FLAGS_UNUSED_30; - x = _LIB9P_LOCK_FLAGS_UNUSED_29; - x = _LIB9P_LOCK_FLAGS_UNUSED_28; - x = _LIB9P_LOCK_FLAGS_UNUSED_27; - x = _LIB9P_LOCK_FLAGS_UNUSED_26; - x = _LIB9P_LOCK_FLAGS_UNUSED_25; - x = _LIB9P_LOCK_FLAGS_UNUSED_24; - x = _LIB9P_LOCK_FLAGS_UNUSED_23; - x = _LIB9P_LOCK_FLAGS_UNUSED_22; - x = _LIB9P_LOCK_FLAGS_UNUSED_21; - x = _LIB9P_LOCK_FLAGS_UNUSED_20; - x = _LIB9P_LOCK_FLAGS_UNUSED_19; - x = _LIB9P_LOCK_FLAGS_UNUSED_18; - x = _LIB9P_LOCK_FLAGS_UNUSED_17; - x = _LIB9P_LOCK_FLAGS_UNUSED_16; - x = _LIB9P_LOCK_FLAGS_UNUSED_15; - x = _LIB9P_LOCK_FLAGS_UNUSED_14; - x = _LIB9P_LOCK_FLAGS_UNUSED_13; - x = _LIB9P_LOCK_FLAGS_UNUSED_12; - x = _LIB9P_LOCK_FLAGS_UNUSED_11; +#endif +#ifdef LIB9P_SUPER_MAGIC_V9FS_MAGIC + x = LIB9P_SUPER_MAGIC_V9FS_MAGIC; +#endif +#ifdef LIB9P_TAG_NOTAG + x = LIB9P_TAG_NOTAG; +#endif +#ifdef LIB9P_TMSG_MAX_COPY + x = LIB9P_TMSG_MAX_COPY; +#endif +#ifdef LIB9P_TMSG_MAX_IOV + x = LIB9P_TMSG_MAX_IOV; +#endif +#ifdef _LIB9P_DM_PLAN9_MOUNT + x = _LIB9P_DM_PLAN9_MOUNT; +#endif +#ifdef _LIB9P_DM_UNUSED_10 + x = _LIB9P_DM_UNUSED_10; +#endif +#ifdef _LIB9P_DM_UNUSED_11 + x = _LIB9P_DM_UNUSED_11; +#endif +#ifdef _LIB9P_DM_UNUSED_12 + x = _LIB9P_DM_UNUSED_12; +#endif +#ifdef _LIB9P_DM_UNUSED_13 + x = _LIB9P_DM_UNUSED_13; +#endif +#ifdef _LIB9P_DM_UNUSED_14 + x = _LIB9P_DM_UNUSED_14; +#endif +#ifdef _LIB9P_DM_UNUSED_15 + x = _LIB9P_DM_UNUSED_15; +#endif +#ifdef _LIB9P_DM_UNUSED_16 + x = _LIB9P_DM_UNUSED_16; +#endif +#ifdef _LIB9P_DM_UNUSED_17 + x = _LIB9P_DM_UNUSED_17; +#endif +#ifdef _LIB9P_DM_UNUSED_22 + x = _LIB9P_DM_UNUSED_22; +#endif +#ifdef _LIB9P_DM_UNUSED_24 + x = _LIB9P_DM_UNUSED_24; +#endif +#ifdef _LIB9P_DM_UNUSED_25 + x = _LIB9P_DM_UNUSED_25; +#endif +#ifdef _LIB9P_DM_UNUSED_9 + x = _LIB9P_DM_UNUSED_9; +#endif +#ifdef _LIB9P_DT_WHITEOUT + x = _LIB9P_DT_WHITEOUT; +#endif +#ifdef _LIB9P_ENABLE_stat + x = _LIB9P_ENABLE_stat; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_14 + x = _LIB9P_GETATTR_UNUSED_14; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_15 + x = _LIB9P_GETATTR_UNUSED_15; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_16 + x = _LIB9P_GETATTR_UNUSED_16; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_17 + x = _LIB9P_GETATTR_UNUSED_17; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_18 + x = _LIB9P_GETATTR_UNUSED_18; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_19 + x = _LIB9P_GETATTR_UNUSED_19; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_20 + x = _LIB9P_GETATTR_UNUSED_20; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_21 + x = _LIB9P_GETATTR_UNUSED_21; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_22 + x = _LIB9P_GETATTR_UNUSED_22; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_23 + x = _LIB9P_GETATTR_UNUSED_23; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_24 + x = _LIB9P_GETATTR_UNUSED_24; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_25 + x = _LIB9P_GETATTR_UNUSED_25; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_26 + x = _LIB9P_GETATTR_UNUSED_26; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_27 + x = _LIB9P_GETATTR_UNUSED_27; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_28 + x = _LIB9P_GETATTR_UNUSED_28; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_29 + x = _LIB9P_GETATTR_UNUSED_29; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_30 + x = _LIB9P_GETATTR_UNUSED_30; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_31 + x = _LIB9P_GETATTR_UNUSED_31; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_32 + x = _LIB9P_GETATTR_UNUSED_32; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_33 + x = _LIB9P_GETATTR_UNUSED_33; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_34 + x = _LIB9P_GETATTR_UNUSED_34; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_35 + x = _LIB9P_GETATTR_UNUSED_35; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_36 + x = _LIB9P_GETATTR_UNUSED_36; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_37 + x = _LIB9P_GETATTR_UNUSED_37; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_38 + x = _LIB9P_GETATTR_UNUSED_38; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_39 + x = _LIB9P_GETATTR_UNUSED_39; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_40 + x = _LIB9P_GETATTR_UNUSED_40; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_41 + x = _LIB9P_GETATTR_UNUSED_41; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_42 + x = _LIB9P_GETATTR_UNUSED_42; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_43 + x = _LIB9P_GETATTR_UNUSED_43; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_44 + x = _LIB9P_GETATTR_UNUSED_44; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_45 + x = _LIB9P_GETATTR_UNUSED_45; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_46 + x = _LIB9P_GETATTR_UNUSED_46; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_47 + x = _LIB9P_GETATTR_UNUSED_47; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_48 + x = _LIB9P_GETATTR_UNUSED_48; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_49 + x = _LIB9P_GETATTR_UNUSED_49; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_50 + x = _LIB9P_GETATTR_UNUSED_50; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_51 + x = _LIB9P_GETATTR_UNUSED_51; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_52 + x = _LIB9P_GETATTR_UNUSED_52; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_53 + x = _LIB9P_GETATTR_UNUSED_53; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_54 + x = _LIB9P_GETATTR_UNUSED_54; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_55 + x = _LIB9P_GETATTR_UNUSED_55; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_56 + x = _LIB9P_GETATTR_UNUSED_56; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_57 + x = _LIB9P_GETATTR_UNUSED_57; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_58 + x = _LIB9P_GETATTR_UNUSED_58; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_59 + x = _LIB9P_GETATTR_UNUSED_59; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_60 + x = _LIB9P_GETATTR_UNUSED_60; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_61 + x = _LIB9P_GETATTR_UNUSED_61; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_62 + x = _LIB9P_GETATTR_UNUSED_62; +#endif +#ifdef _LIB9P_GETATTR_UNUSED_63 + x = _LIB9P_GETATTR_UNUSED_63; +#endif +#ifdef _LIB9P_LOCK_FLAGS_UNUSED_10 x = _LIB9P_LOCK_FLAGS_UNUSED_10; - x = _LIB9P_LOCK_FLAGS_UNUSED_9; - x = _LIB9P_LOCK_FLAGS_UNUSED_8; - x = _LIB9P_LOCK_FLAGS_UNUSED_7; - x = _LIB9P_LOCK_FLAGS_UNUSED_6; - x = _LIB9P_LOCK_FLAGS_UNUSED_5; - x = _LIB9P_LOCK_FLAGS_UNUSED_4; - x = _LIB9P_LOCK_FLAGS_UNUSED_3; +#endif +#ifdef _LIB9P_LOCK_FLAGS_UNUSED_11 + x = _LIB9P_LOCK_FLAGS_UNUSED_11; +#endif +#ifdef _LIB9P_LOCK_FLAGS_UNUSED_12 + x = _LIB9P_LOCK_FLAGS_UNUSED_12; +#endif +#ifdef _LIB9P_LOCK_FLAGS_UNUSED_13 + x = _LIB9P_LOCK_FLAGS_UNUSED_13; +#endif +#ifdef _LIB9P_LOCK_FLAGS_UNUSED_14 + x = _LIB9P_LOCK_FLAGS_UNUSED_14; +#endif +#ifdef _LIB9P_LOCK_FLAGS_UNUSED_15 + x = _LIB9P_LOCK_FLAGS_UNUSED_15; +#endif +#ifdef _LIB9P_LOCK_FLAGS_UNUSED_16 + x = _LIB9P_LOCK_FLAGS_UNUSED_16; +#endif +#ifdef _LIB9P_LOCK_FLAGS_UNUSED_17 + x = _LIB9P_LOCK_FLAGS_UNUSED_17; +#endif +#ifdef _LIB9P_LOCK_FLAGS_UNUSED_18 + x = _LIB9P_LOCK_FLAGS_UNUSED_18; +#endif +#ifdef _LIB9P_LOCK_FLAGS_UNUSED_19 + x = _LIB9P_LOCK_FLAGS_UNUSED_19; +#endif +#ifdef _LIB9P_LOCK_FLAGS_UNUSED_2 x = _LIB9P_LOCK_FLAGS_UNUSED_2; - x = LIB9P_LOCK_FLAGS_RECLAIM; - x = LIB9P_LOCK_FLAGS_BLOCK; - x = LIB9P_LOCK_STATUS_SUCCESS; - x = LIB9P_LOCK_STATUS_BLOCKED; - x = LIB9P_LOCK_STATUS_ERROR; - x = LIB9P_LOCK_STATUS_GRACE; - x = LIB9P_TMSG_MAX_IOV; - x = LIB9P_TMSG_MAX_IOV; - x = LIB9P_TMSG_MAX_COPY; - x = LIB9P_TMSG_MAX_COPY; - x = LIB9P_TMSG_MAX_COPY; - x = LIB9P_TMSG_MAX_COPY; - x = LIB9P_TMSG_MAX_COPY; - x = LIB9P_TMSG_MAX_COPY; - x = LIB9P_RMSG_MAX_IOV; - x = LIB9P_RMSG_MAX_IOV; - x = LIB9P_RMSG_MAX_IOV; - x = LIB9P_RMSG_MAX_COPY; +#endif +#ifdef _LIB9P_LOCK_FLAGS_UNUSED_20 + x = _LIB9P_LOCK_FLAGS_UNUSED_20; +#endif +#ifdef _LIB9P_LOCK_FLAGS_UNUSED_21 + x = _LIB9P_LOCK_FLAGS_UNUSED_21; +#endif +#ifdef _LIB9P_LOCK_FLAGS_UNUSED_22 + x = _LIB9P_LOCK_FLAGS_UNUSED_22; +#endif +#ifdef _LIB9P_LOCK_FLAGS_UNUSED_23 + x = _LIB9P_LOCK_FLAGS_UNUSED_23; +#endif +#ifdef _LIB9P_LOCK_FLAGS_UNUSED_24 + x = _LIB9P_LOCK_FLAGS_UNUSED_24; +#endif +#ifdef _LIB9P_LOCK_FLAGS_UNUSED_25 + x = _LIB9P_LOCK_FLAGS_UNUSED_25; +#endif +#ifdef _LIB9P_LOCK_FLAGS_UNUSED_26 + x = _LIB9P_LOCK_FLAGS_UNUSED_26; +#endif +#ifdef _LIB9P_LOCK_FLAGS_UNUSED_27 + x = _LIB9P_LOCK_FLAGS_UNUSED_27; +#endif +#ifdef _LIB9P_LOCK_FLAGS_UNUSED_28 + x = _LIB9P_LOCK_FLAGS_UNUSED_28; +#endif +#ifdef _LIB9P_LOCK_FLAGS_UNUSED_29 + x = _LIB9P_LOCK_FLAGS_UNUSED_29; +#endif +#ifdef _LIB9P_LOCK_FLAGS_UNUSED_3 + x = _LIB9P_LOCK_FLAGS_UNUSED_3; +#endif +#ifdef _LIB9P_LOCK_FLAGS_UNUSED_30 + x = _LIB9P_LOCK_FLAGS_UNUSED_30; +#endif +#ifdef _LIB9P_LOCK_FLAGS_UNUSED_31 + x = _LIB9P_LOCK_FLAGS_UNUSED_31; +#endif +#ifdef _LIB9P_LOCK_FLAGS_UNUSED_4 + x = _LIB9P_LOCK_FLAGS_UNUSED_4; +#endif +#ifdef _LIB9P_LOCK_FLAGS_UNUSED_5 + x = _LIB9P_LOCK_FLAGS_UNUSED_5; +#endif +#ifdef _LIB9P_LOCK_FLAGS_UNUSED_6 + x = _LIB9P_LOCK_FLAGS_UNUSED_6; +#endif +#ifdef _LIB9P_LOCK_FLAGS_UNUSED_7 + x = _LIB9P_LOCK_FLAGS_UNUSED_7; +#endif +#ifdef _LIB9P_LOCK_FLAGS_UNUSED_8 + x = _LIB9P_LOCK_FLAGS_UNUSED_8; +#endif +#ifdef _LIB9P_LOCK_FLAGS_UNUSED_9 + x = _LIB9P_LOCK_FLAGS_UNUSED_9; +#endif +#ifdef _LIB9P_LO_UNUSED_2 + x = _LIB9P_LO_UNUSED_2; +#endif +#ifdef _LIB9P_LO_UNUSED_21 + x = _LIB9P_LO_UNUSED_21; +#endif +#ifdef _LIB9P_LO_UNUSED_22 + x = _LIB9P_LO_UNUSED_22; +#endif +#ifdef _LIB9P_LO_UNUSED_23 + x = _LIB9P_LO_UNUSED_23; +#endif +#ifdef _LIB9P_LO_UNUSED_24 + x = _LIB9P_LO_UNUSED_24; +#endif +#ifdef _LIB9P_LO_UNUSED_25 + x = _LIB9P_LO_UNUSED_25; +#endif +#ifdef _LIB9P_LO_UNUSED_26 + x = _LIB9P_LO_UNUSED_26; +#endif +#ifdef _LIB9P_LO_UNUSED_27 + x = _LIB9P_LO_UNUSED_27; +#endif +#ifdef _LIB9P_LO_UNUSED_28 + x = _LIB9P_LO_UNUSED_28; +#endif +#ifdef _LIB9P_LO_UNUSED_29 + x = _LIB9P_LO_UNUSED_29; +#endif +#ifdef _LIB9P_LO_UNUSED_3 + x = _LIB9P_LO_UNUSED_3; +#endif +#ifdef _LIB9P_LO_UNUSED_30 + x = _LIB9P_LO_UNUSED_30; +#endif +#ifdef _LIB9P_LO_UNUSED_31 + x = _LIB9P_LO_UNUSED_31; +#endif +#ifdef _LIB9P_LO_UNUSED_4 + x = _LIB9P_LO_UNUSED_4; +#endif +#ifdef _LIB9P_LO_UNUSED_5 + x = _LIB9P_LO_UNUSED_5; +#endif +#ifdef _LIB9P_MODE_UNUSED_16 + x = _LIB9P_MODE_UNUSED_16; +#endif +#ifdef _LIB9P_MODE_UNUSED_17 + x = _LIB9P_MODE_UNUSED_17; +#endif +#ifdef _LIB9P_MODE_UNUSED_18 + x = _LIB9P_MODE_UNUSED_18; +#endif +#ifdef _LIB9P_MODE_UNUSED_19 + x = _LIB9P_MODE_UNUSED_19; +#endif +#ifdef _LIB9P_MODE_UNUSED_20 + x = _LIB9P_MODE_UNUSED_20; +#endif +#ifdef _LIB9P_MODE_UNUSED_21 + x = _LIB9P_MODE_UNUSED_21; +#endif +#ifdef _LIB9P_MODE_UNUSED_22 + x = _LIB9P_MODE_UNUSED_22; +#endif +#ifdef _LIB9P_MODE_UNUSED_23 + x = _LIB9P_MODE_UNUSED_23; +#endif +#ifdef _LIB9P_MODE_UNUSED_24 + x = _LIB9P_MODE_UNUSED_24; +#endif +#ifdef _LIB9P_MODE_UNUSED_25 + x = _LIB9P_MODE_UNUSED_25; +#endif +#ifdef _LIB9P_MODE_UNUSED_26 + x = _LIB9P_MODE_UNUSED_26; +#endif +#ifdef _LIB9P_MODE_UNUSED_27 + x = _LIB9P_MODE_UNUSED_27; +#endif +#ifdef _LIB9P_MODE_UNUSED_28 + x = _LIB9P_MODE_UNUSED_28; +#endif +#ifdef _LIB9P_MODE_UNUSED_29 + x = _LIB9P_MODE_UNUSED_29; +#endif +#ifdef _LIB9P_MODE_UNUSED_30 + x = _LIB9P_MODE_UNUSED_30; +#endif +#ifdef _LIB9P_MODE_UNUSED_31 + x = _LIB9P_MODE_UNUSED_31; +#endif +#ifdef _LIB9P_O_RESERVED_CEXEC + x = _LIB9P_O_RESERVED_CEXEC; +#endif +#ifdef _LIB9P_O_UNUSED_2 + x = _LIB9P_O_UNUSED_2; +#endif +#ifdef _LIB9P_O_UNUSED_3 + x = _LIB9P_O_UNUSED_3; +#endif +#ifdef _LIB9P_O_UNUSED_7 + x = _LIB9P_O_UNUSED_7; +#endif +#ifdef _LIB9P_QT_PLAN9_MOUNT + x = _LIB9P_QT_PLAN9_MOUNT; +#endif +#ifdef _LIB9P_QT_UNUSED_0 + x = _LIB9P_QT_UNUSED_0; +#endif +#ifdef _LIB9P_SETATTR_UNUSED_10 + x = _LIB9P_SETATTR_UNUSED_10; +#endif +#ifdef _LIB9P_SETATTR_UNUSED_11 + x = _LIB9P_SETATTR_UNUSED_11; +#endif +#ifdef _LIB9P_SETATTR_UNUSED_12 + x = _LIB9P_SETATTR_UNUSED_12; +#endif +#ifdef _LIB9P_SETATTR_UNUSED_13 + x = _LIB9P_SETATTR_UNUSED_13; +#endif +#ifdef _LIB9P_SETATTR_UNUSED_14 + x = _LIB9P_SETATTR_UNUSED_14; +#endif +#ifdef _LIB9P_SETATTR_UNUSED_15 + x = _LIB9P_SETATTR_UNUSED_15; +#endif +#ifdef _LIB9P_SETATTR_UNUSED_16 + x = _LIB9P_SETATTR_UNUSED_16; +#endif +#ifdef _LIB9P_SETATTR_UNUSED_17 + x = _LIB9P_SETATTR_UNUSED_17; +#endif +#ifdef _LIB9P_SETATTR_UNUSED_18 + x = _LIB9P_SETATTR_UNUSED_18; +#endif +#ifdef _LIB9P_SETATTR_UNUSED_19 + x = _LIB9P_SETATTR_UNUSED_19; +#endif +#ifdef _LIB9P_SETATTR_UNUSED_20 + x = _LIB9P_SETATTR_UNUSED_20; +#endif +#ifdef _LIB9P_SETATTR_UNUSED_21 + x = _LIB9P_SETATTR_UNUSED_21; +#endif +#ifdef _LIB9P_SETATTR_UNUSED_22 + x = _LIB9P_SETATTR_UNUSED_22; +#endif +#ifdef _LIB9P_SETATTR_UNUSED_23 + x = _LIB9P_SETATTR_UNUSED_23; +#endif +#ifdef _LIB9P_SETATTR_UNUSED_24 + x = _LIB9P_SETATTR_UNUSED_24; +#endif +#ifdef _LIB9P_SETATTR_UNUSED_25 + x = _LIB9P_SETATTR_UNUSED_25; +#endif +#ifdef _LIB9P_SETATTR_UNUSED_26 + x = _LIB9P_SETATTR_UNUSED_26; +#endif +#ifdef _LIB9P_SETATTR_UNUSED_27 + x = _LIB9P_SETATTR_UNUSED_27; +#endif +#ifdef _LIB9P_SETATTR_UNUSED_28 + x = _LIB9P_SETATTR_UNUSED_28; +#endif +#ifdef _LIB9P_SETATTR_UNUSED_29 + x = _LIB9P_SETATTR_UNUSED_29; +#endif +#ifdef _LIB9P_SETATTR_UNUSED_30 + x = _LIB9P_SETATTR_UNUSED_30; +#endif +#ifdef _LIB9P_SETATTR_UNUSED_31 + x = _LIB9P_SETATTR_UNUSED_31; +#endif +#ifdef _LIB9P_SETATTR_UNUSED_9 + x = _LIB9P_SETATTR_UNUSED_9; +#endif return 0; } diff --git a/lib9p/tests/test_compile.c.gen b/lib9p/tests/test_compile.c.gen index 47046b3..eb89c54 100755 --- a/lib9p/tests/test_compile.c.gen +++ b/lib9p/tests/test_compile.c.gen @@ -10,10 +10,10 @@ outfile=$2 { echo "/* ${outfile} - Generated by $0. DO NOT EDIT! */" echo - echo "#include <lib9p/9p.h>" + echo "#include <lib9p/core.h>" echo 'int main(void) {' echo ' [[gnu::unused]] uint64_t x;' - sed -nE 's/^\s*#\s*define\s*(\S[^ (]*)\s.*/ x = \1;/p' <"$generated_h" + <"$generated_h" sed -nE 's/^\s*#\s*define\s*(\S[^ (]*)\s.*/\1/p' | LC_COLLATE=C sort -u | sed 's/.*/#ifdef &\n x = &;\n#endif/' echo ' return 0;' echo '}' } >"$outfile" diff --git a/lib9p/tests/test_compile_config/config.h b/lib9p/tests/test_compile_config/config.h index cc8eec1..02cb8e5 100644 --- a/lib9p/tests/test_compile_config/config.h +++ b/lib9p/tests/test_compile_config/config.h @@ -12,17 +12,10 @@ #define CONFIG_9P_MAX_ERR_SIZE 128 #define CONFIG_9P_MAX_9P2000_e_WELEM 16 +/* 9P_SRV *********************************************************************/ + #define CONFIG_9P_SRV_MAX_MSG_SIZE ((4*1024)+24) #define CONFIG_9P_SRV_MAX_HOSTMSG_SIZE CONFIG_9P_SRV_MAX_MSG_SIZE+16 -#define CONFIG_9P_SRV_MAX_FIDS 16 -#define CONFIG_9P_SRV_MAX_REQS 2 -#define CONFIG_9P_SRV_MAX_DEPTH 3 - -#define CONFIG_9P_ENABLE_9P2000 1 /* bool */ -#define CONFIG_9P_ENABLE_9P2000_u 1 /* bool */ -#define CONFIG_9P_ENABLE_9P2000_e 1 /* bool */ -#define CONFIG_9P_ENABLE_9P2000_L 1 /* bool */ -#define CONFIG_9P_ENABLE_9P2000_p9p 1 /* bool */ /* COROUTINE ******************************************************************/ @@ -33,6 +26,6 @@ #define CONFIG_COROUTINE_DEBUG 0 /* bool */ #define CONFIG_COROUTINE_VALGRIND 1 /* bool */ #define CONFIG_COROUTINE_GDB 1 /* bool */ -#define CONFIG_COROUTINE_NUM 2 +#define CONFIG_COROUTINE_NUM 8 #endif /* _CONFIG_H_ */ diff --git a/lib9p/tests/test_server/CMakeLists.txt b/lib9p/tests/test_server/CMakeLists.txt index 5313917..c61d344 100644 --- a/lib9p/tests/test_server/CMakeLists.txt +++ b/lib9p/tests/test_server/CMakeLists.txt @@ -9,6 +9,9 @@ if (PICO_PLATFORM STREQUAL "host") add_library(test_server_objs OBJECT main.c + fs_flush.c + fs_shutdown.c + fs_whoami.c ) target_include_directories(test_server_objs PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/config) target_include_directories(test_server_objs PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) @@ -16,7 +19,6 @@ target_link_libraries(test_server_objs libcr libcr_ipc libmisc - lib9p lib9p_util libhw_cr ) diff --git a/lib9p/tests/test_server/config/config.h b/lib9p/tests/test_server/config/config.h index 03143e1..f49894b 100644 --- a/lib9p/tests/test_server/config/config.h +++ b/lib9p/tests/test_server/config/config.h @@ -7,13 +7,23 @@ #ifndef _CONFIG_H_ #define _CONFIG_H_ -#define _CONFIG_9P_NUM_SOCKS 8 -#define CONFIG_SRV9P_NUM_CONNS _CONFIG_9P_NUM_SOCKS +#define _CONFIG_9P_MAX_CONNS 8 +#define _CONFIG_9P_MAX_REQS (2*_CONFIG_9P_MAX_CONNS) /* 9P *************************************************************************/ #define CONFIG_9P_MAX_ERR_SIZE 128 /* 128 is what Plan 9 4e uses */ +#define CONFIG_9P_ENABLE_9P2000 1 /* bool */ +#define CONFIG_9P_ENABLE_9P2000_u 1 /* bool */ +#define CONFIG_9P_ENABLE_9P2000_e 0 /* bool */ +#define CONFIG_9P_ENABLE_9P2000_L 0 /* bool */ +#define CONFIG_9P_ENABLE_9P2000_p9p 0 /* bool */ + +/* 9P_SRV *********************************************************************/ + +#define CONFIG_9P_SRV_DEBUG 1 /* bool */ + /** * This max-msg-size is sized so that a Twrite message can return * 8KiB of data. @@ -38,15 +48,6 @@ * struct padding, (2) array pointers. */ #define CONFIG_9P_SRV_MAX_HOSTMSG_SIZE CONFIG_9P_SRV_MAX_MSG_SIZE+16 -#define CONFIG_9P_SRV_MAX_FIDS 16 -#define CONFIG_9P_SRV_MAX_REQS 2 -#define CONFIG_9P_SRV_MAX_DEPTH 3 - -#define CONFIG_9P_ENABLE_9P2000 1 /* bool */ -#define CONFIG_9P_ENABLE_9P2000_u 1 /* bool */ -#define CONFIG_9P_ENABLE_9P2000_e 0 /* bool */ -#define CONFIG_9P_ENABLE_9P2000_L 0 /* bool */ -#define CONFIG_9P_ENABLE_9P2000_p9p 0 /* bool */ /* COROUTINE ******************************************************************/ @@ -57,10 +58,10 @@ #define CONFIG_COROUTINE_DEBUG 0 /* bool */ #define CONFIG_COROUTINE_VALGRIND 1 /* bool */ #define CONFIG_COROUTINE_GDB 1 /* bool */ -#define CONFIG_COROUTINE_NUM ( \ - 1 /* usb_common */ + \ - 1 /* usb_keyboard */ + \ - CONFIG_SRV9P_NUM_CONNS /* accept+read */ + \ - (CONFIG_9P_SRV_MAX_REQS*CONFIG_SRV9P_NUM_CONNS) /* work+write */ ) +#define CONFIG_COROUTINE_NUM ( \ + 1 /* usb_common */ + \ + 1 /* usb_keyboard */ + \ + _CONFIG_9P_MAX_CONNS /* accept+read */ + \ + _CONFIG_9P_MAX_REQS /* work+write */ ) #endif /* _CONFIG_H_ */ diff --git a/lib9p/tests/test_server/fs_flush.c b/lib9p/tests/test_server/fs_flush.c new file mode 100644 index 0000000..e6408d7 --- /dev/null +++ b/lib9p/tests/test_server/fs_flush.c @@ -0,0 +1,131 @@ +/* lib9p/tests/test_server/fs_flush.c - flush-* API endpoints + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include <libmisc/alloc.h> + +#define IMPLEMENTATION_FOR_LIB9P_SRV_H YES /* for ctx->flush_ch */ +#include "fs_flush.h" + +LO_IMPLEMENTATION_C(lib9p_srv_file, struct flush_file, flush_file, static); + +struct flush_fio { + struct flush_file *parent; +}; +LO_IMPLEMENTATION_H(lib9p_srv_fio, struct flush_fio, flush_fio); +LO_IMPLEMENTATION_C(lib9p_srv_fio, struct flush_fio, flush_fio, static); + +/* srv_file *******************************************************************/ + +static void flush_file_free(struct flush_file *self) { + assert(self); +} +static struct lib9p_qid flush_file_qid(struct flush_file *self) { + assert(self); + return (struct lib9p_qid){ + .type = LIB9P_QT_FILE, + .vers = 1, + .path = self->pathnum, + }; +} + +static struct lib9p_srv_stat flush_file_stat(struct flush_file *self, struct lib9p_srv_ctx *ctx) { + assert(self); + assert(ctx); + return (struct lib9p_srv_stat){ + .qid = flush_file_qid(self), + .mode = 0444, + .atime_sec = UTIL9P_ATIME, + .mtime_sec = UTIL9P_MTIME, + .size = 6, + .name = lib9p_str(self->name), + .owner_uid = { .name = lib9p_str("root"), .num = 0 }, + .owner_gid = { .name = lib9p_str("root"), .num = 0 }, + .last_modifier_uid = { .name = lib9p_str("root"), .num = 0 }, + .extension = lib9p_str(NULL), + }; +} +static void flush_file_wstat(struct flush_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_srv_stat) { + assert(self); + assert(ctx); + lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "cannot wstat API file"); +} +static void flush_file_remove(struct flush_file *self, struct lib9p_srv_ctx *ctx) { + assert(self); + assert(ctx); + lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "cannot remove API file"); +} + +LIB9P_SRV_NOTDIR(struct flush_file, flush_file) + +static lo_interface lib9p_srv_fio flush_file_fopen(struct flush_file *self, struct lib9p_srv_ctx *ctx, bool, bool, bool) { + assert(self); + assert(ctx); + + struct flush_fio *ret = heap_alloc(1, struct flush_fio); + ret->parent = self; + + return lo_box_flush_fio_as_lib9p_srv_fio(ret); +} + +/* srv_fio ********************************************************************/ + +static void flush_fio_iofree(struct flush_fio *self) { + assert(self); + free(self); +} + +static struct lib9p_qid flush_fio_qid(struct flush_fio *self) { + assert(self); + return flush_file_qid(self->parent); +} + +static uint32_t flush_fio_iounit(struct flush_fio *self) { + assert(self); + return 0; +} + +static uint32_t flush_fio_pwrite(struct flush_fio *LM_UNUSED(self), + struct lib9p_srv_ctx *LM_UNUSED(ctx), + void *LM_UNUSED(buf), uint32_t LM_UNUSED(byte_count), + uint64_t LM_UNUSED(offset)) { + assert_notreached("not writable"); +} + +static void flush_fio_pread(struct flush_fio *self, struct lib9p_srv_ctx *ctx, + uint32_t byte_count, uint64_t LM_UNUSED(byte_offset), + struct iovec *ret) { + assert(self); + assert(ctx); + assert(ret); + + /* Wait for first Tflush */ + while (!lib9p_srv_flush_requested(ctx)) + cr_yield(); + + /* Wait for the specified number of Tflush (may be higher *or* + * lower than 1; lower would mean that the first Tflush needs + * to be flushed itself). */ + while (cr_chan_num_waiters(&ctx->flush_ch) != self->parent->flush_cnt) + cr_yield(); + + /* Return */ + switch (self->parent->flush_behavior) { + case FLUSH_READ: + *ret = (struct iovec){ + .iov_base = "Sloth\n", + .iov_len = 6 < byte_count ? 6 : byte_count, + }; + break; + case FLUSH_ERROR: + lib9p_srv_acknowledge_flush(ctx); + lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_ECANCELED, "request canceled by flush"); + break; + case FLUSH_SILENT: + lib9p_srv_acknowledge_flush(ctx); + break; + } + cr_yield(); +} diff --git a/lib9p/tests/test_server/fs_flush.h b/lib9p/tests/test_server/fs_flush.h new file mode 100644 index 0000000..a509c4a --- /dev/null +++ b/lib9p/tests/test_server/fs_flush.h @@ -0,0 +1,27 @@ +/* lib9p/tests/test_server/fs_flush.h - flush-* API endpoints + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#ifndef _LIB9P_TESTS_TEST_SERVER_FS_FLUSH_H_ +#define _LIB9P_TESTS_TEST_SERVER_FS_FLUSH_H_ + +#include <util9p/static.h> +#include <libhw/host_net.h> + +struct flush_file { + char *name; + uint64_t pathnum; + + unsigned int flush_cnt; + enum { + FLUSH_READ, + FLUSH_ERROR, + FLUSH_SILENT, + } flush_behavior; +}; +LO_IMPLEMENTATION_H(lib9p_srv_file, struct flush_file, flush_file); +#define lo_box_flush_file_as_lib9p_srv_file(obj) util9p_box(flush_file, obj) + +#endif /* _LIB9P_TESTS_TEST_SERVER_FS_FLUSH_H_ */ diff --git a/lib9p/tests/test_server/fs_shutdown.c b/lib9p/tests/test_server/fs_shutdown.c new file mode 100644 index 0000000..d4ae67e --- /dev/null +++ b/lib9p/tests/test_server/fs_shutdown.c @@ -0,0 +1,104 @@ +/* lib9p/tests/test_server/fs_shutdown.c - /shutdown API endpoint + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include <libmisc/alloc.h> + +#include "fs_shutdown.h" + +LO_IMPLEMENTATION_C(lib9p_srv_file, struct shutdown_file, shutdown_file, static); + +struct shutdown_fio { + struct shutdown_file *parent; +}; +LO_IMPLEMENTATION_H(lib9p_srv_fio, struct shutdown_fio, shutdown_fio); +LO_IMPLEMENTATION_C(lib9p_srv_fio, struct shutdown_fio, shutdown_fio, static); + +/* srv_file *******************************************************************/ + +static void shutdown_file_free(struct shutdown_file *self) { + assert(self); +} +static struct lib9p_qid shutdown_file_qid(struct shutdown_file *self) { + assert(self); + return (struct lib9p_qid){ + .type = LIB9P_QT_FILE | LIB9P_QT_APPEND, + .vers = 1, + .path = self->pathnum, + }; +} + +static struct lib9p_srv_stat shutdown_file_stat(struct shutdown_file *self, struct lib9p_srv_ctx *ctx) { + assert(self); + assert(ctx); + return (struct lib9p_srv_stat){ + .qid = shutdown_file_qid(self), + .mode = 0222 | LIB9P_DM_APPEND, + .atime_sec = UTIL9P_ATIME, + .mtime_sec = UTIL9P_MTIME, + .size = 0, + .name = lib9p_str(self->name), + .owner_uid = { .name=lib9p_str("root"), .num=0 }, + .owner_gid = { .name=lib9p_str("root"), .num=0 }, + .last_modifier_uid = { .name=lib9p_str("root"), .num=0 }, + .extension = lib9p_str(NULL), + }; +} +static void shutdown_file_wstat(struct shutdown_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_srv_stat) { + assert(self); + assert(ctx); + lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "cannot wstat API file"); +} +static void shutdown_file_remove(struct shutdown_file *self, struct lib9p_srv_ctx *ctx) { + assert(self); + assert(ctx); + lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "cannot remove API file"); +} + +LIB9P_SRV_NOTDIR(struct shutdown_file, shutdown_file) + +static lo_interface lib9p_srv_fio shutdown_file_fopen(struct shutdown_file *self, struct lib9p_srv_ctx *ctx, bool, bool, bool) { + assert(self); + assert(ctx); + + struct shutdown_fio *ret = heap_alloc(1, struct shutdown_fio); + ret->parent = self; + + return lo_box_shutdown_fio_as_lib9p_srv_fio(ret); +} + +/* srv_fio ********************************************************************/ + +static void shutdown_fio_iofree(struct shutdown_fio *self) { + assert(self); + free(self); +} + +static struct lib9p_qid shutdown_fio_qid(struct shutdown_fio *self) { + assert(self); + return shutdown_file_qid(self->parent); +} + +static uint32_t shutdown_fio_iounit(struct shutdown_fio *self) { + assert(self); + return 0; +} + +static uint32_t shutdown_fio_pwrite(struct shutdown_fio *self, struct lib9p_srv_ctx *ctx, void *buf, uint32_t byte_count, uint64_t offset) { + assert(self); + assert(ctx); + assert(buf); + assert(offset == 0); + if (byte_count == 0) + return 0; + for (size_t i = 0; i < self->parent->nlisteners; i++) + LO_CALL(lo_box_hostnet_tcplist_as_net_stream_listener(&self->parent->listeners[i]), close); + return byte_count; +} +static void shutdown_fio_pread(struct shutdown_fio *LM_UNUSED(self), struct lib9p_srv_ctx *LM_UNUSED(ctx), + uint32_t LM_UNUSED(byte_count), uint64_t LM_UNUSED(byte_offset), + struct iovec *LM_UNUSED(ret)) { + assert_notreached("not readable"); +} diff --git a/lib9p/tests/test_server/fs_shutdown.h b/lib9p/tests/test_server/fs_shutdown.h new file mode 100644 index 0000000..65956db --- /dev/null +++ b/lib9p/tests/test_server/fs_shutdown.h @@ -0,0 +1,23 @@ +/* lib9p/tests/test_server/fs_shutdown.h - /shutdown API endpoint + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#ifndef _LIB9P_TESTS_TEST_SERVER_FS_SHUTDOWN_H_ +#define _LIB9P_TESTS_TEST_SERVER_FS_SHUTDOWN_H_ + +#include <util9p/static.h> +#include <libhw/host_net.h> + +struct shutdown_file { + char *name; + uint64_t pathnum; + + struct hostnet_tcp_listener *listeners; + size_t nlisteners; +}; +LO_IMPLEMENTATION_H(lib9p_srv_file, struct shutdown_file, shutdown_file); +#define lo_box_shutdown_file_as_lib9p_srv_file(obj) util9p_box(shutdown_file, obj) + +#endif /* _LIB9P_TESTS_TEST_SERVER_FS_SHUTDOWN_H_ */ diff --git a/lib9p/tests/test_server/fs_whoami.c b/lib9p/tests/test_server/fs_whoami.c new file mode 100644 index 0000000..8d9752a --- /dev/null +++ b/lib9p/tests/test_server/fs_whoami.c @@ -0,0 +1,153 @@ +/* lib9p/tests/test_server/fs_whoami.c - /whoami API endpoint + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include <stdio.h> /* for snprintf() */ +#include <stdlib.h> /* for realloc(), free() */ + +#include <libmisc/alloc.h> + +#include "fs_whoami.h" + +LO_IMPLEMENTATION_C(lib9p_srv_file, struct whoami_file, whoami_file, static); + +struct whoami_fio { + struct whoami_file *parent; + size_t buf_len; + char *buf; +}; +LO_IMPLEMENTATION_H(lib9p_srv_fio, struct whoami_fio, whoami_fio); +LO_IMPLEMENTATION_C(lib9p_srv_fio, struct whoami_fio, whoami_fio, static); + +size_t whoami_len(struct lib9p_srv_ctx *ctx) { + assert(ctx); + assert(ctx->user); + + size_t len = 0; + uint32_t uid = ctx->user->num; + while (uid) { + len++; + uid /= 10; + } + if (!len) + len++; + len += 2; + len += ctx->user->name.len; + return len; +} + +/* srv_file *******************************************************************/ + +static void whoami_file_free(struct whoami_file *self) { + assert(self); +} +static struct lib9p_qid whoami_file_qid(struct whoami_file *self) { + assert(self); + return (struct lib9p_qid){ + .type = LIB9P_QT_FILE, + .vers = 1, + .path = self->pathnum, + }; +} + +static struct lib9p_srv_stat whoami_file_stat(struct whoami_file *self, struct lib9p_srv_ctx *ctx) { + assert(self); + assert(ctx); + + return (struct lib9p_srv_stat){ + .qid = whoami_file_qid(self), + .mode = 0444, + .atime_sec = UTIL9P_ATIME, + .mtime_sec = UTIL9P_MTIME, + .size = whoami_len(ctx), + .name = lib9p_str(self->name), + .owner_uid = { .name=lib9p_str("root"), .num=0 }, + .owner_gid = { .name=lib9p_str("root"), .num=0 }, + .last_modifier_uid = { .name=lib9p_str("root"), .num=0 }, + .extension = lib9p_str(NULL), + }; +} +static void whoami_file_wstat(struct whoami_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_srv_stat) { + assert(self); + assert(ctx); + lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "cannot wstat API file"); +} +static void whoami_file_remove(struct whoami_file *self, struct lib9p_srv_ctx *ctx) { + assert(self); + assert(ctx); + lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "cannot remove API file"); +} + +LIB9P_SRV_NOTDIR(struct whoami_file, whoami_file) + +static lo_interface lib9p_srv_fio whoami_file_fopen(struct whoami_file *self, struct lib9p_srv_ctx *ctx, bool, bool, bool) { + assert(self); + assert(ctx); + + struct whoami_fio *ret = heap_alloc(1, struct whoami_fio); + ret->parent = self; + ret->buf_len = 0; + ret->buf = NULL; + + return lo_box_whoami_fio_as_lib9p_srv_fio(ret); +} + +/* srv_fio ********************************************************************/ + +static void whoami_fio_iofree(struct whoami_fio *self) { + assert(self); + if (self->buf) + free(self->buf); + free(self); +} + +static struct lib9p_qid whoami_fio_qid(struct whoami_fio *self) { + assert(self); + assert(self->parent); + return whoami_file_qid(self->parent); +} + +static uint32_t whoami_fio_iounit(struct whoami_fio *self) { + assert(self); + return 0; +} + +static uint32_t whoami_fio_pwrite(struct whoami_fio *LM_UNUSED(self), + struct lib9p_srv_ctx *LM_UNUSED(ctx), + void *LM_UNUSED(buf), uint32_t LM_UNUSED(byte_count), + uint64_t LM_UNUSED(offset)) { + assert_notreached("not writable"); +} +static void whoami_fio_pread(struct whoami_fio *self, struct lib9p_srv_ctx *ctx, + uint32_t byte_count, uint64_t byte_offset, + struct iovec *ret) { + assert(self); + assert(ctx); + assert(ret); + + size_t data_size = whoami_len(ctx); + if (self->buf_len < data_size+1) { + self->buf = realloc(self->buf, data_size+1); + self->buf_len = data_size+1; + } + snprintf(self->buf, self->buf_len, "%"PRIu32" %.*s\n", + ctx->user->num, ctx->user->name.len, ctx->user->name.utf8); + + if (byte_offset > (uint64_t)data_size) { + lib9p_error(&ctx->basectx, + LIB9P_ERRNO_L_EINVAL, "offset is past end-of-file length"); + return; + } + + size_t beg_off = (size_t)byte_offset; + size_t end_off = beg_off + (size_t)byte_count; + if (end_off > data_size) + end_off = data_size; + + *ret = (struct iovec){ + .iov_base = &self->buf[beg_off], + .iov_len = end_off-beg_off, + }; +} diff --git a/lib9p/tests/test_server/fs_whoami.h b/lib9p/tests/test_server/fs_whoami.h new file mode 100644 index 0000000..0d3d311 --- /dev/null +++ b/lib9p/tests/test_server/fs_whoami.h @@ -0,0 +1,20 @@ +/* lib9p/tests/test_server/fs_whoami.h - /whoami API endpoint + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#ifndef _LIB9P_TESTS_TEST_SERVER_FS_WHOAMI_H_ +#define _LIB9P_TESTS_TEST_SERVER_FS_WHOAMI_H_ + +#include <util9p/static.h> +#include <libhw/host_net.h> + +struct whoami_file { + char *name; + uint64_t pathnum; +}; +LO_IMPLEMENTATION_H(lib9p_srv_file, struct whoami_file, whoami_file); +#define lo_box_whoami_file_as_lib9p_srv_file(obj) util9p_box(whoami_file, obj) + +#endif /* _LIB9P_TESTS_TEST_SERVER_FS_WHOAMI_H_ */ diff --git a/lib9p/tests/test_server/main.c b/lib9p/tests/test_server/main.c index a31c083..d7819eb 100644 --- a/lib9p/tests/test_server/main.c +++ b/lib9p/tests/test_server/main.c @@ -5,6 +5,8 @@ */ #include <error.h> +#include <errno.h> +#include <stdio.h> #include <stdlib.h> /* for atoi() */ #include <lib9p/srv.h> @@ -17,13 +19,19 @@ #include <util9p/static.h> #include "static.h" +#include "fs_flush.h" +#include "fs_shutdown.h" +#include "fs_whoami.h" /* configuration **************************************************************/ #include "config.h" -#ifndef CONFIG_SRV9P_NUM_CONNS - #error config.h must define CONFIG_SRV9P_NUM_CONNS +#ifndef _CONFIG_9P_MAX_CONNS + #error config.h must define _CONFIG_9P_MAX_CONNS +#endif +#ifndef _CONFIG_9P_MAX_REQS + #error config.h must define _CONFIG_9P_MAX_REQS #endif /* globals ********************************************************************/ @@ -34,123 +42,46 @@ const char *hexdig = "0123456789abcdef"; struct { uint16_t port; - struct hostnet_tcp_listener listeners[CONFIG_SRV9P_NUM_CONNS]; + struct hostnet_tcp_listener listeners[_CONFIG_9P_MAX_CONNS]; struct lib9p_srv srv; + FILE *logstream; } globals = { .srv = (struct lib9p_srv){ .rootdir = get_root, }, }; -/* api ************************************************************************/ - -struct api_file { - uint64_t pathnum; -}; -LO_IMPLEMENTATION_H(lib9p_srv_file, struct api_file, api); -LO_IMPLEMENTATION_H(lib9p_srv_fio, struct api_file, api); - -LO_IMPLEMENTATION_C(lib9p_srv_file, struct api_file, api, static); -LO_IMPLEMENTATION_C(lib9p_srv_fio, struct api_file, api, static); - -static void api_free(struct api_file *self) { - assert(self); -} -static struct lib9p_qid api_qid(struct api_file *self) { - assert(self); - return (struct lib9p_qid){ - .type = LIB9P_QT_FILE, - .vers = 1, - .path = self->pathnum, - }; -} - -static struct lib9p_stat api_stat(struct api_file *self, struct lib9p_srv_ctx *ctx) { - assert(self); - assert(ctx); - return (struct lib9p_stat){ - .kern_type = 0, - .kern_dev = 0, - .file_qid = api_qid(self), - .file_mode = 0222, - .file_atime = UTIL9P_ATIME, - .file_mtime = UTIL9P_MTIME, - .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 void api_wstat(struct api_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_stat) { - assert(self); - assert(ctx); - lib9p_error(&ctx->basectx, LINUX_EROFS, "cannot wstat API file"); -} -static void api_remove(struct api_file *self, struct lib9p_srv_ctx *ctx) { - assert(self); - assert(ctx); - lib9p_error(&ctx->basectx, LINUX_EROFS, "cannot remove API file"); -} - -LIB9P_SRV_NOTDIR(struct api_file, api) - -static lo_interface lib9p_srv_fio api_fopen(struct api_file *self, struct lib9p_srv_ctx *ctx, bool, bool, bool) { - assert(self); - assert(ctx); - return lo_box_api_as_lib9p_srv_fio(self); -} - -static void api_iofree(struct api_file *self) { - assert(self); -} - -static uint32_t api_iounit(struct api_file *self) { - assert(self); - return 0; -} - -static uint32_t api_pwrite(struct api_file *self, struct lib9p_srv_ctx *ctx, void *buf, uint32_t byte_count, uint64_t LM_UNUSED(offset)) { - assert(self); - assert(ctx); - assert(buf); - if (byte_count == 0) - return 0; - for (int i = 0; i < CONFIG_SRV9P_NUM_CONNS; i++) - LO_CALL(lo_box_hostnet_tcplist_as_net_stream_listener(&globals.listeners[i]), close); - return byte_count; -} -static void api_pread(struct api_file *LM_UNUSED(self), struct lib9p_srv_ctx *LM_UNUSED(ctx), - uint32_t LM_UNUSED(byte_count), uint64_t LM_UNUSED(byte_offset), - struct iovec *LM_UNUSED(ret)) { - assert_notreached("not readable"); -} - -#define lo_box_api_as_lib9p_srv_file(obj) util9p_box(api, obj) - /* file tree ******************************************************************/ -enum { PATH_BASE = __COUNTER__ }; -#define PATH_COUNTER __COUNTER__ - PATH_BASE - -#define STATIC_FILE(STRNAME, SYMNAME) \ - UTIL9P_STATIC_FILE(PATH_COUNTER, STRNAME, \ +#define STATIC_FILE(N, STRNAME, SYMNAME) \ + UTIL9P_STATIC_FILE(N, STRNAME, \ .data_start = _binary_static_##SYMNAME##_start, \ .data_end = _binary_static_##SYMNAME##_end) -#define STATIC_DIR(STRNAME, ...) \ - UTIL9P_STATIC_DIR(PATH_COUNTER, STRNAME, __VA_ARGS__) +#define STATIC_DIR(N, STRNAME, ...) \ + UTIL9P_STATIC_DIR(N, STRNAME, __VA_ARGS__) + +#define API_FILE(N, STRNAME, SYMNAME, ...) \ + lo_box_##SYMNAME##_file_as_lib9p_srv_file(&((struct SYMNAME##_file){ \ + .name = STRNAME, \ + .pathnum = N \ + __VA_OPT__(,) __VA_ARGS__ \ + })) struct lib9p_srv_file root = - STATIC_DIR("", - STATIC_DIR("Documentation", - STATIC_FILE("x", Documentation_x_txt), + STATIC_DIR(1, "", + STATIC_DIR(2, "Documentation", + STATIC_FILE(3, "x", Documentation_x_txt), ), - STATIC_FILE("README.md", README_md), - lo_box_api_as_lib9p_srv_file(&(struct api_file){.pathnum = PATH_COUNTER}), + STATIC_FILE(4, "README.md", README_md), + API_FILE(5, "shutdown", shutdown, + .listeners = globals.listeners, + .nlisteners = LM_ARRAY_LEN(globals.listeners)), + API_FILE(8, "whoami", whoami), + API_FILE(9, "flush-read", flush, .flush_cnt=1, .flush_behavior=FLUSH_READ), + API_FILE(10, "flush-error", flush, .flush_cnt=1, .flush_behavior=FLUSH_ERROR), + API_FILE(11, "flush-silent", flush, .flush_cnt=1, .flush_behavior=FLUSH_SILENT), + API_FILE(12, "flush-slowsilent", flush, .flush_cnt=2, .flush_behavior=FLUSH_SILENT), + API_FILE(13, "flush-slowread", flush, .flush_cnt=0, .flush_behavior=FLUSH_READ), ); static lo_interface lib9p_srv_file get_root(struct lib9p_srv_ctx *LM_UNUSED(ctx), struct lib9p_s LM_UNUSED(treename)) { @@ -165,7 +96,15 @@ static COROUTINE read_cr(void *_i) { hostnet_tcp_listener_init(&globals.listeners[i], globals.port); - lib9p_srv_read_cr(&globals.srv, lo_box_hostnet_tcplist_as_net_stream_listener(&globals.listeners[i])); + lib9p_srv_accept_and_read_loop(&globals.srv, lo_box_hostnet_tcplist_as_net_stream_listener(&globals.listeners[i])); + + cr_end(); +} + +static COROUTINE write_cr(void *) { + cr_begin(); + + lib9p_srv_worker_loop(&globals.srv); cr_end(); } @@ -173,31 +112,57 @@ static COROUTINE read_cr(void *_i) { static COROUTINE init_cr(void *) { cr_begin(); - sleep_for_ms(1); + sleep_for_ms(1); /* test that sleep works */ - for (int i = 0; i < CONFIG_SRV9P_NUM_CONNS; i++) { + for (int i = 0; i < _CONFIG_9P_MAX_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++) { + for (int i = 0; i < _CONFIG_9P_MAX_REQS; 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)"); + if (!coroutine_add(name, write_cr, NULL)) + error(1, 0, "coroutine_add(write_cr, NULL)"); } cr_exit(); } +static void log_fct(char character, void *_stream) { + FILE *stream = _stream; + putc(character, stream); + putchar(character); +} + +static void log_msg(struct lib9p_srv_ctx *ctx, enum lib9p_msg_type typ, void *hostmsg) { + /* It sucks that %v trips -Wformat and -Wformat-extra-args + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47781 */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" +#pragma GCC diagnostic ignored "-Wformat-extra-args" + fmt_fctprintf(log_fct, globals.logstream, + "%c %v\n", typ % 2 ? '<' : '>', + lo_box_lib9p_msg_as_fmt_formatter(&ctx->basectx, typ, hostmsg)); +#pragma GCC diagnostic pop + fflush(globals.logstream); +} + int main(int argc, char *argv[]) { - if (argc != 2) - error(2, 0, "usage: %s PORT_NUMBER", argv[0]); + if (argc != 3) + error(2, 0, "usage: %s PORT_NUMBER LOGFILE", argv[0]); + globals.port = atoi(argv[1]); + globals.logstream = fopen(argv[2], "w"); + if (!globals.logstream) + error(2, errno, "fopen"); + globals.srv.msglog = log_msg; + struct hostclock clock_monotonic = { .clock_id = CLOCK_MONOTONIC, }; bootclock = lo_box_hostclock_as_alarmclock(&clock_monotonic); coroutine_add("init", init_cr, NULL); coroutine_main(); + fclose(globals.logstream); return 0; } diff --git a/lib9p/tests/testclient-p9p b/lib9p/tests/testclient-p9p new file mode 100755 index 0000000..09ce746 --- /dev/null +++ b/lib9p/tests/testclient-p9p @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +# lib9p/tests/testclient-p9p - Test the 9P `test_server` against Plan 9 Port's `9p` utility +# +# Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com> +# SPDX-License-Identifier: AGPL-3.0-or-later + +set -euE -o pipefail + +if [[ $# != 1 ]]; then + echo >&2 "Usage: $0 SERVER_PORT" + echo >&2 "Usage: ./runtest $0 EXPLOG" + exit 2 +fi + +expect_lines() ( + { set +x; } &>/dev/null + printf >&2 '+ diff -u expected.txt actual.txt\n' + diff -u <(printf '%s\n' "$@") <(printf '%s\n' "$out") +) + +set -x +client=(unshare --user 9p -a "localhost:${1}") + +out=$("${client[@]}" ls -l '') +expect_lines \ + 'd-r-xr-xr-x M 0 root root 0 Oct 7 2024 Documentation' \ + '--r--r--r-- M 0 root root 166 Oct 7 2024 README.md' \ + '--r--r--r-- M 0 root root 6 Oct 7 2024 flush-error' \ + '--r--r--r-- M 0 root root 6 Oct 7 2024 flush-read' \ + '--r--r--r-- M 0 root root 6 Oct 7 2024 flush-silent' \ + '--r--r--r-- M 0 root root 6 Oct 7 2024 flush-slowread' \ + '--r--r--r-- M 0 root root 6 Oct 7 2024 flush-slowsilent' \ + 'a--w--w--w- M 0 root root 0 Oct 7 2024 shutdown' \ + '--r--r--r-- M 0 root root 9 Oct 7 2024 whoami' + +out=$("${client[@]}" ls -l 'Documentation/') +expect_lines \ + '--r--r--r-- M 0 root root 166 Oct 7 2024 x' + +out=$("${client[@]}" read 'README.md') +expect_lines \ + '<!--' \ + ' README.md - test static file' \ + '' \ + ' Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>' \ + ' SPDX-License-Identifier: AGPL-3.0-or-later' \ + '-->' \ + 'Hello, world!' + +out=$("${client[@]}" read 'Documentation/x') +expect_lines \ + '<!--' \ + ' Documentation/x.txt - test static file' \ + '' \ + ' Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>' \ + ' SPDX-License-Identifier: AGPL-3.0-or-later' \ + '-->' \ + 'foo' + +out=$("${client[@]}" stat 'Documentation/x') +expect_lines \ + "'x' 'root' 'root' 'root' q (0000000000000003 1 ) m 0444 at 1728337905 mt 1728337904 l 166 t 0 d 0" + +out=$("${client[@]}" write 'shutdown' <<<1) +expect_lines '' diff --git a/lib9p/tests/testclient-p9p.explog b/lib9p/tests/testclient-p9p.explog new file mode 100644 index 0000000..54f1e4b --- /dev/null +++ b/lib9p/tests/testclient-p9p.explog @@ -0,0 +1,106 @@ +# lib9p/tests/testclient-p9p.explog - Expected 9P logfile of testclient-p9p +# +# Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com> +# SPDX-License-Identifier: AGPL-3.0-or-later +> Tversion { tag=NOTAG max_msg_size=8192 version="9P2000" } +< Rversion { tag=NOTAG max_msg_size=4120 version="9P2000" } +> Tauth { tag=0 afid=0 uname="nobody" aname="" unum=0 } +< Rerror { tag=0 errstr="authentication not required" errnum=L_EOPNOTSUPP } +> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" unum=0 } +< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } } +> Twalk { tag=0 fid=0 newfid=1 nwname=0 wname=[ ] } +< Rwalk { tag=0 nwqid=0 wqid=[ ] } +> Tstat { tag=0 fid=1 } +< Rstat { tag=0 stat={ fstype=0 fsdev=0 qid={ type=(DIR) vers=1 path=1 } mode=(DIR|0555) atime=1728337905 mtime=1728337904 length=0 name="" owner_uname="root" owner_gname="root" last_modifier_uname="root" extension="" owner_unum=0 owner_gnum=0 last_modifier_unum=0 } } +> Tclunk { tag=0 fid=1 } +< Rclunk { tag=0 } +> Twalk { tag=0 fid=0 newfid=1 nwname=0 wname=[ ] } +< Rwalk { tag=0 nwqid=0 wqid=[ ] } +> Topen { tag=0 fid=1 mode=(MODE_READ) } +< Ropen { tag=0 qid={ type=(DIR) vers=1 path=1 } iounit=0 } +> Tread { tag=0 fid=1 offset=0 count=4096 } +< Rread { tag=0 count=648 data=<bytedata> } +> Tread { tag=0 fid=1 offset=648 count=4096 } +< Rread { tag=0 count=0 data="" } +> Tclunk { tag=0 fid=1 } +< Rclunk { tag=0 } +> Tversion { tag=NOTAG max_msg_size=8192 version="9P2000" } +< Rversion { tag=NOTAG max_msg_size=4120 version="9P2000" } +> Tauth { tag=0 afid=0 uname="nobody" aname="" unum=0 } +< Rerror { tag=0 errstr="authentication not required" errnum=L_EOPNOTSUPP } +> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" unum=0 } +< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } } +> Twalk { tag=0 fid=0 newfid=1 nwname=1 wname=[ "Documentation" ] } +< Rwalk { tag=0 nwqid=1 wqid=[ { type=(DIR) vers=1 path=2 } ] } +> Tstat { tag=0 fid=1 } +< Rstat { tag=0 stat={ fstype=0 fsdev=0 qid={ type=(DIR) vers=1 path=2 } mode=(DIR|0555) atime=1728337905 mtime=1728337904 length=0 name="Documentation" owner_uname="root" owner_gname="root" last_modifier_uname="root" extension="" owner_unum=0 owner_gnum=0 last_modifier_unum=0 } } +> Tclunk { tag=0 fid=1 } +< Rclunk { tag=0 } +> Twalk { tag=0 fid=0 newfid=1 nwname=1 wname=[ "Documentation" ] } +< Rwalk { tag=0 nwqid=1 wqid=[ { type=(DIR) vers=1 path=2 } ] } +> Topen { tag=0 fid=1 mode=(MODE_READ) } +< Ropen { tag=0 qid={ type=(DIR) vers=1 path=2 } iounit=0 } +> Tread { tag=0 fid=1 offset=0 count=4096 } +< Rread { tag=0 count=62 data=<bytedata> } +> Tread { tag=0 fid=1 offset=62 count=4096 } +< Rread { tag=0 count=0 data="" } +> Tclunk { tag=0 fid=1 } +< Rclunk { tag=0 } +> Tversion { tag=NOTAG max_msg_size=8192 version="9P2000" } +< Rversion { tag=NOTAG max_msg_size=4120 version="9P2000" } +> Tauth { tag=0 afid=0 uname="nobody" aname="" unum=0 } +< Rerror { tag=0 errstr="authentication not required" errnum=L_EOPNOTSUPP } +> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" unum=0 } +< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } } +> Twalk { tag=0 fid=0 newfid=1 nwname=1 wname=[ "README.md" ] } +< Rwalk { tag=0 nwqid=1 wqid=[ { type=(0) vers=1 path=4 } ] } +> Topen { tag=0 fid=1 mode=(MODE_READ) } +< Ropen { tag=0 qid={ type=(0) vers=1 path=4 } iounit=0 } +> Tread { tag=0 fid=1 offset=0 count=4096 } +< Rread { tag=0 count=166 data="<!--\n README.md - test static file\n\n Copyright ("... } +> Tread { tag=0 fid=1 offset=166 count=4096 } +< Rread { tag=0 count=0 data="" } +> Tclunk { tag=0 fid=1 } +< Rclunk { tag=0 } +> Tversion { tag=NOTAG max_msg_size=8192 version="9P2000" } +< Rversion { tag=NOTAG max_msg_size=4120 version="9P2000" } +> Tauth { tag=0 afid=0 uname="nobody" aname="" unum=0 } +< Rerror { tag=0 errstr="authentication not required" errnum=L_EOPNOTSUPP } +> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" unum=0 } +< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } } +> Twalk { tag=0 fid=0 newfid=1 nwname=2 wname=[ "Documentation", "x" ] } +< Rwalk { tag=0 nwqid=2 wqid=[ { type=(DIR) vers=1 path=2 }, { type=(0) vers=1 path=3 } ] } +> Topen { tag=0 fid=1 mode=(MODE_READ) } +< Ropen { tag=0 qid={ type=(0) vers=1 path=3 } iounit=0 } +> Tread { tag=0 fid=1 offset=0 count=4096 } +< Rread { tag=0 count=166 data="<!--\n Documentation/x.txt - test static file\n\n C"... } +> Tread { tag=0 fid=1 offset=166 count=4096 } +< Rread { tag=0 count=0 data="" } +> Tclunk { tag=0 fid=1 } +< Rclunk { tag=0 } +> Tversion { tag=NOTAG max_msg_size=8192 version="9P2000" } +< Rversion { tag=NOTAG max_msg_size=4120 version="9P2000" } +> Tauth { tag=0 afid=0 uname="nobody" aname="" unum=0 } +< Rerror { tag=0 errstr="authentication not required" errnum=L_EOPNOTSUPP } +> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" unum=0 } +< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } } +> Twalk { tag=0 fid=0 newfid=1 nwname=2 wname=[ "Documentation", "x" ] } +< Rwalk { tag=0 nwqid=2 wqid=[ { type=(DIR) vers=1 path=2 }, { type=(0) vers=1 path=3 } ] } +> Tstat { tag=0 fid=1 } +< Rstat { tag=0 stat={ fstype=0 fsdev=0 qid={ type=(0) vers=1 path=3 } mode=(0444) atime=1728337905 mtime=1728337904 length=166 name="x" owner_uname="root" owner_gname="root" last_modifier_uname="root" extension="" owner_unum=0 owner_gnum=0 last_modifier_unum=0 } } +> Tclunk { tag=0 fid=1 } +< Rclunk { tag=0 } +> Tversion { tag=NOTAG max_msg_size=8192 version="9P2000" } +< Rversion { tag=NOTAG max_msg_size=4120 version="9P2000" } +> Tauth { tag=0 afid=0 uname="nobody" aname="" unum=0 } +< Rerror { tag=0 errstr="authentication not required" errnum=L_EOPNOTSUPP } +> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" unum=0 } +< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } } +> Twalk { tag=0 fid=0 newfid=1 nwname=1 wname=[ "shutdown" ] } +< Rwalk { tag=0 nwqid=1 wqid=[ { type=(APPEND) vers=1 path=5 } ] } +> Topen { tag=0 fid=1 mode=(TRUNC|MODE_WRITE) } +< Ropen { tag=0 qid={ type=(APPEND) vers=1 path=5 } iounit=0 } +> Twrite { tag=0 fid=1 offset=0 count=2 data="1\n" } +< Rwrite { tag=0 count=2 } +> Tclunk { tag=0 fid=1 } +< Rclunk { tag=0 } diff --git a/lib9p/tests/testclient-sess.c b/lib9p/tests/testclient-sess.c new file mode 100644 index 0000000..7cb7f97 --- /dev/null +++ b/lib9p/tests/testclient-sess.c @@ -0,0 +1,243 @@ +/* lib9p/tests/testclient-sess.c - Test the 9P `test_server`'s sessions + * + * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include <arpa/inet.h> /* for htons(), inet_addr() */ +#include <errno.h> +#include <error.h> +#include <netinet/in.h> /* for struct sockaddr{,_in} */ +#include <stdlib.h> /* for atoi() */ +#include <sys/socket.h> /* for socket(), connect() */ +#include <sys/uio.h> /* for writev() */ +#include <unistd.h> /* for read() */ + +#include <libmisc/assert.h> +#include <libmisc/endian.h> +#include <lib9p/core.h> + +#define MAX_MSG_SIZE (8*1024) + +static void _send9p(int fd, struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body) { + struct lib9p_Tmsg_send_buf buf; + bool err = lib9p_Tmsg_marshal(ctx, typ, body, &buf); + assert(!err); + size_t exp = 0; + for (size_t i = 0; i < buf.iov_cnt; i++) + exp += buf.iov[i].iov_len; + ssize_t act = writev(fd, buf.iov, buf.iov_cnt); + if (act < 0) + error(1, errno, "writev"); + assert((size_t)act == exp); +} + +#define send9p(typ, ...) _send9p(fd, &ctx, LIB9P_TYP_##typ, &((struct lib9p_msg_##typ){ __VA_ARGS__ })) + +static void _recv9p(int fd) { + uint8_t buf[MAX_MSG_SIZE]; + size_t goal = 4; + size_t done = 0; + while (done < goal) { + ssize_t n = read(fd, &buf[done], goal-done); + if (n < 0) + error(1, errno, "read"); + done += n; + } + goal = uint32le_decode(buf); + assert(goal <= MAX_MSG_SIZE); + while (done < goal) { + ssize_t n = read(fd, &buf[done], goal-done); + if (n < 0) + error(1, errno, "read"); + done += n; + } +} + +#define recv9p() _recv9p(fd) + +int main(int argc, char *argv[]) { + if (argc != 2) + error(2, 0, "Usage: %s SERVER_PORT", argv[0]); + uint16_t server_port = atoi(argv[1]); + + union { + struct sockaddr gen; + struct sockaddr_in in; + } server_addr = {}; + server_addr.in.sin_family = AF_INET; + server_addr.in.sin_addr.s_addr = inet_addr("127.0.0.1"); + server_addr.in.sin_port = htons(server_port); + + int fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) + error(1, errno, "socket"); + if (connect(fd, &server_addr.gen, sizeof(server_addr)) < 0) + error(1, errno, "connect"); + + struct lib9p_ctx ctx = { + .max_msg_size = 16*1024, + }; + + struct lib9p_s wname[1]; + + /* numeric downgrade, unknown ext *************************************/ + send9p(Tversion, .tag=0, .max_msg_size=57, .version=lib9p_str("9P2025.x")); + recv9p(); /* Rversion */ + ctx.version = LIB9P_VER_9P2000; + + /* numeric downgrade, known ext ***************************************/ + send9p(Tversion, .tag=0, .max_msg_size=57, .version=lib9p_str("9P2025.u")); + recv9p(); /* Rversion */ + ctx.version = LIB9P_VER_9P2000_u; + + /* ext version, users *************************************************/ + send9p(Tversion, .tag=0, .max_msg_size=(8*1024), .version=lib9p_str("9P2000.u")); + recv9p(); /* Rversion */ + ctx.version = LIB9P_VER_9P2000_u; + send9p(Tattach, .tag=0, .fid=0, .afid=LIB9P_FID_NOFID, .uname=lib9p_str("alice"), .unum=1000, .aname=lib9p_str("")); + recv9p(); /* Rattach */ + send9p(Tattach, .tag=0, .fid=1, .afid=LIB9P_FID_NOFID, .uname=lib9p_str("bob"), .unum=1001, .aname=lib9p_str("")); + recv9p(); /* Rattach */ + wname[0] = lib9p_str("whoami"); send9p(Twalk, .tag=0, .fid=0, .newfid=2, .nwname=1, .wname=wname); + recv9p(); /* Rwalk */ + wname[0] = lib9p_str("whoami"); send9p(Twalk, .tag=0, .fid=1, .newfid=3, .nwname=1, .wname=wname); + recv9p(); /* Rwalk */ + send9p(Topen, .tag=0, .fid=2, .mode=LIB9P_O_MODE_READ); + recv9p(); /* Ropen */ + send9p(Topen, .tag=0, .fid=3, .mode=LIB9P_O_MODE_READ); + recv9p(); /* Ropen */ + send9p(Tread, .tag=0, .fid=2, .offset=0, .count=100); + recv9p(); /* Rread */ + send9p(Tread, .tag=0, .fid=3, .offset=0, .count=100); + recv9p(); /* Rread */ + + /* walk ***************************************************************/ + send9p(Tversion, .tag=0, .max_msg_size=(8*1024), .version=lib9p_str("9P2000")); + recv9p(); /* Rversion */ + ctx.version = LIB9P_VER_9P2000; + send9p(Tattach, .tag=0, .fid=0, .afid=LIB9P_FID_NOFID, .uname=lib9p_str("nobody"), .aname=lib9p_str("")); + recv9p(); /* Rattach */ + + /* dup */ + send9p(Twalk, .tag=0, .fid=0, .newfid=1, .nwname=0); + recv9p(); /* Rwalk */ + + /* "The walk request carries as arguments an existing fid"... */ + send9p(Twalk, .tag=0, .fid=2, .newfid=3, .nwname=0); + recv9p(); /* Rerror */ + + /* ..."and a proposed newfid"... */ + send9p(Twalk, .tag=0, .fid=1, .newfid=0xffffffff, .nwname=0); + recv9p(); /* Rerror */ + + /* ..."(which must not be in use"... */ + send9p(Twalk, .tag=0, .fid=1, .newfid=0, .nwname=0); + recv9p(); /* Rerror */ + + /* ..."unless it is the same as fid)"... */ + send9p(Twalk, .tag=0, .fid=1, .newfid=1, .nwname=0); + recv9p(); /* Rwalk */ + + /* ... "that the client wishes to associate with the result of + * traversing the directory hierarchy by `walking' the heierarchy using + * the successive path name elements wname."... */ + + /* ..."The fid must represent a directory"... */ + wname[0] = lib9p_str("README.md"); send9p(Twalk, .tag=0, .fid=1, .newfid=2, .nwname=1, .wname=wname); + recv9p(); /* Rwalk */ + wname[0] = lib9p_str(".."); send9p(Twalk, .tag=0, .fid=2, .newfid=3, .nwname=1, .wname=wname); + recv9p(); /* Rerror */ + + /* ..."unless zero path name elements are specified." */ + send9p(Twalk, .tag=0, .fid=2, .newfid=3, .nwname=0); + recv9p(); /* Rwalk */ + + /* "The fid must be valid in the current session" (tested above)... */ + + /* ..."and must not have been opened for I/O by an open or create + * message."... */ + send9p(Topen, .tag=0, .fid=3, .mode=LIB9P_O_MODE_READ); + recv9p(); /* Ropen */ + send9p(Twalk, .tag=0, .fid=3, .newfid=4, .nwname=0); + recv9p(); /* Rerror */ + + /* flush **************************************************************/ + send9p(Tversion, .tag=0, .max_msg_size=(8*1024), .version=lib9p_str("9P2000")); + recv9p(); /* Rversion */ + ctx.version = LIB9P_VER_9P2000; + send9p(Tattach, .tag=0, .fid=0, .afid=LIB9P_FID_NOFID, .uname=lib9p_str("nobody"), .aname=lib9p_str("")); + recv9p(); /* Rattach */ + + /* flush, but original response comes back first */ + wname[0] = lib9p_str("flush-read"); send9p(Twalk, .tag=0, .fid=0, .newfid=1, .nwname=1, .wname=wname); + recv9p(); /* Rwalk */ + send9p(Topen, .tag=0, .fid=1, .mode=LIB9P_O_MODE_READ); + recv9p(); /* Ropen */ + send9p(Tread, .tag=0, .fid=1, .offset=0, .count=10); + send9p(Tflush, .tag=1, .oldtag=0); + recv9p(); /* Rread */ + recv9p(); /* Rflush */ + + /* flush, original request is aborted with error */ + wname[0] = lib9p_str("flush-error"); send9p(Twalk, .tag=0, .fid=0, .newfid=2, .nwname=1, .wname=wname); + recv9p(); /* Rwalk */ + send9p(Topen, .tag=0, .fid=2, .mode=LIB9P_O_MODE_READ); + recv9p(); /* Ropen */ + send9p(Tread, .tag=0, .fid=2, .offset=0, .count=10); + send9p(Tflush, .tag=1, .oldtag=0); + recv9p(); /* Rerror */ + recv9p(); /* Rflush */ + + /* flush, original request is aborted without error */ + wname[0] = lib9p_str("flush-silent"); send9p(Twalk, .tag=0, .fid=0, .newfid=3, .nwname=1, .wname=wname); + recv9p(); /* Rwalk */ + send9p(Topen, .tag=0, .fid=3, .mode=LIB9P_O_MODE_READ); + recv9p(); /* Ropen */ + send9p(Tread, .tag=0, .fid=3, .offset=0, .count=10); + send9p(Tflush, .tag=1, .oldtag=0); + recv9p(); /* Rflush */ + + /* multiflush, original request is aborted without error */ + wname[0] = lib9p_str("flush-slowsilent"); send9p(Twalk, .tag=0, .fid=0, .newfid=4, .nwname=1, .wname=wname); + recv9p(); /* Rwalk */ + send9p(Topen, .tag=0, .fid=4, .mode=LIB9P_O_MODE_READ); + recv9p(); /* Ropen */ + send9p(Tread, .tag=0, .fid=4, .offset=0, .count=10); + send9p(Tflush, .tag=1, .oldtag=0); + send9p(Tflush, .tag=2, .oldtag=0); + recv9p(); /* Rflush */ + + /* flush, but flush is flushed */ + wname[0] = lib9p_str("flush-slowread"); send9p(Twalk, .tag=0, .fid=0, .newfid=5, .nwname=1, .wname=wname); + recv9p(); /* Rwalk */ + send9p(Topen, .tag=0, .fid=5, .mode=LIB9P_O_MODE_READ); + recv9p(); /* Ropen */ + send9p(Tread, .tag=0, .fid=5, .offset=0, .count=10); + send9p(Tflush, .tag=1, .oldtag=0); + send9p(Tflush, .tag=2, .oldtag=1); + recv9p(); /* Rflush */ + recv9p(); /* Rread */ + + /* flush, unknown tag */ + send9p(Tflush, .tag=0, .oldtag=99); + recv9p(); /* Rflush */ + + /* flushed by Tversion */ + send9p(Tread, .tag=0, .fid=3, .offset=0, .count=10); + + /* shutdown ***********************************************************/ + send9p(Tversion, .tag=0, .max_msg_size=(8*1024), .version=lib9p_str("9P2000")); + recv9p(); /* Rversion */ + ctx.version = LIB9P_VER_9P2000; + send9p(Tattach, .tag=0, .fid=0, .afid=LIB9P_FID_NOFID, .uname=lib9p_str("nobody"), .aname=lib9p_str("")); + recv9p(); /* Rattach */ + /* check the newfid==fid case */ + wname[0] = lib9p_str("shutdown"); send9p(Twalk, .tag=0, .fid=0, .newfid=0, .nwname=1, .wname=wname); + recv9p(); /* Rwalk */ + send9p(Topen, .tag=0, .fid=0, .mode=LIB9P_O_MODE_WRITE); + recv9p(); /* Ropen */ + send9p(Twrite, .tag=0, .fid=0, .offset=0, .count=2, .data="1\n"); + recv9p(); /* Rwrite */ + return 0; +} diff --git a/lib9p/tests/testclient-sess.explog b/lib9p/tests/testclient-sess.explog new file mode 100644 index 0000000..a3838ac --- /dev/null +++ b/lib9p/tests/testclient-sess.explog @@ -0,0 +1,156 @@ +# lib9p/tests/testclient-sess.explog - Expected 9P logfile of testclient-sess.c +# +# Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com> +# SPDX-License-Identifier: AGPL-3.0-or-later + +# numeric downgrade, unknown ext ############################################### +> Tversion { tag=0 max_msg_size=57 version="9P2025.x" } +< Rversion { tag=0 max_msg_size=57 version="9P2000" } + +# numeric downgrade, known ext ################################################# +> Tversion { tag=0 max_msg_size=57 version="9P2025.u" } +< Rversion { tag=0 max_msg_size=57 version="9P2000.u" } + +# ext version, users ########################################################### +> Tversion { tag=0 max_msg_size=8192 version="9P2000.u" } +< Rversion { tag=0 max_msg_size=4120 version="9P2000.u" } +> Tattach { tag=0 fid=0 afid=NOFID uname="alice" aname="" unum=1000 } +< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } } +> Tattach { tag=0 fid=1 afid=NOFID uname="bob" aname="" unum=1001 } +< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } } +> Twalk { tag=0 fid=0 newfid=2 nwname=1 wname=[ "whoami" ] } +< Rwalk { tag=0 nwqid=1 wqid=[ { type=(0) vers=1 path=8 } ] } +> Twalk { tag=0 fid=1 newfid=3 nwname=1 wname=[ "whoami" ] } +< Rwalk { tag=0 nwqid=1 wqid=[ { type=(0) vers=1 path=8 } ] } +> Topen { tag=0 fid=2 mode=(MODE_READ) } +< Ropen { tag=0 qid={ type=(0) vers=1 path=8 } iounit=0 } +> Topen { tag=0 fid=3 mode=(MODE_READ) } +< Ropen { tag=0 qid={ type=(0) vers=1 path=8 } iounit=0 } +> Tread { tag=0 fid=2 offset=0 count=100 } +< Rread { tag=0 count=11 data="1000 alice\n" } +> Tread { tag=0 fid=3 offset=0 count=100 } +< Rread { tag=0 count=9 data="1001 bob\n" } + +# walk ######################################################################### +> Tversion { tag=0 max_msg_size=8192 version="9P2000" } +< Rversion { tag=0 max_msg_size=4120 version="9P2000" } +> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" unum=0 } +< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } } + +# dup +> Twalk { tag=0 fid=0 newfid=1 nwname=0 wname=[ ] } +< Rwalk { tag=0 nwqid=0 wqid=[ ] } + +# "The walk request carries as arguments an existing fid"... +> Twalk { tag=0 fid=2 newfid=3 nwname=0 wname=[ ] } +< Rerror { tag=0 errstr="bad file number 2" errnum=L_EBADF } + +# ..."and a proposed newfid"... +> Twalk { tag=0 fid=1 newfid=NOFID nwname=0 wname=[ ] } +< Rerror { tag=0 errstr="cannot assign to NOFID" errnum=L_EBADF } + +# ..."(which must not be in use"... +> Twalk { tag=0 fid=1 newfid=0 nwname=0 wname=[ ] } +< Rerror { tag=0 errstr="FID already in use" errnum=L_EBADF } + +# ..."unless it is the same as fid)"... +> Twalk { tag=0 fid=1 newfid=1 nwname=0 wname=[ ] } +< Rwalk { tag=0 nwqid=0 wqid=[ ] } + +# ... "that the client wishes to associate with the result of +# traversing the directory hierarchy by `walking' the heierarchy using +# the successive path name elements wname."... + +# ..."The fid must represent a directory"... +> Twalk { tag=0 fid=1 newfid=2 nwname=1 wname=[ "README.md" ] } +< Rwalk { tag=0 nwqid=1 wqid=[ { type=(0) vers=1 path=4 } ] } +> Twalk { tag=0 fid=2 newfid=3 nwname=1 wname=[ ".." ] } +< Rerror { tag=0 errstr="not a directory" errnum=L_ENOTDIR } + +# ..."unless zero path name elements are specified." +> Twalk { tag=0 fid=2 newfid=3 nwname=0 wname=[ ] } +< Rwalk { tag=0 nwqid=0 wqid=[ ] } + +# "The fid must be valid in the current session" (tested above)... + +# ..."and must not have been opened for I/O by an open or create +# message."... +> Topen { tag=0 fid=3 mode=(MODE_READ) } +< Ropen { tag=0 qid={ type=(0) vers=1 path=4 } iounit=0 } +> Twalk { tag=0 fid=3 newfid=4 nwname=0 wname=[ ] } +< Rerror { tag=0 errstr="cannot walk on FID open for I/O" errnum=L_EALREADY } + +# flush ######################################################################## +> Tversion { tag=0 max_msg_size=8192 version="9P2000" } +< Rversion { tag=0 max_msg_size=4120 version="9P2000" } +> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" unum=0 } +< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } } + +# flush, but original response comes back first +> Twalk { tag=0 fid=0 newfid=1 nwname=1 wname=[ "flush-read" ] } +< Rwalk { tag=0 nwqid=1 wqid=[ { type=(0) vers=1 path=9 } ] } +> Topen { tag=0 fid=1 mode=(MODE_READ) } +< Ropen { tag=0 qid={ type=(0) vers=1 path=9 } iounit=0 } +> Tread { tag=0 fid=1 offset=0 count=10 } +> Tflush { tag=1 oldtag=0 } +< Rread { tag=0 count=6 data="Sloth\n" } +< Rflush { tag=1 } + +# flush, original request is aborted with error +> Twalk { tag=0 fid=0 newfid=2 nwname=1 wname=[ "flush-error" ] } +< Rwalk { tag=0 nwqid=1 wqid=[ { type=(0) vers=1 path=10 } ] } +> Topen { tag=0 fid=2 mode=(MODE_READ) } +< Ropen { tag=0 qid={ type=(0) vers=1 path=10 } iounit=0 } +> Tread { tag=0 fid=2 offset=0 count=10 } +> Tflush { tag=1 oldtag=0 } +< Rerror { tag=0 errstr="request canceled by flush" errnum=L_ECANCELED } +< Rflush { tag=1 } + +# flush, original request is aborted without error +> Twalk { tag=0 fid=0 newfid=3 nwname=1 wname=[ "flush-silent" ] } +< Rwalk { tag=0 nwqid=1 wqid=[ { type=(0) vers=1 path=11 } ] } +> Topen { tag=0 fid=3 mode=(MODE_READ) } +< Ropen { tag=0 qid={ type=(0) vers=1 path=11 } iounit=0 } +> Tread { tag=0 fid=3 offset=0 count=10 } +> Tflush { tag=1 oldtag=0 } +< Rflush { tag=1 } + +# multiflush, original request is aborted without error +> Twalk { tag=0 fid=0 newfid=4 nwname=1 wname=[ "flush-slowsilent" ] } +< Rwalk { tag=0 nwqid=1 wqid=[ { type=(0) vers=1 path=12 } ] } +> Topen { tag=0 fid=4 mode=(MODE_READ) } +< Ropen { tag=0 qid={ type=(0) vers=1 path=12 } iounit=0 } +> Tread { tag=0 fid=4 offset=0 count=10 } +> Tflush { tag=1 oldtag=0 } +> Tflush { tag=2 oldtag=0 } +< Rflush { tag=2 } + +# flush, but flush is flushed +> Twalk { tag=0 fid=0 newfid=5 nwname=1 wname=[ "flush-slowread" ] } +< Rwalk { tag=0 nwqid=1 wqid=[ { type=(0) vers=1 path=13 } ] } +> Topen { tag=0 fid=5 mode=(MODE_READ) } +< Ropen { tag=0 qid={ type=(0) vers=1 path=13 } iounit=0 } +> Tread { tag=0 fid=5 offset=0 count=10 } +> Tflush { tag=1 oldtag=0 } +> Tflush { tag=2 oldtag=1 } +< Rflush { tag=2 } +< Rread { tag=0 count=6 data="Sloth\n" } + +# flush, unknown tag +> Tflush { tag=0 oldtag=99 } +< Rflush { tag=0 } + +# flushed by Tversion +> Tread { tag=0 fid=3 offset=0 count=10 } + +# shutdown ##################################################################### +> Tversion { tag=0 max_msg_size=8192 version="9P2000" } +< Rversion { tag=0 max_msg_size=4120 version="9P2000" } +> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" unum=0 } +< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } } +> Twalk { tag=0 fid=0 newfid=0 nwname=1 wname=[ "shutdown" ] } +< Rwalk { tag=0 nwqid=1 wqid=[ { type=(APPEND) vers=1 path=5 } ] } +> Topen { tag=0 fid=0 mode=(MODE_WRITE) } +< Ropen { tag=0 qid={ type=(APPEND) vers=1 path=5 } iounit=0 } +> Twrite { tag=0 fid=0 offset=0 count=2 data="1\n" } +< Rwrite { tag=0 count=2 } diff --git a/lib9p_util/CMakeLists.txt b/lib9p_util/CMakeLists.txt index 2e5790e..feeada7 100644 --- a/lib9p_util/CMakeLists.txt +++ b/lib9p_util/CMakeLists.txt @@ -9,5 +9,5 @@ target_sources(lib9p_util INTERFACE static.c ) target_link_libraries(lib9p_util INTERFACE - lib9p + lib9p_srv ) diff --git a/lib9p_util/static.c b/lib9p_util/static.c index 7f1e6b7..1726319 100644 --- a/lib9p_util/static.c +++ b/lib9p_util/static.c @@ -33,40 +33,35 @@ static struct lib9p_qid util9p_static_dir_qid(struct util9p_static_dir *self) { }; } -static struct lib9p_stat util9p_static_dir_stat(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx) { +static struct lib9p_srv_stat util9p_static_dir_stat(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx) { assert(self); assert(ctx); - return (struct lib9p_stat){ - .kern_type = 0, - .kern_dev = 0, - .file_qid = util9p_static_dir_qid(self), - .file_mode = LIB9P_DM_DIR | (self->perm & 0555), - .file_atime = self->atime, - .file_mtime = self->mtime, - .file_size = 0, - .file_name = lib9p_str(self->name), - .file_owner_uid = lib9p_str(self->u_name), - .file_owner_gid = lib9p_str(self->g_name), - .file_last_modified_uid = lib9p_str(self->m_name), - .file_extension = lib9p_str(NULL), - .file_owner_n_uid = self->u_num, - .file_owner_n_gid = self->g_num, - .file_last_modified_n_uid = self->m_num, + return (struct lib9p_srv_stat){ + .qid = util9p_static_dir_qid(self), + .mode = LIB9P_DM_DIR | (self->perm & 0555), + .atime_sec = self->atime, + .mtime_sec = self->mtime, + .size = 0, + .name = lib9p_str(self->name), + .owner_uid = { .name = lib9p_str(self->u_name), .num = self->u_num }, + .owner_gid = { .name = lib9p_str(self->g_name), .num = self->g_num }, + .last_modifier_uid = { .name = lib9p_str(self->m_name), .num = self->m_num }, + .extension = lib9p_str(NULL), }; } static void util9p_static_dir_wstat(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx, - struct lib9p_stat) { + struct lib9p_srv_stat) { assert(self); assert(ctx); - lib9p_error(&ctx->basectx, LINUX_EROFS, "read-only part of filesystem"); + lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "read-only part of filesystem"); } static void util9p_static_dir_remove(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx) { assert(self); assert(ctx); - lib9p_error(&ctx->basectx, LINUX_EROFS, "read-only part of filesystem"); + lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "read-only part of filesystem"); } static lo_interface lib9p_srv_file util9p_static_dir_dwalk(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx, @@ -76,25 +71,27 @@ static lo_interface lib9p_srv_file util9p_static_dir_dwalk(struct util9p_static_ for (size_t i = 0; !LO_IS_NULL(self->members[i]); i++) { lo_interface lib9p_srv_file file = self->members[i]; - struct lib9p_stat stat = LO_CALL(file, stat, ctx); + struct lib9p_srv_stat stat = LO_CALL(file, stat, ctx); if (lib9p_ctx_has_error(&ctx->basectx)) break; - lib9p_stat_assert(stat); - if (lib9p_str_eq(stat.file_name, childname)) + lib9p_srv_stat_assert(stat); + if (lib9p_str_eq(stat.name, childname)) return file; } lib9p_error(&ctx->basectx, - LINUX_ENOENT, "no such file or directory"); + LIB9P_ERRNO_L_ENOENT, "no such file or directory"); return LO_NULL(lib9p_srv_file); } static lo_interface lib9p_srv_file util9p_static_dir_dcreate(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx, struct lib9p_s LM_UNUSED(childname), - lib9p_dm_t LM_UNUSED(perm), lib9p_o_t LM_UNUSED(flags)) { + struct lib9p_srv_userid *LM_UNUSED(user), + struct lib9p_srv_userid *LM_UNUSED(group), + lib9p_dm_t LM_UNUSED(perm)) { assert(self); assert(ctx); - lib9p_error(&ctx->basectx, LINUX_EROFS, "read-only part of filesystem"); + lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "read-only part of filesystem"); return LO_NULL(lib9p_srv_file); } @@ -108,33 +105,23 @@ static lo_interface lib9p_srv_dio util9p_static_dir_dopen(struct util9p_static_d static void util9p_static_dir_iofree(struct util9p_static_dir *self) { assert(self); } -static size_t util9p_static_dir_dread(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx, - uint8_t *buf, - uint32_t byte_count, - size_t _obj_offset) { +static struct lib9p_srv_dirent util9p_static_dir_dread(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx, size_t idx) { assert(self); assert(ctx); - uint32_t byte_offset = 0; - size_t obj_offset = _obj_offset; - while (!LO_IS_NULL(self->members[obj_offset])) { - lo_interface lib9p_srv_file file = self->members[obj_offset]; - struct lib9p_stat stat = LO_CALL(file, stat, ctx); - if (lib9p_ctx_has_error(&ctx->basectx)) - break; - lib9p_stat_assert(stat); - uint32_t nbytes = lib9p_stat_marshal(&ctx->basectx, byte_count-byte_offset, &stat, - &buf[byte_offset]); - if (!nbytes) { - if (obj_offset == _obj_offset) - lib9p_error(&ctx->basectx, - LINUX_ERANGE, "stat object does not fit into negotiated max message size"); - break; - } - byte_offset += nbytes; - obj_offset++; - } - return obj_offset - _obj_offset; + lo_interface lib9p_srv_file file = self->members[idx]; + if (LO_IS_NULL(file)) + return (struct lib9p_srv_dirent){}; + + struct lib9p_srv_stat stat = LO_CALL(file, stat, ctx); + if (lib9p_ctx_has_error(&ctx->basectx)) + return (struct lib9p_srv_dirent){}; + lib9p_srv_stat_assert(stat); + + return (struct lib9p_srv_dirent){ + .qid = stat.qid, + .name = stat.name, + }; } /* file ***********************************************************************/ @@ -164,40 +151,35 @@ static inline size_t util9p_static_file_size(struct util9p_static_file *file) { } -static struct lib9p_stat util9p_static_file_stat(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx) { +static struct lib9p_srv_stat util9p_static_file_stat(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx) { assert(self); assert(ctx); - return (struct lib9p_stat){ - .kern_type = 0, - .kern_dev = 0, - .file_qid = util9p_static_file_qid(self), - .file_mode = self->perm & 0444, - .file_atime = self->atime, - .file_mtime = self->mtime, - .file_size = (uint64_t)util9p_static_file_size(self), - .file_name = lib9p_str(self->name), - .file_owner_uid = lib9p_str(self->u_name), - .file_owner_gid = lib9p_str(self->g_name), - .file_last_modified_uid = lib9p_str(self->m_name), - .file_extension = lib9p_str(NULL), - .file_owner_n_uid = self->u_num, - .file_owner_n_gid = self->g_num, - .file_last_modified_n_uid = self->m_num, + return (struct lib9p_srv_stat){ + .qid = util9p_static_file_qid(self), + .mode = self->perm & 0444, + .atime_sec = self->atime, + .mtime_sec = self->mtime, + .size = (uint64_t)util9p_static_file_size(self), + .name = lib9p_str(self->name), + .owner_uid = { .name = lib9p_str(self->u_name), .num = self->u_num }, + .owner_gid = { .name = lib9p_str(self->g_name), .num = self->g_num }, + .last_modifier_uid = { .name = lib9p_str(self->m_name), .num = self->m_num }, + .extension = lib9p_str(NULL), }; } static void util9p_static_file_wstat(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx, - struct lib9p_stat) { + struct lib9p_srv_stat) { assert(self); assert(ctx); - lib9p_error(&ctx->basectx, LINUX_EROFS, "read-only part of filesystem"); + lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "read-only part of filesystem"); } static void util9p_static_file_remove(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx) { assert(self); assert(ctx); - lib9p_error(&ctx->basectx, LINUX_EROFS, "read-only part of filesystem"); + lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "read-only part of filesystem"); } LIB9P_SRV_NOTDIR(struct util9p_static_file, util9p_static_file); @@ -229,7 +211,7 @@ static void util9p_static_file_pread(struct util9p_static_file *self, struct lib if (byte_offset > (uint64_t)data_size) { lib9p_error(&ctx->basectx, - LINUX_EINVAL, "offset is past end-of-file length"); + LIB9P_ERRNO_L_EINVAL, "offset is past end-of-file length"); return; } @@ -247,6 +229,6 @@ static uint32_t util9p_static_file_pwrite(struct util9p_static_file *self, struc assert(self); assert(ctx); - lib9p_error(&ctx->basectx, LINUX_EROFS, "read-only part of filesystem"); + lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "read-only part of filesystem"); return 0; } diff --git a/libcr/CMakeLists.txt b/libcr/CMakeLists.txt index 80a4ece..2e66020 100644 --- a/libcr/CMakeLists.txt +++ b/libcr/CMakeLists.txt @@ -30,7 +30,7 @@ function(add_libcr_matrix_test n defs) if ("CONFIG_COROUTINE_VALGRIND=1" IN_LIST defs) add_test( NAME "libcr/test_matrix${n}" - COMMAND valgrind --error-exitcode=2 "./test_matrix${n}" + COMMAND "${CMAKE_SOURCE_DIR}/build-aux/valgrind" "./test_matrix${n}" ) else() add_test( diff --git a/libcr/tests/test_matrix.c b/libcr/tests/test_matrix.c index 1f23455..eaa4bdc 100644 --- a/libcr/tests/test_matrix.c +++ b/libcr/tests/test_matrix.c @@ -1,6 +1,6 @@ /* libcr/tests/test_matrix.c - Tests for libcr * - * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later */ @@ -8,14 +8,14 @@ int a = 1; -COROUTINE cr_init(void *) { +COROUTINE init_cr(void *) { cr_begin(); a = 2; cr_end(); } int main() { - coroutine_add("init", cr_init, NULL); + coroutine_add("init", init_cr, NULL); coroutine_main(); if (a != 2) return 1; diff --git a/libcr_ipc/CMakeLists.txt b/libcr_ipc/CMakeLists.txt index 8545798..60d3f2d 100644 --- a/libcr_ipc/CMakeLists.txt +++ b/libcr_ipc/CMakeLists.txt @@ -7,18 +7,22 @@ add_library(libcr_ipc INTERFACE) target_include_directories(libcr_ipc PUBLIC INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include) target_sources(libcr_ipc INTERFACE chan.c - select.c + mutex.c + rpc.c + rwmutex.c + sema.c ) target_link_libraries(libcr_ipc INTERFACE libcr + libmisc ) set(ipc_tests chan - #select - #mutex - #owned_mutex + mutex rpc + rwmutex + select sema ) foreach(test IN LISTS ipc_tests) diff --git a/libcr_ipc/chan.c b/libcr_ipc/chan.c index 7dd1132..b7ecfc8 100644 --- a/libcr_ipc/chan.c +++ b/libcr_ipc/chan.c @@ -4,37 +4,131 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ +#include <string.h> /* for memcpy() */ + +#include <libcr/coroutine.h> /* for cid_t, cr_* */ +#include <libmisc/assert.h> +#include <libmisc/rand.h> + +#define IMPLEMENTATION_FOR_LIBCR_IPC_CHAN_H YES #include <libcr_ipc/chan.h> -void _cr_chan_dequeue(void *_ch, size_t) { - struct _cr_chan *ch = _ch; - _cr_ipc_dll_pop_from_front(&ch->waiters); -} +struct _cr_select_waiter { + cid_t cid; + struct _cr_select_arg_list_node *arg_vec; + size_t arg_cnt; -void _cr_chan_xfer(enum _cr_chan_waiter_typ self_typ, struct _cr_chan *ch, void *val_ptr, size_t val_size) { - assert(ch); - assert(val_ptr); + size_t ret; +}; - if (ch->waiters.front && ch->waiter_typ != self_typ) { /* non-blocking fast-path */ - /* Copy. */ - struct _cr_chan_waiter *front = _cr_ipc_dll_node_cast(struct _cr_chan_waiter, ch->waiters.front); - if (self_typ == _CR_CHAN_SENDER) - memcpy(front->val_ptr, val_ptr, val_size); +enum cr_select_class { + CR_SELECT_CLASS_DEFAULT, + CR_SELECT_CLASS_BLOCKING, + CR_SELECT_CLASS_NONBLOCK, +}; + +static inline enum cr_select_class cr_select_getclass(struct _cr_select_arg *arg) { + switch (arg->op) { + case _CR_SELECT_OP_RECV: + if (arg->ch->waiters.front && arg->ch->waiters.front->val.op == _CR_SELECT_OP_SEND) + return CR_SELECT_CLASS_NONBLOCK; + else + return CR_SELECT_CLASS_BLOCKING; + case _CR_SELECT_OP_SEND: + if (arg->ch->waiters.front && arg->ch->waiters.front->val.op == _CR_SELECT_OP_RECV) + return CR_SELECT_CLASS_NONBLOCK; else - memcpy(val_ptr, front->val_ptr, val_size); - cr_unpause(front->cid); - front->dequeue(front->dequeue_arg1, - front->dequeue_arg2); + return CR_SELECT_CLASS_BLOCKING; + case _CR_SELECT_OP_DEFAULT: + return CR_SELECT_CLASS_DEFAULT; + default: + assert_notreached("invalid arg->op"); + } +} + +size_t cr_select_v(size_t arg_cnt, struct _cr_select_arg_list_node arg_vec[]) { + size_t cnt_blocking = 0; + size_t cnt_nonblock = 0; + size_t cnt_default = 0; + + assert(arg_cnt); + assert(arg_vec); + cr_assert_in_coroutine(); + + for (size_t i = 0; i < arg_cnt; i++) { + switch (cr_select_getclass(&arg_vec[i].val)) { + case CR_SELECT_CLASS_BLOCKING: + cnt_blocking++; + break; + case CR_SELECT_CLASS_NONBLOCK: + cnt_nonblock++; + break; + case CR_SELECT_CLASS_DEFAULT: + cnt_default++; + break; + } + } + + if (cnt_nonblock) { + size_t choice_among_nonblock = rand_uint63n(cnt_nonblock); + size_t choice_among_all = arg_cnt; + for (size_t i = 0, seen = 0; i < choice_among_all; i++) { + if (cr_select_getclass(&arg_vec[i].val) == CR_SELECT_CLASS_NONBLOCK) { + if (seen == choice_among_nonblock) + choice_among_all = i; + seen++; + } + } + assert(choice_among_all < arg_cnt); + + struct _cr_select_arg *this = &arg_vec[choice_among_all].val; + assert(this->ch->waiters.front); + struct _cr_select_arg *other = &this->ch->waiters.front->val; + assert(this->val_siz == other->val_siz); + assert(this->ch == other->ch); + switch (this->op) { + case _CR_SELECT_OP_SEND: + assert(other->op == _CR_SELECT_OP_RECV); + memcpy(other->val_ptr, this->val_ptr, this->val_siz); + break; + case _CR_SELECT_OP_RECV: + assert(other->op == _CR_SELECT_OP_SEND); + memcpy(this->val_ptr, other->val_ptr, this->val_siz); + break; + case _CR_SELECT_OP_DEFAULT: + assert_notreached("_CR_SELECT_OP_DEFAULT is not CR_SELECT_CLASS_NONBLOCK"); + } + struct _cr_select_waiter *waiter = other->waiter; + for (size_t i = 0; i < waiter->arg_cnt; i++) { + waiter->arg_vec[i].val.ch->nwaiters--; + dlist_remove(&waiter->arg_vec[i].val.ch->waiters, &waiter->arg_vec[i]); + if (&waiter->arg_vec[i].val == other) + waiter->ret = i; + } + cr_unpause(waiter->cid); cr_yield(); - } else { /* blocking slow-path */ - struct _cr_chan_waiter self = { - .cid = cr_getcid(), - .val_ptr = val_ptr, - .dequeue = _cr_chan_dequeue, - .dequeue_arg1 = ch, - }; - _cr_ipc_dll_push_to_rear(&ch->waiters, &self); - ch->waiter_typ = self_typ; - cr_pause_and_yield(); + return choice_among_all; + } + + if (cnt_default) { + for (size_t i = 0; i < arg_cnt; i++) + if (cr_select_getclass(&arg_vec[i].val) == CR_SELECT_CLASS_DEFAULT) + return i; + assert_notreached("should have returned from inside for() loop"); + } + + assert(cnt_blocking && cnt_blocking == arg_cnt); + + struct _cr_select_waiter waiter = { + .cid = cr_getcid(), + .arg_vec = arg_vec, + .arg_cnt = arg_cnt, + }; + for (size_t i = 0; i < arg_cnt; i++) { + arg_vec[i].val.waiter = &waiter; + arg_vec[i].val.ch->nwaiters++; + dlist_push_to_rear(&arg_vec[i].val.ch->waiters, &arg_vec[i]); } + cr_pause_and_yield(); + return waiter.ret; } diff --git a/libcr_ipc/include/libcr_ipc/_linkedlist.h b/libcr_ipc/include/libcr_ipc/_linkedlist.h deleted file mode 100644 index 543e058..0000000 --- a/libcr_ipc/include/libcr_ipc/_linkedlist.h +++ /dev/null @@ -1,99 +0,0 @@ -/* libcr_ipc/_linkedlist.h - Common low-level linked lists for use in libcr_ipc - * - * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -#ifndef _LIBCR_IPC__LINKEDLIST_H_ -#define _LIBCR_IPC__LINKEDLIST_H_ - -#include <libmisc/assert.h> - -/* singly linked list *********************************************************/ - -typedef struct __cr_ipc_sll_node { - struct __cr_ipc_sll_node *rear; -} _cr_ipc_sll_node; - -typedef struct { - _cr_ipc_sll_node *front, *rear; -} _cr_ipc_sll_root; - -#define _cr_ipc_sll_node_cast(node_typ, node_ptr) \ - ({ \ - static_assert(_Generic(node_ptr, _cr_ipc_sll_node *: 1, default: 0), \ - "typeof("#node_ptr") != _cr_ipc_sll_node *"); \ - assert(node_ptr); \ - static_assert(offsetof(node_typ, _cr_ipc_sll_node) == 0); \ - ((node_typ*)(node_ptr)); \ - }) - -static inline void _cr_ipc_sll_push_to_rear(_cr_ipc_sll_root *root, _cr_ipc_sll_node *node) { - assert(root); - node->rear = NULL; - if (root->rear) - root->rear->rear = node; - else - root->front = node; - root->rear = node; -} - -static inline void _cr_ipc_sll_pop_from_front(_cr_ipc_sll_root *root) { - assert(root); - assert(root->front); - root->front = root->front->rear; - if (!root->front) - root->rear = NULL; -} - -/* doubly linked list *********************************************************/ - -typedef struct __cr_ipc_dll_node { - struct __cr_ipc_dll_node *front, *rear; -} _cr_ipc_dll_node; - -typedef struct { - _cr_ipc_dll_node *front, *rear; -} _cr_ipc_dll_root; - -#define _cr_ipc_dll_node_cast(node_typ, node_ptr) \ - ({ \ - static_assert(_Generic(node_ptr, _cr_ipc_dll_node *: 1, default: 0), \ - "typeof("#node_ptr") != _cr_ipc_dll_node *"); \ - assert(node_ptr); \ - static_assert(offsetof(node_typ, _cr_ipc_dll_node) == 0); \ - ((node_typ*)(node_ptr)); \ - }) - -static inline void _cr_ipc_dll_push_to_rear(_cr_ipc_dll_root *root, _cr_ipc_dll_node *node) { - assert(root); - assert(node); - node->front = root->rear; - node->rear = NULL; - if (root->rear) - root->rear->rear = node; - else - root->front = node; - root->rear = node; -} - -static inline void _cr_ipc_dll_remove(_cr_ipc_dll_root *root, _cr_ipc_dll_node *node) { - assert(root); - assert(node); - if (node->front) - node->front->rear = node->rear; - else - root->front = node->rear; - if (node->rear) - node->rear->front = node->front; - else - root->rear = node->front; -} - -static inline void _cr_ipc_dll_pop_from_front(_cr_ipc_dll_root *root) { - assert(root); - assert(root->front); - _cr_ipc_dll_remove(root, root->front); -} - -#endif /* _LIBCR_IPC__LINKEDLIST_H_ */ diff --git a/libcr_ipc/include/libcr_ipc/chan.h b/libcr_ipc/include/libcr_ipc/chan.h index dafc92d..c57979a 100644 --- a/libcr_ipc/include/libcr_ipc/chan.h +++ b/libcr_ipc/include/libcr_ipc/chan.h @@ -9,17 +9,14 @@ #include <stdbool.h> /* for bool */ #include <stddef.h> /* for size_t */ -#include <string.h> /* for memcpy */ -#include <libcr/coroutine.h> /* for cid_t, cr_* */ +#include <libmisc/linkedlist.h> /* for DLIST_DECLARE() */ +#include <libmisc/private.h> -#include <libcr_ipc/_linkedlist.h> +/* base channels **************************************************************/ /** - * CR_CHAN_DECLARE(NAME, VAL_T) declares the following type and - * methods: - * - * type: + * CR_CHAN_DECLARE(NAME, VAL_T) declares the following type: * * / ** * * A NAME##_t is a fair unbuffered channel that transports @@ -32,97 +29,163 @@ * * something from an interrupt handler. * * / * typedef ... NAME##_t; + */ +#define CR_CHAN_DECLARE(NAME, VAL_T) \ + typedef struct { \ + struct _cr_chan core; \ + VAL_T val_typ[0]; \ + } NAME##_t + +/** + * cr_chan_send(ch, val) sends `val` over `ch`. * - * methods: + * @runs_in coroutine + * @cr_pauses maybe + * @cr_yields always * - * / ** - * * NAME##_send(ch, val) sends `val` over `ch`. - * * - * * @runs_in coroutine - * * @cr_pauses maybe - * * @cr_yields always - * * / - * void NAME##_send(NAME##_t *ch, VAL_T val); + * void cr_chan_send(NAME##_t *ch, VAL_T val); + */ +#define cr_chan_send(CH, VAL) do { \ + typeof((CH)->val_typ[0]) _val_lvalue = VAL; \ + (void)cr_select_l(CR_SELECT_SEND(CH, &_val_lvalue)); \ +} while (0) + +/** + * cr_chan_recv(ch) reads and returns a value from ch. * - * / ** - * * NAME##_recv(ch) reads and returns a value from ch. - * * - * * @runs_in coroutine - * * @cr_pauses maybe - * * @cr_yields always - * * / - * VAL_T NAME##_recv(NAME##_t *ch); + * @runs_in coroutine + * @cr_pauses maybe + * @cr_yields always * - * / ** - * * NAME##_can_send(ch) returns whether NAME##_send(ch, val) - * * would run without pausing. - * * - * * @runs_in coroutine - * * @cr_pauses never - * * @cr_yields never - * * / - * bool NAME##_can_send(NAME##_t *ch); + * VAL_T cr_chan_recv(NAME##_T ch); + */ +#define cr_chan_recv(CH) ({ \ + typeof((CH)->val_typ[0]) _val_lvalue; \ + (void)cr_select_l(CR_SELECT_RECV(CH, &_val_lvalue)); \ + _val_lvalue; \ +}) + +/** + * cr_chan_can_send(ch) returns whether cr_chan_send(ch, val) would + * run without pausing. * - * / ** - * * NAME##_can_recv(ch) returns whether NAME##_recv(ch) would - * * return without pausing. - * * - * * @runs_in coroutine - * * @cr_pauses never - * * @cr_yields never - * * / - * NAME##_can_recv(NAME##_t *ch); + * @runs_in coroutine + * @cr_pauses never + * @cr_yields never + * + * bool cr_chan_can_send(NAME##_t *ch); */ -#define CR_CHAN_DECLARE(NAME, VAL_T) \ - typedef struct { \ - struct _cr_chan core; \ - VAL_T vals[0]; \ - } NAME##_t; \ - \ - static inline void NAME##_send(NAME##_t *ch, VAL_T val) { \ - cr_assert_in_coroutine(); \ - _cr_chan_xfer(_CR_CHAN_SENDER, &ch->core, &val, sizeof(val)); \ - } \ - \ - static inline VAL_T NAME##_recv(NAME##_t *ch) { \ - cr_assert_in_coroutine(); \ - VAL_T val; \ - _cr_chan_xfer(_CR_CHAN_RECVER, &ch->core, &val, sizeof(val)); \ - return val; \ - } \ - \ - static inline bool NAME##_can_send(NAME##_t *ch) { \ - cr_assert_in_coroutine(); \ - return ch->core.waiters.front && \ - ch->core.waiter_typ == _CR_CHAN_RECVER; \ - } \ - \ - static inline bool NAME##_can_recv(NAME##_t *ch) { \ - cr_assert_in_coroutine(); \ - return ch->core.waiters.front && \ - ch->core.waiter_typ == _CR_CHAN_SENDER; \ - } - -enum _cr_chan_waiter_typ { - _CR_CHAN_SENDER, - _CR_CHAN_RECVER, +#define cr_chan_can_send(CH) ({ \ + cr_assert_in_coroutine(); \ + (bool)((CH)->core.waiters.front && \ + (CH)->core.waiters.front->val.op == _CR_SELECT_OP_RECV); \ +}) + +/** + * cr_chan_can_recv(ch) returns whether cr_chan_recv(ch) would return + * without pausing. + * + * @runs_in coroutine + * @cr_pauses never + * @cr_yields never + * + * bool cr_chan_can_recv(NAME##_t *ch); + */ +#define cr_chan_can_recv(CH) ({ \ + cr_assert_in_coroutine(); \ + (bool)((CH)->core.waiters.front && \ + (CH)->core.waiters.front->val.op == _CR_SELECT_OP_SEND); \ +}) + +/** + * cr_chan_num_waiters(ch) returns the number of coroutines currently + * blocked on the channel. + * + * @runs_in coroutine + * @cr_pauses never + * @cr_yields never + * + * size_t cr_chan_num_waiters(NAME##_t *ch); + */ +#define cr_chan_num_waiters(CH) ({ \ + cr_assert_in_coroutine(); \ + ((CH)->core.nwaiters); \ +}) + +DLIST_DECLARE(_cr_select_arg_list); +struct _cr_chan { + struct _cr_select_arg_list waiters; + size_t nwaiters; }; -struct _cr_chan_waiter { - _cr_ipc_dll_node; - cid_t cid; +/* cr_select arguments ********************************************************/ + +/** + * Do not populate cr_select_arg yourself; use the + * CR_SELECT_{RECV,SEND,DEFAULT} macros. + */ +struct _cr_select_waiter; +struct _cr_select_arg { + enum { + _CR_SELECT_OP_RECV, + _CR_SELECT_OP_SEND, + _CR_SELECT_OP_DEFAULT, + } op; + struct _cr_chan *ch; void *val_ptr; - void (*dequeue)(void *, size_t); - void *dequeue_arg1; - size_t dequeue_arg2; + size_t val_siz; + BEGIN_PRIVATE(LIBCR_IPC_CHAN_H); + struct _cr_select_waiter *waiter; + END_PRIVATE(LIBCR_IPC_CHAN_H); }; +DLIST_DECLARE_NODE(_cr_select_arg_list, struct _cr_select_arg); +#define cr_select_arg _cr_select_arg_list_node -struct _cr_chan { - enum _cr_chan_waiter_typ waiter_typ; - _cr_ipc_dll_root waiters; -}; +#define CR_SELECT_RECV(CH, VALP) ((struct cr_select_arg){ .val = { \ + .op = _CR_SELECT_OP_RECV, \ + .ch = &((CH)->core), \ + /* The _valp temporary variable is to get the compiler to check that \ + * the types are compatible. */ \ + .val_ptr = ({ typeof((CH)->val_typ[0]) *_valp = VALP; _valp; }), \ + .val_siz = sizeof((CH)->val_typ[0]), \ +}}) + +/* BUG: It's bogus that CR_SELECT_SEND takes VALP instead of VAL, but + * since we need an address, taking VAL would introduce uncomfortable + * questions about where VAL sits on the stack. */ +#define CR_SELECT_SEND(CH, VALP) ((struct cr_select_arg){ .val = { \ + .op = _CR_SELECT_OP_SEND, \ + .ch = &((CH)->core), \ + /* The _valp temporary variable is to get the compiler to check that \ + * the types are compatible. */ \ + .val_ptr = ({ typeof((CH)->val_typ[0]) *_valp = VALP; _valp; }), \ + .val_siz = sizeof((CH)->val_typ[0]), \ +}}) + +#define CR_SELECT_DEFAULT ((struct cr_select_arg){ .val = { \ + .op = _CR_SELECT_OP_DEFAULT, \ +}}) + +/* cr_select_v(arg_cnt, arg_vec) **********************************************/ -void _cr_chan_dequeue(void *_ch, size_t); -void _cr_chan_xfer(enum _cr_chan_waiter_typ self_typ, struct _cr_chan *ch, void *val_ptr, size_t val_size); +/** + * @runs_in coroutine + * @cr_pauses maybe + * @cr_yields always + */ +size_t cr_select_v(size_t arg_cnt, struct cr_select_arg arg_vec[]); + +/* cr_select_l(arg1, arg2, arg3, ...) ******************************************/ + +/** + * @runs_in coroutine + * @cr_pauses maybe + * @cr_yields always + */ +#define cr_select_l(...) ({ \ + struct cr_select_arg _cr_select_args[] = { __VA_ARGS__ }; \ + cr_select_v(sizeof(_cr_select_args)/sizeof(_cr_select_args[0]), \ + _cr_select_args); \ +}) #endif /* _LIBCR_IPC_CHAN_H_ */ diff --git a/libcr_ipc/include/libcr_ipc/mutex.h b/libcr_ipc/include/libcr_ipc/mutex.h index cba8c19..e5f43c8 100644 --- a/libcr_ipc/include/libcr_ipc/mutex.h +++ b/libcr_ipc/include/libcr_ipc/mutex.h @@ -1,6 +1,6 @@ /* libcr_ipc/mutex.h - Simple mutexes for libcr * - * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later */ @@ -9,14 +9,10 @@ #include <stdbool.h> /* for bool */ -#include <libcr/coroutine.h> /* for cid_t, cr_* */ +#include <libmisc/linkedlist.h> /* for SLIST_DECLARE() */ +#include <libmisc/private.h> -#include <libcr_ipc/_linkedlist.h> - -struct _cr_mutex_waiter { - _cr_ipc_sll_node; - cid_t cid; -}; +SLIST_DECLARE(_cr_mutex_waiter_list); /** * A cr_mutex_t is a fair mutex. @@ -27,8 +23,10 @@ struct _cr_mutex_waiter { * first place, then it has no business unlocking one. */ typedef struct { - bool locked; - _cr_ipc_sll_root waiters; + BEGIN_PRIVATE(LIBCR_IPC_MUTEX_H); + bool locked; + struct _cr_mutex_waiter_list waiters; + END_PRIVATE(LIBCR_IPC_MUTEX_H); } cr_mutex_t; /** @@ -38,21 +36,7 @@ typedef struct { * @cr_pauses maybe * @cr_yields maybe */ -static inline void cr_mutex_lock(cr_mutex_t *mu) { - assert(mu); - cr_assert_in_coroutine(); - - if (!mu->locked) /* non-blocking fast-path */ - mu->locked = true; - else { /* blocking slow-path */ - struct _cr_mutex_waiter self = { - .cid = cr_getcid(), - }; - _cr_ipc_sll_push_to_rear(&mu->waiters, &self); - cr_pause_and_yield(); - } - assert(mu->locked); -} +void cr_mutex_lock(cr_mutex_t *mu); /** * Unlock the mutex. Unblocks a coroutine that is blocked on @@ -62,16 +46,6 @@ static inline void cr_mutex_lock(cr_mutex_t *mu) { * @cr_pauses never * @cr_yields never */ -static inline void cr_mutex_unlock(cr_mutex_t *mu) { - assert(mu); - cr_assert_in_coroutine(); - - assert(mu->locked); - if (mu->waiters.front) { - cr_unpause(_cr_ipc_sll_node_cast(struct _cr_mutex_waiter, mu->waiters.front)->cid); - _cr_ipc_sll_pop_from_front(&mu->waiters); - } else - mu->locked = false; -} +void cr_mutex_unlock(cr_mutex_t *mu); #endif /* _LIBCR_IPC_MUTEX_H_ */ diff --git a/libcr_ipc/include/libcr_ipc/owned_mutex.h b/libcr_ipc/include/libcr_ipc/owned_mutex.h deleted file mode 100644 index c66240f..0000000 --- a/libcr_ipc/include/libcr_ipc/owned_mutex.h +++ /dev/null @@ -1,79 +0,0 @@ -/* libcr_ipc/owned_mutex.h - Owned mutexes for libcr - * - * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -#ifndef _LIBCR_IPC_OWNED_MUTEX_H_ -#define _LIBCR_IPC_OWNED_MUTEX_H_ - -#include <stdbool.h> /* for bool */ - -#include <libcr/coroutine.h> /* for cid_t, cr_unpause(), cr_pause_and_yield() */ - -#include <libcr_ipc/_linkedlist.h> - -struct _cr_owned_mutex_waiter { - _cr_ipc_sll_node; - cid_t cid; -}; - -/** - * A cr_owned_mutex_t is a fair mutex that tracks not just whether it - * is locked, but which coroutine has it locked. - * - * None of the methods have `_from_intrhandler` variants because (1) - * an interrupt handler can't block, so it shouldn't ever lock a mutex - * because that can block; and (2) if it can't lock a mutex in the - * first place, then it has no business unlocking one. - */ -typedef struct { - cid_t owner; - _cr_ipc_sll_root waiters; -} cr_owned_mutex_t; - -/** - * Lock the mutex. Blocks if it is already locked. - * - * @runs_in coroutine - * @cr_pauses maybe - * @cr_yields maybe - */ -static inline void cr_owned_mutex_lock(cr_owned_mutex_t *mu) { - assert(mu); - - if (!mu->owner) /* non-blocking fast-path */ - mu->owner = cr_getcid(); - else { /* blocking slow-path */ - struct _cr_owned_mutex_waiter self = { - .cid = cr_getcid(), - }; - _cr_ipc_sll_push_to_rear(&mu->waiters, &self); - cr_pause_and_yield(); - } - assert(mu->owner == cr_getcid()); -} - -/** - * Unlock the mutex. Unblocks a coroutine that is blocked on - * cr_owned_mutex_lock(). Must be the called from the same coroutine - * that called cr_owned_mutex_lock(). - * - * @runs_in coroutine - * @cr_pauses never - * @cr_yields never - */ -static inline void cr_owned_mutex_unlock(cr_owned_mutex_t *mu) { - assert(mu); - - assert(mu->owner == cr_getcid()); - if (mu->waiters.front) { - cid_t waiter = _cr_ipc_sll_node_cast(struct _cr_owned_mutex_waiter, mu->waiters.front)->cid; - cr_unpause(waiter); - mu->owner = waiter; - _cr_ipc_sll_pop_from_front(&mu->waiters); - } else - mu->owner = 0; -} - -#endif /* _LIBCR_IPC_OWNED_MUTEX_H_ */ diff --git a/libcr_ipc/include/libcr_ipc/rpc.h b/libcr_ipc/include/libcr_ipc/rpc.h index 0600399..bfa0a04 100644 --- a/libcr_ipc/include/libcr_ipc/rpc.h +++ b/libcr_ipc/include/libcr_ipc/rpc.h @@ -8,17 +8,11 @@ #define _LIBCR_IPC_RPC_H_ #include <stdbool.h> /* for bool */ -#include <string.h> /* for memcpy() */ -#include <libcr/coroutine.h> /* for cid_t, cr_* */ - -#include <libcr_ipc/_linkedlist.h> +#include <libmisc/linkedlist.h> /* for SLIST_DECLARE() */ /** - * CR_RPC_DECLARE(NAME, REQ_T, RESP_T) declares the following types - * and methods: - * - * type: + * CR_RPC_DECLARE(NAME, REQ_T, RESP_T) declares the following types: * * / ** * * A NAME##_t is a fair rpc-channel on which the requester submits a @@ -40,191 +34,112 @@ * * the response RESP_T to the correct requester. `REQ_T req` is the * * only public member. * typedef struct { REQ_T req; ... } NAME##_req_t; + */ +#define CR_RPC_DECLARE(NAME, REQ_T, RESP_T) \ + typedef struct { \ + REQ_T req; \ + \ + RESP_T *_resp; /* where to write resp to */ \ + cid_t _requester; \ + } NAME##_req_t; \ + \ + typedef struct { \ + struct _cr_rpc core; \ + NAME##_req_t handle_typ[0]; \ + } NAME##_t + +/* Methods for NAME##_t *******************************************************/ + +/** + * cr_rpc_send_req(ch, req) submits the `req` request over `ch` and + * returns the response. * - * methods: + * @runs_in coroutine + * @cr_pauses always + * @cr_yields always * - * / ** - * * NAME##_send_req(ch, req) submits the `req` request over `ch` and - * * returns the response. - * * - * * @runs_in coroutine - * * @cr_pauses always - * * @cr_yields always - * * / - * RESP_T NAME##_send_req(NAME##_t *ch, REQ_T req); + * RESP_T cr_rpc_send_req(NAME##_t *ch, REQ_T req); + */ +#define cr_rpc_send_req(CH, REQ) ({ \ + cr_assert_in_coroutine(); \ + typeof((CH)->handle_typ[0].req) _req_lvalue = REQ; \ + typeof(*(CH)->handle_typ[0]._resp) _resp_lvalue; \ + _cr_rpc_send_req(&(CH)->core, \ + &_req_lvalue, sizeof(_req_lvalue), \ + &_resp_lvalue); \ + _resp_lvalue; \ +}) + +/** + * cr_rpc_recv_req(ch) reads a request from ch, and returns a + * NAME##_req_t handle wrapping that request. * - * / ** - * * NAME##_recv_req(ch) reads a request from ch, and returns a - * * NAME##_req_t handle wrapping that request. - * * - * * @runs_in coroutine - * * @cr_pauses maybe - * * @cr_yields maybe - * * / - * NAME##_req_t NAME##_recv_req(NAME##_t *ch); + * @runs_in coroutine + * @cr_pauses maybe + * @cr_yields maybe * - * / ** - * * NAME##_can_recv_req(ch) returns whether NAME##_recv_req(ch) - * * would return without pausing. - * * - * * @runs_in coroutine - * * @cr_pauses never - * * @cr_yields never - * * / - * bool NAME##_can_recv_req(NAME##_t *ch); + * NAME##_req_t cr_rcp_recv_req(NAME##_t *ch); + */ +#define cr_rpc_recv_req(CH) ({ \ + cr_assert_in_coroutine(); \ + typeof((CH)->handle_typ[0]) ret; \ + _cr_rpc_recv_req(&(CH)->core, \ + &ret.req, sizeof(ret.req), \ + (void **)&ret._resp, \ + &ret._requester); \ + ret; \ +}) + +/** + * cr_rpc_can_recv_req(ch) returns whether NAME##_recv_req(ch) + * would return without pausing. * - * type: + * @runs_in coroutine + * @cr_pauses never + * @cr_yields never * - * / ** - * * A NAME##_req_t is a handle that wraps a REQ_T, and is a channel - * * that a response may be written to. - * * / - * typedef ... NAME##_req_t; + * bool cr_rpc_can_recv_req(NAME##_t *ch); + */ +#define cr_rpc_can_recv_req(CH) ({ \ + cr_assert_in_coroutine(); \ + (bool)((CH)->core.waiters.front && \ + (CH)->core.waiter_typ == _CR_RPC_REQUESTER); \ +}) + +/* Methods for NAME##_req_t ***************************************************/ + +/** + * cr_rpc_send_resp(req, resp) sends the given response to the given + * request. * - * methods: + * @runs_in coroutine + * @cr_pauses never + * @cr_yields always * - * / ** - * * cr_rpc_send_resp(req, resp) sends the given response to the given - * * request. - * * - * * @runs_in coroutine - * * @cr_pauses never - * * @cr_yields always - * * / - * void NAME##_send_resp(NAME##_req_t req, RESP_T resp); + * void cr_rpc_send_resp(NAME##_req_t req, RESP_T resp); */ -#define CR_RPC_DECLARE(NAME, REQ_T, RESP_T) \ - typedef struct { \ - REQ_T req; \ - \ - RESP_T *_resp; /* where to write resp to */ \ - cid_t _requester; \ - } NAME##_req_t; \ - \ - typedef struct { \ - struct _cr_rpc core; \ - NAME##_req_t handle[0]; \ - } NAME##_t; \ - \ - static inline RESP_T NAME##_send_req(NAME##_t *ch, REQ_T req) { \ - cr_assert_in_coroutine(); \ - RESP_T resp; \ - _cr_rpc_send_req(&ch->core, \ - &req, sizeof(req), \ - &resp); \ - return resp; \ - } \ - \ - static inline NAME##_req_t NAME##_recv_req(NAME##_t *ch) { \ - cr_assert_in_coroutine(); \ - NAME##_req_t ret; \ - _cr_rpc_recv_req(&ch->core, \ - &ret.req, sizeof(ret.req), \ - (void **)&ret._resp, \ - &ret._requester); \ - return ret; \ - } \ - \ - static inline bool NAME##_can_recv_req(NAME##_t *ch) { \ - cr_assert_in_coroutine(); \ - return ch->core.waiters.front && \ - ch->core.waiter_typ == _CR_RPC_REQUESTER; \ - } \ - \ - static inline void NAME##_send_resp(NAME##_req_t req, RESP_T resp) { \ - cr_assert_in_coroutine(); \ - *(req._resp) = resp; \ - cr_unpause(req._requester); \ - cr_yield(); \ - } +#define cr_rpc_send_resp(REQ, RESP) { \ + cr_assert_in_coroutine(); \ + *((REQ)._resp) = RESP; \ + cr_unpause(REQ._requester); \ + cr_yield(); \ +} while (0) + +/* Background details *********************************************************/ enum _cr_rpc_waiter_typ { _CR_RPC_REQUESTER, _CR_RPC_RESPONDER, }; -struct _cr_rpc_requester { - _cr_ipc_sll_node; - cid_t cid; - void *req_ptr; /* where to read req from */ - void *resp_ptr; /* where to write resp to */ -}; - -struct _cr_rpc_responder { - _cr_ipc_sll_node; - /* before enqueued | after dequeued */ - /* -------------------+-------------------- */ - cid_t cid; /* responder cid | requester cid */ - void *ptr; /* where to write req | where to write resp */ -}; +SLIST_DECLARE(_cr_rpc_waiter_list); struct _cr_rpc { enum _cr_rpc_waiter_typ waiter_typ; - _cr_ipc_sll_root waiters; + struct _cr_rpc_waiter_list waiters; }; -static inline void _cr_rpc_send_req(struct _cr_rpc *ch, - void *req_ptr, size_t req_size, - void *resp_ptr) -{ - assert(ch); - assert(req_ptr); - assert(resp_ptr); - - if (ch->waiters.front && ch->waiter_typ != _CR_RPC_REQUESTER) { /* fast-path (still blocks) */ - struct _cr_rpc_responder *responder = - _cr_ipc_sll_node_cast(struct _cr_rpc_responder, ch->waiters.front); - _cr_ipc_sll_pop_from_front(&ch->waiters); - /* Copy the req to the responder's stack. */ - memcpy(responder->ptr, req_ptr, req_size); - /* Notify the responder that we have done so. */ - cr_unpause(responder->cid); - responder->cid = cr_getcid(); - responder->ptr = resp_ptr; - /* Wait for the responder to set `*resp_ptr`. */ - cr_pause_and_yield(); - } else { /* blocking slow-path */ - struct _cr_rpc_requester self = { - .cid = cr_getcid(), - .req_ptr = req_ptr, - .resp_ptr = resp_ptr, - }; - _cr_ipc_sll_push_to_rear(&ch->waiters, &self); - /* Wait for a responder to both copy our req and sed - * `*resp_ptr`. */ - cr_pause_and_yield(); - } -} - -static inline void _cr_rpc_recv_req(struct _cr_rpc *ch, - void *req_ptr, size_t req_size, - void **ret_resp_ptr, - cid_t *ret_requester) -{ - assert(ch); - assert(req_ptr); - assert(ret_resp_ptr); - assert(ret_requester); - - if (ch->waiters.front && ch->waiter_typ != _CR_RPC_RESPONDER) { /* non-blocking fast-path */ - struct _cr_rpc_requester *requester = - _cr_ipc_sll_node_cast(struct _cr_rpc_requester, ch->waiters.front); - _cr_ipc_sll_pop_from_front(&ch->waiters); - - memcpy(req_ptr, requester->req_ptr, req_size); - *ret_requester = requester->cid; - *ret_resp_ptr = requester->resp_ptr; - } else { /* blocking slow-path */ - struct _cr_rpc_responder self = { - .cid = cr_getcid(), - .ptr = req_ptr, - }; - _cr_ipc_sll_push_to_rear(&ch->waiters, &self); - ch->waiter_typ = _CR_RPC_RESPONDER; - cr_pause_and_yield(); - *ret_requester = self.cid; - *ret_resp_ptr = self.ptr; - } -} +void _cr_rpc_send_req(struct _cr_rpc *ch, void *req_ptr, size_t req_size, void *resp_ptr); +void _cr_rpc_recv_req(struct _cr_rpc *ch, void *req_ptr, size_t req_size, void **ret_resp_ptr, cid_t *ret_requester); #endif /* _LIBCR_IPC_RPC_H_ */ diff --git a/libcr_ipc/include/libcr_ipc/rwmutex.h b/libcr_ipc/include/libcr_ipc/rwmutex.h new file mode 100644 index 0000000..8ccae63 --- /dev/null +++ b/libcr_ipc/include/libcr_ipc/rwmutex.h @@ -0,0 +1,78 @@ +/* libcr_ipc/rwmutex.h - Simple read/write mutexes for libcr + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#ifndef _LIBCR_IPC_RWMUTEX_H_ +#define _LIBCR_IPC_RWMUTEX_H_ + +#include <stdbool.h> + +#include <libmisc/linkedlist.h> /* for SLIST_DECLARE() */ +#include <libmisc/private.h> + +SLIST_DECLARE(_cr_rwmutex_waiter_list); + +/** + * A cr_rwmutex_t is a fair read/write mutex. + * + * A waiting writer blocks any new readers; this ensures that the + * writer is able to eventually get the lock. + * + * None of the methods have `_from_intrhandler` variants because (1) + * an interrupt handler can't block, so it shouldn't ever lock a mutex + * because that can block; and (2) if it can't lock a mutex in the + * first place, then it has no business unlocking one. + */ +typedef struct { + BEGIN_PRIVATE(LIBCR_IPC_RWMUTEX_H); + unsigned nreaders; + bool locked; + bool unpausing; + struct _cr_rwmutex_waiter_list waiters; + END_PRIVATE(LIBCR_IPC_RWMUTEX_H); +} cr_rwmutex_t; + +/** + * Lock the mutex for writing. Blocks if it is already locked. + * + * @runs_in coroutine + * @cr_pauses maybe + * @cr_yields maybe + */ +void cr_rwmutex_lock(cr_rwmutex_t *mu); + +/** + * Undo a single cr_rwmutex_lock() call. Unblocks either a single + * coroutine that is blocked on cr_rwmutex_lock() or arbitrarily many + * coroutines that are blocked on cr_rwmutex_rlock(). + * + * @runs_in coroutine + * @cr_pauses never + * @cr_yields never + */ +void cr_rwmutex_unlock(cr_rwmutex_t *mu); + +/** + * Lock the mutex for reading. Blocks if it is already locked for + * writing. + * + * @runs_in coroutine + * @cr_pauses maybe + * @cr_yields maybe + */ +void cr_rwmutex_rlock(cr_rwmutex_t *mu); + +/** + * Undo a single cr_rwmutext_rock() call. If the reader count is + * reduced to zero, unblocks a single coroutine that is blocked on + * cr_rwmutex_lock(). + * + * @runs_in coroutine + * @cr_pauses never + * @cr_yields never + */ +void cr_rwmutex_runlock(cr_rwmutex_t *mu); + +#endif /* _LIBCR_IPC_RWMUTEX_H_ */ diff --git a/libcr_ipc/include/libcr_ipc/select.h b/libcr_ipc/include/libcr_ipc/select.h deleted file mode 100644 index 0e35351..0000000 --- a/libcr_ipc/include/libcr_ipc/select.h +++ /dev/null @@ -1,85 +0,0 @@ -/* libcr_ipc/select.h - Select between channels - * - * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -#include <alloca.h> /* for alloca() */ -#include <stddef.h> /* for size_t */ - -#include <libmisc/assert.h> -#include <libmisc/rand.h> - -#include <libcr_ipc/chan.h> - -#ifndef _LIBCR_IPC_SELECT_H_ -#define _LIBCR_IPC_SELECT_H_ - -/* arguments ******************************************************************/ - -/** - * Do not populate cr_select_arg yourself; use the - * CR_SELECT_{RECV,SEND,DEFAULT} macros. - */ -struct cr_select_arg { - enum { - _CR_SELECT_OP_RECV, - _CR_SELECT_OP_SEND, - _CR_SELECT_OP_DEFAULT, - } op; - struct _cr_chan *ch; - void *val_ptr; - size_t val_siz; -}; - -#define CR_SELECT_RECV(CH, VALP) ({ \ - /* The _valp indirection is to get the \ - * compiler to check that the types are \ - * compatible. */ \ - typeof((CH)->vals[0]) *_valp = VALP; \ - ((struct cr_select_arg){ \ - .op = _CR_SELECT_OP_RECV, \ - .ch = &((CH)->core), \ - .val_ptr = _valp, \ - .val_siz = sizeof((CH)->vals[0]), \ - }); \ - }) -#define CR_SELECT_SEND(CH, VAL) ({ \ - typeof((CH)->vals[0]) val_lvalue = VAL; \ - ((struct cr_select_arg){ \ - .op = _CR_SELECT_OP_SEND, \ - .ch = &((CH)->core), \ - .val_ptr = &val_lvalue;, \ - .val_siz = sizeof((CH)->vals[0]), \ - }); \ - }) -#define CR_SELECT_DEFAULT \ - ((struct cr_select_arg){ \ - .op = _CR_SELECT_OP_DEFAULT, \ - }) - -/* cr_select_v(arg_cnt, arg_vec) **********************************************/ - -enum _cr_select_class { - _CR_SELECT_CLASS_DEFAULT, - _CR_SELECT_CLASS_BLOCKING, - _CR_SELECT_CLASS_NONBLOCK, -}; - -struct _cr_select_waiters { - size_t cnt; - struct cr_select_arg *args; - struct _cr_chan_waiter *nodes; -}; - -void _cr_select_dequeue(void *_waiters, size_t idx); -size_t cr_select_v(size_t arg_cnt, struct cr_select_arg arg_vec[]); - -/* cr_select_l(arg1, arg2, arg3, ...) ******************************************/ - -#define cr_select_l(...) ({ \ - struct cr_select_arg _cr_select_args[] = { __VA_ARGS__ }; \ - cr_select_v(sizeof(_cr_select_args)/sizeof(_cr_select_args[0])); \ -}) - -#endif /* _LIBCR_IPC_SELECT_H_ */ diff --git a/libcr_ipc/include/libcr_ipc/sema.h b/libcr_ipc/include/libcr_ipc/sema.h index fcabf28..8b5ac5b 100644 --- a/libcr_ipc/include/libcr_ipc/sema.h +++ b/libcr_ipc/include/libcr_ipc/sema.h @@ -9,14 +9,10 @@ #include <stdbool.h> -#include <libcr/coroutine.h> /* for cid_t, cr_* */ +#include <libmisc/linkedlist.h> /* for SLIST_DECLARE() */ +#include <libmisc/private.h> -#include <libcr_ipc/_linkedlist.h> - -struct _cr_sema_waiter { - _cr_ipc_sll_node; - cid_t cid; -}; +SLIST_DECLARE(_cr_sema_waiter_list); /** * A cr_sema_t is a fair unbounded[1] counting semaphore. @@ -24,9 +20,11 @@ struct _cr_sema_waiter { * [1]: Well, UINT_MAX */ typedef struct { - unsigned int cnt; - bool unpausing; - _cr_ipc_sll_root waiters; + BEGIN_PRIVATE(LIBCR_IPC_SEMA_H); + unsigned int cnt; + bool unpausing; + struct _cr_sema_waiter_list waiters; + END_PRIVATE(LIBCR_IPC_SEMA_H); } cr_sema_t; /** @@ -36,36 +34,14 @@ typedef struct { * @cr_pauses never * @cr_yields never */ -static inline void cr_sema_signal(cr_sema_t *sema) { - assert(sema); - cr_assert_in_coroutine(); - - bool saved = cr_save_and_disable_interrupts(); - sema->cnt++; - if (sema->waiters.front && !sema->unpausing) { - cr_unpause( - _cr_ipc_sll_node_cast(struct _cr_sema_waiter, sema->waiters.front)->cid); - sema->unpausing = true; - } - cr_restore_interrupts(saved); -} +void cr_sema_signal(cr_sema_t *sema); /** * Like cr_sema_signal(), but for use from an interrupt handler. * * @runs_in intrhandler */ -static inline void cr_sema_signal_from_intrhandler(cr_sema_t *sema) { - assert(sema); - cr_assert_in_intrhandler(); - - sema->cnt++; - if (sema->waiters.front && !sema->unpausing) { - cr_unpause_from_intrhandler( - _cr_ipc_sll_node_cast(struct _cr_sema_waiter, sema->waiters.front)->cid); - sema->unpausing = true; - } -} +void cr_sema_signal_from_intrhandler(cr_sema_t *sema); /** * Wait until the semaphore is >0, then decrement it. @@ -74,27 +50,6 @@ static inline void cr_sema_signal_from_intrhandler(cr_sema_t *sema) { * @cr_pauses maybe * @cr_yields maybe */ -static inline void cr_sema_wait(cr_sema_t *sema) { - assert(sema); - cr_assert_in_coroutine(); - - bool saved = cr_save_and_disable_interrupts(); - - struct _cr_sema_waiter self = { - .cid = cr_getcid(), - }; - _cr_ipc_sll_push_to_rear(&sema->waiters, &self); - if (sema->waiters.front != &self._cr_ipc_sll_node || !sema->cnt) - cr_pause_and_yield(); - assert(sema->waiters.front == &self._cr_ipc_sll_node && sema->cnt); - _cr_ipc_sll_pop_from_front(&sema->waiters); - sema->cnt--; - if (sema->cnt && sema->waiters.front) - cr_unpause( - _cr_ipc_sll_node_cast(struct _cr_sema_waiter, sema->waiters.front)->cid); - else - sema->unpausing = false; - cr_restore_interrupts(saved); -} +void cr_sema_wait(cr_sema_t *sema); #endif /* _LIBCR_IPC_SEMA_H_ */ diff --git a/libcr_ipc/mutex.c b/libcr_ipc/mutex.c new file mode 100644 index 0000000..1b4e626 --- /dev/null +++ b/libcr_ipc/mutex.c @@ -0,0 +1,44 @@ +/* libcr_ipc/mutex.c - Simple mutexes for libcr + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include <libcr/coroutine.h> /* for cid_t, cr_* */ +#include <libmisc/assert.h> + +#define IMPLEMENTATION_FOR_LIBCR_IPC_MUTEX_H YES +#include <libcr_ipc/mutex.h> + +struct cr_mutex_waiter { + cid_t cid; +}; +SLIST_DECLARE_NODE(_cr_mutex_waiter_list, struct cr_mutex_waiter); + +void cr_mutex_lock(cr_mutex_t *mu) { + assert(mu); + cr_assert_in_coroutine(); + + if (!mu->locked) /* non-blocking fast-path */ + mu->locked = true; + else { /* blocking slow-path */ + struct _cr_mutex_waiter_list_node self = { .val = { + .cid = cr_getcid(), + }}; + slist_push_to_rear(&mu->waiters, &self); + cr_pause_and_yield(); + } + assert(mu->locked); +} + +void cr_mutex_unlock(cr_mutex_t *mu) { + assert(mu); + cr_assert_in_coroutine(); + + assert(mu->locked); + if (mu->waiters.front) { + cr_unpause(mu->waiters.front->val.cid); + slist_pop_from_front(&mu->waiters); + } else + mu->locked = false; +} diff --git a/libcr_ipc/rpc.c b/libcr_ipc/rpc.c new file mode 100644 index 0000000..fcf51ba --- /dev/null +++ b/libcr_ipc/rpc.c @@ -0,0 +1,84 @@ +/* libcr_ipc/rpc.c - Simple request/response system for libcr + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include <string.h> /* for memcpy() */ + +#include <libcr/coroutine.h> /* for cid_t, cr_* */ +#include <libmisc/assert.h> + +#include <libcr_ipc/rpc.h> + +struct cr_rpc_requester { + cid_t cid; + void *req_ptr; /* where to read req from */ + void *resp_ptr; /* where to write resp to */ +}; +struct cr_rpc_responder { + /* before enqueued | after dequeued */ + /* -------------------+-------------------- */ + cid_t cid; /* responder cid | requester cid */ + void *ptr; /* where to write req | where to write resp */ +}; +union cr_rpc_waiter { + struct cr_rpc_requester requester; + struct cr_rpc_responder responder; +}; +SLIST_DECLARE_NODE(_cr_rpc_waiter_list, union cr_rpc_waiter); + +void _cr_rpc_send_req(struct _cr_rpc *ch, void *req_ptr, size_t req_size, void *resp_ptr) { + assert(ch); + assert(req_ptr); + assert(resp_ptr); + + if (ch->waiters.front && ch->waiter_typ != _CR_RPC_REQUESTER) { /* fast-path (still blocks) */ + struct cr_rpc_responder *responder = &ch->waiters.front->val.responder; + slist_pop_from_front(&ch->waiters); + /* Copy the req to the responder's stack. */ + memcpy(responder->ptr, req_ptr, req_size); + /* Notify the responder that we have done so. */ + cr_unpause(responder->cid); + responder->cid = cr_getcid(); + responder->ptr = resp_ptr; + /* Wait for the responder to set `*resp_ptr`. */ + cr_pause_and_yield(); + } else { /* blocking slow-path */ + struct _cr_rpc_waiter_list_node self = { .val = { .requester = { + .cid = cr_getcid(), + .req_ptr = req_ptr, + .resp_ptr = resp_ptr, + }}}; + slist_push_to_rear(&ch->waiters, &self); + /* Wait for a responder to both copy our req and sed + * `*resp_ptr`. */ + cr_pause_and_yield(); + } +} + +void _cr_rpc_recv_req(struct _cr_rpc *ch, void *req_ptr, size_t req_size, void **ret_resp_ptr, cid_t *ret_requester) { + assert(ch); + assert(req_ptr); + assert(ret_resp_ptr); + assert(ret_requester); + + if (ch->waiters.front && ch->waiter_typ != _CR_RPC_RESPONDER) { /* non-blocking fast-path */ + struct cr_rpc_requester *requester = &ch->waiters.front->val.requester; + slist_pop_from_front(&ch->waiters); + + memcpy(req_ptr, requester->req_ptr, req_size); + *ret_requester = requester->cid; + *ret_resp_ptr = requester->resp_ptr; + } else { /* blocking slow-path */ + struct _cr_rpc_waiter_list_node self = { .val = { .responder = { + .cid = cr_getcid(), + .ptr = req_ptr, + }}}; + slist_push_to_rear(&ch->waiters, &self); + ch->waiter_typ = _CR_RPC_RESPONDER; + cr_pause_and_yield(); + *ret_requester = self.val.responder.cid; + *ret_resp_ptr = self.val.responder.ptr; + } +} diff --git a/libcr_ipc/rwmutex.c b/libcr_ipc/rwmutex.c new file mode 100644 index 0000000..191b7fe --- /dev/null +++ b/libcr_ipc/rwmutex.c @@ -0,0 +1,98 @@ +/* libcr_ipc/rwmutex.c - Simple read/write mutexes for libcr + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include <libcr/coroutine.h> /* for cid_t, cr_* */ +#include <libmisc/assert.h> + +#define IMPLEMENTATION_FOR_LIBCR_IPC_RWMUTEX_H YES +#include <libcr_ipc/rwmutex.h> + +struct cr_rwmutex_waiter { + bool is_reader; + cid_t cid; +}; +SLIST_DECLARE_NODE(_cr_rwmutex_waiter_list, struct cr_rwmutex_waiter); + +void cr_rwmutex_lock(cr_rwmutex_t *mu) { + assert(mu); + cr_assert_in_coroutine(); + + struct _cr_rwmutex_waiter_list_node self = { .val = { + .is_reader = false, + .cid = cr_getcid(), + }}; + slist_push_to_rear(&mu->waiters, &self); + if (mu->waiters.front != &self || mu->locked) + cr_pause_and_yield(); + assert(mu->waiters.front == &self); + + /* We now hold the lock (and are mu->waiters.front). */ + slist_pop_from_front(&mu->waiters); + assert(mu->nreaders == 0); + mu->locked = true; + mu->unpausing = false; +} + +void cr_rwmutex_rlock(cr_rwmutex_t *mu) { + assert(mu); + cr_assert_in_coroutine(); + + struct _cr_rwmutex_waiter_list_node self = { .val = { + .is_reader = true, + .cid = cr_getcid(), + }}; + slist_push_to_rear(&mu->waiters, &self); + if (mu->waiters.front != &self || (mu->locked && mu->nreaders == 0)) + cr_pause_and_yield(); + assert(mu->waiters.front == &self); + + /* We now hold the lock (and are mu->waiters.front). */ + slist_pop_from_front(&mu->waiters); + mu->nreaders++; + mu->locked = true; + struct _cr_rwmutex_waiter_list_node *waiter = mu->waiters.front; + if (waiter && waiter->val.is_reader) { + assert(mu->unpausing); + cr_unpause(waiter->val.cid); + } else { + mu->unpausing = false; + } +} + +void cr_rwmutex_unlock(cr_rwmutex_t *mu) { + assert(mu); + cr_assert_in_coroutine(); + + assert(mu->locked); + assert(mu->nreaders == 0); + assert(!mu->unpausing); + if (mu->waiters.front) { + struct _cr_rwmutex_waiter_list_node *waiter = mu->waiters.front; + mu->unpausing = true; + cr_unpause(waiter->val.cid); + } else { + mu->locked = false; + } +} + +void cr_rwmutex_runlock(cr_rwmutex_t *mu) { + assert(mu); + cr_assert_in_coroutine(); + + assert(mu->locked); + assert(mu->nreaders > 0); + mu->nreaders--; + if (mu->nreaders == 0 && !mu->unpausing) { + if (mu->waiters.front) { + struct _cr_rwmutex_waiter_list_node *waiter = mu->waiters.front; + assert(!waiter->val.is_reader); + mu->unpausing = true; + cr_unpause(waiter->val.cid); + } else { + mu->locked = false; + } + } +} diff --git a/libcr_ipc/select.c b/libcr_ipc/select.c deleted file mode 100644 index 4bd9067..0000000 --- a/libcr_ipc/select.c +++ /dev/null @@ -1,102 +0,0 @@ -/* libcr_ipc/select.c - Select between channels - * - * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -#include <libcr_ipc/select.h> - -static inline enum _cr_select_class _cr_select_getclass(struct cr_select_arg arg) { - switch (arg.op) { - case _CR_SELECT_OP_RECV: - if (arg.ch->waiters.front && arg.ch->waiter_typ == _CR_CHAN_SENDER) - return _CR_SELECT_CLASS_NONBLOCK; - else - return _CR_SELECT_CLASS_BLOCKING; - case _CR_SELECT_OP_SEND: - if (arg.ch->waiters.front && arg.ch->waiter_typ == _CR_CHAN_RECVER) - return _CR_SELECT_CLASS_NONBLOCK; - else - return _CR_SELECT_CLASS_BLOCKING; - case _CR_SELECT_OP_DEFAULT: - return _CR_SELECT_CLASS_DEFAULT; - default: - assert_notreached("invalid arg.op"); - } -} - -void _cr_select_dequeue(void *_waiters, size_t idx) { - struct _cr_select_waiters *waiters = _waiters; - for (size_t i = 0; i < waiters->cnt; i++) - _cr_ipc_dll_remove(&(waiters->args[i].ch->waiters), - &(waiters->nodes[i])); - waiters->cnt = idx; -} - -size_t cr_select_v(size_t arg_cnt, struct cr_select_arg arg_vec[]) { - size_t cnt_blocking = 0; - size_t cnt_nonblock = 0; - size_t cnt_default = 0; - - assert(arg_cnt); - assert(arg_vec); - cr_assert_in_coroutine(); - - for (size_t i = 0; i < arg_cnt; i++) { - switch (_cr_select_getclass(arg_vec[i])) { - case _CR_SELECT_CLASS_BLOCKING: - cnt_blocking++; - break; - case _CR_SELECT_CLASS_NONBLOCK: - cnt_nonblock++; - break; - case _CR_SELECT_CLASS_DEFAULT: - cnt_default++; - break; - } - } - - if (cnt_nonblock) { - size_t choice = rand_uint63n(cnt_nonblock); - for (size_t i = 0, seen = 0; i < arg_cnt; i++) { - if (_cr_select_getclass(arg_vec[i]) == _CR_SELECT_CLASS_NONBLOCK) { - if (seen == choice) { - _cr_chan_xfer(arg_vec[i].op == _CR_SELECT_OP_RECV - ? _CR_CHAN_RECVER - : _CR_CHAN_SENDER, - arg_vec[i].ch, - arg_vec[i].val_ptr, - arg_vec[i].val_siz); - return i; - } - seen++; - } - } - assert_notreached("should have returned from inside for() loop"); - } - - if (cnt_default) { - for (size_t i = 0; i < arg_cnt; i++) - if (_cr_select_getclass(arg_vec[i]) == _CR_SELECT_CLASS_DEFAULT) - return i; - assert_notreached("should have returned from inside for() loop"); - } - - struct _cr_select_waiters waiters = { - .cnt = arg_cnt, - .args = arg_vec, - .nodes = alloca(sizeof(struct _cr_chan_waiter) * arg_cnt), - }; - for (size_t i = 0; i < arg_cnt; i++) { - waiters.nodes[i] = (struct _cr_chan_waiter){ - .cid = cr_getcid(), - .val_ptr = arg_vec[i].val_ptr, - .dequeue = _cr_select_dequeue, - .dequeue_arg1 = &waiters, - .dequeue_arg2 = i, - }; - _cr_ipc_dll_push_to_rear(&arg_vec[i].ch->waiters, &waiters.nodes[i]); - } - cr_pause_and_yield(); - return waiters.cnt; -} diff --git a/libcr_ipc/sema.c b/libcr_ipc/sema.c new file mode 100644 index 0000000..f2ac9b6 --- /dev/null +++ b/libcr_ipc/sema.c @@ -0,0 +1,62 @@ +/* libcr_ipc/sema.c - Simple semaphores for libcr + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include <libcr/coroutine.h> /* for cid_t, cr_* */ +#include <libmisc/assert.h> + +#define IMPLEMENTATION_FOR_LIBCR_IPC_SEMA_H YES +#include <libcr_ipc/sema.h> + +struct cr_sema_waiter { + cid_t cid; +}; +SLIST_DECLARE_NODE(_cr_sema_waiter_list, struct cr_sema_waiter); + +void cr_sema_signal(cr_sema_t *sema) { + assert(sema); + cr_assert_in_coroutine(); + + bool saved = cr_save_and_disable_interrupts(); + sema->cnt++; + if (sema->waiters.front && !sema->unpausing) { + cr_unpause(sema->waiters.front->val.cid); + sema->unpausing = true; + } + cr_restore_interrupts(saved); +} + +void cr_sema_signal_from_intrhandler(cr_sema_t *sema) { + assert(sema); + cr_assert_in_intrhandler(); + + sema->cnt++; + if (sema->waiters.front && !sema->unpausing) { + cr_unpause_from_intrhandler(sema->waiters.front->val.cid); + sema->unpausing = true; + } +} + +void cr_sema_wait(cr_sema_t *sema) { + assert(sema); + cr_assert_in_coroutine(); + + bool saved = cr_save_and_disable_interrupts(); + + struct _cr_sema_waiter_list_node self = { .val = { + .cid = cr_getcid(), + }}; + slist_push_to_rear(&sema->waiters, &self); + if (sema->waiters.front != &self || !sema->cnt) + cr_pause_and_yield(); + assert(sema->waiters.front == &self && sema->cnt); + slist_pop_from_front(&sema->waiters); + sema->cnt--; + if (sema->cnt && sema->waiters.front) + cr_unpause(sema->waiters.front->val.cid); + else + sema->unpausing = false; + cr_restore_interrupts(saved); +} diff --git a/libcr_ipc/tests/config.h b/libcr_ipc/tests/config.h index b00508c..a648589 100644 --- a/libcr_ipc/tests/config.h +++ b/libcr_ipc/tests/config.h @@ -7,9 +7,9 @@ #ifndef _CONFIG_H_ #define _CONFIG_H_ -#define CONFIG_COROUTINE_STACK_SIZE_DEFAULT (4*1024) +#define CONFIG_COROUTINE_STACK_SIZE_DEFAULT (8*1024) #define CONFIG_COROUTINE_NAME_LEN 16 -#define CONFIG_COROUTINE_NUM 8 +#define CONFIG_COROUTINE_NUM 16 #define CONFIG_COROUTINE_MEASURE_STACK 1 #define CONFIG_COROUTINE_PROTECT_STACK 1 diff --git a/libcr_ipc/tests/test_chan.c b/libcr_ipc/tests/test_chan.c index 9d6eecf..4788dd4 100644 --- a/libcr_ipc/tests/test_chan.c +++ b/libcr_ipc/tests/test_chan.c @@ -1,6 +1,6 @@ /* libcr_ipc/tests/test_chan.c - Tests for <libcr_ipc/chan.h> * - * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later */ @@ -9,32 +9,32 @@ #include "test.h" -CR_CHAN_DECLARE(intchan, int) +CR_CHAN_DECLARE(intchan, int); -COROUTINE cr_producer(void *_ch) { +COROUTINE producer_cr(void *_ch) { intchan_t *ch = _ch; cr_begin(); - intchan_send(ch, 1); + cr_chan_send(ch, 1); - while (!intchan_can_send(ch)) + while (!cr_chan_can_send(ch)) cr_yield(); - intchan_send(ch, 2); + cr_chan_send(ch, 2); cr_end(); } -COROUTINE cr_consumer(void *_ch) { +COROUTINE consumer_cr(void *_ch) { int x; intchan_t *ch = _ch; cr_begin(); - x = intchan_recv(ch); + x = cr_chan_recv(ch); test_assert(x == 1); - x = intchan_recv(ch); + x = cr_chan_recv(ch); test_assert(x == 2); cr_end(); @@ -42,8 +42,8 @@ COROUTINE cr_consumer(void *_ch) { int main() { intchan_t ch = {0}; - coroutine_add("producer", cr_producer, &ch); - coroutine_add("consumer", cr_consumer, &ch); + coroutine_add("producer", producer_cr, &ch); + coroutine_add("consumer", consumer_cr, &ch); coroutine_main(); return 0; } diff --git a/libcr_ipc/tests/test_mutex.c b/libcr_ipc/tests/test_mutex.c new file mode 100644 index 0000000..d08315d --- /dev/null +++ b/libcr_ipc/tests/test_mutex.c @@ -0,0 +1,37 @@ +/* libcr_ipc/tests/test_mutex.c - Tests for <libcr_ipc/mutex.h> + * + * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include <libcr/coroutine.h> +#include <libcr_ipc/mutex.h> + +#include "test.h" + +int counter = 0; + +COROUTINE worker_cr(void *_mu) { + cr_mutex_t *mu = _mu; + cr_begin(); + + for (int i = 0; i < 100; i++) { + cr_mutex_lock(mu); + int a = counter; + cr_yield(); + counter = a + 1; + cr_mutex_unlock(mu); + cr_yield(); + } + + cr_end(); +} + +int main() { + cr_mutex_t mu = {}; + coroutine_add("a", worker_cr, &mu); + coroutine_add("b", worker_cr, &mu); + coroutine_main(); + test_assert(counter == 200); + return 0; +} diff --git a/libcr_ipc/tests/test_rpc.c b/libcr_ipc/tests/test_rpc.c index 4aff5ca..1461450 100644 --- a/libcr_ipc/tests/test_rpc.c +++ b/libcr_ipc/tests/test_rpc.c @@ -9,51 +9,51 @@ #include "test.h" -CR_RPC_DECLARE(intrpc, int, int) +CR_RPC_DECLARE(intrpc, int, int); /* Test that the RPC is fair, have worker1 start waiting first, and * ensure that it gets the first request. */ -COROUTINE cr_caller(void *_ch) { +COROUTINE caller_cr(void *_ch) { intrpc_t *ch = _ch; cr_begin(); - int resp = intrpc_send_req(ch, 1); + int resp = cr_rpc_send_req(ch, 1); test_assert(resp == 2); - resp = intrpc_send_req(ch, 3); + resp = cr_rpc_send_req(ch, 3); test_assert(resp == 4); cr_exit(); } -COROUTINE cr_worker1(void *_ch) { +COROUTINE worker1_cr(void *_ch) { intrpc_t *ch = _ch; cr_begin(); - intrpc_req_t req = intrpc_recv_req(ch); + intrpc_req_t req = cr_rpc_recv_req(ch); test_assert(req.req == 1); - intrpc_send_resp(req, 2); + cr_rpc_send_resp(req, 2); cr_exit(); } -COROUTINE cr_worker2(void *_ch) { +COROUTINE worker2_cr(void *_ch) { intrpc_t *ch = _ch; cr_begin(); - intrpc_req_t req = intrpc_recv_req(ch); + intrpc_req_t req = cr_rpc_recv_req(ch); test_assert(req.req == 3); - intrpc_send_resp(req, 4); + cr_rpc_send_resp(req, 4); cr_exit(); } int main() { intrpc_t ch = {0}; - coroutine_add("worker1", cr_worker1, &ch); - coroutine_add("caller", cr_caller, &ch); - coroutine_add("worker2", cr_worker2, &ch); + coroutine_add("worker1", worker1_cr, &ch); + coroutine_add("caller", caller_cr, &ch); + coroutine_add("worker2", worker2_cr, &ch); coroutine_main(); return 0; } diff --git a/libcr_ipc/tests/test_rwmutex.c b/libcr_ipc/tests/test_rwmutex.c new file mode 100644 index 0000000..77e8c7c --- /dev/null +++ b/libcr_ipc/tests/test_rwmutex.c @@ -0,0 +1,88 @@ +/* libcr_ipc/tests/test_rwmutex.c - Tests for <libcr_ipc/rwmutex.h> + * + * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include <string.h> + +#include <libcr/coroutine.h> +#include <libcr_ipc/rwmutex.h> + +#include "test.h" + +cr_rwmutex_t mu = {}; +char out[10] = {0}; +size_t len = 0; + +COROUTINE cr1_reader(void *_mu) { + cr_rwmutex_t *mu = _mu; + cr_begin(); + + cr_rwmutex_rlock(mu); + out[len++] = 'r'; + cr_yield(); + cr_rwmutex_runlock(mu); + + cr_end(); +} + +COROUTINE cr1_writer(void *_mu) { + cr_rwmutex_t *mu = _mu; + cr_begin(); + + cr_rwmutex_lock(mu); + out[len++] = 'w'; + cr_yield(); + cr_rwmutex_unlock(mu); + + cr_end(); +} + +COROUTINE cr2_waiter(void *_ch) { + char ch = *(char *)_ch; + cr_begin(); + + cr_rwmutex_rlock(&mu); + out[len++] = ch; + cr_rwmutex_runlock(&mu); + + cr_end(); +} + +COROUTINE cr2_init(void *) { + cr_begin(); + + char ch; + cr_rwmutex_lock(&mu); + ch = 'a'; coroutine_add("wait-a", cr2_waiter, &ch); + ch = 'b'; coroutine_add("wait-b", cr2_waiter, &ch); + cr_yield(); + ch = 'c'; coroutine_add("wait-c", cr2_waiter, &ch); + cr_rwmutex_unlock(&mu); + + cr_end(); +} + +int main() { + printf("== test 1 =========================================\n"); + coroutine_add("r1", cr1_reader, &mu); + coroutine_add("r2", cr1_reader, &mu); + coroutine_add("w", cr1_writer, &mu); + coroutine_add("r3", cr1_reader, &mu); + coroutine_add("r4", cr1_reader, &mu); + coroutine_main(); + test_assert(len == 5); + test_assert(strcmp(out, "rrwrr") == 0); + + printf("== test 2 =========================================\n"); + mu = (cr_rwmutex_t){}; + len = 0; + memset(out, 0, sizeof(out)); + coroutine_add("init", cr2_init, NULL); + coroutine_main(); + test_assert(len == 3); + test_assert(strcmp(out, "abc") == 0); + + return 0; +} diff --git a/libcr_ipc/tests/test_select.c b/libcr_ipc/tests/test_select.c new file mode 100644 index 0000000..9b5d117 --- /dev/null +++ b/libcr_ipc/tests/test_select.c @@ -0,0 +1,89 @@ +/* libcr_ipc/tests/test_select.c - Tests for <libcr_ipc/select.h> + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include <libcr/coroutine.h> +#include <libcr_ipc/chan.h> + +#include "test.h" + +CR_CHAN_DECLARE(intchan, int); + +intchan_t ch[10] = {0}; +intchan_t fch = {0}; + +COROUTINE consumer_cr(void *) { + cr_begin(); + + struct cr_select_arg args[11]; + + bool chdone[10] = {0}; + int arg2ch[10]; + for (;;) { + int ret_ch; + int i_arg = 0; + for (int i_ch = 0; i_ch < 10; i_ch++) { + if (!chdone[i_ch]) { + args[i_arg] = CR_SELECT_RECV(&ch[i_ch], &ret_ch); + arg2ch[i_arg] = i_ch; + i_arg++; + } + } + if (!i_arg) + break; + args[i_arg] = CR_SELECT_DEFAULT; /* check that default doesn't trigger */ + test_assert(i_arg <= 10); + int ret_arg = cr_select_v(i_arg+1, args); + test_assert(ret_arg < i_arg); + test_assert(arg2ch[ret_arg] == ret_ch); + chdone[ret_ch] = true; + } + int ret_ch, ret_arg; + args[0] = CR_SELECT_RECV(&ch[0], &ret_ch); + args[1] = CR_SELECT_DEFAULT; + ret_arg = cr_select_v(2, args); + test_assert(ret_arg == 1); + + int send = 567; + args[0] = CR_SELECT_SEND(&fch, &send); + args[1] = CR_SELECT_DEFAULT; + ret_arg = cr_select_v(2, args); + test_assert(ret_arg == 0); + + send = 890; + ret_arg = cr_select_l(CR_SELECT_SEND(&fch, &send), + CR_SELECT_DEFAULT); + test_assert(ret_arg == 1); + + cr_end(); +} + +COROUTINE producer_cr(void *_n) { + int n = *(int *)_n; + cr_begin(); + + cr_chan_send(&ch[n], n); + + cr_end(); +} + +COROUTINE final_cr(void *) { + cr_begin(); + + int ret = cr_chan_recv(&fch); + printf("ret=%d\n", ret); + test_assert(ret == 567); + + cr_end(); +} + +int main() { + for (int i = 0; i < 10; i++) + coroutine_add("producer", producer_cr, &i); + coroutine_add("consumer", consumer_cr, NULL); + coroutine_add("final", final_cr, NULL); + coroutine_main(); + return 0; +} diff --git a/libcr_ipc/tests/test_sema.c b/libcr_ipc/tests/test_sema.c index 3208237..435c01a 100644 --- a/libcr_ipc/tests/test_sema.c +++ b/libcr_ipc/tests/test_sema.c @@ -5,13 +5,15 @@ */ #include <libcr/coroutine.h> + +#define IMPLEMENTATION_FOR_LIBCR_IPC_SEMA_H YES /* so we can access .cnt */ #include <libcr_ipc/sema.h> #include "test.h" int counter = 0; -COROUTINE cr_first(void *_sema) { +COROUTINE first_cr(void *_sema) { cr_sema_t *sema = _sema; cr_begin(); @@ -22,7 +24,7 @@ COROUTINE cr_first(void *_sema) { cr_exit(); } -COROUTINE cr_second(void *_sema) { +COROUTINE second_cr(void *_sema) { cr_sema_t *sema = _sema; cr_begin(); @@ -33,7 +35,7 @@ COROUTINE cr_second(void *_sema) { cr_exit(); } -COROUTINE cr_producer(void *_sema) { +COROUTINE producer_cr(void *_sema) { cr_sema_t *sema = _sema; cr_begin(); @@ -43,7 +45,7 @@ COROUTINE cr_producer(void *_sema) { cr_end(); } -COROUTINE cr_consumer(void *_sema) { +COROUTINE consumer_cr(void *_sema) { cr_sema_t *sema = _sema; cr_begin(); @@ -54,19 +56,19 @@ COROUTINE cr_consumer(void *_sema) { } int main() { - cr_sema_t sema = {0}; + cr_sema_t sema = {}; printf("== test 1 =========================================\n"); - coroutine_add("first", cr_first, &sema); - coroutine_add("second", cr_second, &sema); + coroutine_add("first", first_cr, &sema); + coroutine_add("second", second_cr, &sema); coroutine_main(); test_assert(sema.cnt == 0); printf("== test 2 =========================================\n"); - coroutine_add("consumer", cr_consumer, &sema); - coroutine_add("producer", cr_producer, &sema); + coroutine_add("consumer", consumer_cr, &sema); + coroutine_add("producer", producer_cr, &sema); coroutine_main(); - coroutine_add("consumer", cr_consumer, &sema); + coroutine_add("consumer", consumer_cr, &sema); coroutine_main(); test_assert(sema.cnt == 0); diff --git a/libfmt/libmisc.c b/libfmt/libmisc.c index 97a2c80..803b281 100644 --- a/libfmt/libmisc.c +++ b/libfmt/libmisc.c @@ -5,7 +5,7 @@ */ #include <stdarg.h> /* for va_list, va_start(), va_end() */ -#include <stdio.h> /* for vprintf(), putchar() */ +#include <stdio.h> /* for vprintf(), putchar(), fflush() */ #if LIB_PICO_STDIO #include <pico/stdio.h> /* for stdio_putchar_raw() */ #endif @@ -37,6 +37,7 @@ int __lm_printf(const char *format, ...) { int ret = vprintf(format, va); #else int ret = fmt_vfctprintf(libfmt_libc_fct, NULL, format, va); + fflush(stdout); #endif va_end(va); return ret; @@ -55,6 +56,7 @@ int __lm_light_printf(const char *format, ...) { stdio_flush(); #else int ret = fmt_vfctprintf(libfmt_libc_fct, NULL, format, va); + fflush(stdout); #endif va_end(va); return ret; diff --git a/libhw_cr/host_net.c b/libhw_cr/host_net.c index 6ed6e46..ba634a6 100644 --- a/libhw_cr/host_net.c +++ b/libhw_cr/host_net.c @@ -19,6 +19,7 @@ #include <signal.h> /* for siginfo_t, struct sigaction, enum sigval, sigaction(), SA_SIGINFO */ #include <libcr/coroutine.h> +#include <libmisc/alloc.h> #include <libmisc/assert.h> #include <libmisc/macro.h> #include <libobj/obj.h> @@ -283,7 +284,7 @@ static void *hostnet_pthread_writev(void *_args) { struct hostnet_pthread_writev_args *args = _args; size_t count = 0; - struct iovec *iov = alloca(sizeof(struct iovec)*args->iovcnt); + struct iovec *iov = stack_alloc(args->iovcnt, struct iovec); for (int i = 0; i < args->iovcnt; i++) { iov[i] = args->iov[i]; count += args->iov[i].iov_len; diff --git a/libhw_cr/host_util.c b/libhw_cr/host_util.c index 958ed9c..7b3200c 100644 --- a/libhw_cr/host_util.c +++ b/libhw_cr/host_util.c @@ -1,6 +1,6 @@ /* libhw_cr/host_util.c - Utilities for GNU/Linux hosts * - * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later */ diff --git a/libhw_cr/host_util.h b/libhw_cr/host_util.h index 8c53fab..02c04dc 100644 --- a/libhw_cr/host_util.h +++ b/libhw_cr/host_util.h @@ -1,6 +1,6 @@ /* libhw_cr/host_util.h - Utilities for GNU/Linux hosts * - * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later */ diff --git a/libhw_cr/rp2040_hwspi.c b/libhw_cr/rp2040_hwspi.c index 646d8ba..29a7bac 100644 --- a/libhw_cr/rp2040_hwspi.c +++ b/libhw_cr/rp2040_hwspi.c @@ -4,7 +4,6 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ -#include <alloca.h> #include <inttypes.h> /* for PRIu{n} */ #include <hardware/clocks.h> /* for clock_get_hz() and clk_peri */ @@ -12,6 +11,7 @@ #include <hardware/spi.h> #include <libcr/coroutine.h> +#include <libmisc/alloc.h> #include <libmisc/assert.h> #define LOG_NAME RP2040_SPI @@ -130,7 +130,7 @@ void _rp2040_hwspi_init(struct rp2040_hwspi *self, self->dma_tx_data = dma3; self->dma_rx_data = dma4; self->dead_until_ns = 0; - self->sema = (cr_sema_t){0}; + self->sema = (cr_sema_t){}; /* Initialize the interrupt handler. */ /* We do this on (just) the rx channel, because the way the @@ -198,8 +198,8 @@ static void rp2040_hwspi_readwritev(struct rp2040_hwspi *self, const struct dupl * happens, so the IRQ machinery doesn't need to be engaged * at all. */ - struct dma_alias1 *tx_data_blocks = alloca(sizeof(struct dma_alias1)*(pruned_iovcnt+1)); - struct dma_alias0 *rx_data_blocks = alloca(sizeof(struct dma_alias0)*(pruned_iovcnt+1)); + struct dma_alias1 *tx_data_blocks = stack_alloc(pruned_iovcnt+1, struct dma_alias1); + struct dma_alias0 *rx_data_blocks = stack_alloc(pruned_iovcnt+1, struct dma_alias0); static_assert(!DMA_IS_TRIGGER(typeof(tx_data_blocks[0]), ctrl)); static_assert(DMA_IS_TRIGGER(typeof(rx_data_blocks[0]), ctrl)); diff --git a/libhw_cr/rp2040_include/libhw/rp2040_hwspi.h b/libhw_cr/rp2040_include/libhw/rp2040_hwspi.h index 4951136..8d4effa 100644 --- a/libhw_cr/rp2040_include/libhw/rp2040_hwspi.h +++ b/libhw_cr/rp2040_include/libhw/rp2040_hwspi.h @@ -99,7 +99,7 @@ LO_IMPLEMENTATION_H(spi, struct rp2040_hwspi, rp2040_hwspi); min_delay_ns, bogus_data, \ pin_miso, pin_mosi, pin_clk, pin_cs, \ dma1, dma2, dma3, dma4); \ - } while(0) + } while (0) void _rp2040_hwspi_init(struct rp2040_hwspi *self, enum rp2040_hwspi_instance inst_num, enum spi_mode mode, diff --git a/libhw_cr/rp2040_include/libhw/w5500.h b/libhw_cr/rp2040_include/libhw/w5500.h index 8db6a58..8dda1a1 100644 --- a/libhw_cr/rp2040_include/libhw/w5500.h +++ b/libhw_cr/rp2040_include/libhw/w5500.h @@ -17,7 +17,7 @@ #include <libhw/generic/net.h> #include <libhw/generic/spi.h> -CR_CHAN_DECLARE(_w5500_sockintr_ch, uint8_t) +CR_CHAN_DECLARE(_w5500_sockintr_ch, uint8_t); struct _w5500_socket { BEGIN_PRIVATE(LIBHW_W5500_H); diff --git a/libhw_cr/w5500.c b/libhw_cr/w5500.c index fa427d9..c04e344 100644 --- a/libhw_cr/w5500.c +++ b/libhw_cr/w5500.c @@ -217,7 +217,7 @@ static COROUTINE w5500_irq_cr(void *_chip) { } if (send_bits) { debugf("w5500_irq_cr(): signal sock[%"PRIu8"]->write_ch", socknum); - _w5500_sockintr_ch_send(&socket->write_ch, send_bits); + cr_chan_send(&socket->write_ch, send_bits); } break; } @@ -666,7 +666,7 @@ static ssize_t w5500_tcp_writev(struct _w5500_socket *socket, const struct iovec w5500_socket_cmd(socket, CMD_SEND); cr_mutex_unlock(&chip->mu); - switch (_w5500_sockintr_ch_recv(&socket->write_ch)) { + switch (cr_chan_recv(&socket->write_ch)) { case SOCKINTR_SEND_OK: debugf(" => sent %zu", freesize); done += freesize; @@ -853,7 +853,7 @@ static ssize_t w5500_udp_sendto(struct _w5500_socket *socket, void *buf, size_t w5500_socket_cmd(socket, CMD_SEND); cr_mutex_unlock(&chip->mu); - switch (_w5500_sockintr_ch_recv(&socket->write_ch)) { + switch (cr_chan_recv(&socket->write_ch)) { case SOCKINTR_SEND_OK: debugf(" => sent"); return count; diff --git a/libhw_cr/w5500_ll.h b/libhw_cr/w5500_ll.h index 2506cd2..8b98f9d 100644 --- a/libhw_cr/w5500_ll.h +++ b/libhw_cr/w5500_ll.h @@ -10,10 +10,10 @@ #ifndef _LIBHW_CR_W5500_LL_H_ #define _LIBHW_CR_W5500_LL_H_ -#include <alloca.h> /* for alloca() */ #include <stdint.h> /* for uint{n}_t */ #include <string.h> /* for memcmp() */ +#include <libmisc/alloc.h> /* for stack_alloc() */ #include <libmisc/assert.h> /* for assert(), static_assert() */ #include <libmisc/endian.h> /* for uint16be_t */ @@ -94,7 +94,7 @@ w5500ll_writev( (block & CTL_MASK_BLOCK) | CTL_W | CTL_OM_VDM, }; int inner_cnt = 1+io_slice_cnt(iov, iovcnt, skip, max); - struct duplex_iovec *inner = alloca(sizeof(struct duplex_iovec)*inner_cnt); + struct duplex_iovec *inner = stack_alloc(inner_cnt, struct duplex_iovec); inner[0] = (struct duplex_iovec){ .iov_read_to = IOVEC_DISCARD, .iov_write_from = header, @@ -131,7 +131,7 @@ w5500ll_readv( (block & CTL_MASK_BLOCK) | CTL_R | CTL_OM_VDM, }; int inner_cnt = 1+io_slice_cnt(iov, iovcnt, 0, max); - struct duplex_iovec *inner = alloca(sizeof(struct duplex_iovec)*inner_cnt); + struct duplex_iovec *inner = stack_alloc(inner_cnt, struct duplex_iovec); inner[0] = (struct duplex_iovec){ .iov_read_to = IOVEC_DISCARD, .iov_write_from = header, diff --git a/libmisc/CMakeLists.txt b/libmisc/CMakeLists.txt index 4599ead..fdbe949 100644 --- a/libmisc/CMakeLists.txt +++ b/libmisc/CMakeLists.txt @@ -8,7 +8,9 @@ target_include_directories(libmisc PUBLIC INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/ target_sources(libmisc INTERFACE assert.c intercept.c + linkedlist.c log.c + map.c ) target_compile_options(libmisc INTERFACE "$<$<COMPILE_LANGUAGE:C>:-fplan9-extensions>") @@ -18,5 +20,6 @@ add_lib_test(libmisc test_endian) add_lib_test(libmisc test_hash) add_lib_test(libmisc test_log) add_lib_test(libmisc test_macro) +add_lib_test(libmisc test_map) add_lib_test(libmisc test_private) add_lib_test(libmisc test_rand) diff --git a/libmisc/include/libmisc/alloc.h b/libmisc/include/libmisc/alloc.h new file mode 100644 index 0000000..afddbce --- /dev/null +++ b/libmisc/include/libmisc/alloc.h @@ -0,0 +1,26 @@ +/* libmisc/alloc.h - Type-safe wrappers around alloca and malloc + * + * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#ifndef _LIBMISC_ALLOC_H_ +#define _LIBMISC_ALLOC_H_ + +#include <alloca.h> /* for alloca() */ +#include <stdlib.h> /* for calloc(), free() */ +#include <string.h> /* for memset() */ + +#define stack_alloc(N, TYP) ({ \ + size_t _size; \ + TYP *_ret = NULL; \ + if (!__builtin_mul_overflow(N, sizeof(TYP), &_size)) { \ + _ret = alloca(_size); \ + memset(_ret, 0, _size); \ + } \ + _ret; \ +}) + +#define heap_alloc(N, TYP) ((TYP *)calloc(N, sizeof(TYP))) + +#endif /* _LIBMISC_ALLOC_H_ */ diff --git a/libmisc/include/libmisc/assert.h b/libmisc/include/libmisc/assert.h index 8cf0735..ccdb288 100644 --- a/libmisc/include/libmisc/assert.h +++ b/libmisc/include/libmisc/assert.h @@ -1,6 +1,6 @@ /* libmisc/assert.h - More assertions * - * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later */ @@ -10,15 +10,20 @@ #ifdef NDEBUG # define __assert_msg(expr, expr_str, msg) ((void)0) #else -# define __assert_msg(expr, expr_str, msg) do { if (!(expr)) __assert_msg_fail(expr_str, __FILE__, __LINE__, __func__, msg); } while (0) +# define __assert_msg(expr, expr_str, msg) \ + do { \ + if (!(expr)) \ + __assert_msg_fail(expr_str, __FILE__, __LINE__, __func__, msg); \ + } while (0) [[noreturn]] void __assert_msg_fail(const char *expr, const char *file, unsigned int line, const char *func, const char *msg); #endif -#define assert_msg(expr, msg) __assert_msg(expr, #expr, msg) /* libmisc */ -#define assert(expr) __assert_msg(expr, #expr, 0) /* C89, POSIX-2001 */ -#define assert_notreached(msg) do { __assert_msg(0, "notreached", msg); __builtin_unreachable(); } while (0) /* libmisc */ -#define static_assert _Static_assert /* C11 */ +#define assert_msg(expr, msg) __assert_msg(expr, #expr, msg) /* libmisc */ +#define assert(expr) __assert_msg(expr, #expr, 0) /* C89, POSIX-2001 */ +#define assert_notreached(msg) do { __assert_msg(0, "notreached", msg); __builtin_unreachable(); } while (0) /* libmisc */ +#define static_assert _Static_assert /* C11 */ +#define static_assert_as_expr(...) (sizeof(struct {static_assert(__VA_ARGS__);})) /* libmisc */ #endif /* _LIBMISC_ASSERT_H_ */ diff --git a/libmisc/include/libmisc/linkedlist.h b/libmisc/include/libmisc/linkedlist.h new file mode 100644 index 0000000..b6ff688 --- /dev/null +++ b/libmisc/include/libmisc/linkedlist.h @@ -0,0 +1,108 @@ +/* libmisc/linkedlist.h - Singly- and doubly- linked lists + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#ifndef _LIBMISC_LINKEDLIST_H_ +#define _LIBMISC_LINKEDLIST_H_ + +/* low-level (intrusive) singly linked list ***********************************/ + +struct _slist_node { + struct _slist_node *rear; +}; + +struct _slist_root { + struct _slist_node *front, *rear; +}; + +void _slist_push_to_rear(struct _slist_root *root, struct _slist_node *node); +void _slist_pop_from_front(struct _slist_root *root); + +/* low-level (intrusive) doubly linked list ***********************************/ + +struct _dlist_node { + struct _dlist_node *front, *rear; +}; + +struct _dlist_root { + struct _dlist_node *front, *rear; +}; + +void _dlist_push_to_rear(struct _dlist_root *root, struct _dlist_node *node); +void _dlist_remove(struct _dlist_root *root, struct _dlist_node *node); +void _dlist_pop_from_front(struct _dlist_root *root); + +/* singly linked list (non-intrusive) *****************************************/ + +#define SLIST_DECLARE(NAME) \ + struct NAME##_node; \ + struct NAME { \ + struct NAME##_node *front, *rear; \ + struct NAME *_slist_root_typ[0]; \ + } + +#define SLIST_DECLARE_NODE(NAME, VAL_T) \ + struct NAME##_node { \ + struct NAME##_node *rear; \ + VAL_T val; \ + } + +#define slist_push_to_rear(ROOT, NODE) { \ + /* These temporary variables are to get the compiler to check \ + * the types. */ \ + typeof(*(ROOT)->_slist_root_typ[0]) *_rootp = ROOT; \ + typeof(*_rootp->front) *_nodep = NODE; \ + _slist_push_to_rear((struct _slist_root *)_rootp, \ + (struct _slist_node *)_nodep); \ +} while (0) + +#define slist_pop_from_front(ROOT) { \ + /* This temporary variables are to get the compiler to check \ + * the type. */ \ + typeof(*(ROOT)->_slist_root_typ[0]) *_rootp = ROOT; \ + _slist_pop_from_front((struct _slist_root *)_rootp); \ +} while (0) + +/* doubly linked list (non-intrusive) *****************************************/ + +#define DLIST_DECLARE(NAME) \ + struct NAME##_node; \ + struct NAME { \ + struct NAME##_node *front, *rear; \ + struct NAME *_dlist_root_typ[0]; \ + } + +#define DLIST_DECLARE_NODE(NAME, VAL_T) \ + struct NAME##_node { \ + struct NAME##_node *front, *rear; \ + VAL_T val; \ + } + +#define dlist_push_to_rear(ROOT, NODE) { \ + /* These temporary variables are to get the compiler to check \ + * the types. */ \ + typeof(*(ROOT)->_dlist_root_typ[0]) *_rootp = ROOT; \ + typeof(*_rootp->front) *_nodep = NODE; \ + _dlist_push_to_rear((struct _dlist_root *)_rootp, \ + (struct _dlist_node *)_nodep); \ +} while (0) + +#define dlist_remove(ROOT, NODE) { \ + /* These temporary variables are to get the compiler to check \ + * the types. */ \ + typeof(*(ROOT)->_dlist_root_typ[0]) *_rootp = ROOT; \ + typeof(*_rootp->front) *_nodep = NODE; \ + _dlist_remove((struct _dlist_root *)_rootp, \ + (struct _dlist_node *)_nodep); \ +} while (0) + +#define dlist_pop_from_front(ROOT) { \ + /* This temporary variables are to get the compiler to check \ + * the type. */ \ + typeof(*(ROOT)->_dlist_root_typ[0]) *_rootp = ROOT; \ + _dlist_pop_from_front((struct _dlist_root *)_rootp); \ +} while (0) + +#endif /* _LIBMISC_LINKEDLIST_H_ */ diff --git a/libmisc/include/libmisc/macro.h b/libmisc/include/libmisc/macro.h index b3e235c..a95ac82 100644 --- a/libmisc/include/libmisc/macro.h +++ b/libmisc/include/libmisc/macro.h @@ -7,6 +7,8 @@ #ifndef _LIBMISC_MACRO_H_ #define _LIBMISC_MACRO_H_ +#include <libmisc/assert.h> + /* for function definitions */ #define LM_UNUSED(argname) @@ -14,9 +16,22 @@ #define LM_NEVER_INLINE [[gnu::noinline]] #define LM_FLATTEN [[gnu::flatten]] +/* types */ + +/* If it's a pointer instead of an array, then typeof(&ptr[0]) == typeof(ptr) */ +#define _LM_IS_ARRAY(ary) (!__builtin_types_compatible_p(typeof(&(ary)[0]), typeof(ary))) +#define LM_ARRAY_LEN(ary) ( (sizeof(ary)/sizeof((ary)[0])) + static_assert_as_expr(_LM_IS_ARRAY(ary)) ) + +#define LM_CAST_FIELD_TO_STRUCT(STRUCT_TYP, FIELD_NAME, PTR_TO_FIELD) ({ \ + /* The _fptr assignment is to get the compiler to do type checking. */ \ + typeof(((STRUCT_TYP *)NULL)->FIELD_NAME) *_fptr = (PTR_TO_FIELD); \ + _fptr \ + ? ((STRUCT_TYP*)( ((void*)_fptr) - offsetof(STRUCT_TYP, FIELD_NAME))) \ + : NULL; \ +}) + /* numeric */ -#define LM_ARRAY_LEN(ary) (sizeof(ary)/sizeof((ary)[0])) #define LM_CEILDIV(n, d) ( ((n)+(d)-1) / (d) ) /** Return ceil(n/d) */ #define LM_ROUND_UP(n, d) ( LM_CEILDIV(n, d) * (d) ) /** Return `n` rounded up to the nearest multiple of `d` */ #define LM_ROUND_DOWN(n, d) ( ((n)/(d)) * (d) ) /** Return `n` rounded down to the nearest multiple of `d` */ diff --git a/libmisc/include/libmisc/map.h b/libmisc/include/libmisc/map.h new file mode 100644 index 0000000..6622595 --- /dev/null +++ b/libmisc/include/libmisc/map.h @@ -0,0 +1,146 @@ +/* libmisc/map.h - A map/dict data structure + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#ifndef _LIBMISC_MAP_H_ +#define _LIBMISC_MAP_H_ + +#include <stdbool.h> +#include <stddef.h> /* for size_t */ +#include <stdint.h> /* for uint8_t */ + +#include <libmisc/linkedlist.h> + +/* Type ***********************************************************************/ + +DLIST_DECLARE(_map_kv_list); + +struct _map { + size_t len; + size_t nbuckets; + struct _map_kv_list *buckets; + + unsigned int iterating; + + size_t sizeof_kv; + size_t offsetof_k, sizeof_k; + size_t offsetof_v, sizeof_v; +}; + +/** + * MAP_DECLARE(MAPNAME, KEY_T, VAL_T) declares `struct MAPNAME`. + */ +#define MAP_DECLARE(MAPNAME, KEY_T, VAL_T) \ + struct _##MAPNAME##_kv { \ + uint8_t flags; \ + KEY_T key; \ + VAL_T val; \ + }; \ + DLIST_DECLARE_NODE(_##MAPNAME##_kv_list, struct _##MAPNAME##_kv); \ + struct MAPNAME { \ + struct _map core; \ + struct _##MAPNAME##_kv_list_node kv_typ[0]; \ + } + +#define _map_init(M) do { \ + if (!(M)->core.sizeof_kv) { \ + (M)->core.sizeof_kv = sizeof((M)->kv_typ[0]); \ + (M)->core.sizeof_k = sizeof((M)->kv_typ[0].val.key); \ + (M)->core.sizeof_v = sizeof((M)->kv_typ[0].val.val); \ + (M)->core.offsetof_k = offsetof(typeof((M)->kv_typ[0]), val.key); \ + (M)->core.offsetof_v = offsetof(typeof((M)->kv_typ[0]), val.val); \ + } \ +} while (0) + +/* Methods ********************************************************************/ + +/** + * map_len(map) returns the number of entries currently in `map`. + */ +#define map_len(M) ((M)->core.len) + +/** + * map_load(map, key) returns a pointer to the value in `map` + * associated with `key`, or else NULL. + */ +#define map_load(M, K) ({ \ + _map_init(M); \ + typeof((M)->kv_typ[0].val.key) _k = K; \ + (typeof((M)->kv_typ[0].val.val)*)_map_load(&(M)->core, &_k); \ +}) +void *_map_load(struct _map *m, void *kp); + +/** + * map_del(map, key) ensures that `key` is not present in `map`. + * Returns whether `key` was in `map` before the call. + */ +#define map_del(M, K) ({ \ + _map_init(M); \ + typeof((M)->kv_typ[0].val.key) _k = K; \ + _map_del(&(M)->core, &_k); \ +}) +bool _map_del(struct _map *m, void *kp); + +/** + * map_store(map, key, val) sets a value in the map. Returns a + * pointer to the map's copy of `val`. + */ +#define map_store(M, K, ...) ({ \ + _map_init(M); \ + typeof((M)->kv_typ[0].val.key) _k = K; \ + typeof((M)->kv_typ[0].val.val) _v = __VA_ARGS__; \ + (typeof((M)->kv_typ[0].val.val)*)_map_store(&(M)->core, &_k, &_v); \ +}) +void *_map_store(struct _map *m, void *kp, void *vp); + +/** + * map_free(map) frees the memory associated with the map. + */ +#define map_free(M) _map_free(&(M)->core); +void _map_free(struct _map *m); + +/* Iteration ******************************************************************/ + +struct _map_iter { + struct _map *m; + void *keyp; + void **valpp; + + size_t i; + struct _map_kv_list_node *kv; +}; + +/** + * MAP_FOREACH iterates over a map: + * + * MAP_FOREACH(MAP_EACH(MAP, key, valp)) { + * ... + * } + * + * It is safe to mutate the map with map_store() and, map_del() while + * iterating, but entries added by map_store() may or may not be + * visited by the iteration. + */ +#define MAP_FOREACH(M, KNAME, VNAME) _MAP_FOREACH(__COUNTER__, M, KNAME, VNAME) +#define _MAP_FOREACH(CNT, M, KNAME, VNAME) \ + for (bool _once_##CNT = true; _once_##CNT;) \ + for (typeof((M)->kv_typ[0].val.key) KNAME; _once_##CNT;) \ + for (typeof((M)->kv_typ[0].val.val) *VNAME; _once_##CNT;) \ + for ( \ + struct _map_iter _iter_##CNT = ({ \ + _map_init(M); \ + _map_iter_before(&(M)->core, &KNAME, (void**)&VNAME); \ + }); \ + _once_##CNT; \ + ({ \ + _once_##CNT = false; \ + _map_iter_after(&_iter_##CNT); \ + })) \ + while (_map_iter_next(&_iter_##CNT)) +struct _map_iter _map_iter_before(struct _map *m, void *keyp, void **valpp); +bool _map_iter_next(struct _map_iter *iter); +void _map_iter_after(struct _map_iter *iter); + +#endif /* _LIBMISC_MAP_H_ */ diff --git a/libmisc/include/libmisc/rand.h b/libmisc/include/libmisc/rand.h index bb1ec0b..7ef238b 100644 --- a/libmisc/include/libmisc/rand.h +++ b/libmisc/include/libmisc/rand.h @@ -1,6 +1,6 @@ /* libmisc/rand.h - Non-crytpographic random-number utilities * - * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later */ diff --git a/libmisc/linkedlist.c b/libmisc/linkedlist.c new file mode 100644 index 0000000..71a0aa9 --- /dev/null +++ b/libmisc/linkedlist.c @@ -0,0 +1,64 @@ +/* libmisc/linkedlist.c - Singly- and doubly- linked lists + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include <stddef.h> /* for NULL */ + +#include <libmisc/assert.h> + +#include <libmisc/linkedlist.h> + +/* singly linked list *********************************************************/ + +void _slist_push_to_rear(struct _slist_root *root, struct _slist_node *node) { + assert(root); + node->rear = NULL; + if (root->rear) + root->rear->rear = node; + else + root->front = node; + root->rear = node; +} + +void _slist_pop_from_front(struct _slist_root *root) { + assert(root); + assert(root->front); + root->front = root->front->rear; + if (!root->front) + root->rear = NULL; +} + +/* doubly linked list *********************************************************/ + +void _dlist_push_to_rear(struct _dlist_root *root, struct _dlist_node *node) { + assert(root); + assert(node); + node->front = root->rear; + node->rear = NULL; + if (root->rear) + root->rear->rear = node; + else + root->front = node; + root->rear = node; +} + +void _dlist_remove(struct _dlist_root *root, struct _dlist_node *node) { + assert(root); + assert(node); + if (node->front) + node->front->rear = node->rear; + else + root->front = node->rear; + if (node->rear) + node->rear->front = node->front; + else + root->rear = node->front; +} + +void _dlist_pop_from_front(struct _dlist_root *root) { + assert(root); + assert(root->front); + _dlist_remove(root, root->front); +} diff --git a/libmisc/map.c b/libmisc/map.c new file mode 100644 index 0000000..cc34c16 --- /dev/null +++ b/libmisc/map.c @@ -0,0 +1,230 @@ +/* libmisc/map.c - A map/dict data structure + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include <stdlib.h> +#include <string.h> + +#include <libmisc/hash.h> +#include <libmisc/alloc.h> +#include <libmisc/assert.h> +#include <libmisc/map.h> + +#define FLAG_ITER (UINT8_C(1)<<0) +#define FLAG_DEL (UINT8_C(1)<<1) + +/* Internal utilities *********************************************************/ + +struct _map_kv { + uint8_t flags; + /* opaque key; */ + /* opaque val; */ +}; +DLIST_DECLARE_NODE(_map_kv_list, struct _map_kv); + +static inline void *_map_kv_keyp(struct _map *m, struct _map_kv_list_node *kv) { + assert(m); + assert(kv); + return ((void*)kv)+m->offsetof_k; +} +static inline void *_map_kv_valp(struct _map *m, struct _map_kv_list_node *kv) { + assert(m); + assert(kv); + return ((void*)kv)+m->offsetof_v; +} + +static inline void _map_lookup(struct _map *m, void *keyp, + hash_t *ret_hash, + struct _map_kv_list **ret_bucket, + struct _map_kv_list_node **ret_kv) { + assert(m); + assert(keyp); + assert(ret_hash); + assert(ret_bucket); + assert(ret_kv); + *ret_hash = hash(keyp, m->sizeof_k); + if (m->nbuckets == 0) { + *ret_bucket = NULL; + *ret_kv = NULL; + return; + } + *ret_bucket = &m->buckets[*ret_hash % m->nbuckets]; + for (struct _map_kv_list_node *kv = (*ret_bucket)->front; kv; kv = kv->rear) { + if (!(kv->val.flags & FLAG_DEL) && + memcmp(_map_kv_keyp(m, kv), keyp, m->sizeof_k) == 0) { + *ret_kv = kv; + return; + } + } + *ret_kv = NULL; +} + +static inline void _map_resize(struct _map *m, size_t new_nbuckets) { + assert(m); + assert(new_nbuckets); + struct _map_kv_list *new_buckets = heap_alloc(new_nbuckets, struct _map_kv_list); + for (size_t i = 0; i < m->nbuckets; i++) { + while (m->buckets[i].front) { + struct _map_kv_list_node *kv = m->buckets[i].front; + dlist_pop_from_front(&m->buckets[i]); + hash_t h = hash(_map_kv_keyp(m, kv), m->sizeof_k); + dlist_push_to_rear(&new_buckets[h % new_nbuckets], kv); + } + } + m->nbuckets = new_nbuckets; + free(m->buckets); + m->buckets = new_buckets; +} + +static bool _map_autoresize(struct _map *m) { + assert(m); + if (m->len > (m->nbuckets * 8/10)) { + size_t nbuckets = 1; + while (m->len > (nbuckets * 8/10)) + nbuckets <<= 1; + _map_resize(m, nbuckets); + return true; + } + return false; +} + +/* Methods ********************************************************************/ + +void *_map_load(struct _map *m, void *keyp) { + assert(m); + assert(keyp); + + hash_t h; + struct _map_kv_list *bucket; + struct _map_kv_list_node *kv; + _map_lookup(m, keyp, &h, &bucket, &kv); + + if (!kv) + return NULL; + return _map_kv_valp(m, kv); +} + +bool _map_del(struct _map *m, void *keyp) { + assert(m); + assert(keyp); + + hash_t h; + struct _map_kv_list *bucket; + struct _map_kv_list_node *kv; + _map_lookup(m, keyp, &h, &bucket, &kv); + + if (!kv) + return false; + if (kv->val.flags & FLAG_ITER) { + kv->val.flags |= FLAG_DEL; + } else { + dlist_remove(bucket, kv); + free(kv); + } + m->len--; + return true; +} + +void *_map_store(struct _map *m, void *keyp, void *valp) { + assert(m); + assert(keyp); + assert(valp); + + hash_t h; + struct _map_kv_list *bucket; + struct _map_kv_list_node *old; + _map_lookup(m, keyp, &h, &bucket, &old); + + if (old) { + dlist_remove(bucket, old); + free(old); + m->len--; + } + m->len++; + if (!m->iterating && _map_autoresize(m)) { + h = hash(keyp, m->sizeof_k); + bucket = &m->buckets[h % m->nbuckets]; + } + struct _map_kv_list_node *kv = calloc(1, m->sizeof_kv); + memcpy(_map_kv_keyp(m, kv), keyp, m->sizeof_k); + memcpy(_map_kv_valp(m, kv), valp, m->sizeof_v); + dlist_push_to_rear(bucket, kv); + return _map_kv_valp(m, kv); +} + +void _map_free(struct _map *m) { + assert(m); + + for (size_t i = 0; i < m->nbuckets; i++) { + while (m->buckets[i].front) { + struct _map_kv_list_node *kv = m->buckets[i].front; + dlist_pop_from_front(&m->buckets[i]); + free(kv); + } + } + free(m->buckets); + m->len = 0; + m->nbuckets = 0; + m->buckets = NULL; +} + +/* Iteration ******************************************************************/ + +struct _map_iter _map_iter_before(struct _map *m, void *keyp, void **valpp) { + assert(m); + assert(keyp); + assert(valpp); + + struct _map_iter state = { + .m = m, + .keyp = keyp, + .valpp = valpp, + }; + m->iterating++; + return state; +} + +void _map_iter_after(struct _map_iter *state) { + assert(state); + assert(state->m); + + state->m->iterating--; + if (!state->m->iterating) + _map_autoresize(state->m); +} + +bool _map_iter_next(struct _map_iter *state) { + assert(state); + assert(state->m); + assert(state->valpp); + + if (!state->kv) { + if (!state->m->len) + return false; + while (!state->m->buckets[state->i].front) + state->i++; + state->kv = state->m->buckets[state->i].front; + } else { + struct _map_kv_list_node *old_kv = state->kv; + state->kv = old_kv->rear; + + old_kv->val.flags &= ~FLAG_ITER; + if (old_kv->val.flags & FLAG_DEL) { + dlist_remove(&state->m->buckets[state->i], old_kv); + free(old_kv); + } + + while (!state->kv) { + state->i++; + if (state->i == state->m->nbuckets) + return false; + state->kv = state->m->buckets[state->i].front; + } + } + state->kv->val.flags |= FLAG_ITER; + memcpy(state->keyp, _map_kv_keyp(state->m, state->kv), state->m->sizeof_k); + *(state->valpp) = _map_kv_valp(state->m, state->kv); + return true; +} diff --git a/libmisc/tests/test_map.c b/libmisc/tests/test_map.c new file mode 100644 index 0000000..855dace --- /dev/null +++ b/libmisc/tests/test_map.c @@ -0,0 +1,60 @@ +/* libmisc/tests/test_map.c - Tests for <libmisc/map.h> + * + * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include <libmisc/map.h> + +#include "test.h" + +MAP_DECLARE(intmap, int, int); + +int main() { + struct intmap m = {}; + test_assert(map_len(&m) == 0); + + int *v = map_store(&m, 3, 8); + test_assert(v && *v == 8); + test_assert(map_len(&m) == 1); + + v = map_load(&m, 3); + test_assert(v); + test_assert(*v == 8); + + v = NULL; + + test_assert(map_del(&m, 3)); + test_assert(map_len(&m) == 0); + test_assert(!map_del(&m, 3)); + + map_store(&m, 1, 11); + map_store(&m, 2, 12); + map_store(&m, 3, 13); + test_assert(map_len(&m) == 3); + bool seen_1 = false, seen_2 = false, seen_3 = false; + MAP_FOREACH(&m, ik, iv) { + switch (ik) { + case 1: seen_1 = true; break; + case 2: seen_2 = true; break; + case 3: seen_3 = true; break; + } + switch (ik) { + case 1: case 2: case 3: + map_store(&m, ik+20, (*iv)+20); + test_assert(map_del(&m, ik)); + test_assert(!map_del(&m, ik)); + test_assert(map_load(&m, ik) == NULL); + break; + } + } + test_assert(map_len(&m) == 3); + test_assert(seen_1); v = map_load(&m, 21); test_assert(v && *v == 31); v = map_load(&m, 1); test_assert(!v); + test_assert(seen_2); v = map_load(&m, 22); test_assert(v && *v == 32); v = map_load(&m, 2); test_assert(!v); + test_assert(seen_3); v = map_load(&m, 23); test_assert(v && *v == 33); v = map_load(&m, 3); test_assert(!v); + + map_free(&m); + test_assert(map_len(&m) == 0); + + return 0; +} diff --git a/libmisc/tests/test_private.c b/libmisc/tests/test_private.c index 9b39932..024dddb 100644 --- a/libmisc/tests/test_private.c +++ b/libmisc/tests/test_private.c @@ -1,6 +1,6 @@ /* libmisc/tests/test_private.c - Tests for <libmisc/private.h> * - * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later */ diff --git a/libusb/CMakeLists.txt b/libusb/CMakeLists.txt index 9be44ac..b11e798 100644 --- a/libusb/CMakeLists.txt +++ b/libusb/CMakeLists.txt @@ -1,6 +1,6 @@ # libusb/CMakeLists.txt - Build script for libusb support library # -# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> +# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> # SPDX-License-Identifier: AGPL-3.0-or-later add_library(libusb INTERFACE) diff --git a/libusb/include/libusb/tusb_helpers.h b/libusb/include/libusb/tusb_helpers.h index 1b4e48e..0c35f62 100644 --- a/libusb/include/libusb/tusb_helpers.h +++ b/libusb/include/libusb/tusb_helpers.h @@ -1,7 +1,7 @@ /* Generated by `libusb/include/libusb/tusb_helpers.h.gen `. DO NOT EDIT! */ /* libusb/tusb_helpers.h - Preprocessor macros that I think should be included in TinyUSB * - * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * * SPDX-License-Identifier: MIT * diff --git a/libusb/include/libusb/tusb_helpers.h.gen b/libusb/include/libusb/tusb_helpers.h.gen index 5a5d1ac..1de1d09 100755 --- a/libusb/include/libusb/tusb_helpers.h.gen +++ b/libusb/include/libusb/tusb_helpers.h.gen @@ -7,7 +7,7 @@ echo "/* Generated by \`$0 $*\`. DO NOT EDIT! */" cat <<'EOT' /* libusb/tusb_helpers.h - Preprocessor macros that I think should be included in TinyUSB * - * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * * SPDX-License-Identifier: MIT * @@ -70,12 +70,19 @@ fi if [[ ! -f 3rd-party/MS-LCID.txt || 3rd-party/MS-LCID.txt -ot 3rd-party/MS-LCID.pdf ]]; then pdftotext -layout 3rd-party/MS-LCID.pdf fi -<3rd-party/MS-LCID.txt \ - grep -E '^\s*0x[0-9A-F]{4}\s+[a-z]' | sed 's/,.*//' | grep -v reserved | # find the lines we're interested in - sed -E 's/^\s*0x(..)(..)\s+(\S.*)/\2 \1 \3/p' | tr '[:lower:]-' '[:upper:]_' | # format them as 'PRIhex SUBhex UPPER_STR' - sort | - sed -E 's/(..) (..) (.*)/#define LANGID_\3 0x\2\1/' | # format them as '#define LANGID_UPPER_STR 0xSUBPRI' - column --table --output-separator=' ' +{ + { + # find the lines we're interested in + grep -E '^\s*0x[0-9A-F]{4}\s+[a-z]' | sed 's/,.*//' | grep -v reserved + } | { + # format them as 'PRIhex SUBhex UPPER_STR' + sed -E 's/^\s*0x(..)(..)\s+(\S.*)/\2 \1 \3/p' | tr '[:lower:]-' '[:upper:]_' + } | sort | { + # format them as '#define LANGID_UPPER_STR 0xSUBPRI' + sed -E 's/(..) (..) (.*)/#define LANGID_\3 0x\2\1/' | + column --table --output-separator=' ' + } +} <3rd-party/MS-LCID.txt cat <<'EOT' /** USB 2.0 ยง9.6.6 "Endpoint", field bEndpointAddress, bit 7 */ @@ -187,3 +187,7 @@ OpenBMC - Sipeed NanoKVM - https://github.com/stefanklug/picoKVM (~$20 Arduino, ~$5 HDMI capture), non-IP + +---- + +https://hackaday.com/2022/08/26/bit-banged-ethernet-on-the-raspberry-pi-pico/ |