summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.editorconfig10
-rw-r--r--.gitignore4
-rw-r--r--CMakeLists.txt8
-rw-r--r--GNUmakefile119
-rw-r--r--HACKING.md4
-rw-r--r--PLAN.md31
-rw-r--r--README.md15
-rwxr-xr-xbuild-aux/gcov-prune33
-rwxr-xr-xbuild-aux/get-dscname36
-rwxr-xr-xbuild-aux/lint-bin14
-rwxr-xr-xbuild-aux/lint-generic60
-rwxr-xr-xbuild-aux/lint-h27
-rwxr-xr-xbuild-aux/lint-src160
-rwxr-xr-xbuild-aux/lint-unknown24
-rw-r--r--build-aux/measurestack/analyze.py7
-rw-r--r--build-aux/measurestack/app_main.py4
-rw-r--r--build-aux/measurestack/app_output.py46
-rw-r--r--build-aux/measurestack/app_plugins.py173
-rw-r--r--build-aux/measurestack/testutil.py3
-rw-r--r--build-aux/measurestack/util.py14
-rwxr-xr-xbuild-aux/tent-graph180
-rwxr-xr-xbuild-aux/valgrind2
-rw-r--r--cmd/sbc_harness/CMakeLists.txt81
-rw-r--r--cmd/sbc_harness/fs_harness_flash_bin.c307
-rw-r--r--cmd/sbc_harness/fs_harness_uptime_txt.c150
-rw-r--r--cmd/sbc_harness/fs_harness_uptime_txt.h19
-rw-r--r--cmd/sbc_harness/static/Documentation/harness_uptime_txt.txt17
-rw-r--r--flashimg/cpu_hdmi/CMakeLists.txt20
-rw-r--r--flashimg/cpu_hdmi/main.c9
-rw-r--r--flashimg/cpu_main/CMakeLists.txt105
-rw-r--r--flashimg/cpu_main/config/config.h (renamed from cmd/sbc_harness/config/config.h)37
-rw-r--r--flashimg/cpu_main/config/tusb_config.h (renamed from cmd/sbc_harness/config/tusb_config.h)2
-rw-r--r--flashimg/cpu_main/fs_harness_flash_bin.c332
-rw-r--r--flashimg/cpu_main/fs_harness_flash_bin.h (renamed from cmd/sbc_harness/fs_harness_flash_bin.h)26
-rw-r--r--flashimg/cpu_main/fs_harness_uptime_txt.c157
-rw-r--r--flashimg/cpu_main/fs_harness_uptime_txt.h18
-rw-r--r--flashimg/cpu_main/ihex.c231
-rw-r--r--flashimg/cpu_main/ihex.h49
-rw-r--r--flashimg/cpu_main/main.c (renamed from cmd/sbc_harness/main.c)83
-rw-r--r--flashimg/cpu_main/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS.md (renamed from cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS.md)0
l---------flashimg/cpu_main/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/agpl-3.0.txt (renamed from cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/agpl-3.0.txt)0
l---------flashimg/cpu_main/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/dhcp.bsd3-mit.txt (renamed from cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/dhcp.bsd3-mit.txt)0
l---------flashimg/cpu_main/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/newlib.txt (renamed from cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/newlib.txt)0
l---------flashimg/cpu_main/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/pico-sdk.bsd3.txt (renamed from cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/pico-sdk.bsd3.txt)0
l---------flashimg/cpu_main/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/tinyusb.mit.txt (renamed from cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/tinyusb.mit.txt)0
-rw-r--r--flashimg/cpu_main/static/Documentation/harness_flash.bin.txt (renamed from cmd/sbc_harness/static/Documentation/harness_flash_bin.txt)24
-rw-r--r--flashimg/cpu_main/static/Documentation/harness_rom.bin.txt (renamed from cmd/sbc_harness/static/Documentation/harness_rom_bin.txt)0
-rw-r--r--flashimg/cpu_main/static/Documentation/harness_uptime.txt.txt27
-rw-r--r--flashimg/cpu_main/tests/test_ihex.c128
-rw-r--r--flashimg/cpu_main/tusb_log.c (renamed from cmd/sbc_harness/tusb_log.c)2
-rw-r--r--flashimg/cpu_main/usb_keyboard.c (renamed from cmd/sbc_harness/usb_keyboard.c)31
-rw-r--r--flashimg/cpu_main/usb_keyboard.h (renamed from cmd/sbc_harness/usb_keyboard.h)8
-rw-r--r--lib9p/CMakeLists.txt33
-rw-r--r--lib9p/core.c102
-rwxr-xr-xlib9p/core.gen2
-rw-r--r--lib9p/core_gen/c.py9
-rw-r--r--lib9p/core_gen/c9util.py4
-rw-r--r--lib9p/core_gen/c_fmt_print.py2
-rw-r--r--lib9p/core_gen/c_marshal.py39
-rw-r--r--lib9p/core_gen/c_validate.py28
-rw-r--r--lib9p/core_gen/h.py7
-rw-r--r--lib9p/core_generated.c1543
-rw-r--r--lib9p/core_include/lib9p/_core_generated.h51
-rw-r--r--lib9p/core_include/lib9p/core.h104
-rw-r--r--lib9p/core_tables.h8
-rw-r--r--lib9p/core_utf8.h36
-rw-r--r--lib9p/idl/1992-9P0.9p.wip2
-rwxr-xr-xlib9p/idl/2010-9P2000.L.9p.gen2
-rw-r--r--lib9p/srv.c958
-rw-r--r--lib9p/srv_errno.h14
-rw-r--r--lib9p/srv_generated.c91
-rwxr-xr-xlib9p/srv_generated.c.gen30
-rw-r--r--lib9p/srv_include/lib9p/srv.h174
-rw-r--r--lib9p/tests/client_config/config.h3
-rw-r--r--lib9p/tests/test_compile.c836
-rwxr-xr-xlib9p/tests/test_compile.c.gen8
-rw-r--r--lib9p/tests/test_compile_config/config.h11
-rw-r--r--lib9p/tests/test_server/CMakeLists.txt26
-rw-r--r--lib9p/tests/test_server/config/config.h14
-rw-r--r--lib9p/tests/test_server/fs_flush.c67
-rw-r--r--lib9p/tests/test_server/fs_flush.h3
-rw-r--r--lib9p/tests/test_server/fs_shutdown.c50
-rw-r--r--lib9p/tests/test_server/fs_shutdown.h3
-rw-r--r--lib9p/tests/test_server/fs_whoami.c64
-rw-r--r--lib9p/tests/test_server/fs_whoami.h3
-rw-r--r--lib9p/tests/test_server/main.c32
-rw-r--r--lib9p/tests/testclient-hangup.c100
-rw-r--r--lib9p/tests/testclient-hangup.explog14
-rw-r--r--lib9p/tests/testclient-sess.c33
-rw-r--r--lib9p/tests/testclient-sess.explog2
-rw-r--r--lib9p_util/include/util9p/static.h8
-rw-r--r--lib9p_util/static.c156
-rw-r--r--libcr/CMakeLists.txt5
-rw-r--r--libcr/coroutine.c74
-rw-r--r--libcr/include/libcr/coroutine.h43
-rw-r--r--libcr/tests/test_matrix/config.h2
-rw-r--r--libcr_ipc/CMakeLists.txt11
-rw-r--r--libcr_ipc/chan.c2
-rw-r--r--libcr_ipc/include/libcr_ipc/chan.h2
-rw-r--r--libcr_ipc/include/libcr_ipc/rpc.h1
-rw-r--r--libcr_ipc/rpc.c2
-rw-r--r--libcr_ipc/tests/config.h2
-rw-r--r--libcr_ipc/tests/test_chan.c92
-rw-r--r--libcr_ipc/tests/test_chan_compile.c13
-rw-r--r--libcr_ipc/tests/test_mutex_compile.c11
-rw-r--r--libcr_ipc/tests/test_rpc_compile.c13
-rw-r--r--libcr_ipc/tests/test_rwmutex_compile.c11
-rw-r--r--libcr_ipc/tests/test_select.c89
-rw-r--r--libcr_ipc/tests/test_sema_compile.c11
-rw-r--r--libdhcp/CMakeLists.txt7
-rw-r--r--libdhcp/dhcp_client.c110
-rw-r--r--libdhcp/dhcp_common.c104
-rw-r--r--libdhcp/dhcp_common.h96
-rw-r--r--libdhcp/include/libdhcp/client.h60
-rw-r--r--libdhcp/tests/config.h25
l---------libdhcp/tests/test.h1
-rw-r--r--libdhcp/tests/test_client.c120
-rw-r--r--libhw_cr/CMakeLists.txt1
-rw-r--r--libhw_cr/host_alarmclock.c39
-rw-r--r--libhw_cr/host_include/libhw/host_alarmclock.h4
-rw-r--r--libhw_cr/host_include/libhw/host_net.h9
-rw-r--r--libhw_cr/host_net.c309
-rw-r--r--libhw_cr/host_util.c128
-rw-r--r--libhw_cr/host_util.h41
-rw-r--r--libhw_cr/rp2040_dma.c21
-rw-r--r--libhw_cr/rp2040_dma.h39
-rw-r--r--libhw_cr/rp2040_gpioirq.c2
-rw-r--r--libhw_cr/rp2040_hwspi.c14
-rw-r--r--libhw_cr/rp2040_hwtimer.c29
-rw-r--r--libhw_cr/rp2040_include/libhw/w5500.h13
-rw-r--r--libhw_cr/w5500.c150
-rw-r--r--libhw_cr/w5500_ll.c116
-rw-r--r--libhw_cr/w5500_ll.h210
-rw-r--r--libhw_generic/CMakeLists.txt8
-rw-r--r--libhw_generic/alarmclock.c16
-rw-r--r--libhw_generic/include/libhw/generic/alarmclock.h26
-rw-r--r--libhw_generic/include/libhw/generic/io.h193
-rw-r--r--libhw_generic/include/libhw/generic/net.h59
-rw-r--r--libhw_generic/include/libhw/generic/spi.h8
-rw-r--r--libhw_generic/io.c45
-rw-r--r--libhw_generic/net.c12
-rw-r--r--libhw_generic/tests/test_io.c8
-rw-r--r--libmisc/CMakeLists.txt16
-rw-r--r--libmisc/assert.c6
-rw-r--r--libmisc/endian.c136
-rw-r--r--libmisc/error.c35
-rw-r--r--libmisc/error_generated.c186
-rwxr-xr-xlibmisc/error_generated.c.gen35
-rw-r--r--libmisc/fmt.c97
-rw-r--r--libmisc/hash.c24
-rw-r--r--libmisc/include/libmisc/alloc.h17
-rw-r--r--libmisc/include/libmisc/assert.h11
-rw-r--r--libmisc/include/libmisc/endian.h219
-rw-r--r--libmisc/include/libmisc/error.h171
-rw-r--r--libmisc/include/libmisc/fmt.h55
-rw-r--r--libmisc/include/libmisc/hash.h24
-rw-r--r--libmisc/include/libmisc/log.h4
-rw-r--r--libmisc/include/libmisc/macro.h36
-rw-r--r--libmisc/include/libmisc/map.h20
-rw-r--r--libmisc/include/libmisc/obj.h144
-rw-r--r--libmisc/include/libmisc/rand.h32
-rw-r--r--libmisc/include/libmisc/utf8.h25
-rw-r--r--libmisc/intercept.c2
-rw-r--r--libmisc/log.c5
-rw-r--r--libmisc/map.c2
-rw-r--r--libmisc/rand.c38
-rw-r--r--libmisc/tests/test_assert.c5
-rw-r--r--libmisc/tests/test_fmt.c73
-rw-r--r--libmisc/tests/test_log.c1
-rw-r--r--libmisc/tests/test_macro.c9
-rw-r--r--libmisc/tests/test_obj.c8
-rw-r--r--libmisc/tests/test_obj_autobox.c77
-rwxr-xr-xlibmisc/tests/test_obj_autobox.c.gen17
-rw-r--r--libmisc/tests/test_obj_nest.c33
-rw-r--r--libmisc/tests/test_rand.c2
-rw-r--r--libmisc/utf8.c44
-rwxr-xr-xlibmisc/wrap-cc186
-rw-r--r--libusb/usb_common.c15
-rw-r--r--notes.md193
179 files changed, 7216 insertions, 4703 deletions
diff --git a/.editorconfig b/.editorconfig
index c632054..ced4c65 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -45,13 +45,13 @@ _mode = gitignore
# By specific filename (non-lib9p) #############################################
-[{build-aux/lint-{generic,unknown},build-aux/embed-sources.h.gen}]
+[{build-aux/embed-sources.h.gen,build-aux/valgrind,libmisc/tests/test_obj_autobox.c.gen}]
_mode = sh
-[{build-aux/lint-{bin,h},build-aux/get-dscname,build-aux/valgrind,libusb/include/libusb/tusb_helpers.h.gen}]
+[{build-aux/lint-{src,bin},build-aux/gcov-prune,libmisc/error_generated.c.gen,libusb/include/libusb/tusb_helpers.h.gen}]
_mode = bash
-[build-aux/stack.c.gen]
+[{build-aux/stack.c.gen,build-aux/tent-graph,libmisc/wrap-cc}]
_mode = python3
indent_style = space
indent_size = 4
@@ -67,10 +67,10 @@ _mode = 9p-idl
[lib9p/tests/*.explog]
_mode = 9p-log
-[{lib9p/tests/test_server/static.h.gen,lib9p/tests/test_compile.c.gen}]
+[lib9p/tests/test_server/static.h.gen]
_mode = sh
-[{lib9p/linux-errno.txt.gen,lib9p/tests/runtest,lib9p/tests/testclient-p9p}]
+[{lib9p/linux-errno.txt.gen,lib9p/srv_generated.c.gen,lib9p/tests/test_compile.c.gen,lib9p/tests/runtest,lib9p/tests/testclient-p9p}]
_mode = bash
[{lib9p/core.gen,lib9p/idl/2010-9P2000.L.9p.gen}]
diff --git a/.gitignore b/.gitignore
index e1f5883..9d27e6a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,11 +1,13 @@
# .gitignore - Which files to ignore
#
-# 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
*.o
*.log
*.tmp
+*.gcov.json.gz
+
.mypy_cache/
__pycache__/
.gdb_history
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5ce49ed..2d40b05 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -44,6 +44,11 @@ function(_suppress_tinyusb_warnings)
COMPILE_OPTIONS "-Wno-switch-enum")
endfunction()
+if (PICO_PLATFORM STREQUAL "host")
+ add_compile_options(--coverage)
+ add_link_options(--coverage)
+endif()
+
function(target_embed_sources arg_compile_target arg_link_target arg_hdrname)
set(embed_objs)
foreach(embed_src IN LISTS ARGN)
@@ -159,4 +164,5 @@ add_subdirectory(libusb)
add_subdirectory(lib9p)
add_subdirectory(lib9p_util)
-add_subdirectory(cmd/sbc_harness)
+add_subdirectory(flashimg/cpu_main)
+add_subdirectory(flashimg/cpu_hdmi)
diff --git a/GNUmakefile b/GNUmakefile
index e5e59b2..272306a 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -33,10 +33,18 @@ generate/files += 3rd-party/COPYING.newlib.txt
3rd-party/COPYING.newlib.txt: /usr/share/licenses/arm-none-eabi-newlib/COPYING.NEWLIB
cp $< $@
+generate/files += libmisc/tests/test_obj_autobox.c
+libmisc/tests/test_obj_autobox.c: %: %.gen libmisc/tests/test_obj_nest.c
+ $^ $@
+
generate/files += 3rd-party/linux-errno.txt
3rd-party/linux-errno.txt: lib9p/linux-errno.txt.gen
$< $(linux.git) $@
+generate/files += libmisc/error_generated.c
+libmisc/error_generated.c: %: %.gen libmisc/include/libmisc/error.h
+ $^ $@
+
generate/files += lib9p/idl/2010-9P2000.L.9p
lib9p/idl/2010-9P2000.L.9p: %: %.gen 3rd-party/linux-errno.txt
$^ >$@
@@ -45,6 +53,10 @@ generate/files += lib9p/core_generated.c lib9p/core_include/lib9p/_core_generate
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/srv_generated.c
+lib9p/srv_generated.c: %: %.gen libmisc/include/libmisc/error.h
+ $^ $@
+
generate/files += lib9p/tests/test_compile.c
lib9p/tests/test_compile.c: %: %.gen lib9p/core_include/lib9p/_core_generated.h
$^ $@
@@ -57,18 +69,28 @@ generate/files += build-aux/sources.mk
ifeq ($(INNER),)
nonsource/files = $(generate/files)
nonsource/files += 3rd-party/COPYING.wiznet-dhcp.txt
+# 100644 blob/regular file
+# 100755 blob/executable file
+# 120000 blob/symlink
+# 160000 commit (submodule)
+# 040000 tree (directory)
build-aux/sources.mk: $(if $(wildcard .git),FORCE)
- git ls-files | grep -vFx $(foreach f,$(nonsource/files),-e $f) \
- | sed 's,^,$(CURDIR)/,' | xargs editorconfig \
- | sed -nE -e 's,\[$(CURDIR)/(.*)\],\1,p' -e 's/^_mode=//p' \
- | sed -E '{N;s/(.*)\n(.*)/sources_\2 += \1/;}' \
- | sort \
+ git ls-files --format='%(objectmode) %(path)' \
+ | sed -n 's/^100... //p' \
+ | grep -vFx $(foreach f,$(nonsource/files),-e $f) \
+ | sed 's,^,$(CURDIR)/,' | xargs editorconfig \
+ | sed -nE -e 's,\[$(CURDIR)/(.*)\],\1,p' -e 's/^_mode=//p' \
+ | sed -E '{N;s/(.*)\n(.*)/sources_\2 += \1/;}' \
+ | sort \
>$@.tmp
if ! cmp -s $@.tmp $@; then mv $@.tmp $@; fi
@echo '################################################################################'
endif
+generate:
+ifeq ($(INNER),)
generate: $(generate/files)
+endif
.PHONY: generate
generate-clean:
@@ -77,26 +99,50 @@ generate-clean:
# `build` and `check` ##########################################################
-platforms := rp2040 host # $(shell sed -nE 's/if *\(PICO_PLATFORM STREQUAL "(.*)"\)/\1/p' cmd/*/CMakeLists.txt)
+# define the matrix
+
+platforms_build = rp2040
+platforms_check = host
+platforms = $(platforms_build) $(platforms_check)
build_types = Debug Release RelWithDebInfo MinSizeRel
-build: $(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/build))
+# span the matrix
+
+build: $(foreach t,$(build_types),$(foreach p,$(platforms_build),build/$p-$t/build))
.PHONY: build
+build-check: $(foreach t,$(build_types),$(foreach p,$(platforms_check),build/$p-$t/build))
+.PHONY: build-check
+
+check: generate
+ $(MAKE) -k INNER=t $(foreach t,$(build_types),$(foreach p,$(platforms_check),build/$p-$t/check))
+.PHONY: check
+
+# define the cells
+
+# build/{matrix}/Makefile
$(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/Makefile)): build/%/Makefile:
mkdir -p $(@D) && cd $(@D) && cmake -DPICO_PLATFORM=$(firstword $(subst -, ,$*)) -DCMAKE_BUILD_TYPE=$(lastword $(subst -, ,$*)) ../..
+# build/{matrix}/build
$(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/build)): build/%/build: build/%/Makefile generate
$(MAKE) -C $(<D)
.PHONY: $(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/build))
-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/%/build
+# build/{matrix}/check
+#
+# `gcc` writes .gcno
+# Running the program writes .gcda (updates existing files, concurrent-safe)
+# GCC `gcov` post-processes .gcno+.gcda to .gcov
+# `gcovr` is a Python script that calls `gcov` and merges and post-processes the .gcov files to other formats
+gcovr_flags = --txt=$(@D)/coverage.txt
+gcovr_flags += --html=$(@D)/coverage.html --html-details --html-single-page=js-enabled
+gcovr_flags += --sort uncovered-number --sort-reverse
+$(foreach t,$(build_types),$(foreach p,$(platforms_check),build/$p-$t/check)): build/%/check: build/%/build
+ ./build-aux/gcov-prune $(@D)
+cd $(@D) && ctest --output-on-failure $(if $(filter --jobserver-auth=%,$(MAKEFLAGS)),--parallel)
-.PHONY: $(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/check))
+ gcovr $(gcovr_flags) -- $(@D)
+.PHONY: $(foreach t,$(build_types),$(foreach p,$(platforms_check),build/$p-$t/check))
# `lint` and `format` ##########################################################
@@ -108,47 +154,30 @@ build-aux/venv: build-aux/requirements.txt
$@/bin/pip install -r $<
touch --no-create $@
+flashimgs = $(patsubst flashimg/%/CMakeLists.txt,%,$(filter flashimg/%/CMakeLists.txt,$(sources_cmake)))
+
# `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: lint/src .WAIT lint/bin
+lint/src:
+ $(MAKE) -k INNER=t $(patsubst sources_%,lint/%,$(filter-out sources_all,$(filter sources_%,$(.VARIABLES))))
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_$*)
+ ./build-aux/lint-bin $(foreach i,$(flashimgs),$(foreach t,$(build_types),$(foreach p,$(platforms_build),build/$p-$t/flashimg/$i/$i.elf)))
+$(patsubst sources_%,lint/%,$(filter-out sources_all,$(filter sources_%,$(.VARIABLES)))): build-aux/lint-src
+ ./build-aux/lint-src $(@F) $(sources_$(@F))
+lint/python3: build-aux/venv
.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/core.gen lib9p/core_gen/*.py
- ./build-aux/venv/bin/pytest $(foreach f,$(sources_python3),$(if $(filter test_%.py,$(notdir $f)),$f))
-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` #############################
# generic ##########
-format:
- $(MAKE) -k INNER=t $(patsubst sources_%,format/%,$(filter-out sources_all sources_unknown,$(filter sources_%,$(.VARIABLES))))
+format: $(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/make format/cmake format/gitignore format/ini format/9p-idl format/9p-log format/markdown format/pip format/man-cat: format/%:
+ shfmt --write --case-indent --simplify $(sources_$(@F))
+format/python3: ./build-aux/venv
+ ./build-aux/venv/bin/black $(sources_$(@F))
+ ./build-aux/venv/bin/isort $(sources_$(@F))
+format/make format/cmake format/gitignore format/ini format/9p-idl format/9p-log format/markdown format/pip format/man-cat:
@: TODO: Write/adopt formatters for these file types
diff --git a/HACKING.md b/HACKING.md
index 3403b45..04835f1 100644
--- a/HACKING.md
+++ b/HACKING.md
@@ -27,7 +27,7 @@ Libraries for generic parts of what the harness is doing:
- `libdhcp/`: A DHCP client
- `libusb/`: Wrapper and utilities for TinyUSB
- - `cmd/sbc_harness/`: The main firmware image
+ - `flashimg/cpu_main/`: The main firmware image
- `3rd-party/`: Sources from third parties; some definitions of
things (USB language codes, Linux kernel errnos), and the Pico-SDK
(for the RP2040 CPU, and its included TinyUSB). Does not include
@@ -153,7 +153,7 @@ Example use:
> - `openocd -f interface/cmsis-dap.cfg -c 'set USE_CORE 0' -f target/rp2040.cfg -c "adapter speed 5000"`
> (Explanation of `USE_CORE`: https://github.com/raspberrypi/debugprobe/issues/45)
> In another terminal:
-> - `arm-none-eabi-gdb ./build/rp2040-Debug/cmd/sbc_harness/sbc_harness.elf`
+> - `arm-none-eabi-gdb ./build/rp2040-Debug/flashimg/cpu_main/cpu_main.elf`
> ```
> target extended-remote localhost:3333
> monitor reset init
diff --git a/PLAN.md b/PLAN.md
deleted file mode 100644
index 3201122..0000000
--- a/PLAN.md
+++ /dev/null
@@ -1,31 +0,0 @@
-<!--
- PLAN.md - Misc planning notes
-
- 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)
- 3. [ ] forward port 21 as a USB keyboard
- 4. [ ] forward a 9p file as a USB keyboard
- 5. [ ] connect UART as a 9p socket
-- waiting on hardware:
- - sdcard slot:
- 1. [ ] whatever the "hello world" of SD is
- 2. [ ] as a device on 9p
- - HDMI socket
- 1. [ ] PicoDVI hello-world
- 2. [ ] "PiciDVI" to network
- 3. [ ] reverse the flow of PicoDVI
diff --git a/README.md b/README.md
index 4ad8158..8b7cb10 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,7 @@ At the time of this writing, on Parabola GNU/Linux-libre that means:
- picotool 2.1.1-1
Then, simply run `make`. This will create
-`build/rp2040-*/cmd/sbc_harness/sbc_harness.{elf,bin,hex,uf2}` files:
+`build/rp2040-*/flashimg/cpu_main/cpu_main.{elf,bin,hex,uf2}` files:
- The `.elf` is the firmware image plus debugger symbols and
relocation data.
@@ -48,20 +48,19 @@ There are several ways of putting this firmware file onto the harness:
harness will appear to a host PC as a USB storage device. Simply
mount the device and copy the `.uf2` file to the device. It will
automatically reboot into the new firmware image.
- 2. debug port: Using OpenOCD (see `HACKING.md`), run the OpenOCD command
- `program /path/to/sbc_harness.elf reset` (TODO: I don't really
- understand what OpenOCD is doing that it wants the `.elf` instead
- of the `.bin`)
- .
+ 2. debug port: Using OpenOCD (see `HACKING.md`), run the OpenOCD
+ command `program /path/to/cpu_main.elf reset` (TODO: I don't
+ really understand what OpenOCD is doing that it wants the `.elf`
+ instead of the `.bin`) .
If OpenOCD is not already running:
```
- openocd -f interface/cmsis-dap.cfg -f target/rp2040.cfg -c "program $PWD/build/rp2040-Debug/cmd/sbc_harness/sbc_harness.elf reset exit"`
+ openocd -f interface/cmsis-dap.cfg -f target/rp2040.cfg -c 'adapter speed 5000' -c "program $PWD/build/rp2040-Debug/flashimg/cpu_main/cpu_main.elf reset exit"
```
If OpenOCD is already running:
```
- socat STDIO TCP:localhost:4444 <<<"program $PWD/build/rp2040-Debug/cmd/sbc_harness/sbc_harness.elf reset"
+ socat STDIO TCP:localhost:4444 <<<"program $PWD/build/rp2040-Debug/flashimg/cpu_main/cpu_main.elf reset"
```
3. Use `flashprog` or `flashrom` and a SOIC-8 clip to directly
program the flash chip. I'm not sure why you would do this
diff --git a/build-aux/gcov-prune b/build-aux/gcov-prune
new file mode 100755
index 0000000..dc190a9
--- /dev/null
+++ b/build-aux/gcov-prune
@@ -0,0 +1,33 @@
+#!/usr/bin/env bash
+# build-aux/gcov-prune - Prune old GCC coverage files
+#
+# Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+set -e
+
+[[ $# == 1 ]]
+
+sourcedir="$(realpath -- .)"
+builddir="$(realpath -- "$1")"
+
+# `gcc` writes .gcno
+# Running the program writes .gcda (updates existing files, concurrent-safe)
+# GCC `gcov` post-processes .gcno+.gcda to .gcov
+# `gcovr` is a Python script that calls `gcov` and merges and post-processes the .gcov files to other formats
+
+# Prune orphaned .gcno files.
+find "$builddir" -name '*.gcno' -printf '%P\0' | while read -d '' -r gcno_file; do
+ rel_base="${gcno_file%/CMakeFiles/*}"
+ src_file="$gcno_file"
+ src_file="${src_file#*/CMakeFiles/*.dir/}"
+ src_file="${src_file%.gcno}"
+ src_file="${src_file//__/..}"
+ src_file="$rel_base/$src_file"
+ if [[ ! -e "$sourcedir/$src_file" || "$sourcedir/$src_file" -nt "$builddir/$gcno_file" ]]; then
+ rm -fv -- "$builddir/$gcno_file"
+ fi
+done
+
+# Prune all .gcda files.
+find "$builddir" -name '*.gcda' -delete
diff --git a/build-aux/get-dscname b/build-aux/get-dscname
deleted file mode 100755
index 34a1b08..0000000
--- a/build-aux/get-dscname
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/usr/bin/env bash
-# build-aux/get-dscname - Get a file's self-described filename
-#
-# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
-# SPDX-License-Identifier: AGPL-3.0-or-later
-
-if [ $# -ne 1 ]; then
- echo "$0: expected exactly 1 argument"
- exit 2
-fi
-
-if [[ $1 == */Documentation/* ]] && [[ "$(sed 1q -- "$1")" == 'NAME' ]]; then
- sed -n '
- 2{
- s,[/.],_,g;
- s,^\s*_,Documentation/,;
- s,$,.txt,;
-
- p;
- q;
- }
- ' -- "$1"
-else
- sed -n '
- 1,3{
- /^\#!/d;
- /^<!--$/d;
- /-\*- .* -\*-/d;
- s,[/*\# ]*,,;
- s/ - .*//;
-
- p;
- q;
- }
- ' -- "$1"
-fi
diff --git a/build-aux/lint-bin b/build-aux/lint-bin
index 19d3a3b..3b9eb4b 100755
--- a/build-aux/lint-bin
+++ b/build-aux/lint-bin
@@ -18,7 +18,7 @@ shopt -s extglob
# Textual info:
# - ${elf%.elf}.dis : `objdump --section-headers ${elf}; objdump --disassemble ${elf}; picotool coprodis --quiet ${elf}`
# - ${elf}.map : `ld --print-map` info
-# - ${elf%.elf}_stack.c : `stack.c.gen`
+# - stack.c : `stack.c.gen`
RED=$(tput setaf 1)
RESET=$(tput sgr0)
@@ -97,13 +97,13 @@ lint_stack() {
while read -r line; do
func=${line#$'\t'}
if [[ $line == $'\t'* ]]; then
- err "$in_elffile" "function in binary but not _stack.c: ${func}"
+ err "$in_elffile" "function in binary but not stack.c: ${func}"
else
- err "$in_elffile" "function in _stack.c but not binary: ${func}"
+ err "$in_elffile" "function in stack.c but not binary: ${func}"
fi
done < <(
comm -3 \
- <(sed -En 's/^included: (.*:)?//p' "${in_elffile%.elf}_stack.c" | sort -u) \
+ <(sed -En 's/^included: (.*:)?//p' "${in_elffile%/*}/stack.c" | sort -u) \
<(readelf_funcs "$in_elffile" | sed -E -e 's/\.part\.[0-9]*$//' -e 's/^__(.*)_veneer$/\1/' | sort -u)
)
}
@@ -132,6 +132,12 @@ main() {
{
echo 'Global variables:'
lint_globals "${elf}.map" | sed 's/^/ /'
+ echo
+ heap=$(grep -B1 'HeapLimit =' -- "${elf}.map" |
+ sed -E -e 's/^\s*(\.heap\s*)?0x/0x/' -e 's/\s.*//' |
+ sed -E -e '1{N;s/(.*)\n(.*)/\2-\1/;}' -e 's/.*/print(&)/' |
+ python)
+ printf "Left for heap: 0x%04x (%'d)\n" "$heap" "$heap"
} >"${elf%.elf}.lint.globals"
(lint_stack "$elf") &>"${elf%.elf}.lint.stack"
lint_func_blocklist "$elf"
diff --git a/build-aux/lint-generic b/build-aux/lint-generic
deleted file mode 100755
index 70e814a..0000000
--- a/build-aux/lint-generic
+++ /dev/null
@@ -1,60 +0,0 @@
-#!/bin/sh
-# build-aux/lint-generic - Non-language-specific lint checks
-#
-# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
-# SPDX-License-Identifier: AGPL-3.0-or-later
-
-RED=$(tput setaf 1)
-RESET=$(tput sgr0)
-
-err() {
- printf "${RED}%s${RESET}: %s\n" "$1" "$2" >&2
- r=1
-}
-
-r=0
-for filename in "$@"; do
- if ! { [ -f "$filename" ] && ! [ -h "$filename" ]; }; then
- # Ignore non-files
- continue
- fi
-
- # File header ##########################################################
-
- shebang="$(sed -n '1{/^#!/{/^#!\/hint\//q; p;};}' "$filename")"
- 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 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
-
- dscname_act=$(./build-aux/get-dscname "$filename")
- dscname_exp=$(echo "$filename" | sed \
- -e 's,.*/config/,,' \
- -e 's,.*/config\.h$,config.h,' \
- -e 's,.*include/,,' \
- -e 's,.*static/,,' \
- -e 's/\.wip$//')
- if [ "$dscname_act" != "$dscname_exp" ] && [ "cmd/$dscname_act" != "$dscname_exp" ]; then
- err "$filename" "self-identifies as $dscname_act (expected $dscname_exp)"
- fi
-
- # File body ############################################################
-
- if grep -n --color=auto "$(printf '\\S\t')" "$filename"; then
- err "$filename" 'uses tabs for alignment'
- fi
-done
-exit $r
diff --git a/build-aux/lint-h b/build-aux/lint-h
deleted file mode 100755
index 7459032..0000000
--- a/build-aux/lint-h
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/usr/bin/env bash
-# build-aux/lint-h - Lint checks for C header files
-#
-# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
-# SPDX-License-Identifier: AGPL-3.0-or-later
-
-RED=$(tput setaf 1)
-RESET=$(tput sgr0)
-
-err() {
- printf "${RED}%s${RESET}: %s\n" "$1" "$2" >&2
- r=1
-}
-
-r=0
-for filename in "$@"; do
- dscname=$(./build-aux/get-dscname "$filename")
- guard=${dscname//'/'/'_'}
- guard=${guard//'.'/'_'}
- guard="_${guard^^}_"
- 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
-exit $r
diff --git a/build-aux/lint-src b/build-aux/lint-src
new file mode 100755
index 0000000..d536631
--- /dev/null
+++ b/build-aux/lint-src
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+# build-aux/lint-src - Lint checks for source files
+#
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+RED=$(tput setaf 1)
+RESET=$(tput sgr0)
+
+err() {
+ printf "${RED}%s${RESET}: %s\n" "$1" "$2" >&2
+ r=1
+}
+
+# `get-dscname FILENAME` reads FILENAME and prints the name that the
+# comment at the top of the file self-identifies the file as.
+get-dscname() {
+ if [[ $1 == */Documentation/* && "$(sed 1q -- "$1")" == 'NAME' ]]; then
+ sed -n '
+ 2{
+ s,/,_,g;
+ s,^\s*_,Documentation/,;
+ s,$,.txt,;
+
+ p;
+ q;
+ }
+ ' -- "$1"
+ else
+ sed -n '
+ 1,3{
+ /^\#!/d;
+ /^<!--$/d;
+ /-\*- .* -\*-/d;
+ s,[/*\# ]*,,;
+ s/ - .*//;
+
+ p;
+ q;
+ }
+ ' -- "$1"
+ fi
+}
+
+{
+ filetype=$1
+ filenames=("${@:2}")
+
+ r=0
+ for filename in "${filenames[@]}"; do
+ # File header ##########################################################
+
+ shebang="$(sed -n '1{/^#!/p;}' "$filename")"
+ if [[ -x $filename && (-z $shebang || $shebang == '#!/hint/'*) ]]; then
+ err "$filename" 'is executable but does not have a shebang'
+ elif [[ (-n $shebang && $shebang != '#!/hint/'*) && ! -x $filename ]]; then
+ err "$filename" 'has a shebang but is not executable'
+ fi
+ case "$shebang" in
+ '') : ;;
+ '#!/bin/sh') : ;;
+ '#!/usr/bin/env bash') : ;;
+ '#!/usr/bin/env python3') : ;;
+ *) err "$filename" 'has an unrecognized shebang' ;;
+ esac
+ if [[ -n $shebang && $shebang != */"$filetype" && $shebang != *' '"$filetype" ]]; then
+ err "$filename" "wrong shebang for $filetype"
+ 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
+
+ dscname_act=$(get-dscname "$filename")
+ dscname_exp=$(echo "$filename" | sed \
+ -e 's,.*include/,,' \
+ -e 's,.*static/,,' \
+ -e 's/\.wip$//')
+ if [[ $dscname_act != "$dscname_exp" ]]; then
+ err "$filename" "self-identifies as $dscname_act (expected $dscname_exp)"
+ fi
+
+ # File body ############################################################
+
+ if grep -n --color=auto $'\\S\t' "$filename"; then
+ err "$filename" 'uses tabs for alignment'
+ fi
+ done
+ case "$filetype" in
+ unknown)
+ for filename in "${filenames[@]}"; do
+ err "$filename" 'cannot lint unknown file type'
+ done
+ ;;
+ c)
+ for filename in "${filenames[@]}"; do
+ if [[ $filename == *.h ]]; then
+ dscname=$(get-dscname "$filename")
+ guard=$dscname
+ guard=${guard#*/config/}
+ if [[ $guard == */config.h ]]; then
+ guard=config.h
+ fi
+ guard=${guard//'/'/'_'}
+ guard=${guard//'.'/'_'}
+ guard="_${guard^^}_"
+ 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
+ if [[ $filename != libmisc/include/libmisc/obj.h ]] &&
+ grep -Fn --color=auto -e LO_IMPLEMENTATION_C -e LO_IMPLEMENTATION_STATIC "$filename"; then
+ err "$filename" "contains LO_IMPLEMENTATION_C and/or LO_IMPLEMENTATION_STATIC"
+ fi
+ fi
+ if [[ $filename == *.c ]]; then
+ if [[ $filename != libmisc/tests/test_obj.c ]] &&
+ grep -Fn --color=auto L_IMPLEMENTATION_H "$filename"; then
+ err "$filename" "contains LO_IMPLEMENTATION_H"
+ fi
+ fi
+ done
+ ;;
+ sh | bash)
+ shellcheck "${filenames[@]}" || exit $?
+ shfmt --diff --case-indent --simplify "${filenames[@]}" || exit $?
+ ;;
+ python3)
+ ./build-aux/venv/bin/mypy --strict --scripts-are-modules "${filenames[@]}" || exit $?
+ ./build-aux/venv/bin/black --check "${filenames[@]}" || exit $?
+ ./build-aux/venv/bin/isort --check "${filenames[@]}" || exit $?
+ ./build-aux/venv/bin/pylint "${filenames[@]}" || exit $?
+ if grep -nh 'SPECIAL$$' -- lib9p/core.gen lib9p/core_gen/*.py; then exit 1; fi
+ testfiles=()
+ for filename in "${filenames[@]}"; do
+ if [[ ${filename##*/} == test_*.py ]]; then
+ testfiles+=("$filename")
+ fi
+ done
+ ./build-aux/venv/bin/pytest "${testfiles[@]}" || exit $?
+ ;;
+ make | cmake | gitignore | ini | 9p-idl | 9p-log | markdown | pip | man-cat)
+ # TODO: Write/adopt linters for these file types
+ :
+ ;;
+ *)
+ err "$0" "unknown filetype: ${filetype}"
+ ;;
+ esac
+ exit $r
+}
diff --git a/build-aux/lint-unknown b/build-aux/lint-unknown
deleted file mode 100755
index dda9541..0000000
--- a/build-aux/lint-unknown
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/sh
-# build-aux/lint-unknown - Lint checks for unknown files
-#
-# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
-# SPDX-License-Identifier: AGPL-3.0-or-later
-
-RED=$(tput setaf 1)
-RESET=$(tput sgr0)
-
-err() {
- printf "${RED}%s${RESET}: %s\n" "$1" "$2" >&2
- r=1
-}
-
-r=0
-for filename in "$@"; do
- if ! { [ -f "$filename" ] && ! [ -h "$filename" ]; }; then
- # Ignore non-files
- continue
- fi
-
- err "$filename" 'cannot lint unknown file type'
-done
-exit $r
diff --git a/build-aux/measurestack/analyze.py b/build-aux/measurestack/analyze.py
index 97f1769..f151642 100644
--- a/build-aux/measurestack/analyze.py
+++ b/build-aux/measurestack/analyze.py
@@ -268,6 +268,7 @@ class SkipModel(typing.NamedTuple):
class Application(typing.Protocol):
def extra_nodes(self) -> typing.Collection[Node]: ...
+ def mutate_node(self, node: Node) -> None: ...
def indirect_callees(
self, elem: vcg.VCGElem
) -> tuple[typing.Collection[QName], bool]: ...
@@ -448,6 +449,9 @@ def _make_graph(
raise ValueError(f"unknown caller: {caller}")
if callee == QName("__indirect_call"):
callees, missing_ok = app.indirect_callees(elem)
+ assert (
+ len(callees) > 0
+ ), f"app returning 0 callees for {elem.attrs.get('label')} indicates the code would crash"
for callee in maybe_sorted(callees):
if callee not in graph[caller].calls:
graph[caller].calls[callee] = missing_ok
@@ -469,6 +473,9 @@ def _make_graph(
raise ValueError(f"duplicate node {node.funcname}")
graph[node.funcname] = node
+ for node in graph.values():
+ app.mutate_node(node)
+
ret = _Graph()
ret.graph = graph
ret.qualified = {}
diff --git a/build-aux/measurestack/app_main.py b/build-aux/measurestack/app_main.py
index 4fdfd5c..884aeee 100644
--- a/build-aux/measurestack/app_main.py
+++ b/build-aux/measurestack/app_main.py
@@ -67,6 +67,7 @@ def main(
plugins += [
app_plugins.PicoSDKPlugin(
get_init_array=get_init_array,
+ PICO_PANIC_FUNCTION="assert_panic",
),
app_plugins.TinyUSBDevicePlugin(arg_c_fnames),
app_plugins.NewlibPlugin(),
@@ -89,9 +90,6 @@ def main(
QName("__assert_msg_fail"),
]:
return 1, False
- for prefix in ["fmt_print_", "_fmt_print_"]:
- if str(name.base()).startswith(prefix):
- return 1, False
if str(name.base()).endswith("_putb"):
return 1, False
return 0, False
diff --git a/build-aux/measurestack/app_output.py b/build-aux/measurestack/app_output.py
index 5336b85..5cf7d17 100644
--- a/build-aux/measurestack/app_output.py
+++ b/build-aux/measurestack/app_output.py
@@ -1,4 +1,4 @@
-# build-aux/measurestack/app_output.py - Generate `*_stack.c` files
+# build-aux/measurestack/app_output.py - Generate `stack.c` files
#
# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
# SPDX-License-Identifier: AGPL-3.0-or-later
@@ -51,14 +51,14 @@ def print_group(
print(sep1)
-def next_power_of_2(x: int) -> int:
- return 1 << (x.bit_length())
+def lm_round_up(n: int, d: int) -> int:
+ return ((n + d - 1) // d) * d
def print_c(
result: analyze.AnalyzeResult, location_xform: typing.Callable[[QName], str]
) -> None:
- print("#include <stddef.h> /* for size_t */")
+ print('#include "config.h" /* for COROUTINE_STACK_* extern declarations */')
print()
print("/*")
print_group(result, location_xform, "Threads")
@@ -75,6 +75,9 @@ def print_c(
base: int
size: int
+ print("[[gnu::aligned]] void _bogus_aligned_fn(void) {};")
+ print("#define STACK_ALIGNED [[gnu::aligned(__alignof__(_bogus_aligned_fn))]]")
+
rows: list[CrRow] = []
mainrow: CrRow | None = None
for funcname, val in result.groups["Threads"].rows.items():
@@ -84,20 +87,20 @@ def print_c(
if name in ["main", "_entry_point"]:
mainrow = CrRow(name=name, cnt=1, base=base, size=size)
else:
- size = next_power_of_2(size + stack_guard_size) - stack_guard_size
+ size = lm_round_up(size + stack_guard_size, 512)
rows.append(CrRow(name=name, cnt=val.cnt, base=base, size=size))
- namelen = max(len(r.name) for r in rows)
+ namelen = max(len(f"{r.name}{r.cnt}" if r.cnt > 1 else r.name) for r in rows)
baselen = max(len(str(r.base)) for r in rows)
sizesum = sum(r.cnt * (r.size + stack_guard_size) for r in rows)
sizelen = len(str(max(sizesum, mainrow.size if mainrow else 0)))
def print_row(comment: bool, name: str, size: int, eqn: str | None = None) -> None:
- prefix = "const size_t CONFIG_COROUTINE_STACK_SIZE_"
+ prefix = "STACK_ALIGNED char COROUTINE_STACK_"
if comment:
print(f"/* {name}".ljust(len(prefix) + namelen), end="")
else:
print(f"{prefix}{name:<{namelen}}", end="")
- print(f" = {size:>{sizelen}};", end="")
+ print(f"[{size:>{sizelen}}];", end="")
if comment:
print(" */", end="")
elif eqn:
@@ -107,13 +110,15 @@ def print_c(
print()
for row in sorted(rows):
- print_row(
- False,
- row.name,
- row.size,
- f"LM_NEXT_POWER_OF_2({row.base:>{baselen}}+{intrstack}+{stack_guard_size})-{stack_guard_size}",
+ comment = (
+ f"LM_ROUND_UP({row.base:>{baselen}}+{intrstack}+{stack_guard_size}, 512)"
)
- print_row(True, "TOTAL (inc. stack guard)", sizesum)
+ if row.cnt > 1:
+ for i in range(row.cnt):
+ print_row(False, f"{row.name}{i}", row.size, comment)
+ else:
+ print_row(False, row.name, row.size, comment)
+ print_row(True, "TOTAL", sizesum)
if mainrow:
print_row(
True,
@@ -122,6 +127,19 @@ def print_c(
f" {mainrow.base:>{baselen}}+{intrstack}",
)
print()
+ for row in sorted(rows):
+ name = row.name
+ if row.cnt > 1:
+ name += "0"
+ print(f"char *const COROUTINE_STACK_{row.name}[{row.cnt}] = {{")
+ for i in range(row.cnt):
+ print(f"\tCOROUTINE_STACK_{row.name}{i},")
+ print("};")
+ print(
+ f"const size_t COROUTINE_STACK_{row.name}_len = sizeof(COROUTINE_STACK_{name});"
+ )
+
+ print()
print("/*")
print_group(result, location_xform, "Misc")
diff --git a/build-aux/measurestack/app_plugins.py b/build-aux/measurestack/app_plugins.py
index 6fc81ec..a921407 100644
--- a/build-aux/measurestack/app_plugins.py
+++ b/build-aux/measurestack/app_plugins.py
@@ -39,15 +39,35 @@ class CmdPlugin:
def extra_nodes(self) -> typing.Collection[Node]:
return []
+ def mutate_node(self, node: Node) -> None:
+ pass
+
def indirect_callees(
self, loc: str, line: str
) -> tuple[typing.Collection[QName], bool] | None:
if "/3rd-party/" in loc:
return None
if "srv->auth" in line:
- return [], False
+ return [QName("__indirect_call_with_null_check:srv->auth")], False
if "srv->rootdir" in line:
return [QName("get_root")], False
+ if "/ihex.c" in loc:
+ if "self->handle_data" in line:
+ return [QName("flash_handle_ihex_data")], False
+ if "self->handle_eof" in line:
+ return [QName("flash_handle_ihex_eof")], False
+ if "self->handle_set_exec_start_lin" in line:
+ return [
+ QName(
+ "__indirect_call_with_null_check:self->handle_set_exec_start_lin"
+ )
+ ], False
+ if "self->handle_set_exec_start_seg" in line:
+ return [
+ QName(
+ "__indirect_call_with_null_check:self->handle_set_exec_start_seg"
+ )
+ ], False
return None
def skipmodels(self) -> dict[BaseName, analyze.SkipModel]:
@@ -60,9 +80,12 @@ class LibMiscPlugin:
re_lo_iface = re.compile(r"^\s*#\s*define\s+(?P<name>\S+)_LO_IFACE")
re_lo_func = re.compile(r"LO_FUNC *\([^,]*, *(?P<name>[^,) ]+) *[,)]")
re_lo_implementation = re.compile(
- r"^LO_IMPLEMENTATION_[HC]\s*\(\s*(?P<iface>[^, ]+)\s*,\s*(?P<impl_typ>[^,]+)\s*,\s*(?P<impl_name>[^, ]+)\s*[,)].*"
+ r"^LO_IMPLEMENTATION_(?P<vis>H|C|STATIC)\s*\("
+ r"\s*(?P<iface>[^, ]+)\s*,"
+ r"\s*(?P<impl_typ>[^,]+)\s*,"
+ r"\s*(?P<impl_name>[^, ]+)\s*\)"
)
- re_call_objcall = re.compile(r"LO_CALL\((?P<obj>[^,]+), (?P<meth>[^,)]+)[,)].*")
+ re_lo_call = re.compile(r".*\bLO_CALL\((?P<obj>[^,]+), (?P<meth>[^,)]+)[,)].*")
objcalls: dict[str, set[QName]] # method_name => {method_impls}
@@ -114,14 +137,25 @@ class LibMiscPlugin:
def extra_nodes(self) -> typing.Collection[Node]:
return []
+ def mutate_node(self, node: Node) -> None:
+ pass
+
def indirect_callees(
self, loc: str, line: str
) -> tuple[typing.Collection[QName], bool] | None:
if "/3rd-party/" in loc:
return None
- if m := self.re_call_objcall.fullmatch(line):
- if m.group("meth") in self.objcalls:
- return self.objcalls[m.group("meth")], False
+ if m := self.re_lo_call.fullmatch(line):
+ meth = m.group("meth")
+ if meth in self.objcalls:
+ callees: typing.Collection[QName] = self.objcalls[meth]
+ if len(callees) == 0:
+ raise ValueError(f"{loc}: no implementors of {meth}")
+ if meth == "writev" and "lib9p/srv.c" in loc: # KLUDGE
+ callees = [
+ c for c in callees if c.base() != BaseName("rread_writev")
+ ]
+ return callees, False
return [
QName(f"__indirect_call:{m.group('obj')}.vtable->{m.group('meth')}")
], False
@@ -157,6 +191,9 @@ class LibHWPlugin:
def extra_nodes(self) -> typing.Collection[Node]:
return []
+ def mutate_node(self, node: Node) -> None:
+ pass
+
def indirect_callees(
self, loc: str, line: str
) -> tuple[typing.Collection[QName], bool] | None:
@@ -172,10 +209,13 @@ class LibHWPlugin:
]:
if f"{fn}(" in line:
return self.libmisc.indirect_callees(loc, f"LO_CALL(x, {fn[3:]})")
- if "io_read(" in line:
- return self.libmisc.indirect_callees(loc, "LO_CALL(x, readv)")
- if "io_writev(" in line:
- return self.libmisc.indirect_callees(loc, "LO_CALL(x, writev)")
+ for fn in [
+ "io_read",
+ "io_write",
+ ]:
+ if f"{fn}(" in line:
+ # Like above, but add a "v" to the end.
+ return self.libmisc.indirect_callees(loc, f"LO_CALL(x, {fn[3:]}v)")
if "trigger->cb(trigger->cb_arg)" in line:
ret = [
QName("alarmclock_sleep_intrhandler"),
@@ -215,6 +255,9 @@ class LibCRPlugin:
def extra_nodes(self) -> typing.Collection[Node]:
return []
+ def mutate_node(self, node: Node) -> None:
+ pass
+
def indirect_callees(
self, loc: str, line: str
) -> tuple[typing.Collection[QName], bool] | None:
@@ -237,6 +280,9 @@ class LibCRIPCPlugin:
def extra_nodes(self) -> typing.Collection[Node]:
return []
+ def mutate_node(self, node: Node) -> None:
+ pass
+
def indirect_callees(
self, loc: str, line: str
) -> tuple[typing.Collection[QName], bool] | None:
@@ -299,7 +345,7 @@ class Lib9PPlugin:
return int(eval(line)) # pylint: disable=eval-used
return None
- self._CONFIG_9P_MAX_CONNS = config_h_get("_CONFIG_9P_MAX_REQS")
+ self._CONFIG_9P_MAX_CONNS = config_h_get("_CONFIG_9P_MAX_CONNS")
self._CONFIG_9P_MAX_REQS = config_h_get("_CONFIG_9P_MAX_REQS")
# Read sources #########################################################
@@ -335,6 +381,9 @@ class Lib9PPlugin:
def extra_nodes(self) -> typing.Collection[Node]:
return []
+ def mutate_node(self, node: Node) -> None:
+ pass
+
re_table_call = re.compile(
r"\s*_lib9p_(?P<meth>validate|unmarshal|marshal)\(.*(?P<grp>[RT])msg.*\);\s*"
)
@@ -372,11 +421,13 @@ class PicoSDKPlugin:
get_init_array: typing.Callable[[], typing.Collection[QName]]
app_init_array: typing.Collection[QName] | None
app_preinit_array: typing.Collection[QName]
+ _PICO_PANIC_FUNCTION: str | None
def __init__(
self,
*,
get_init_array: typing.Callable[[], typing.Collection[QName]],
+ PICO_PANIC_FUNCTION: str | None,
) -> None:
# grep for '__attribute__((constructor))' / '[[gnu::constructor]]'.
self.get_init_array = get_init_array
@@ -410,6 +461,8 @@ class PicoSDKPlugin:
QName("runtime_init_install_ram_vector_table"),
]
+ self._PICO_PANIC_FUNCTION = PICO_PANIC_FUNCTION
+
def is_intrhandler(self, name: QName) -> bool:
return name.base() in [
BaseName("isr_invalid"),
@@ -468,7 +521,7 @@ class PicoSDKPlugin:
case "in_chars":
return [QName("stdio_uart_in_chars")], False
if "/newlib_interface.c:" in loc:
- if line == "*p)();":
+ if line == "(*p)();":
if self.app_init_array is None:
self.app_init_array = self.get_init_array()
return self.app_init_array, False
@@ -482,11 +535,6 @@ class PicoSDKPlugin:
def extra_nodes(self) -> typing.Collection[Node]:
ret = []
- # src/rp2_common/hardware_divider/include/hardware/divider_helper.S
- save_div_state_and_lr = 5 * 4
- # src/rp2_common/pico_divider/divider_hardware.S
- save_div_state_and_lr_64 = 5 * 4
-
# src/src/rp2_common/pico_crt0/crt0.S
for n in range(32):
ret += [synthetic_node(f"isr_irq{n}", 0, {"__unhandled_user_irq"})]
@@ -502,10 +550,16 @@ class PicoSDKPlugin:
synthetic_node("_reset_handler", 0, {"runtime_init", "main", "exit"}),
]
+ # src/rp2_common/pico_int64_ops/pico_int64_ops_aeabi.S
ret += [
- # src/rp2_common/pico_int64_ops/pico_int64_ops_aeabi.S
synthetic_node("__wrap___aeabi_lmul", 4),
- # src/rp2_common/pico_divider/divider_hardware.S
+ ]
+
+ # src/rp2_common/hardware_divider/include/hardware/divider_helper.S
+ save_div_state_and_lr = 5 * 4
+ # src/rp2_common/pico_divider/divider_hardware.S
+ save_div_state_and_lr_64 = 5 * 4
+ ret += [
# s32 aliases
synthetic_node("div_s32s32", 0, {"divmod_s32s32"}),
synthetic_node("__wrap___aeabi_idiv", 0, {"divmod_s32s32"}),
@@ -560,7 +614,10 @@ class PicoSDKPlugin:
# *_rem
synthetic_node("divod_s64s64_rem", 2 * 4, {"divmod_s64s64"}),
synthetic_node("divod_u64u64_rem", 2 * 4, {"divmod_u64u64"}),
- # src/rp2_common/pico_mem_ops/mem_ops_aeabi.S
+ ]
+
+ # src/rp2_common/pico_mem_ops/mem_ops_aeabi.S
+ ret += [
synthetic_node("__aeabi_mem_init", 0, {"rom_funcs_lookup"}),
synthetic_node(
"__wrap___aeabi_memset", 0, {"rom_func_lookup(ROM_FUNC_MEMSET)"}
@@ -576,7 +633,10 @@ class PicoSDKPlugin:
synthetic_node("__wrap_memset", 0, {"rom_func_lookup(ROM_FUNC_MEMSET)"}),
synthetic_node("__wrap___aeabi_memcpy", 0, {"__wrap_memcpy"}),
synthetic_node("__wrap_memcpy", 0, {"rom_func_lookup(ROM_FUNC_MEMCPY)"}),
- # src/rp2_common/pico_bit_ops/bit_ops_aeabi.S
+ ]
+
+ # src/rp2_common/pico_bit_ops/bit_ops_aeabi.S
+ ret += [
synthetic_node("__aeabi_bits_init", 0, {"rom_funcs_lookup"}),
synthetic_node("__wrap___clz", 0, {"__wrap___clzsi2"}),
synthetic_node("__wrap___clzl", 0, {"__wrap___clzsi2"}),
@@ -596,18 +656,34 @@ class PicoSDKPlugin:
synthetic_node("reverse32", 0, {"rom_func_lookup(ROM_FUNC_REVERSE32)"}),
synthetic_node("__revll", 0, {"reverse64"}),
synthetic_node("reverse64", 3 * 4, {"rom_func_lookup(ROM_FUNC_REVERSE32)"}),
- # src/rp2040/boot_stage2/boot2_${name,,}.S for name=W25Q080,
- # controlled by `#define PICO_BOOT_STAGE2_{name} 1` in
- # src/boards/include/boards/pico.h
+ ]
+
+ # src/rp2040/boot_stage2/boot2_${name,,}.S for name=W25Q080,
+ # controlled by `#define PICO_BOOT_STAGE2_{name} 1` in
+ # src/boards/include/boards/pico.h
+ ret += [
# synthetic_node("_stage2_boot", 0), # TODO
- # https://github.com/raspberrypi/pico-bootrom-rp2040
+ ]
+
+ # https://github.com/raspberrypi/pico-bootrom-rp2040
+ ret += [
# synthetic_node("rom_func_lookup(ROM_FUNC_CONNECT_INTERNAL_FLASH)", 0), # TODO
# synthetic_node("rom_func_lookup(ROM_FUNC_FLASH_EXIT_XIP)", 0), # TODO
# synthetic_node("rom_func_lookup(ROM_FUNC_FLASH_FLUSH_CACHE)", 0), # TODO
# synthetic_node("rom_hword_as_ptr(BOOTROM_TABLE_LOOKUP_OFFSET)", 0), # TODO
]
+
return ret
+ def mutate_node(self, node: Node) -> None:
+ if self._PICO_PANIC_FUNCTION and node.funcname.base() == BaseName("panic"):
+ # inline assembly from src/rp2_common/pico_platform_panic/panic.c
+ assert node.nstatic == 0
+ assert node.ndynamic == 0
+ assert len(node.calls) == 0
+ node.nstatic += 4
+ node.calls[QName(self._PICO_PANIC_FUNCTION)] = False
+
class TinyUSBDevicePlugin:
re_tud_class = re.compile(
@@ -686,6 +762,9 @@ class TinyUSBDevicePlugin:
def extra_nodes(self) -> typing.Collection[Node]:
return []
+ def mutate_node(self, node: Node) -> None:
+ pass
+
def indirect_callees(
self, loc: str, line: str
) -> tuple[typing.Collection[QName], bool] | None:
@@ -702,10 +781,18 @@ class TinyUSBDevicePlugin:
ret.update(self.tud_drivers["control_xfer_cb"])
return ret, False
if call.startswith("driver->"):
- return self.tud_drivers[call[len("driver->") :]], False
+ meth = call[len("driver->") :]
+ callees = self.tud_drivers[meth]
+ if len(callees) == 0:
+ if meth == "sof":
+ return [QName(f"__indirect_call_with_null_check:{call}")], False
+ raise ValueError(f"{loc}: no implementors of {meth}")
+ return callees, False
if call == "event.func_call.func":
# callback from usb_defer_func()
- return [], False
+ return [
+ QName("__indirect_call_with_null_check:event.func_call.func")
+ ], False
return None
@@ -727,11 +814,14 @@ class NewlibPlugin:
]
def extra_nodes(self) -> typing.Collection[Node]:
+ ret = []
+
# This is accurate to
# /usr/arm-none-eabi/lib/thumb/v6-m/nofp/libg.a as of
# Parabola's arm-none-eabi-newlib 4.5.0.20241231-1.
- return [
- # malloc
+
+ # malloc
+ ret += [
synthetic_node("free", 8, {"_free_r"}),
synthetic_node("malloc", 8, {"_malloc_r"}),
synthetic_node("realloc", 8, {"_realloc_r"}),
@@ -741,20 +831,27 @@ class NewlibPlugin:
# synthetic_node("_malloc_r", 0), # TODO
# synthetic_node("_realloc_r", 0), # TODO
# synthetic_node("_memalign_r", 0), # TODO
- # execution
+ ]
+
+ # execution
+ ret += [
synthetic_node("raise", 16, {"_getpid_r"}),
synthetic_node("abort", 8, {"raise", "_exit"}),
synthetic_node("longjmp", 0),
synthetic_node("setjmp", 0),
- # <strings.h>
+ ]
+
+ # <strings.h>
+ ret += [
synthetic_node("memcmp", 12),
- synthetic_node("memcpy", 28),
- synthetic_node("memset", 20),
synthetic_node("strcmp", 16),
synthetic_node("strlen", 8),
synthetic_node("strncpy", 16),
synthetic_node("strnlen", 8),
- # other
+ ]
+
+ # other
+ ret += [
synthetic_node("__errno", 0),
synthetic_node("_getpid_r", 8, {"_getpid"}),
synthetic_node("random", 8),
@@ -771,6 +868,11 @@ class NewlibPlugin:
synthetic_node("__libc_fini_array", 16, {"_fini"}),
]
+ return ret
+
+ def mutate_node(self, node: Node) -> None:
+ pass
+
def indirect_callees(
self, loc: str, line: str
) -> tuple[typing.Collection[QName], bool] | None:
@@ -801,6 +903,9 @@ class LibGCCPlugin:
synthetic_node("_fini", 24),
]
+ def mutate_node(self, node: Node) -> None:
+ pass
+
def indirect_callees(
self, loc: str, line: str
) -> tuple[typing.Collection[QName], bool] | None:
diff --git a/build-aux/measurestack/testutil.py b/build-aux/measurestack/testutil.py
index 751e57f..3c32134 100644
--- a/build-aux/measurestack/testutil.py
+++ b/build-aux/measurestack/testutil.py
@@ -69,6 +69,9 @@ class NopPlugin:
def extra_nodes(self) -> typing.Collection[analyze.Node]:
return []
+ def mutate_node(self, node: analyze.Node) -> None:
+ pass
+
class GraphProviderPlugin(NopPlugin):
_nodes: typing.Sequence[analyze.Node]
diff --git a/build-aux/measurestack/util.py b/build-aux/measurestack/util.py
index 0af3d02..c94ce07 100644
--- a/build-aux/measurestack/util.py
+++ b/build-aux/measurestack/util.py
@@ -46,9 +46,9 @@ def read_source(location: str) -> str:
raise ValueError(f"unexpected label value {location!r}")
filename = m.group("filename")
row = int(m.group("row")) - 1
- col = int(m.group("col")) - 1
+ # col = int(m.group("col")) - 1
with open(filename, "r", encoding="utf-8") as fh:
- return fh.readlines()[row][col:].rstrip()
+ return fh.readlines()[row].strip()
def get_zero_or_one(
@@ -61,7 +61,7 @@ def get_zero_or_one(
return None
-re_call_other = re.compile(r"(?P<func>[^(]+)\(.*")
+re_call_other = re.compile(r".*?\b(?P<func>(?!if\b)[->.a-zA-Z0-9_]+)\(.*")
class Plugin(typing.Protocol):
@@ -79,6 +79,7 @@ class Plugin(typing.Protocol):
def extra_includes(self) -> typing.Collection[BaseName]: ...
def extra_nodes(self) -> typing.Collection[Node]: ...
+ def mutate_node(self, node: Node) -> None: ...
def indirect_callees(
self, loc: str, line: str
) -> tuple[typing.Collection[QName], bool] | None: ...
@@ -101,6 +102,10 @@ class PluginApplication:
ret.extend(plugin.extra_nodes())
return ret
+ def mutate_node(self, node: Node) -> None:
+ for plugin in self._plugins:
+ plugin.mutate_node(node)
+
def indirect_callees(
self, elem: vcg.VCGElem
) -> tuple[typing.Collection[QName], bool]:
@@ -110,6 +115,9 @@ class PluginApplication:
for plugin in self._plugins:
ret = plugin.indirect_callees(loc, line)
if ret is not None:
+ assert (
+ len(ret[0]) > 0
+ ), f"{plugin.__class__.__name__} returning 0 calles for {loc} indicates the code would crash"
return ret
placeholder = "__indirect_call"
diff --git a/build-aux/tent-graph b/build-aux/tent-graph
new file mode 100755
index 0000000..25c58c5
--- /dev/null
+++ b/build-aux/tent-graph
@@ -0,0 +1,180 @@
+#!/usr/bin/env python3
+# build-aux/tent-graph - Take dbg_noncache=True dbg_nstatic=True stack.c on stdin, and produce a tent graph SVG on stdout
+#
+# Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+import ast
+import re
+import sys
+
+
+class Block:
+ title: str
+ parent: "Block|None"
+ children: list["Block"]
+ nbytes: int
+
+ def __init__(self, *, title: str, nbytes: int, parent: "Block|None") -> None:
+ self.title = title
+ self.parent = parent
+ self.children = []
+ self.nbytes = nbytes
+
+ @property
+ def rows(self) -> int:
+ if not self.children:
+ return 1
+ return sum(c.rows for c in self.children)
+
+ @property
+ def sum_nbytes(self) -> int:
+ if not self.children:
+ return self.nbytes
+ return self.nbytes + max(c.sum_nbytes for c in self.children)
+
+ def prune(self) -> None:
+ tgt = self.sum_nbytes - self.nbytes
+ self.children = [c for c in self.children if c.sum_nbytes == tgt]
+
+
+re_line = re.compile(
+ r"^//dbg-nstatic:(?P<indent>(?: -)*) QName\((?P<func>.*)\)\t(?P<size>[0-9]+)$"
+)
+
+
+def parse() -> list[Block]:
+ roots: list[Block] = []
+
+ stack: list[Block] = []
+ for line in sys.stdin:
+ m = re_line.fullmatch(line.strip())
+ if not m:
+ continue
+
+ depth = len(m.group("indent")) // 2
+ func = ast.literal_eval(m.group("func"))
+ size = int(m.group("size"), 10)
+
+ stack = stack[:depth]
+
+ block = Block(
+ title=func,
+ nbytes=size,
+ parent=stack[-1] if stack else None,
+ )
+ if block.parent:
+ block.parent.children.append(block)
+ else:
+ roots.append(block)
+ stack.append(block)
+
+ return roots
+
+
+def render(roots: list[Block]) -> None:
+ total_nbytes = max(r.sum_nbytes for r in roots)
+ total_rows = sum(r.rows for r in roots)
+
+ img_w = 1920
+ img_h = 948
+
+ details_h = 16
+ text_yoff = 12
+ text_xoff = 3
+
+ main_h = img_h - details_h
+ nbyte_h = main_h / total_nbytes
+ row_w = img_w / total_rows
+
+ print(
+ f"""<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" width="{img_w}" height="{img_h}" onload="init(evt)" viewBox="0 0 {img_w} {img_h}" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<style type="text/css">
+ .func_g:hover {{ stroke:black; stroke-width:0.5; }}
+ .func_g rect {{ rx: 2px; ry: 2px; }}
+ rect#background {{ fill: #EEEEEE; }}
+ text {{ font-size: 12px; font-family: Verdana; fill: rgb(0,0,0); }}
+</style>
+<script type="text/ecmascript">
+<![CDATA[
+ var details;
+ function init(evt) {{ details = document.getElementById("details").firstChild; }}
+ function s(info) {{ details.nodeValue = "Function: " + info; }}
+ function c() {{ details.nodeValue = ' '; }}
+]]>
+</script>
+<rect id="background" x="0" y="0" width="{img_w}" height="{img_h}" />
+<text text-anchor="" x="{text_xoff}" y="{img_h-details_h+text_yoff}" id="details"> </text>"""
+ )
+
+ min_nbytes = roots[0].nbytes
+ max_nbytes = 0
+
+ def visit(b: Block) -> None:
+ nonlocal min_nbytes
+ nonlocal max_nbytes
+ min_nbytes = min(min_nbytes, b.nbytes)
+ max_nbytes = max(max_nbytes, b.nbytes)
+ for c in b.children:
+ visit(c)
+
+ for r in roots:
+ visit(r)
+
+ def print_block(block: Block, nbyte: int, row: int) -> None:
+ nonlocal min_nbytes
+ nonlocal max_nbytes
+
+ if block.nbytes:
+ hue = 100 - int(
+ ((block.nbytes - min_nbytes) / (max_nbytes - min_nbytes)) * 100
+ )
+
+ x = row * row_w
+ y = nbyte * nbyte_h
+ w = max(1, block.rows * row_w - 1)
+ h = block.nbytes * nbyte_h
+ title = f"{block.title} = {block.nbytes} / {block.sum_nbytes} bytes"
+
+ nonlocal main_h
+ print(f'<g class="func_g" onmouseover="s(\'{title}\')" onmouseout="c()">')
+ print(f"\t<title>{title}</title>")
+ print(
+ f'\t<rect x="{x}" y="{main_h-y-h}" width="{w}" height="{h}" fill="hsl({hue} 60% 60%)" />'
+ )
+
+ short_title = title.rsplit(":", 1)[-1]
+ if h > details_h and w > len(short_title) * 10:
+ print(
+ f'\t<text x="{x+text_xoff}" y="{main_h-y-h+text_yoff}">{short_title}</text>'
+ )
+ print("</g>")
+
+ def sort_key(c: Block) -> int:
+ return c.sum_nbytes
+
+ for c in sorted(block.children, key=sort_key, reverse=True):
+ print_block(c, nbyte + block.nbytes, row)
+ row += c.rows
+
+ row = 0
+ for r in roots:
+ print_block(r, 0, row)
+ row += r.rows
+
+ print("</svg>")
+
+
+def main() -> None:
+ roots = parse()
+
+ # tgt = max(r.sum_nbytes for r in roots)
+ # roots = [r for r in roots if r.sum_nbytes == tgt]
+
+ render(roots)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/build-aux/valgrind b/build-aux/valgrind
index 7ad2712..0700e4d 100755
--- a/build-aux/valgrind
+++ b/build-aux/valgrind
@@ -1,4 +1,4 @@
-#!/bin/env bash
+#!/bin/sh
# build-aux/valgrind - Wrapper around valgrind to keep flags consistent
#
# Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
diff --git a/cmd/sbc_harness/CMakeLists.txt b/cmd/sbc_harness/CMakeLists.txt
deleted file mode 100644
index 0e904ab..0000000
--- a/cmd/sbc_harness/CMakeLists.txt
+++ /dev/null
@@ -1,81 +0,0 @@
-# cmd/sbc_harness/CMakeLists.txt - Build script for main sbc_harness.uf2 firmware file
-#
-# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
-# SPDX-License-Identifier: AGPL-3.0-or-later
-
-if (PICO_PLATFORM STREQUAL "rp2040")
-
-# Compile ######################################################################
-
-add_library(sbc_harness_objs OBJECT
- main.c
- usb_keyboard.c
- tusb_log.c
-
- fs_harness_flash_bin.c
- fs_harness_uptime_txt.c
-)
-target_include_directories(sbc_harness_objs PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/config)
-target_include_directories(sbc_harness_objs PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
-target_include_directories(sbc_harness_objs PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
-target_link_libraries(sbc_harness_objs
- pico_runtime
- pico_stdio_uart
-
- hardware_flash
- hardware_watchdog
-
- libmisc
- libusb
- libdhcp
- libhw_cr
- lib9p_srv
- lib9p_util
-)
-pico_minimize_runtime(sbc_harness_objs)
-target_compile_definitions(sbc_harness_objs PRIVATE
- #PICO_USE_FASTEST_SUPPORTED_CLOCK=1
-
- # Calculated by `./3rd-party/pico-sdk/src/rp2_common/hardware_clocks/scripts/vcocalc.py --cmake-only 170`
- PLL_SYS_REFDIV=2
- PLL_SYS_VCO_FREQ_HZ=1530000000
- PLL_SYS_POSTDIV1=3
- PLL_SYS_POSTDIV2=3
- SYS_CLK_HZ=170000000
-)
-
-suppress_tinyusb_warnings()
-
-# Analyze the stack ############################################################
-
-add_stack_analysis(sbc_harness_stack.c sbc_harness_objs)
-
-# Link #########################################################################
-
-add_executable(sbc_harness)
-target_sources(sbc_harness PRIVATE
- sbc_harness_stack.c
- "$<TARGET_OBJECTS:sbc_harness_objs>"
-)
-target_link_libraries(sbc_harness
- pico_standard_link
-)
-target_link_options(sbc_harness PRIVATE "$<TARGET_PROPERTY:sbc_harness_objs,LINK_OPTIONS>")
-pico_add_extra_outputs(sbc_harness) # create .map/.bin/.hex/.uf2 files in addition to .elf
-pico_set_program_url(sbc_harness "https://git.lukeshu.com/sbc-harness")
-
-# Embed ########################################################################
-
-target_embed_sources(sbc_harness_objs sbc_harness static.h
- static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS.md
- static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/agpl-3.0.txt
- static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/dhcp.bsd3-mit.txt
- static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/newlib.txt
- static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/pico-sdk.bsd3.txt
- static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/tinyusb.mit.txt
- static/Documentation/harness_rom_bin.txt
- static/Documentation/harness_flash_bin.txt
- static/Documentation/harness_uptime_txt.txt
-)
-
-endif()
diff --git a/cmd/sbc_harness/fs_harness_flash_bin.c b/cmd/sbc_harness/fs_harness_flash_bin.c
deleted file mode 100644
index 3c3fa16..0000000
--- a/cmd/sbc_harness/fs_harness_flash_bin.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/* sbc_harness/fs_harness_flash_bin.c - 9P access to flash storage
- *
- * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-#include <string.h>
-
-#include <hardware/flash.h>
-#include <hardware/watchdog.h>
-
-#define LOG_NAME FLASH
-#include <libmisc/log.h>
-
-#include <util9p/static.h>
-
-#define IMPLEMENTATION_FOR_FS_HARNESS_FLASH_BIN YES
-#include "fs_harness_flash_bin.h"
-
-LO_IMPLEMENTATION_C(lib9p_srv_file, struct flash_file, flash_file, static);
-
-LO_IMPLEMENTATION_H(lib9p_srv_fio, struct flash_file, flash_file);
-LO_IMPLEMENTATION_C(lib9p_srv_fio, struct flash_file, flash_file, static);
-
-#define DATA_START ((const char *)(XIP_NOALLOC_BASE))
-#define DATA_SIZE PICO_FLASH_SIZE_BYTES
-#define DATA_HSIZE (DATA_SIZE/2)
-static_assert(DATA_SIZE % FLASH_SECTOR_SIZE == 0);
-static_assert(DATA_HSIZE % FLASH_SECTOR_SIZE == 0);
-
-/* There are some memcpy()s (and memcmp()s?) in here that can (and
- * arguably should) be replaced with SSI DMA. */
-
-/* ab_flash_* (mid-level utilities for our A/B write scheme) ******************/
-
-/**
- * Copy the upper half of flash to the lower half of flash, then reboot.
- *
- * @param buf : a scratch buffer that is at least FLASH_SECTOR_SIZE
- */
-[[noreturn]] static void __no_inline_not_in_flash_func(ab_flash_finalize)(uint8_t *buf) {
- assert(buf);
-
- log_infoln("copying upper flash to lower flash...");
-
- cr_save_and_disable_interrupts();
-
- for (size_t off = 0; off < DATA_HSIZE; off += FLASH_SECTOR_SIZE) {
- memcpy(buf, DATA_START+DATA_HSIZE+off, FLASH_SECTOR_SIZE);
- if (memcmp(DATA_START+off, buf, FLASH_SECTOR_SIZE) == 0)
- continue;
- flash_range_erase(off, FLASH_SECTOR_SIZE);
- flash_range_program(off, buf, FLASH_SECTOR_SIZE);
- }
-
- log_infoln("rebooting...");
-
- watchdog_reboot(0, 0, 300);
-
- for (;;)
- asm volatile ("nop");
-}
-
-/**
- * Set the upper half of flash to all zero bytes.
- *
- * @param buf : a scratch buffer that is at least FLASH_SECTOR_SIZE
- */
-static void ab_flash_initialize_zero(uint8_t *buf) {
- assert(buf);
-
- memset(buf, 0, FLASH_SECTOR_SIZE);
-
- log_infoln("zeroing upper flash...");
- for (size_t off = DATA_HSIZE; off < DATA_SIZE; off += FLASH_SECTOR_SIZE) {
- if (memcmp(buf, DATA_START+off, FLASH_SECTOR_SIZE) == 0)
- continue;
- bool saved = cr_save_and_disable_interrupts();
- /* No need to `flash_range_erase()`; the way the flash
- * works is that _erase() sets all bits to 1, and
- * _program() sets some bits to 0. If we don't need
- * any bits to be 1, then we can skip the
- * _erase(). */
- flash_range_program(off, buf, FLASH_SECTOR_SIZE);
- cr_restore_interrupts(saved);
- }
- log_debugln("... zeroed");
-}
-
-/**
- * Copy the lower half of flash to the upper half of flash.
- *
- * @param buf : a scratch buffer that is at least FLASH_SECTOR_SIZE
- */
-static void ab_flash_initialize(uint8_t *buf) {
- assert(buf);
-
- log_infoln("initializing upper flash...");
- for (size_t off = 0; off < DATA_HSIZE; off += FLASH_SECTOR_SIZE) {
- memcpy(buf, DATA_START+off, FLASH_SECTOR_SIZE);
- if (memcmp(buf, DATA_START+DATA_HSIZE+off, FLASH_SECTOR_SIZE) == 0)
- continue;
- bool saved = cr_save_and_disable_interrupts();
- flash_range_erase(DATA_HSIZE+off, FLASH_SECTOR_SIZE);
- flash_range_program(DATA_HSIZE+off, buf, FLASH_SECTOR_SIZE);
- cr_restore_interrupts(saved);
- }
- log_debugln("... initialized");
-}
-
-/**
- * Write `dat` to flash sector `pos`+(DATA_SIZE/2) (i.e. `pos` is a
- * sector in the lower half, but this function writes to the upper
- * half).
- *
- * @param pos : start-position of the sector to write to, must be in the upper half of the flash
- * @param dat : the FLASH_SECTOR_SIZE bytes to write
- */
-static void ab_flash_write_sector(size_t pos, uint8_t *dat) {
- assert(pos < DATA_HSIZE);
- assert(pos % FLASH_SECTOR_SIZE == 0);
- assert(dat);
-
- pos += DATA_HSIZE;
-
- log_infoln("write flash sector @ %zu...", pos);
- if (memcmp(dat, DATA_START+pos, FLASH_SECTOR_SIZE) != 0) {
- bool saved = cr_save_and_disable_interrupts();
- flash_range_erase(pos, FLASH_SECTOR_SIZE);
- flash_range_program(pos, dat, FLASH_SECTOR_SIZE);
- cr_restore_interrupts(saved);
- }
- log_debugln("... written");
-}
-
-/* srv_file *******************************************************************/
-
-static void flash_file_free(struct flash_file *self) {
- assert(self);
-}
-static struct lib9p_qid flash_file_qid(struct flash_file *self) {
- assert(self);
-
- return (struct lib9p_qid){
- .type = LIB9P_QT_FILE|LIB9P_QT_EXCL,
- .vers = 1,
- .path = self->pathnum,
- };
-}
-
-static struct lib9p_srv_stat flash_file_stat(struct flash_file *self, struct lib9p_srv_ctx *ctx) {
- assert(self);
- assert(ctx);
-
- 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_srv_stat) {
- assert(self);
- assert(ctx);
-
- 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, LIB9P_ERRNO_L_EROFS, "read-only part of filesystem");
-}
-
-LIB9P_SRV_NOTDIR(struct flash_file, flash_file);
-
-static lo_interface lib9p_srv_fio flash_file_fopen(struct flash_file *self, struct lib9p_srv_ctx *ctx,
- bool rd, bool wr, bool trunc) {
- assert(self);
- assert(ctx);
-
- if (rd) {
- self->rbuf.ok = false;
- }
-
- if (wr) {
- if (trunc) {
- ab_flash_initialize_zero(self->wbuf.dat);
- self->written = true;
- } else {
- ab_flash_initialize(self->wbuf.dat);
- self->written = false;
- }
- self->wbuf.ok = false;
- }
-
- return lo_box_flash_file_as_lib9p_srv_fio(self);
-}
-
-/* srv_fio ********************************************************************/
-
-static uint32_t flash_file_iounit(struct flash_file *self) {
- assert(self);
- return FLASH_SECTOR_SIZE;
-}
-
-static void flash_file_iofree(struct flash_file *self) {
- assert(self);
-
- if (self->wbuf.ok)
- ab_flash_write_sector(self->wbuf.pos, self->wbuf.dat);
-
- if (self->written)
- ab_flash_finalize(self->wbuf.dat);
-}
-
-static void flash_file_pread(struct flash_file *self, struct lib9p_srv_ctx *ctx,
- uint32_t byte_count, uint64_t byte_offset,
- struct iovec *ret) {
- assert(self);
- assert(ctx);
- assert(ret);
-
- if (byte_offset > DATA_SIZE) {
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EINVAL, "offset is past the chip size");
- return;
- }
-
- /* Assume that somewhere down the line the iovec we return
- * will be passed to DMA. We don't want the DMA engine to hit
- * (slow) XIP (for instance, this can cause reads/writes to
- * the SSP to get out of sync with eachother), so copy the
- * data to a buffer in (fast) RAM first. It's lame that the
- * DMA engine can only have a DREQ on one side of the channel.
- */
- if (byte_offset == DATA_SIZE) {
- *ret = (struct iovec){
- .iov_len = 0,
- };
- return;
- }
- size_t sector_base = LM_ROUND_DOWN(byte_offset, FLASH_SECTOR_SIZE);
- if (byte_offset + byte_count > sector_base + FLASH_SECTOR_SIZE)
- byte_count = (sector_base + FLASH_SECTOR_SIZE) - byte_offset;
- assert(byte_offset + byte_count <= DATA_SIZE);
-
- if (!self->rbuf.ok || self->rbuf.pos != sector_base) {
- self->rbuf.ok = true;
- self->rbuf.pos = sector_base;
- memcpy(self->rbuf.dat, DATA_START+sector_base, FLASH_SECTOR_SIZE);
- }
-
- *ret = (struct iovec){
- .iov_base = &self->rbuf.dat[byte_offset-sector_base],
- .iov_len = byte_count,
- };
-}
-
-/* TODO: Short/corrupt writes are dangerous. This should either (1)
- * check a checksum, (2) use uf2 instead of verbatim data, or (3) use
- * ihex instead of verbatim data. */
-static uint32_t flash_file_pwrite(struct flash_file *self, struct lib9p_srv_ctx *ctx,
- void *buf,
- uint32_t byte_count,
- uint64_t byte_offset) {
- assert(self);
- assert(ctx);
-
- if (byte_offset > DATA_HSIZE) {
- lib9p_error(&ctx->basectx,
- 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,
- LIB9P_ERRNO_L_EINVAL, "offset is at half the chip size");
- return 0;
- }
-
- size_t sector_base = LM_ROUND_DOWN(byte_offset, FLASH_SECTOR_SIZE);
- if (byte_offset + byte_count > sector_base + FLASH_SECTOR_SIZE)
- byte_count = (sector_base + FLASH_SECTOR_SIZE) - byte_offset;
- assert(byte_offset + byte_count < DATA_HSIZE);
-
- if (self->wbuf.ok && self->wbuf.pos != sector_base)
- ab_flash_write_sector(self->wbuf.pos, self->wbuf.dat);
- if (!self->wbuf.ok || self->wbuf.pos != sector_base) {
- self->wbuf.ok = true;
- self->wbuf.pos = sector_base;
- if (byte_count != FLASH_SECTOR_SIZE)
- memcpy(self->wbuf.dat, DATA_START+DATA_HSIZE+sector_base, FLASH_SECTOR_SIZE);
- }
- memcpy(&self->wbuf.dat[byte_offset-sector_base], buf, byte_count);
-
- self->written = true;
- return byte_count;
-}
diff --git a/cmd/sbc_harness/fs_harness_uptime_txt.c b/cmd/sbc_harness/fs_harness_uptime_txt.c
deleted file mode 100644
index 97246ea..0000000
--- a/cmd/sbc_harness/fs_harness_uptime_txt.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/* sbc_harness/fs_harness_uptime_txt.c - 9P access to harness uptime
- *
- * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-#include <libhw/generic/alarmclock.h>
-#include <util9p/static.h>
-#include <libmisc/alloc.h> /* for heap_alloc(), free() */
-#include <libmisc/fmt.h> /* for fmt_snprint() */
-
-#include "fs_harness_uptime_txt.h"
-
-LO_IMPLEMENTATION_C(lib9p_srv_file, struct uptime_file, uptime_file, static);
-
-struct uptime_fio {
- struct uptime_file *parent;
- size_t buf_len;
- char buf[24]; /* len(str(UINT64_MAX)+"ns\n\0") */
-};
-
-LO_IMPLEMENTATION_H(lib9p_srv_fio, struct uptime_fio, uptime_fio);
-LO_IMPLEMENTATION_C(lib9p_srv_fio, struct uptime_fio, uptime_fio, static);
-
-/* srv_file *******************************************************************/
-
-static void uptime_file_free(struct uptime_file *self) {
- assert(self);
-}
-static struct lib9p_qid uptime_file_qid(struct uptime_file *self) {
- assert(self);
-
- return (struct lib9p_qid){
- .type = LIB9P_QT_FILE,
- .vers = 1,
- .path = self->pathnum,
- };
-}
-
-static struct lib9p_srv_stat uptime_file_stat(struct uptime_file *self, struct lib9p_srv_ctx *ctx) {
- assert(self);
- assert(ctx);
-
- uint64_t now = LO_CALL(bootclock, get_time_ns);
- uint64_t size = 0;
- while (now) {
- size++;
- now /= 10;
- }
- if (!size)
- size++;
- size += 3;
-
- 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_srv_stat) {
- assert(self);
- assert(ctx);
-
- 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, LIB9P_ERRNO_L_EROFS, "read-only part of filesystem");
-}
-
-LIB9P_SRV_NOTDIR(struct uptime_file, uptime_file);
-
-static lo_interface lib9p_srv_fio uptime_file_fopen(struct uptime_file *self, struct lib9p_srv_ctx *ctx,
- bool LM_UNUSED(rd), bool LM_UNUSED(wr), bool LM_UNUSED(trunc)) {
- assert(self);
- assert(ctx);
-
- struct uptime_fio *ret = heap_alloc(1, struct uptime_fio);
- ret->parent = self;
- ret->buf_len = 0;
-
- return lo_box_uptime_fio_as_lib9p_srv_fio(ret);
-}
-
-/* srv_fio ********************************************************************/
-
-static uint32_t uptime_fio_iounit(struct uptime_fio *self) {
- assert(self);
- return sizeof(self->buf)-1;
-}
-
-static void uptime_fio_iofree(struct uptime_fio *self) {
- assert(self);
- free(self);
-}
-
-static struct lib9p_qid uptime_fio_qid(struct uptime_fio *self) {
- assert(self);
- assert(self->parent);
- return uptime_file_qid(self->parent);
-}
-
-static void uptime_fio_pread(struct uptime_fio *self, struct lib9p_srv_ctx *ctx,
- uint32_t byte_count, uint64_t byte_offset,
- struct iovec *ret) {
- assert(self);
- assert(ctx);
- assert(ret);
-
- if (byte_offset == 0 || self->buf_len == 0) {
- uint64_t now = LO_CALL(bootclock, get_time_ns);
- self->buf_len = fmt_snprint(self->buf, sizeof(self->buf), now, "ns\n");
- }
-
- if (byte_offset > (uint64_t)self->buf_len) {
- 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 > self->buf_len)
- end_off = self->buf_len;
- *ret = (struct iovec){
- .iov_base = &self->buf[beg_off],
- .iov_len = end_off-beg_off,
- };
-}
-
-static uint32_t uptime_fio_pwrite(struct uptime_fio *self, struct lib9p_srv_ctx *ctx,
- void *LM_UNUSED(buf),
- uint32_t LM_UNUSED(byte_count),
- uint64_t LM_UNUSED(byte_offset)) {
- assert(self);
- assert(ctx);
-
- lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "read-only part of filesystem");
- return 0;
-}
diff --git a/cmd/sbc_harness/fs_harness_uptime_txt.h b/cmd/sbc_harness/fs_harness_uptime_txt.h
deleted file mode 100644
index 7bf2945..0000000
--- a/cmd/sbc_harness/fs_harness_uptime_txt.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* sbc_harness/fs_harness_uptime_txt.h - 9P access to harness uptime
- *
- * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-#ifndef _SBC_HARNESS_FS_HARNESS_UPTIME_TXT_H_
-#define _SBC_HARNESS_FS_HARNESS_UPTIME_TXT_H_
-
-#include <lib9p/srv.h>
-
-struct uptime_file {
- char *name;
- uint64_t pathnum;
-};
-LO_IMPLEMENTATION_H(lib9p_srv_file, struct uptime_file, uptime_file);
-#define lo_box_uptime_file_as_lib9p_srv_file(obj) util9p_box(uptime_file, obj)
-
-#endif /* _SBC_HARNESS_FS_HARNESS_UPTIME_TXT_H_ */
diff --git a/cmd/sbc_harness/static/Documentation/harness_uptime_txt.txt b/cmd/sbc_harness/static/Documentation/harness_uptime_txt.txt
deleted file mode 100644
index 1ab86f7..0000000
--- a/cmd/sbc_harness/static/Documentation/harness_uptime_txt.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-NAME
- /harness/uptime.txt
-
-DESCRIPTION
- Reading this file gives a text string of the format
- `sprintf("%uns\n", uptime_ns)` indicating the harness's uptime
- in an integer number of nanoseconds.
-
-BUGS
- Using nanoseconds gives the illusion of more precision than
- there actually is; the harness' clock only has microsecond
- resolution; the last 3 digits of the returned nanosecond count
- will always be 0.
-
-AUTHOR
- Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
- SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/flashimg/cpu_hdmi/CMakeLists.txt b/flashimg/cpu_hdmi/CMakeLists.txt
new file mode 100644
index 0000000..9fc1c08
--- /dev/null
+++ b/flashimg/cpu_hdmi/CMakeLists.txt
@@ -0,0 +1,20 @@
+# flashimg/cpu_hdmi/CMakeLists.txt - Build script for auxiliary cpu_hdmi.uf2 firmware file
+#
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+if (PICO_PLATFORM STREQUAL "rp2040")
+
+add_executable(cpu_hdmi
+ main.c
+)
+target_link_libraries(cpu_hdmi
+ pico_runtime
+ pico_stdio
+)
+pico_minimize_runtime(cpu_hdmi)
+
+pico_add_extra_outputs(cpu_hdmi) # create .map/.bin/.hex/.uf2 files in addition to .elf
+pico_set_program_url(cpu_hdmi "https://git.lukeshu.com/sbc-harness")
+
+endif()
diff --git a/flashimg/cpu_hdmi/main.c b/flashimg/cpu_hdmi/main.c
new file mode 100644
index 0000000..cdba958
--- /dev/null
+++ b/flashimg/cpu_hdmi/main.c
@@ -0,0 +1,9 @@
+/* flashimg/cpu_hdmi/main.c - Entry point for the HDMI-decoder co-processor
+ *
+ * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+int main() {
+ return 0;
+}
diff --git a/flashimg/cpu_main/CMakeLists.txt b/flashimg/cpu_main/CMakeLists.txt
new file mode 100644
index 0000000..ba47e88
--- /dev/null
+++ b/flashimg/cpu_main/CMakeLists.txt
@@ -0,0 +1,105 @@
+# flashimg/cpu_main/CMakeLists.txt - Build script for main cpu_main.uf2 firmware file
+#
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+if (PICO_PLATFORM STREQUAL "rp2040")
+
+# Compile ######################################################################
+
+add_library(cpu_main_objs OBJECT
+ main.c
+ usb_keyboard.c
+ tusb_log.c
+
+ fs_harness_flash_bin.c
+ fs_harness_uptime_txt.c
+
+ ihex.c
+)
+target_include_directories(cpu_main_objs PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/config)
+target_include_directories(cpu_main_objs PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
+target_include_directories(cpu_main_objs PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
+target_link_libraries(cpu_main_objs
+ pico_runtime
+
+ hardware_flash
+ hardware_uart
+ hardware_watchdog
+
+ libmisc
+ libusb
+ libdhcp
+ libhw_cr
+ lib9p_srv
+ lib9p_util
+)
+pico_minimize_runtime(cpu_main_objs
+ INCLUDE PANIC
+)
+target_compile_definitions(cpu_main_objs PRIVATE
+ PICO_PANIC_FUNCTION=assert_panic
+
+ #PICO_USE_FASTEST_SUPPORTED_CLOCK=1
+
+ # Calculated by `./3rd-party/pico-sdk/src/rp2_common/hardware_clocks/scripts/vcocalc.py --cmake-only 170`
+ PLL_SYS_REFDIV=2
+ PLL_SYS_VCO_FREQ_HZ=1530000000
+ PLL_SYS_POSTDIV1=3
+ PLL_SYS_POSTDIV2=3
+ SYS_CLK_HZ=170000000
+)
+
+suppress_tinyusb_warnings()
+set_source_files_properties(
+ ${PICO_SDK_PATH}/src/rp2_common/pico_clib_interface/newlib_interface.c
+ PROPERTIES
+ COMPILE_OPTIONS "-Wno-unused-parameter")
+
+# Analyze the stack ############################################################
+
+add_stack_analysis(stack.c cpu_main_objs)
+
+# Link #########################################################################
+
+add_executable(cpu_main)
+target_include_directories(cpu_main PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/config)
+target_sources(cpu_main PRIVATE
+ stack.c
+ "$<TARGET_OBJECTS:cpu_main_objs>"
+)
+target_link_libraries(cpu_main
+ pico_standard_link
+)
+target_link_options(cpu_main PRIVATE "$<TARGET_PROPERTY:cpu_main_objs,LINK_OPTIONS>")
+pico_add_extra_outputs(cpu_main) # create .map/.bin/.hex/.uf2 files in addition to .elf
+pico_set_program_url(cpu_main "https://git.lukeshu.com/sbc-harness")
+
+# Embed ########################################################################
+
+target_embed_sources(cpu_main_objs cpu_main static.h
+ static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS.md
+ static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/agpl-3.0.txt
+ static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/dhcp.bsd3-mit.txt
+ static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/newlib.txt
+ static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/pico-sdk.bsd3.txt
+ static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/tinyusb.mit.txt
+ static/Documentation/harness_rom.bin.txt
+ static/Documentation/harness_flash.bin.txt
+ static/Documentation/harness_uptime.txt.txt
+)
+
+endif()
+
+# Tests ########################################################################
+if ((PICO_PLATFORM STREQUAL "host") AND (ENABLE_TESTS))
+ add_executable(test_ihex "tests/test_ihex.c" "ihex.c")
+ target_include_directories(test_ihex PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/tests)
+ target_link_libraries(test_ihex
+ libhw_generic
+ )
+ add_test(
+ NAME "flashimg/cpu_main/test_ihex"
+ COMMAND "${CMAKE_SOURCE_DIR}/build-aux/valgrind" "./test_ihex"
+ )
+endif()
diff --git a/cmd/sbc_harness/config/config.h b/flashimg/cpu_main/config/config.h
index ca23462..700b77b 100644
--- a/cmd/sbc_harness/config/config.h
+++ b/flashimg/cpu_main/config/config.h
@@ -1,4 +1,4 @@
-/* config.h - Compile-time configuration for sbc_harness
+/* flashimg/cpu_main/config/config.h - Compile-time configuration for the cpu_main firmware
*
* Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
@@ -37,8 +37,6 @@
/* 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 */
@@ -49,8 +47,6 @@
#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.
@@ -69,6 +65,7 @@
* (8*1024)+160 in 2e and 3e.
*/
#define CONFIG_9P_SRV_MAX_MSG_SIZE ((4*1024)+24)
+#define CONFIG_9P_SRV_MAX_ERR_SIZE 128 /* 128 is what Plan 9 4e uses */
/**
* Maximum host-data-structure size. A message may be larger in
* unmarshaled-host-structures than marshaled-net-bytes due to (1)
@@ -96,13 +93,15 @@
/* COROUTINE ******************************************************************/
-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_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;
+#define CONFIG_COROUTINE_STACK_PREALLOCATE /* defined-or-not */
+extern char COROUTINE_STACK_init_cr []; extern const size_t COROUTINE_STACK_init_cr_len;
+extern char COROUTINE_STACK_dhcp_cr []; extern const size_t COROUTINE_STACK_dhcp_cr_len;
+extern char *const COROUTINE_STACK_read9p_cr []; extern const size_t COROUTINE_STACK_read9p_cr_len;
+extern char *const COROUTINE_STACK_write9p_cr []; extern const size_t COROUTINE_STACK_write9p_cr_len;
+extern char COROUTINE_STACK_usb_common_cr []; extern const size_t COROUTINE_STACK_usb_common_cr_len;
+extern char COROUTINE_STACK_usb_keyboard_cr[]; extern const size_t COROUTINE_STACK_usb_keyboard_cr_len;
+extern char COROUTINE_STACK_w5500_irq_cr []; extern const size_t COROUTINE_STACK_w5500_irq_cr_len;
+
#define CONFIG_COROUTINE_NAME_LEN 16
#define CONFIG_COROUTINE_MEASURE_STACK 1 /* bool */
#define CONFIG_COROUTINE_PROTECT_STACK 1 /* bool */
@@ -110,11 +109,13 @@ 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_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() */ )
+#define CONFIG_COROUTINE_NUM ( \
+ 1 /* init_cr */ + \
+ 1 /* usb_common_cr */ + \
+ 1 /* usb_keyboard_cr */ + \
+ 1 /* dhcp_cr */ + \
+ _CONFIG_9P_MAX_CONNS /* read9p_cr */ + \
+ _CONFIG_9P_MAX_REQS /* write9p_cr */ + \
+ 1 /* W5500_irq_cr */ )
#endif /* _CONFIG_H_ */
diff --git a/cmd/sbc_harness/config/tusb_config.h b/flashimg/cpu_main/config/tusb_config.h
index 2c7c02a..18be9b5 100644
--- a/cmd/sbc_harness/config/tusb_config.h
+++ b/flashimg/cpu_main/config/tusb_config.h
@@ -1,4 +1,4 @@
-/* tusb_config.h - Compile-time configuration for the TinyUSB library
+/* flashimg/cpu_main/config/tusb_config.h - Compile-time configuration for the TinyUSB library
*
* Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/flashimg/cpu_main/fs_harness_flash_bin.c b/flashimg/cpu_main/fs_harness_flash_bin.c
new file mode 100644
index 0000000..7b41c86
--- /dev/null
+++ b/flashimg/cpu_main/fs_harness_flash_bin.c
@@ -0,0 +1,332 @@
+/* flashimg/cpu_main/fs_harness_flash_bin.c - 9P access to flash storage
+ *
+ * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <string.h>
+
+#include <hardware/flash.h>
+#include <hardware/watchdog.h>
+
+#define LOG_NAME FLASH
+#include <libmisc/log.h>
+
+#include <util9p/static.h>
+
+#define IMPLEMENTATION_FOR_FS_HARNESS_FLASH_BIN YES
+#include "fs_harness_flash_bin.h"
+
+LO_IMPLEMENTATION_C(lib9p_srv_file, struct flash_file, flash_file);
+LO_IMPLEMENTATION_STATIC(lib9p_srv_fio, struct flash_file, flash_file);
+
+#define DATA_START ((const char *)(XIP_NOALLOC_BASE))
+#define DATA_SIZE PICO_FLASH_SIZE_BYTES
+#define DATA_HSIZE (DATA_SIZE/2)
+static_assert(DATA_SIZE % FLASH_SECTOR_SIZE == 0);
+static_assert(DATA_HSIZE % FLASH_SECTOR_SIZE == 0);
+
+/* There are some memcpy()s (and memcmp()s?) in here that maybe should
+ * be replaced with SSI DMA. */
+
+/* ab_flash_* (mid-level utilities for our A/B write scheme) ******************/
+
+/**
+ * Copy the upper half of flash to the lower half of flash, then reboot.
+ *
+ * @param buf : a scratch buffer that is at least FLASH_SECTOR_SIZE
+ */
+[[noreturn]] static void __no_inline_not_in_flash_func(ab_flash_finalize)(uint8_t *buf) {
+ assert(buf);
+
+ log_infoln("copying upper flash to lower flash...");
+
+ cr_save_and_disable_interrupts();
+
+ for (size_t off = 0; off < DATA_HSIZE; off += FLASH_SECTOR_SIZE) {
+ memcpy(buf, DATA_START+DATA_HSIZE+off, FLASH_SECTOR_SIZE);
+ if (memcmp(DATA_START+off, buf, FLASH_SECTOR_SIZE) == 0)
+ continue;
+ flash_range_erase(off, FLASH_SECTOR_SIZE);
+ flash_range_program(off, buf, FLASH_SECTOR_SIZE);
+ }
+
+ log_infoln("rebooting...");
+
+ watchdog_reboot(0, 0, 300);
+
+ for (;;)
+ asm volatile ("nop");
+}
+
+/**
+ * Set the upper half of flash to all "1" bits.
+ *
+ * @param buf : a scratch buffer that is at least FLASH_SECTOR_SIZE
+ */
+static void ab_flash_initialize(void *buf) {
+ assert(buf);
+
+ memset(buf, 0xFF, FLASH_SECTOR_SIZE);
+
+ log_infoln("erasing upper flash...");
+ for (size_t off = DATA_HSIZE; off < DATA_SIZE; off += FLASH_SECTOR_SIZE) {
+ if (memcmp(buf, DATA_START+off, FLASH_SECTOR_SIZE) == 0)
+ continue;
+ bool saved = cr_save_and_disable_interrupts();
+ flash_range_erase(off, FLASH_SECTOR_SIZE);
+ cr_restore_interrupts(saved);
+ }
+ log_debugln("... erased");
+}
+
+/**
+ * Write `dat` to flash sector `pos`+(DATA_SIZE/2) (i.e. `pos` is a
+ * sector in the lower half, but this function writes to the upper
+ * half).
+ *
+ * @param pos : start-position of the sector to write to
+ * @param dat : the FLASH_SECTOR_SIZE bytes to write
+ */
+static void ab_flash_write_sector(size_t pos, uint8_t *dat) {
+ assert(pos < DATA_HSIZE);
+ assert(pos % FLASH_SECTOR_SIZE == 0);
+ assert(dat);
+
+ pos += DATA_HSIZE;
+
+ log_infoln("write flash sector @ ", (base16_u32_, pos), "...");
+ if (memcmp(dat, DATA_START+pos, FLASH_SECTOR_SIZE) != 0) {
+ bool saved = cr_save_and_disable_interrupts();
+ flash_range_erase(pos, FLASH_SECTOR_SIZE);
+ flash_range_program(pos, dat, FLASH_SECTOR_SIZE);
+ cr_restore_interrupts(saved);
+ }
+ log_debugln("... written");
+}
+
+/* io_preader_to, io_pwriter, io_closer ***************************************/
+
+LO_IMPLEMENTATION_STATIC(io_preader_to, struct flashio, flashio);
+LO_IMPLEMENTATION_STATIC(io_pwriter, struct flashio, flashio);
+LO_IMPLEMENTATION_STATIC(io_closer, struct flashio, flashio);
+
+/** read from anywhere on the chip */
+static size_t_and_error flashio_pread_to(struct flashio *self, lo_interface io_writer dst, uoff_t _src_offset, size_t count) {
+ assert(self);
+
+ if (_src_offset > DATA_SIZE)
+ return ERROR_AND(size_t, 0, error_new(E_POSIX_EINVAL, "offset is past the chip size"));
+ size_t src_offset = (size_t) _src_offset;
+
+ if (src_offset == DATA_SIZE)
+ return ERROR_AND(size_t, 0, error_new(E_EOF));
+
+ /* Assume that somewhere down the line the pointer we pass to
+ * io_write() will be passed to DMA. We don't want the DMA
+ * engine to hit (slow) XIP (for instance, this can cause
+ * reads/writes to the SSP to get out of sync with eachother).
+ * So, copy the data to a buffer in (fast) RAM first. It's
+ * lame that the DMA engine can only have a DREQ on one side
+ * of the channel.
+ */
+ size_t sector_base = LM_ROUND_DOWN(src_offset, FLASH_SECTOR_SIZE);
+ if (src_offset + count > sector_base + FLASH_SECTOR_SIZE)
+ count = (sector_base + FLASH_SECTOR_SIZE) - src_offset;
+ assert(src_offset + count <= DATA_SIZE);
+
+ if (!self->rbuf.ok || self->rbuf.pos != sector_base) {
+ self->rbuf.ok = true;
+ self->rbuf.pos = sector_base;
+ memcpy(self->rbuf.dat, DATA_START+sector_base, FLASH_SECTOR_SIZE);
+ }
+
+ return io_write(dst, &self->rbuf.dat[src_offset-sector_base], count);
+}
+
+/** takes offsets in the lower half, writes to the upper half */
+static size_t_and_error flashio_pwritev(struct flashio *self, const struct wr_iovec *iov, int iovcnt, uoff_t _offset) {
+ assert(self);
+ assert(iov);
+ assert(iovcnt > 0);
+
+ size_t total_count = 0;
+ for (int i = 0; i < iovcnt; i++)
+ total_count += iov[i].iov_len;
+ assert(total_count > 0);
+
+ if (_offset >= DATA_HSIZE)
+ return ERROR_AND(size_t, 0, error_new(E_POSIX_ENOSPC, "cannot write past half the chip size"));
+ size_t offset = (size_t) _offset;
+
+ size_t total_done = 0;
+ for (int i = 0; i < iovcnt; i++) {
+ size_t iov_done = 0;
+ while (iov_done < iov[i].iov_len) {
+ if (offset >= DATA_HSIZE)
+ return ERROR_AND(size_t, total_done, error_new(E_POSIX_ENOSPC, "cannot write past half the chip size"));
+ size_t sector_base = LM_ROUND_DOWN(offset, FLASH_SECTOR_SIZE);
+ size_t len = iov[i].iov_len - iov_done;
+ if (offset + len > sector_base + FLASH_SECTOR_SIZE)
+ len = (sector_base + FLASH_SECTOR_SIZE) - offset;
+ assert(offset + len <= DATA_HSIZE);
+
+ if (self->wbuf.ok && self->wbuf.pos != sector_base)
+ ab_flash_write_sector(self->wbuf.pos, self->wbuf.dat);
+ if (!self->wbuf.ok || self->wbuf.pos != sector_base) {
+ self->wbuf.ok = true;
+ self->wbuf.pos = sector_base;
+ if (len != FLASH_SECTOR_SIZE)
+ /* Don't bother with a read if we're just going to overwrite it. */
+ memcpy(self->wbuf.dat, DATA_START+DATA_HSIZE+sector_base, FLASH_SECTOR_SIZE);
+ }
+ memcpy(&self->wbuf.dat[offset-sector_base], iov[i].iov_write_from+iov_done, len);
+ total_done += len;
+ iov_done += len;
+ offset += len;
+ }
+ }
+ return ERROR_AND(size_t, total_done, ERROR_NULL);
+}
+
+static error flashio_close(struct flashio *self) {
+ assert(self);
+
+ if (self->finalize) {
+ if (self->wbuf.ok)
+ ab_flash_write_sector(self->wbuf.pos, self->wbuf.dat);
+ ab_flash_finalize(self->wbuf.dat);
+ }
+
+ return ERROR_NULL;
+}
+
+/* srv_file *******************************************************************/
+
+void flash_file_free(struct flash_file *self) {
+ assert(self);
+}
+struct lib9p_qid flash_file_qid(struct flash_file *self) {
+ assert(self);
+
+ return (struct lib9p_qid){
+ .type = LIB9P_QT_FILE|LIB9P_QT_EXCL|LIB9P_QT_APPEND,
+ .vers = 1,
+ .path = self->pathnum,
+ };
+}
+
+error flash_file_stat(struct flash_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_srv_stat *out) {
+ assert(self);
+ assert(ctx);
+ assert(out);
+
+ *out = ((struct lib9p_srv_stat){
+ .qid = flash_file_qid(self),
+ .mode = LIB9P_DM_EXCL|LIB9P_DM_APPEND|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),
+ });
+ return ERROR_NULL;
+}
+error flash_file_wstat(struct flash_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_srv_stat) {
+ assert(self);
+ assert(ctx);
+
+ return error_new(E_POSIX_EROFS, "read-only part of filesystem");
+}
+error flash_file_remove(struct flash_file *self, struct lib9p_srv_ctx *ctx) {
+ assert(self);
+ assert(ctx);
+
+ return error_new(E_POSIX_EROFS, "read-only part of filesystem");
+}
+
+LIB9P_SRV_NOTDIR(, struct flash_file, flash_file);
+
+static error flash_handle_ihex_data(void *, uint32_t off, uint8_t count, uint8_t *dat);
+static error flash_handle_ihex_eof(void *);
+
+lib9p_srv_fio_or_error flash_file_fopen(struct flash_file *self, struct lib9p_srv_ctx *ctx,
+ bool LM_UNUSED(rd), bool wr, bool LM_UNUSED(trunc)) {
+ assert(self);
+ assert(ctx);
+
+ memset(&self->io, 0, sizeof(self->io));
+ if (wr) {
+ ab_flash_initialize(self->io.wbuf.dat);
+ }
+
+ memset(&self->ihex, 0, sizeof(self->ihex));
+ self->ihex.handle_arg = self;
+ self->ihex.handle_data = flash_handle_ihex_data;
+ self->ihex.handle_eof = flash_handle_ihex_eof;
+
+ return ERROR_NEW_VAL(lib9p_srv_fio, LO_BOX(lib9p_srv_fio, self));
+}
+
+/* srv_fio ********************************************************************/
+
+static struct lib9p_qid flash_file_ioqid(struct flash_file *self) {
+ return flash_file_qid(self);
+}
+static uint32_t flash_file_iounit(struct flash_file *self) {
+ assert(self);
+ return FLASH_SECTOR_SIZE;
+}
+
+static void flash_file_iofree(struct flash_file *self) {
+ assert(self);
+
+ error err = flashio_close(&self->io);
+ assert(ERROR_IS_NULL(err));
+
+ err = ihex_decoder_close(&self->ihex);
+ assert(ERROR_IS_NULL(err));
+}
+
+static error flash_file_pread(struct flash_file *self, struct lib9p_srv_ctx *ctx,
+ lo_interface io_writer dst, uint64_t byte_offset, uint32_t byte_count) {
+ assert(self);
+ assert(ctx);
+
+ return flashio_pread_to(&self->io, dst, byte_offset, byte_count).err;
+}
+
+static error flash_handle_ihex_data(void *_self, uint32_t off, uint8_t count, uint8_t *dat) {
+ struct flash_file *self = _self;
+
+ if (off < XIP_BASE || off >= XIP_BASE + DATA_HSIZE)
+ return error_new(E_POSIX_ENOSPC, "cannot write outside of the first half of the chip: ",
+ (base16_u32_, off), " is outside of [", (base16_u32_, XIP_BASE), ",", (base16_u32_, XIP_BASE + DATA_HSIZE), ")");
+
+ return flashio_pwritev(&self->io,
+ &((struct wr_iovec){.iov_write_from = dat, .iov_len = count}), 1,
+ off - XIP_BASE).err;
+}
+static error flash_handle_ihex_eof(void *_self) {
+ struct flash_file *self = _self;
+ self->io.finalize = true;
+ return ERROR_NULL;
+}
+
+/* TODO: Also support uf2, not just ihex. */
+static uint32_t_or_error flash_file_pwrite(struct flash_file *self, struct lib9p_srv_ctx *ctx,
+ const void *buf,
+ uint32_t byte_count,
+ uint64_t LM_UNUSED(byte_offset)) {
+ assert(self);
+ assert(ctx);
+
+ size_t_and_error r = ihex_decoder_writev(&self->ihex,
+ &((struct wr_iovec){.iov_write_from = buf, .iov_len = byte_count}), 1);
+ if (r.size_t == 0 && !ERROR_IS_NULL(r.err))
+ return ERROR_NEW_ERR(uint32_t, r.err);
+ return ERROR_NEW_VAL(uint32_t, (uint32_t) r.size_t);
+}
diff --git a/cmd/sbc_harness/fs_harness_flash_bin.h b/flashimg/cpu_main/fs_harness_flash_bin.h
index 36382be..68cc953 100644
--- a/cmd/sbc_harness/fs_harness_flash_bin.h
+++ b/flashimg/cpu_main/fs_harness_flash_bin.h
@@ -1,30 +1,36 @@
-/* sbc_harness/fs_harness_flash_bin.h - 9P access to flash storage
+/* flashimg/cpu_main/fs_harness_flash_bin.h - 9P access to flash storage
*
* Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-#ifndef _SBC_HARNESS_FS_HARNESS_FLASH_BIN_H_
-#define _SBC_HARNESS_FS_HARNESS_FLASH_BIN_H_
+#ifndef _FLASHIMG_CPU_MAIN_FS_HARNESS_FLASH_BIN_H_
+#define _FLASHIMG_CPU_MAIN_FS_HARNESS_FLASH_BIN_H_
#include <hardware/flash.h> /* for FLASH_SECTOR_SIZE */
#include <lib9p/srv.h>
-struct flash_file {
- char *name;
- uint64_t pathnum;
+#include "ihex.h"
- BEGIN_PRIVATE(FS_HARNESS_FLASH_BIN);
- bool written;
+struct flashio {
+ bool finalize;
struct {
bool ok;
size_t pos;
uint8_t dat[FLASH_SECTOR_SIZE];
} wbuf, rbuf;
+};
+
+struct flash_file {
+ char *name;
+ uint64_t pathnum;
+
+ BEGIN_PRIVATE(FS_HARNESS_FLASH_BIN);
+ struct flashio io;
+ struct ihex_decoder ihex;
END_PRIVATE(FS_HARNESS_FLASH_BIN);
};
LO_IMPLEMENTATION_H(lib9p_srv_file, struct flash_file, flash_file);
-#define lo_box_flash_file_as_lib9p_srv_file(obj) util9p_box(flash_file, obj)
-#endif /* _SBC_HARNESS_FS_HARNESS_FLASH_BIN_H_ */
+#endif /* _FLASHIMG_CPU_MAIN_FS_HARNESS_FLASH_BIN_H_ */
diff --git a/flashimg/cpu_main/fs_harness_uptime_txt.c b/flashimg/cpu_main/fs_harness_uptime_txt.c
new file mode 100644
index 0000000..02e4171
--- /dev/null
+++ b/flashimg/cpu_main/fs_harness_uptime_txt.c
@@ -0,0 +1,157 @@
+/* flashimg/cpu_main/fs_harness_uptime_txt.c - 9P access to harness uptime
+ *
+ * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <libhw/generic/alarmclock.h>
+#include <libmisc/alloc.h> /* for heap_alloc(), free() */
+#include <libmisc/fmt.h> /* for fmt_snprint() */
+#include <util9p/static.h>
+
+#include "fs_harness_uptime_txt.h"
+
+LO_IMPLEMENTATION_C(lib9p_srv_file, struct uptime_file, uptime_file);
+
+struct uptime_fio {
+ struct uptime_file *parent;
+ size_t buf_len;
+ /* The maximum length (UINT64_MAX) string is 52 bytes, not
+ * including a nul-terminator:
+ *
+ * "18446744073709551615ns\n" # 22+1
+ * "584y343d 23h34m33.709551615s\n" # 28+1
+ */
+ char buf[52];
+};
+LO_IMPLEMENTATION_STATIC(lib9p_srv_fio, struct uptime_fio, uptime_fio);
+
+/* srv_file *******************************************************************/
+
+void uptime_file_free(struct uptime_file *self) {
+ assert(self);
+}
+struct lib9p_qid uptime_file_qid(struct uptime_file *self) {
+ assert(self);
+
+ return (struct lib9p_qid){
+ .type = LIB9P_QT_FILE,
+ .vers = 1,
+ .path = self->pathnum,
+ };
+}
+
+error uptime_file_stat(struct uptime_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_srv_stat *out) {
+ assert(self);
+ assert(ctx);
+ assert(out);
+
+ *out = ((struct lib9p_srv_stat){
+ .qid = uptime_file_qid(self),
+ .mode = 0444,
+ .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),
+ });
+ return ERROR_NULL;
+}
+error uptime_file_wstat(struct uptime_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_srv_stat) {
+ assert(self);
+ assert(ctx);
+
+ return error_new(E_POSIX_EROFS, "read-only part of filesystem");
+}
+error uptime_file_remove(struct uptime_file *self, struct lib9p_srv_ctx *ctx) {
+ assert(self);
+ assert(ctx);
+
+ return error_new(E_POSIX_EROFS, "read-only part of filesystem");
+}
+
+LIB9P_SRV_NOTDIR(, struct uptime_file, uptime_file);
+
+lib9p_srv_fio_or_error uptime_file_fopen(struct uptime_file *self, struct lib9p_srv_ctx *ctx,
+ bool LM_UNUSED(rd), bool LM_UNUSED(wr), bool LM_UNUSED(trunc)) {
+ assert(self);
+ assert(ctx);
+
+ struct uptime_fio *ret = heap_alloc(1, struct uptime_fio);
+ ret->parent = self;
+ ret->buf_len = 0;
+
+ return ERROR_NEW_VAL(lib9p_srv_fio, LO_BOX(lib9p_srv_fio, ret));
+}
+
+/* srv_fio ********************************************************************/
+
+static uint32_t uptime_fio_iounit(struct uptime_fio *self) {
+ assert(self);
+ return sizeof(self->buf);
+}
+
+static void uptime_fio_iofree(struct uptime_fio *self) {
+ assert(self);
+ free(self);
+}
+
+static struct lib9p_qid uptime_fio_ioqid(struct uptime_fio *self) {
+ assert(self);
+ assert(self->parent);
+ return uptime_file_qid(self->parent);
+}
+
+#define NS_PER_M (NS_PER_S*60)
+#define NS_PER_H (NS_PER_S*60*60)
+#define NS_PER_D (NS_PER_S*60*60*24)
+#define NS_PER_Y (NS_PER_S*60*60*24*365)
+
+static error uptime_fio_pread(struct uptime_fio *self, struct lib9p_srv_ctx *ctx,
+ lo_interface io_writer dst, uint64_t byte_offset, uint32_t byte_count) {
+ assert(self);
+ assert(ctx);
+
+ if (byte_offset == 0 || self->buf_len == 0) {
+ uint64_t now = LO_CALL(bootclock, get_time_ns);
+ self->buf_len = fmt_snprint(self->buf, sizeof(self->buf), now, "ns\n");
+
+ uint64_t ns = now;
+ uint64_t y = ns/NS_PER_Y; ns -= y*NS_PER_Y;
+ uint64_t d = ns/NS_PER_D; ns -= d*NS_PER_D;
+ uint64_t h = ns/NS_PER_H; ns -= h*NS_PER_H;
+ uint64_t m = ns/NS_PER_M; ns -= m*NS_PER_M;
+ uint64_t s = ns/NS_PER_S; ns -= s*NS_PER_S;
+ if (y)
+ self->buf_len += fmt_snprint(&self->buf[self->buf_len], sizeof(self->buf)-self->buf_len, y, "y");
+ if (y || d)
+ self->buf_len += fmt_snprint(&self->buf[self->buf_len], sizeof(self->buf)-self->buf_len, d, "d ");
+ if (y || d || h)
+ self->buf_len += fmt_snprint(&self->buf[self->buf_len], sizeof(self->buf)-self->buf_len, h, "h");
+ if (y || d || h || m)
+ self->buf_len += fmt_snprint(&self->buf[self->buf_len], sizeof(self->buf)-self->buf_len, m, "m");
+ self->buf_len += fmt_snprint(&self->buf[self->buf_len], sizeof(self->buf)-self->buf_len, s, ".", (rjust, 9, '0', ns), "s\n");
+ }
+
+ if (byte_offset > (uint64_t)self->buf_len)
+ return error_new(E_POSIX_EINVAL, "offset is past end-of-file length");
+
+ size_t beg_off = (size_t)byte_offset;
+ size_t end_off = beg_off + (size_t)byte_count;
+ if (end_off > self->buf_len)
+ end_off = self->buf_len;
+ return io_write(dst, &self->buf[beg_off], end_off-beg_off).err;
+}
+
+static uint32_t_or_error uptime_fio_pwrite(struct uptime_fio *self, struct lib9p_srv_ctx *ctx,
+ const void *LM_UNUSED(buf),
+ uint32_t LM_UNUSED(byte_count),
+ uint64_t LM_UNUSED(byte_offset)) {
+ assert(self);
+ assert(ctx);
+
+ return ERROR_NEW_ERR(uint32_t, error_new(E_POSIX_EROFS, "read-only part of filesystem"));
+}
diff --git a/flashimg/cpu_main/fs_harness_uptime_txt.h b/flashimg/cpu_main/fs_harness_uptime_txt.h
new file mode 100644
index 0000000..fcf8dbc
--- /dev/null
+++ b/flashimg/cpu_main/fs_harness_uptime_txt.h
@@ -0,0 +1,18 @@
+/* flashimg/cpu_main/fs_harness_uptime_txt.h - 9P access to harness uptime
+ *
+ * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#ifndef _FLASHIMG_CPU_MAIN_FS_HARNESS_UPTIME_TXT_H_
+#define _FLASHIMG_CPU_MAIN_FS_HARNESS_UPTIME_TXT_H_
+
+#include <lib9p/srv.h>
+
+struct uptime_file {
+ char *name;
+ uint64_t pathnum;
+};
+LO_IMPLEMENTATION_H(lib9p_srv_file, struct uptime_file, uptime_file);
+
+#endif /* _FLASHIMG_CPU_MAIN_FS_HARNESS_UPTIME_TXT_H_ */
diff --git a/flashimg/cpu_main/ihex.c b/flashimg/cpu_main/ihex.c
new file mode 100644
index 0000000..588a541
--- /dev/null
+++ b/flashimg/cpu_main/ihex.c
@@ -0,0 +1,231 @@
+/* flashimg/cpu_main/ihex.c - Intel Hex decoder
+ *
+ * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+/* https://archive.org/details/IntelHEXStandard */
+
+#include <string.h> /* for memchr() */
+
+#include <libmisc/assert.h>
+#include <libmisc/endian.h>
+
+#define IMPLEMENTATION_FOR_IHEX_H YES
+#include "ihex.h"
+
+LO_IMPLEMENTATION_C(io_writer, struct ihex_decoder, ihex_decoder);
+LO_IMPLEMENTATION_C(io_closer, struct ihex_decoder, ihex_decoder);
+
+enum ihex_record_type {
+ /* [U]SBA: [Upper] Segment Base Address : SBA = USBA<< 4 */
+ /* [U]LBA: [Upper] Linear Base Address : LBA = ULBA<<16 */
+ /* _EXT records define where DATA records are written to */
+ /* _START records define where execution should start */
+ IHEX_REC_DATA = 0x00, /* .dat is .len bytes of data, which go at either (USBA<<4)+(.off%64KiB) or ((ULBA<<16)+.off)%4GiB */
+ IHEX_REC_EOF = 0x01, /* .len=0, .off=0 */
+ IHEX_REC_ADDR_SEG_EXT = 0x02, /* .len=2, .off=0, .dat is u16be USBA */
+ IHEX_REC_ADDR_SEG_START = 0x03, /* .len=4, .off=0, .dat is u16be CS register then u16be IP register */
+ IHEX_REC_ADDR_LIN_EXT = 0x04, /* .len=2, .off=0, .dat is u16be ULBA */
+ IHEX_REC_ADDR_LIN_START = 0x05, /* .len=4, .off=0, .dat is u32be EIP register */
+};
+
+struct ihex_record {
+ uint8_t len;
+ uint16_t off;
+ enum ihex_record_type typ;
+ uint8_t *dat;
+};
+
+static error ihex_handle_record(struct ihex_decoder *self, struct ihex_record *rec) {
+ switch (rec->typ) {
+ case IHEX_REC_ADDR_SEG_EXT:
+ self->addr_mode = _IHEX_MODE_SEG;
+ self->addr_base = ((uint32_t)uint16be_decode(rec->dat)) << 4;
+ return ERROR_NULL;
+ case IHEX_REC_ADDR_LIN_EXT:
+ self->addr_mode = _IHEX_MODE_LIN;
+ self->addr_base = ((uint32_t)uint16be_decode(rec->dat)) << 16;
+ return ERROR_NULL;;
+ case IHEX_REC_DATA:
+ switch (self->addr_mode) {
+ case _IHEX_MODE_NONE:
+ return error_new(E_POSIX_EINVAL, "ihex: data record before base-address record");
+ case _IHEX_MODE_SEG:
+ if (!self->handle_data)
+ return ERROR_NULL;
+ if (rec->len <= UINT16_MAX - rec->off) {
+ /* 1 write */
+ return self->handle_data(self->handle_arg, self->addr_base + rec->off, rec->len, rec->dat);
+ } else {
+ /* wraps around; split into 2 writes */
+ uint8_t first_len = (uint8_t) (UINT16_MAX - rec->off);
+ if (first_len) {
+ error err = self->handle_data(self->handle_arg, self->addr_base + rec->off, first_len, rec->dat);
+ if (!ERROR_IS_NULL(err))
+ return err;
+ }
+ return self->handle_data(self->handle_arg, self->addr_base, rec->len - first_len, &rec->dat[first_len]);
+ }
+ case _IHEX_MODE_LIN:
+ if (!self->handle_data)
+ return ERROR_NULL;
+ uint32_t off = self->addr_base + rec->off;
+ if (rec->len <= UINT32_MAX - off) {
+ /* 1 write */
+ return self->handle_data(self->handle_arg, off, rec->len, rec->dat);
+ } else {
+ /* wraps around; split into 2 writes */
+ uint8_t first_len = (uint8_t) (UINT32_MAX - off);
+ if (first_len) {
+ error err = self->handle_data(self->handle_arg, off, first_len, rec->dat);
+ if (!ERROR_IS_NULL(err))
+ return err;
+ }
+ return self->handle_data(self->handle_arg, 0, rec->len - first_len, &rec->dat[first_len]);
+ }
+ default:
+ assert_notreached("bad addr_mode");
+ }
+ case IHEX_REC_EOF:
+ self->seen_eof = true;
+ if (!self->handle_eof)
+ return ERROR_NULL;
+ return self->handle_eof(self->handle_arg);
+ case IHEX_REC_ADDR_SEG_START:
+ if (!self->handle_set_exec_start_seg)
+ return ERROR_NULL;
+ uint16_t cs = uint16be_decode(&rec->dat[0]);
+ uint16_t ip = uint16be_decode(&rec->dat[2]);
+ return self->handle_set_exec_start_seg(self->handle_arg, cs, ip);
+ case IHEX_REC_ADDR_LIN_START:
+ if (!self->handle_set_exec_start_lin)
+ return ERROR_NULL;
+ uint32_t eip = uint32be_decode(rec->dat);
+ return self->handle_set_exec_start_lin(self->handle_arg, eip);
+ default:
+ assert_notreached("bad record type");
+ }
+}
+
+/**
+ * Hex-decode the byte 0xAB, and push it onto self->buf. If this
+ * completes the record in self->buf, then handle that record.
+ *
+ * @return the number of ASCII bytes consumed (0, 1, or 2) before
+ * encountering an error.
+ */
+static size_t_and_error ihex_decode_byte(struct ihex_decoder *self, char a, char b) {
+ uint8_t byte;
+ if ('0' <= a && a <= '9')
+ byte = (a - '0') << 4;
+ else if ('A' <= a && a <= 'F')
+ byte = (a - 'A' + 10) << 4;
+ else
+ return ERROR_AND(size_t, 0, error_new(E_POSIX_EILSEQ, "ihex: invalid hexadecimal: ", (qbyte, a)));
+ if ('0' <= b && b <= '9')
+ byte |= b - '0';
+ else if ('A' <= b && b <= 'F')
+ byte |= b - 'A' + 10;
+ else
+ return ERROR_AND(size_t, 1, error_new(E_POSIX_EILSEQ, "ihex: invalid hexadecimal: ", (qbyte, b)));
+ self->buf[self->buf_len++] = byte;
+ if (self->buf_len == self->buf[0]+5) {
+ uint8_t sum = 0;
+ for (size_t i = 0; i < (size_t)self->buf[0]+5; i++)
+ sum += self->buf[i];
+ if (sum != 0) {
+ self->sticky_err = error_new(E_POSIX_EPROTO, "ihex: checksum mismatch");
+ return ERROR_AND(size_t, 2, error_dup(self->sticky_err));
+ }
+ struct ihex_record rec = {
+ .len = self->buf[0],
+ .off = uint16be_decode(&self->buf[1]),
+ .typ = self->buf[3],
+ .dat = &self->buf[4],
+ };
+ error err = ihex_handle_record(self, &rec);
+ if (!ERROR_IS_NULL(err)) {
+ self->sticky_err = err;
+ return ERROR_AND(size_t, 2, error_dup(err));
+ }
+ self->in_record = false;
+ self->buf_len = 0;
+ }
+ return ERROR_AND(size_t, 2, ERROR_NULL);
+}
+
+static size_t_and_error ihex_decoder_write(struct ihex_decoder *self, const char *dat, size_t len_in) {
+ assert(self);
+ if (!len_in)
+ return ERROR_AND(size_t, 0, ERROR_NULL);
+ assert(dat);
+
+ if (!ERROR_IS_NULL(self->sticky_err))
+ return ERROR_AND(size_t, 0, error_dup(self->sticky_err));
+
+ size_t len_consumed = 0;
+
+ if (self->buf_char) {
+ assert(self->in_record);
+ size_t_and_error r = ihex_decode_byte(self, self->buf_char, dat[0]);
+ if (r.size_t)
+ len_consumed += r.size_t - 1;
+ self->buf_char = 0;
+ if (!ERROR_IS_NULL(r.err))
+ return ERROR_AND(size_t, len_consumed, r.err);
+ }
+
+ while (len_consumed < len_in) {
+ if (!self->in_record) {
+ const char *marker = memchr(&dat[len_consumed], ':', len_in-len_consumed);
+ if (!marker) {
+ len_consumed = len_in;
+ continue;
+ }
+ len_consumed += marker - &dat[len_consumed];
+
+ assert(dat[len_consumed] == ':');
+ if (self->seen_eof)
+ return ERROR_AND(size_t, len_consumed, error_new(E_POSIX_EPROTO, "ihex: record after EOF record"));
+ len_consumed++;
+ self->in_record = true;
+ }
+ while (len_in - len_consumed >= 2 && self->in_record) {
+ size_t_and_error r = ihex_decode_byte(self, dat[len_consumed], dat[len_consumed+1]);
+ len_consumed += r.size_t;
+ if (!ERROR_IS_NULL(r.err))
+ return ERROR_AND(size_t, len_consumed, r.err);
+ }
+ if (len_in - len_consumed && self->in_record) {
+ assert(len_in - len_consumed == 1);
+ if (!(('0' <= dat[len_consumed] && dat[len_consumed] <= '9') ||
+ ('A' <= dat[len_consumed] && dat[len_consumed] <= 'F')))
+ return ERROR_AND(size_t, len_consumed, error_new(E_POSIX_EILSEQ, "ihex: invalid hexadecimal: ", (qbyte, dat[len_consumed])));
+ self->buf_char = dat[len_consumed++];
+ }
+ }
+
+ assert(len_consumed == len_in);
+ return ERROR_AND(size_t, len_in, ERROR_NULL);
+}
+
+size_t_and_error ihex_decoder_writev(struct ihex_decoder *self, const struct wr_iovec *iov, int iovcnt) {
+ assert(self);
+ assert(iov);
+ assert(iovcnt);
+
+ size_t total = 0;
+ for (int i = 0; i < iovcnt; i++) {
+ size_t_and_error r = ihex_decoder_write(self, iov[i].iov_write_from, iov[i].iov_len);
+ total += r.size_t;
+ if (!ERROR_IS_NULL(r.err))
+ return ERROR_AND(size_t, total, r.err);
+ }
+ return ERROR_AND(size_t, total, ERROR_NULL);
+}
+
+error ihex_decoder_close(struct ihex_decoder *self) {
+ error_cleanup(&self->sticky_err);
+ return ERROR_NULL;
+}
diff --git a/flashimg/cpu_main/ihex.h b/flashimg/cpu_main/ihex.h
new file mode 100644
index 0000000..dafd65e
--- /dev/null
+++ b/flashimg/cpu_main/ihex.h
@@ -0,0 +1,49 @@
+/* flashimg/cpu_main/ihex.h - Intel Hex decoder
+ *
+ * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+/* https://archive.org/details/IntelHEXStandard */
+
+#ifndef _FLASHIMG_CPU_MAIN_IHEX_H_
+#define _FLASHIMG_CPU_MAIN_IHEX_H_
+
+#include <stdbool.h> /* for bool */
+#include <stddef.h> /* for size_t */
+#include <stdint.h> /* for uint{n}_t */
+
+#include <libhw/generic/io.h>
+#include <libmisc/private.h>
+
+struct ihex_decoder {
+ void *handle_arg;
+ error (*handle_data)(void *arg, uint32_t off, uint8_t count, uint8_t *dat);
+ error (*handle_set_exec_start_seg)(void *arg, uint16_t cs, uint16_t ip);
+ error (*handle_set_exec_start_lin)(void *arg, uint32_t eip);
+ error (*handle_eof)(void *arg);
+
+ BEGIN_PRIVATE(IHEX_H);
+
+ bool seen_eof;
+ error sticky_err;
+
+ /* ihex_decoder_write: deal with ASCII soup */
+ bool in_record;
+ char buf_char; /* the first nibble of a byte (still in ASCII) */
+
+ /* ihex_decode_byte: build records from decoded bytes */
+ /* The currently-being-decoded record, after hex decoding. */
+ uint16_t buf_len;
+ uint8_t buf[0xFF+5];
+
+ /* ihex_handle_record: handle record semantics */
+ enum { _IHEX_MODE_NONE, _IHEX_MODE_SEG, _IHEX_MODE_LIN } addr_mode;
+ uint32_t addr_base;
+
+ END_PRIVATE(IHEX_H);
+};
+LO_IMPLEMENTATION_H(io_writer, struct ihex_decoder, ihex_decoder);
+LO_IMPLEMENTATION_H(io_closer, struct ihex_decoder, ihex_decoder);
+
+#endif /* _FLASHIMG_CPU_MAIN_IHEX_H_ */
diff --git a/cmd/sbc_harness/main.c b/flashimg/cpu_main/main.c
index 143bae0..a471d2a 100644
--- a/cmd/sbc_harness/main.c
+++ b/flashimg/cpu_main/main.c
@@ -1,4 +1,4 @@
-/* sbc_harness/main.c - Main entry point and event loop for sbc-harness
+/* flashimg/cpu_main/main.c - Main entry point and event loop for sbc-harness
*
* Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
@@ -8,8 +8,9 @@
#include <string.h> /* libc: for strlen() */
/* pico-sdk */
-#include <pico/stdio_uart.h> /* pico-sdk:pico_stdio_uart: for stdio_uart_init() */
#include <hardware/flash.h> /* pico-sdk:hardware_flash: for flash_get_unique_id() */
+#include <hardware/uart.h>
+#include <hardware/gpio.h>
/* our OS */
#include <libcr/coroutine.h>
@@ -19,10 +20,9 @@
#include <libhw/w5500.h>
/* our application libraries */
+#include <lib9p/srv.h>
#include <libdhcp/client.h>
#include <libusb/usb_common.h>
-#include <lib9p/srv.h>
-#include <util9p/static.h>
/* our utility libraries */
#include <libmisc/hash.h>
@@ -30,10 +30,13 @@
#include <libmisc/log.h>
/* local headers */
-#include "usb_keyboard.h"
#include "static.h"
+#include "usb_keyboard.h"
+
+/* 9P files */
+#include <util9p/static.h>
#include "fs_harness_flash_bin.h"
-#include "fs_harness_uptime_txt.h"
+#include <fs_harness_uptime_txt.h>
/* configuration **************************************************************/
@@ -95,11 +98,11 @@ static struct lib9p_srv_file root =
.data_end = _binary_static_Documentation_harness_uptime_txt_txt_end),
),
STATIC_DIR("harness",
+ API_FILE("flash.bin",
+ flash),
STATIC_FILE("rom.bin",
.data_start = (void*)0x00000000,
.data_size = 16*1024),
- API_FILE("flash.bin",
- flash),
API_FILE("uptime.txt",
uptime),
// TODO: system.log
@@ -114,8 +117,8 @@ static struct lib9p_srv_file root =
),
);
-static lo_interface lib9p_srv_file get_root(struct lib9p_srv_ctx *LM_UNUSED(ctx), struct lib9p_s LM_UNUSED(treename)) {
- return root;
+static lib9p_srv_file_or_error get_root(struct lib9p_srv_ctx *LM_UNUSED(ctx), struct lib9p_s LM_UNUSED(treename)) {
+ return ERROR_NEW_VAL(lib9p_srv_file, root);
}
/* Code ***********************************************************************/
@@ -149,7 +152,7 @@ struct {
static COROUTINE dhcp_cr(void *) {
cr_begin();
- dhcp_client_main(lo_box_w5500_if_as_net_iface(&globals.dev_w5500), "harness");
+ dhcp_client_main(LO_BOX(net_iface, &globals.dev_w5500), "harness");
cr_end();
}
@@ -157,7 +160,7 @@ static COROUTINE dhcp_cr(void *) {
static COROUTINE read9p_cr(void *) {
cr_begin();
- lo_interface net_iface iface = lo_box_w5500_if_as_net_iface(&globals.dev_w5500);
+ lo_interface net_iface iface = LO_BOX(net_iface, &globals.dev_w5500);
lo_interface net_stream_listener listener = LO_CALL(iface, tcp_listen, LIB9P_DEFAULT_PORT_9FS);
lib9p_srv_accept_and_read_loop(&globals.srv, listener);
@@ -204,7 +207,7 @@ COROUTINE init_cr(void *) {
17, /* PIN_CS */
0, 1, 2, 3); /* DMA channels */
w5500_init(&globals.dev_w5500, "W5500",
- lo_box_rp2040_hwspi_as_spi(&globals.dev_spi),
+ LO_BOX(spi, &globals.dev_spi),
21, /* PIN_INTR */
20, /* PIN_RESET */
((struct net_eth_addr){{
@@ -226,28 +229,66 @@ COROUTINE init_cr(void *) {
globals.srv.rootdir = get_root;
/* set up coroutines **************************************************/
- coroutine_add("usb_common", usb_common_cr, NULL);
- 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);
+ cid_t cid;
+ cid = coroutine_add("usb_common", usb_common_cr, NULL);
+ assert(cid);
+ cid = coroutine_add("usb_keyboard", usb_keyboard_cr, &globals.keyboard_chan);
+ assert(cid);
+ //cid = coroutine_add("hello_world", hello_world_cr, &globals.keyboard_chan);
+ assert(cid);
+ cid = coroutine_add("dhcp", dhcp_cr, NULL);
+ assert(cid);
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);
+ cid = coroutine_add_with_stack(COROUTINE_STACK_read9p_cr[i], COROUTINE_STACK_read9p_cr_len,
+ name, read9p_cr, NULL);
+ assert(cid);
}
for (int i = 0; i < _CONFIG_9P_MAX_REQS; i++) {
char name[] = {'w', 'r', 'i', 't', 'e', '-', hexdig[i], '\0'};
- coroutine_add(name, write9p_cr, NULL);
+ cid = coroutine_add_with_stack(COROUTINE_STACK_write9p_cr[i], COROUTINE_STACK_write9p_cr_len,
+ name, write9p_cr, NULL);
+ assert(cid);
}
cr_exit();
}
+void __lm_putchar(unsigned char c) {
+ if (c == '\n') {
+ while (!uart_is_writable(uart0))
+ tight_loop_contents();
+ uart_get_hw(uart0)->dr = '\r';
+ }
+ while (!uart_is_writable(uart0))
+ tight_loop_contents();
+ uart_get_hw(uart0)->dr = c;
+}
+
+void __lm_abort(void) {
+ exit(1);
+}
+
+[[noreturn]] void assert_panic(const char *fmt, ...) {
+ /* Most of the panic()s in pico-sdk are simple strings, very
+ * few use printf-style formatters. And those that do are
+ * still readable if we ignore the formatting. */
+ assert_notreached(fmt);
+}
+
int main() {
bootclock = rp2040_hwtimer(0);
- stdio_uart_init();
+
+ uart_init(uart0, 115200);
+ gpio_set_function(0, GPIO_FUNC_UART); /* tx */
+ gpio_set_function(1, GPIO_FUNC_UART); /* rx */
+ bi_decl(bi_2pins_with_names(0, "UART TX",
+ 1, "UART RX"));
+
/* char *hdr = "=" * (80-strlen("info : MAIN: ")); */
log_infoln("===================================================================");
- coroutine_add("init", init_cr, NULL);
+ cid_t cid = coroutine_add("init", init_cr, NULL);
+ assert(cid);
coroutine_main();
assert_notreached("all coroutines exited");
}
diff --git a/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS.md b/flashimg/cpu_main/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS.md
index b3fc12e..b3fc12e 100644
--- a/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS.md
+++ b/flashimg/cpu_main/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS.md
diff --git a/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/agpl-3.0.txt b/flashimg/cpu_main/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/agpl-3.0.txt
index 8a9b6f3..8a9b6f3 120000
--- a/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/agpl-3.0.txt
+++ b/flashimg/cpu_main/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/agpl-3.0.txt
diff --git a/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/dhcp.bsd3-mit.txt b/flashimg/cpu_main/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/dhcp.bsd3-mit.txt
index 0277bc8..0277bc8 120000
--- a/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/dhcp.bsd3-mit.txt
+++ b/flashimg/cpu_main/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/dhcp.bsd3-mit.txt
diff --git a/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/newlib.txt b/flashimg/cpu_main/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/newlib.txt
index 5c5939c..5c5939c 120000
--- a/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/newlib.txt
+++ b/flashimg/cpu_main/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/newlib.txt
diff --git a/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/pico-sdk.bsd3.txt b/flashimg/cpu_main/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/pico-sdk.bsd3.txt
index 52c4374..52c4374 120000
--- a/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/pico-sdk.bsd3.txt
+++ b/flashimg/cpu_main/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/pico-sdk.bsd3.txt
diff --git a/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/tinyusb.mit.txt b/flashimg/cpu_main/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/tinyusb.mit.txt
index 22a67cf..22a67cf 120000
--- a/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/tinyusb.mit.txt
+++ b/flashimg/cpu_main/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/tinyusb.mit.txt
diff --git a/cmd/sbc_harness/static/Documentation/harness_flash_bin.txt b/flashimg/cpu_main/static/Documentation/harness_flash.bin.txt
index 115f2ee..1b58d6d 100644
--- a/cmd/sbc_harness/static/Documentation/harness_flash_bin.txt
+++ b/flashimg/cpu_main/static/Documentation/harness_flash.bin.txt
@@ -2,14 +2,20 @@ NAME
/harness/flash.bin
DESCRIPTION
- Access to the flash storage chip (where the harness firmware
- is stored).
+ Access the flash storage chip (where the harness firmware is
+ stored).
- Any number of readers may read the flash contents.
+ Reading from the file reads the raw flash contents.
- Only one writer can have the file open at a time; once the
+ Writing to the file does not accept raw data; instead the data
+ must be encapsulated in the [Intel Hex] format, with the Hex
+ file writing to the region 0x1000_0000-0x1010_0000. While less
+ convenient than verbatim data, the Hex format provides in-band
+ checksums and EOF-markers that help prevent rendering the
+ harness unbootable with corrupted or truncated writes. Any
+ holes in the Intel Hex file are filled with "1" bits. Once a
+ complete Intel Hex file has been written without error and the
file is closed, the harness reboots into the new firmware.
- Writes to the top half of the chip will fail.
BUGS
- The size of the chip is configured at compile-time. If the
@@ -21,13 +27,17 @@ BUGS
chip will crash.
- When writing to the flash using this file, only half of the
- chip capacity is usable; the top half and bottom half are
- mirrors of each-other. This is to avoid the firmware
+ chip capacity is usable (the size of the region specified
+ above is half the chip size); the top half and bottom half
+ are mirrors of each-other. This is to avoid the firmware
crashing as its program text is overwritten; the firmware is
executing out of the bottom half, and writing to the top
half; once the file is closed, a minimal in-RAM function
copies the top half to the bottom half and reboots.
+SEE ALSO:
+ [Intel Hex]: https://archive.org/details/IntelHEXStandard
+
AUTHOR
Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/cmd/sbc_harness/static/Documentation/harness_rom_bin.txt b/flashimg/cpu_main/static/Documentation/harness_rom.bin.txt
index 63fd0a3..63fd0a3 100644
--- a/cmd/sbc_harness/static/Documentation/harness_rom_bin.txt
+++ b/flashimg/cpu_main/static/Documentation/harness_rom.bin.txt
diff --git a/flashimg/cpu_main/static/Documentation/harness_uptime.txt.txt b/flashimg/cpu_main/static/Documentation/harness_uptime.txt.txt
new file mode 100644
index 0000000..09e9243
--- /dev/null
+++ b/flashimg/cpu_main/static/Documentation/harness_uptime.txt.txt
@@ -0,0 +1,27 @@
+NAME
+ /harness/uptime.txt
+
+DESCRIPTION
+ Reading this file gives a text string of the format
+
+ {ns}ns
+ [[[[{y}y]{d}d ]{h}h]{m}m]{s.09}s
+
+ That is: the first line is simply the harness's uptime in an
+ integer number of nanoseconds; and the second line is this
+ same number in a more human-readable form; divided into
+ seconds, minutes, hours, days, and years.
+
+BUGS
+ - Using nanoseconds gives the illusion of more precision than
+ there actually is; the harness' clock only has microsecond
+ resolution; the last 3 digits of the returned nanosecond
+ count will always be 0.
+
+ - In the human-readable form, the days are always exactly
+ 60*60*24 seconds (leap seconds are ignored), and the years
+ are always exactly 365 days (leap years are ignored).
+
+AUTHOR
+ Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/flashimg/cpu_main/tests/test_ihex.c b/flashimg/cpu_main/tests/test_ihex.c
new file mode 100644
index 0000000..f173388
--- /dev/null
+++ b/flashimg/cpu_main/tests/test_ihex.c
@@ -0,0 +1,128 @@
+/* flashimg/cpu_main/tests/test_ihex.c - Tests for ihex.c
+ *
+ * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <stdio.h> /* for putchar() */
+#include <string.h>
+
+#include <libmisc/fmt.h>
+
+#include "ihex.h"
+
+struct stdout { size_t len; };
+LO_IMPLEMENTATION_STATIC(fmt_dest, struct stdout, stdout);
+static void stdout_putb(struct stdout *self, uint8_t b) {
+ putchar(b);
+ self->len++;
+}
+static size_t stdout_tell(struct stdout *self) {
+ return self->len;
+}
+
+static lo_interface fmt_dest fmt_stdout = lo_box_stdout_as_fmt_dest(&((struct stdout){}));
+
+#define test_assert(expr) do { \
+ if (!(expr)) \
+ fmt_print( \
+ fmt_stdout, \
+ "test failure: ", __FILE__, ":", __LINE__, ":", __func__, \
+ ": " #expr "\n"); \
+ } while (0)
+
+static char *input =
+ /* ,-byte count
+ * | ,-address
+ * | | ,-record type
+ * | | | ,- checksum
+ *[][--][][..............................][]\r\n */
+ ":020000041000EA\r\n" /* base_addr = linear(0x1000) = 0x1000<<16 */
+ ":1000000000B5324B212058609868022188439860DF\r\n" /* memcpy(chip[base_addr+0x0000], "\x00\xB5\x32\x4B\x21\x20\x58\x60\x98\x68\x02\x21\x88\x43\x98\x60", 16) */
+ ":10001000D860186158612E4B002199600221596106\r\n" /* memcpy(chip[base_addr+0x0010], "\xD8\x60\x18\x61\x58\x61\x2E\x4B\x00\x21\x99\x60\x02\x21\x59\x61", 16) */
+ ":10BE9C000000000000000000000000000000000096\r\n" /* memcpy(chip[base_addr+0xBE9C], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16) */
+ ":04BEAC00CC4A00205C\r\n" /* memcpy(chip[base_addr+0xBEAC], "\x00\xCC\x4A\x00\x20", 5) */
+ ":04000005100001E9FD\r\n" /* start_exec_at = linear(0x100001E9) */
+ ":00000001FF\r\n"; /* EOF */
+
+static int cnt = 0;
+
+static error handle_data(void *, uint32_t off, uint8_t count, uint8_t *dat) {
+ switch (cnt) {
+ case 0:
+ test_assert(off == UINT32_C(0x10000000));
+ test_assert(count == 16);
+ test_assert(memcmp(dat, "\x00\xB5\x32\x4B\x21\x20\x58\x60\x98\x68\x02\x21\x88\x43\x98\x60", 16) == 0);
+ break;
+ case 1:
+ test_assert(off == UINT32_C(0x10000010));
+ test_assert(count == 16);
+ test_assert(memcmp(dat, "\xD8\x60\x18\x61\x58\x61\x2E\x4B\x00\x21\x99\x60\x02\x21\x59\x61", 16) == 0);
+ break;
+ case 2:
+ test_assert(off == UINT32_C(0x1000BE9C));
+ test_assert(count == 16);
+ test_assert(memcmp(dat, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16) == 0);
+ break;
+ case 4:
+ test_assert(off == UINT32_C(0x1000BE9C));
+ test_assert(count == 5);
+ test_assert(memcmp(dat, "\x00\xCC\x4A\x00\x20", 5) == 0);
+ break;
+ default:
+ test_assert(false);
+ }
+ cnt++;
+ return ERROR_NULL;
+}
+static error handle_set_exec_start_seg(void *, uint16_t LM_UNUSED(cs), uint16_t LM_UNUSED(ip)) {
+ switch (cnt) {
+ default:
+ test_assert(false);
+ }
+ cnt++;
+ return ERROR_NULL;
+}
+static error handle_set_exec_start_lin(void *, uint32_t eip) {
+ switch (cnt) {
+ case 5:
+ test_assert(eip == UINT32_C(0x100001E9));
+ break;
+ default:
+ test_assert(false);
+ }
+ cnt++;
+ return ERROR_NULL;
+}
+static error handle_eof(void *) {
+ switch (cnt) {
+ case 6:
+ break;
+ default:
+ test_assert(false);
+ }
+ cnt++;
+ return ERROR_NULL;
+}
+
+int main() {
+ struct ihex_decoder dec = {
+ .handle_data = handle_data,
+ .handle_set_exec_start_seg = handle_set_exec_start_seg,
+ .handle_set_exec_start_lin = handle_set_exec_start_lin,
+ .handle_eof = handle_eof,
+ };
+
+ size_t_and_error ret = ihex_decoder_writev(&dec, &((struct wr_iovec){
+ .iov_write_from = input,
+ .iov_len = strlen(input),
+ }), 1);
+ fmt_print(fmt_stdout,
+ "ret = (", ret.size_t, ", ", (error, ret.err), ")\n",
+ "cnt = ", cnt, "\n");
+ test_assert(ret.size_t == strlen(input));
+ test_assert(ERROR_IS_NULL(ret.err));
+ test_assert(cnt == 6);
+
+ return 0;
+}
diff --git a/cmd/sbc_harness/tusb_log.c b/flashimg/cpu_main/tusb_log.c
index 09fe755..aacec87 100644
--- a/cmd/sbc_harness/tusb_log.c
+++ b/flashimg/cpu_main/tusb_log.c
@@ -1,4 +1,4 @@
-/* sbc_harness/tusb_log.c - Logger for tusb_config.h
+/* flashimg/cpu_main/tusb_log.c - Logger for tusb_config.h
*
* Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/cmd/sbc_harness/usb_keyboard.c b/flashimg/cpu_main/usb_keyboard.c
index 0573dba..dd9e26b 100644
--- a/cmd/sbc_harness/usb_keyboard.c
+++ b/flashimg/cpu_main/usb_keyboard.c
@@ -1,4 +1,4 @@
-/* sbc_harness/usb_keyboard.c - Implementation of a USB keyboard device
+/* flashimg/cpu_main/usb_keyboard.c - Implementation of a USB keyboard device
*
* Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
@@ -6,9 +6,9 @@
#include <tusb.h>
+#include <libmisc/macro.h>
#include <libusb/tusb_helpers.h> /* for TUD_ENDPOINT_IN */
#include <libusb/usb_common.h>
-#include <libmisc/macro.h>
#include "usb_keyboard.h"
@@ -20,7 +20,7 @@ static uint8_t const hid_report_descriptor_keyboard[] = { TUD_HID_REPORT_DESC_KE
static uint8_t kbd_ifc = 0;
-void usb_keyboard_init() {
+void usb_keyboard_init(void) {
if (kbd_ifc)
return;
@@ -85,23 +85,20 @@ COROUTINE usb_keyboard_cr(void *_chan) {
* §6.2.2 "Report Descriptor") for the given index.
*/
uint8_t const *tud_hid_descriptor_report_cb(uint8_t index) {
- static uint8_t const *reports[] = {
- hid_report_descriptor_keyboard,
- };
- if (index >= TU_ARRAY_SIZE(reports))
- return NULL;
- return reports[index];
+ static uint8_t const *reports[] = {
+ hid_report_descriptor_keyboard,
+ };
+ if (index >= TU_ARRAY_SIZE(reports))
+ return NULL;
+ return reports[index];
}
-uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
-{
+uint16_t tud_hid_get_report_cb(uint8_t LM_UNUSED(instance),
+ uint8_t LM_UNUSED(report_id),
+ hid_report_type_t LM_UNUSED(report_type),
+ uint8_t* LM_UNUSED(buffer),
+ uint16_t LM_UNUSED(reqlen)) {
// TODO not implemented
- (void) instance;
- (void) report_id;
- (void) report_type;
- (void) buffer;
- (void) reqlen;
-
return 0;
}
diff --git a/cmd/sbc_harness/usb_keyboard.h b/flashimg/cpu_main/usb_keyboard.h
index cf8483b..52b9b67 100644
--- a/cmd/sbc_harness/usb_keyboard.h
+++ b/flashimg/cpu_main/usb_keyboard.h
@@ -1,11 +1,11 @@
-/* sbc_harness/usb_keyboard.h - Implementation of a USB keyboard device
+/* flashimg/cpu_main/usb_keyboard.h - Implementation of a USB keyboard device
*
* Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-#ifndef _SBC_HARNESS_USB_KEYBOARD_H_
-#define _SBC_HARNESS_USB_KEYBOARD_H_
+#ifndef _FLASHIMG_CPU_MAIN_USB_KEYBOARD_H_
+#define _FLASHIMG_CPU_MAIN_USB_KEYBOARD_H_
#include <stdint.h> /* for uint32_t */
@@ -17,4 +17,4 @@ CR_RPC_DECLARE(usb_keyboard_rpc, uint32_t, int);
void usb_keyboard_init(void);
COROUTINE usb_keyboard_cr(void *arg);
-#endif /* _SBC_HARNESS_USB_KEYBOARD_H_ */
+#endif /* _FLASHIMG_CPU_MAIN_USB_KEYBOARD_H_ */
diff --git a/lib9p/CMakeLists.txt b/lib9p/CMakeLists.txt
index 2a2f858..9ef8465 100644
--- a/lib9p/CMakeLists.txt
+++ b/lib9p/CMakeLists.txt
@@ -3,8 +3,15 @@
# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
# SPDX-License-Identifier: AGPL-3.0-or-later
+add_library(lib9p_core_headers INTERFACE)
+target_include_directories(lib9p_core_headers PUBLIC INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/core_include)
+target_link_libraries(lib9p_core_headers INTERFACE
+ libhw_generic_headers
+ libmisc_headers
+)
+
add_library(lib9p_core INTERFACE)
-target_include_directories(lib9p_core PUBLIC INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/core_include)
+target_link_libraries(lib9p_core INTERFACE lib9p_core_headers)
target_sources(lib9p_core INTERFACE
core.c
core_generated.c
@@ -14,10 +21,18 @@ target_link_libraries(lib9p_core INTERFACE
libmisc
)
+add_library(lib9p_srv_headers INTERFACE)
+target_include_directories(lib9p_srv_headers PUBLIC INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/srv_include)
+target_link_libraries(lib9p_srv_headers INTERFACE
+ lib9p_core_headers
+ libcr_ipc_headers
+)
+
add_library(lib9p_srv INTERFACE)
-target_include_directories(lib9p_srv PUBLIC INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/srv_include)
+target_link_libraries(lib9p_srv INTERFACE lib9p_srv_headers)
target_sources(lib9p_srv INTERFACE
srv.c
+ srv_generated.c
)
target_link_libraries(lib9p_srv INTERFACE
lib9p_core
@@ -48,8 +63,10 @@ if (ENABLE_TESTS)
add_lib9p_executable("testclient-sess")
add_lib9p_test("./testclient-sess")
+ add_lib9p_executable("testclient-hangup")
+ add_lib9p_test("./testclient-hangup")
+
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]"
@@ -57,11 +74,15 @@ if (ENABLE_TESTS)
"CONFIG_9P_ENABLE_9P2000_p9p;[0;1]"
)
function(add_compile_test n defs)
- add_executable("test_compile${n}" "tests/test_compile.c")
- target_link_libraries("test_compile${n}" lib9p_srv)
+ add_library("test_compile${n}" STATIC "tests/test_compile.c"
+ core.c
+ core_generated.c
+ srv.c
+ srv_generated.c
+ )
+ target_link_libraries("test_compile${n}" PUBLIC lib9p_srv_headers)
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/core.c b/lib9p/core.c
index 464b31d..ae2d3ca 100644
--- a/lib9p/core.c
+++ b/lib9p/core.c
@@ -4,8 +4,7 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-#include <stdarg.h> /* for va_* */
-#include <string.h> /* for strlen(), strnlen(), strncpy(), memcmp(), memset() */
+#include <string.h> /* for strlen(), strnlen(), strncpy(), memcmp(), memset() */
#include <libmisc/assert.h> /* for assert() */
#include <libmisc/endian.h> /* for uint32le_decode() */
@@ -17,7 +16,7 @@
/* strings ********************************************************************/
-struct lib9p_s lib9p_str(char *s) {
+struct lib9p_s lib9p_str(const char *s) {
if (!s)
return (struct lib9p_s){};
return (struct lib9p_s){
@@ -25,7 +24,7 @@ struct lib9p_s lib9p_str(char *s) {
.utf8 = s,
};
}
-struct lib9p_s lib9p_strn(char *s, size_t maxlen) {
+struct lib9p_s lib9p_strn(const char *s, size_t maxlen) {
if (maxlen == 0 || !s)
return (struct lib9p_s){};
return (struct lib9p_s){
@@ -46,35 +45,14 @@ bool lib9p_str_eq(struct lib9p_s a, struct lib9p_s b) {
(a.len == 0 || memcmp(a.utf8, b.utf8, a.len) == 0);
}
-/* ctx ************************************************************************/
-
-void lib9p_ctx_clear_error(struct lib9p_ctx *ctx) {
- assert(ctx);
-#if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L
- ctx->err_num = 0;
-#endif
- ctx->err_msg[0] = '\0';
-}
-
-bool lib9p_ctx_has_error(struct lib9p_ctx *ctx) {
- assert(ctx);
- return ctx->err_msg[0];
-}
-
/* bounds checks **************************************************************/
static inline void assert_ver(enum lib9p_version ver) {
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wtype-limits"
assert(0 <= ver && ver < LIB9P_VER_NUM);
-#pragma GCC diagnostic pop
}
static inline void assert_typ(enum lib9p_msg_type typ) {
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wtype-limits"
assert(0 <= typ && typ < 0xFF);
-#pragma GCC diagnostic pop
}
/* simple lookups *************************************************************/
@@ -103,36 +81,38 @@ const char *lib9p_msgtype_str(enum lib9p_version ver, enum lib9p_msg_type typ) {
/* main message functions *****************************************************/
void fmt_print_lib9p_msg(lo_interface fmt_dest w, struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body) {
- assert(ctx);
- assert_ver(ctx->version);
- assert_typ(typ);
- assert(_lib9p_table_msg[ctx->version][typ].print);
- _lib9p_table_msg[ctx->version][typ].print(w, ctx, body);
-}
-
-#define _lib9p_validate(LOW_TYP_BIT, ERRMSG, TABLE) do { \
- assert_ver(ctx->version); \
- /* Inspect the first 5 bytes ourselves. */ \
- uint32_t net_size = uint32le_decode(net_bytes); \
- if (net_size < 5) \
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "message is impossibly short"); \
- uint8_t typ = net_bytes[4]; \
- if (typ % 2 != LOW_TYP_BIT) \
- return lib9p_error(ctx, LIB9P_ERRNO_L_EOPNOTSUPP, ERRMSG ": message_type=", lib9p_msgtype_str(ctx->version, typ)); \
- struct _lib9p_recv_tentry tentry = TABLE[ctx->version][typ/2]; \
- if (!tentry.validate) \
- return lib9p_error(ctx, LIB9P_ERRNO_L_EOPNOTSUPP, "unknown message type: ", lib9p_msgtype_str(ctx->version, typ), \
- " (protocol_version=", lib9p_version_str(ctx->version), ")"); \
- \
- /* Now use the message-type-specific tentry to process the whole thing. */ \
- return tentry.validate(ctx, net_size, net_bytes); \
+ assert(ctx);
+ assert_ver(ctx->version);
+ assert_typ(typ);
+ assert(_lib9p_table_msg[ctx->version][typ].print);
+ _lib9p_table_msg[ctx->version][typ].print(w, ctx, body);
+}
+
+#define _lib9p_validate(LOW_TYP_BIT, ERRMSG, TABLE) do { \
+ assert_ver(ctx->version); \
+ /* Inspect the first 5 bytes ourselves. */ \
+ uint32_t net_size = uint32le_decode(net_bytes); \
+ if (net_size < 5) \
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "message is impossibly short")); \
+ uint8_t typ = net_bytes[4]; \
+ if (typ % 2 != LOW_TYP_BIT) \
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EOPNOTSUPP, ERRMSG ": message_type=", \
+ lib9p_msgtype_str(ctx->version, typ))); \
+ struct _lib9p_recv_tentry tentry = TABLE[ctx->version][typ/2]; \
+ if (!tentry.validate) \
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EOPNOTSUPP, "unknown message type: ", \
+ lib9p_msgtype_str(ctx->version, typ), \
+ " (protocol_version=", lib9p_version_str(ctx->version), ")")); \
+ \
+ /* Now use the message-type-specific tentry to process the whole thing. */ \
+ return tentry.validate(ctx, net_size, net_bytes); \
} while (0)
-ssize_t lib9p_Tmsg_validate(struct lib9p_ctx *ctx, uint8_t *net_bytes) {
+size_t_or_error lib9p_Tmsg_validate(struct lib9p_ctx *ctx, uint8_t *net_bytes) {
_lib9p_validate(0, "expected a T-message but got an R-message", _lib9p_table_Tmsg_recv);
}
-ssize_t lib9p_Rmsg_validate(struct lib9p_ctx *ctx, uint8_t *net_bytes) {
+size_t_or_error lib9p_Rmsg_validate(struct lib9p_ctx *ctx, uint8_t *net_bytes) {
_lib9p_validate(1, "expected an R-message but got a T-message", _lib9p_table_Rmsg_recv);
}
@@ -172,20 +152,20 @@ void lib9p_Rmsg_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes,
struct _lib9p_send_tentry tentry = TABLE[ctx->version][typ/2]; \
assert(tentry.marshal); \
\
- bool ret_erred = tentry.marshal(ctx, body, &_ret); \
+ error ret_err = tentry.marshal(ctx, body, &_ret); \
if (_ret.net_iov[_ret.net_iov_cnt-1].iov_len == 0) \
_ret.net_iov_cnt--; \
\
ret->iov_cnt = _ret.net_iov_cnt; \
- return ret_erred; \
+ return ret_err; \
} while (0)
-bool lib9p_Tmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body,
+error lib9p_Tmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body,
struct lib9p_Tmsg_send_buf *ret) {
_lib9p_marshal(0, _lib9p_table_Tmsg_send);
}
-bool lib9p_Rmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body,
+error lib9p_Rmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body,
struct lib9p_Rmsg_send_buf *ret) {
_lib9p_marshal(1, _lib9p_table_Rmsg_send);
}
@@ -193,14 +173,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,
+error lib9p_stat_validate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes,
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;
+ size_t_or_error host_size = _lib9p_stat_validate(ctx, net_size, net_bytes, ret_net_size);
+ if (host_size.is_err)
+ return host_size.err;
if (ret_host_size)
- *ret_host_size = (size_t)host_size;
- return false;
+ *ret_host_size = host_size.size_t;
+ return ERROR_NULL;
}
void lib9p_stat_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes,
@@ -213,7 +193,7 @@ uint32_t lib9p_stat_marshal(struct lib9p_ctx *ctx, uint32_t max_net_size, struct
struct lib9p_ctx _ctx = *ctx;
_ctx.max_msg_size = max_net_size;
- struct iovec iov = {};
+ struct wr_iovec iov = {};
struct _marshal_ret ret = {
.net_iov_cnt = 1,
.net_iov = &iov,
diff --git a/lib9p/core.gen b/lib9p/core.gen
index b30ec31..24f66de 100755
--- a/lib9p/core.gen
+++ b/lib9p/core.gen
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# lib9p/core.gen - Generate C marshalers/unmarshalers for .9p files
# defining 9P protocol variants.
#
diff --git a/lib9p/core_gen/c.py b/lib9p/core_gen/c.py
index 60ceb70..ab34387 100644
--- a/lib9p/core_gen/c.py
+++ b/lib9p/core_gen/c.py
@@ -23,17 +23,16 @@ def gen_c(versions: set[str], typs: list[idl.UserType]) -> str:
ret = f"""/* Generated by `{' '.join(sys.argv)}`. DO NOT EDIT! */
-#include <stddef.h> /* for size_t */
-#include <inttypes.h> /* for PRI* macros */
-#include <string.h> /* for memset() */
+#include <stddef.h> /* for size_t */
+#include <string.h> /* for memset() */
#include <libmisc/assert.h>
#include <libmisc/endian.h>
+#include <libmisc/utf8.h>
#include <lib9p/core.h>
#include "core_tables.h"
-#include "core_utf8.h"
"""
# utilities ################################################################
ret += """
@@ -176,7 +175,7 @@ def gen_c(versions: set[str], typs: list[idl.UserType]) -> str:
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) {{
+LM_FLATTEN size_t_or_error {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);
}}
LM_FLATTEN void {c9util.ident('_stat_unmarshal')}(struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out) {{
diff --git a/lib9p/core_gen/c9util.py b/lib9p/core_gen/c9util.py
index 84fdee4..7e1e41d 100644
--- a/lib9p/core_gen/c9util.py
+++ b/lib9p/core_gen/c9util.py
@@ -91,7 +91,9 @@ def typename(typ: idl.Type, parent: idl.StructMember | None = None) -> str:
match typ:
case idl.Primitive():
if typ.value == 1 and parent and parent.cnt: # SPECIAL (string)
- return "[[gnu::nonstring]] char"
+ if parent.membname == "utf8":
+ return "[[gnu::nonstring]] const char"
+ return "const void"
return f"uint{typ.value*8}_t"
case idl.Number():
return f"{basename(typ)}_t"
diff --git a/lib9p/core_gen/c_fmt_print.py b/lib9p/core_gen/c_fmt_print.py
index eaacddb..7a0a9d3 100644
--- a/lib9p/core_gen/c_fmt_print.py
+++ b/lib9p/core_gen/c_fmt_print.py
@@ -112,7 +112,7 @@ def gen_c_fmt_print(versions: set[str], typs: list[idl.UserType]) -> str:
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 += f"\tif (utf8_is_valid_without_nul((uint8_t *)self->{member.membname}, (size_t){cnt_str})) {{\n"
ret += f'\t\tfmt_print_str(w, " {member.membname}=");\n'
ret += f"\t\tfmt_print_qmem(w, self->{member.membname}, {cnt_str} < 50 ? {cnt_str} : 50);\n"
ret += f"\t\tif ({cnt_str} > 50)\n"
diff --git a/lib9p/core_gen/c_marshal.py b/lib9p/core_gen/c_marshal.py
index bddf55f..2747ce8 100644
--- a/lib9p/core_gen/c_marshal.py
+++ b/lib9p/core_gen/c_marshal.py
@@ -193,46 +193,46 @@ def gen_c_marshal(versions: set[str], typs: list[idl.UserType]) -> str:
"#define MARSHAL_BYTES_ZEROCOPY(ctx, data, len)\n"
"\tif (ret->net_iov[ret->net_iov_cnt-1].iov_len)\n"
"\t\tret->net_iov_cnt++;\n"
- "\tret->net_iov[ret->net_iov_cnt-1].iov_base = data;\n"
+ "\tret->net_iov[ret->net_iov_cnt-1].iov_write_from = data;\n"
"\tret->net_iov[ret->net_iov_cnt-1].iov_len = len;\n"
"\tret->net_iov_cnt++;\n"
)
ret += cutil.macro(
"#define MARSHAL_BYTES(ctx, data, len)\n"
- "\tif (!ret->net_iov[ret->net_iov_cnt-1].iov_base)\n"
- "\t\tret->net_iov[ret->net_iov_cnt-1].iov_base = &ret->net_copied[ret->net_copied_size];\n"
+ "\tif (!ret->net_iov[ret->net_iov_cnt-1].iov_write_from)\n"
+ "\t\tret->net_iov[ret->net_iov_cnt-1].iov_write_from = &ret->net_copied[ret->net_copied_size];\n"
"\tmemcpy(&ret->net_copied[ret->net_copied_size], data, len);\n"
"\tret->net_copied_size += len;\n"
"\tret->net_iov[ret->net_iov_cnt-1].iov_len += len;\n"
)
ret += cutil.macro(
"#define MARSHAL_U8LE(ctx, val)\n"
- "\tif (!ret->net_iov[ret->net_iov_cnt-1].iov_base)\n"
- "\t\tret->net_iov[ret->net_iov_cnt-1].iov_base = &ret->net_copied[ret->net_copied_size];\n"
+ "\tif (!ret->net_iov[ret->net_iov_cnt-1].iov_write_from)\n"
+ "\t\tret->net_iov[ret->net_iov_cnt-1].iov_write_from = &ret->net_copied[ret->net_copied_size];\n"
"\tret->net_copied[ret->net_copied_size] = val;\n"
"\tret->net_copied_size += 1;\n"
"\tret->net_iov[ret->net_iov_cnt-1].iov_len += 1;\n"
)
ret += cutil.macro(
"#define MARSHAL_U16LE(ctx, val)\n"
- "\tif (!ret->net_iov[ret->net_iov_cnt-1].iov_base)\n"
- "\t\tret->net_iov[ret->net_iov_cnt-1].iov_base = &ret->net_copied[ret->net_copied_size];\n"
+ "\tif (!ret->net_iov[ret->net_iov_cnt-1].iov_write_from)\n"
+ "\t\tret->net_iov[ret->net_iov_cnt-1].iov_write_from = &ret->net_copied[ret->net_copied_size];\n"
"\tuint16le_encode(&ret->net_copied[ret->net_copied_size], val);\n"
"\tret->net_copied_size += 2;\n"
"\tret->net_iov[ret->net_iov_cnt-1].iov_len += 2;\n"
)
ret += cutil.macro(
"#define MARSHAL_U32LE(ctx, val)\n"
- "\tif (!ret->net_iov[ret->net_iov_cnt-1].iov_base)\n"
- "\t\tret->net_iov[ret->net_iov_cnt-1].iov_base = &ret->net_copied[ret->net_copied_size];\n"
+ "\tif (!ret->net_iov[ret->net_iov_cnt-1].iov_write_from)\n"
+ "\t\tret->net_iov[ret->net_iov_cnt-1].iov_write_from = &ret->net_copied[ret->net_copied_size];\n"
"\tuint32le_encode(&ret->net_copied[ret->net_copied_size], val);\n"
"\tret->net_copied_size += 4;\n"
"\tret->net_iov[ret->net_iov_cnt-1].iov_len += 4;\n"
)
ret += cutil.macro(
"#define MARSHAL_U64LE(ctx, val)\n"
- "\tif (!ret->net_iov[ret->net_iov_cnt-1].iov_base)\n"
- "\t\tret->net_iov[ret->net_iov_cnt-1].iov_base = &ret->net_copied[ret->net_copied_size];\n"
+ "\tif (!ret->net_iov[ret->net_iov_cnt-1].iov_write_from)\n"
+ "\t\tret->net_iov[ret->net_iov_cnt-1].iov_write_from = &ret->net_copied[ret->net_copied_size];\n"
"\tuint64le_encode(&ret->net_copied[ret->net_copied_size], val);\n"
"\tret->net_copied_size += 8;\n"
"\tret->net_iov[ret->net_iov_cnt-1].iov_len += 8;\n"
@@ -365,7 +365,10 @@ def gen_c_marshal(versions: set[str], typs: list[idl.UserType]) -> str:
assert isinstance(typ, idl.Struct)
ret += "\n"
ret += cutil.ifdef_push(1, c9util.ver_ifdef(typ.in_versions))
- ret += f"static bool marshal_{typ.typname}(struct lib9p_ctx *ctx, {c9util.typename(typ)} *val, struct _marshal_ret *ret) {{\n"
+ if not isinstance(typ, idl.Message): # SPECIAL (bool for stat)
+ ret += f"static bool marshal_{typ.typname}(struct lib9p_ctx *ctx, {c9util.typename(typ)} *val, struct _marshal_ret *ret) {{\n"
+ else:
+ ret += f"static error marshal_{typ.typname}(struct lib9p_ctx *ctx, {c9util.typename(typ)} *val, struct _marshal_ret *ret) {{\n"
# Pass 1 - check size
max_size = max(typ.max_size(v) for v in typ.in_versions)
@@ -380,11 +383,12 @@ def gen_c_marshal(versions: set[str], typs: list[idl.UserType]) -> str:
ret += "\tif (needed_size > (uint64_t)(ctx->max_msg_size)) {\n"
else:
ret += "\tif (needed_size > ctx->max_msg_size) {\n"
- if isinstance(typ, idl.Message): # SPECIAL (disable for stat)
- ret += f'\t\tlib9p_error(ctx, {c9util.IDENT("ERRNO_L_ERANGE")}, "{typ.typname} message too large to marshal into ",\n'
+ if not isinstance(typ, idl.Message): # SPECIAL (bool for stat)
+ ret += "\t\treturn true;\n"
+ else:
+ ret += f'\t\treturn error_new(E_POSIX_ERANGE, "{typ.typname} message too large to marshal into ",\n'
ret += f'\t\t\tctx->version ? "negotiated" : "{'client' if typ.msgid % 2 == 0 else 'server'}", " limit",\n'
ret += '\t\t\t" (", needed_size, " > ", ctx->max_msg_size, ")");\n'
- ret += "\t\treturn true;\n"
ret += "\t}\n"
# Pass 2 - write data
@@ -396,7 +400,10 @@ def gen_c_marshal(versions: set[str], typs: list[idl.UserType]) -> str:
ret += cutil.ifdef_pop(ifdef_lvl())
# Return
- ret += "\treturn false;\n"
+ if not isinstance(typ, idl.Message): # SPECIAL (bool for stat)
+ ret += "\treturn false;\n"
+ else:
+ ret += "\treturn ERROR_NULL;\n"
ret += "}\n"
ret += cutil.ifdef_pop(0)
return ret
diff --git a/lib9p/core_gen/c_validate.py b/lib9p/core_gen/c_validate.py
index 9c55d8d..1bfe329 100644
--- a/lib9p/core_gen/c_validate.py
+++ b/lib9p/core_gen/c_validate.py
@@ -57,26 +57,26 @@ 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"
- f'\t\treturn lib9p_error(ctx, {c9util.IDENT("ERRNO_L_EBADMSG")}, "message is too short for content");\n'
+ '\t\treturn ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "message is too short for content"));\n'
"\tif (net_offset > net_size)\n"
- f'\t\treturn lib9p_error(ctx, {c9util.IDENT("ERRNO_L_EBADMSG")}, "message is too short for content (", net_offset, " > ", net_size, ")");\n'
+ '\t\treturn ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "message is too short for content (", net_offset, " > ", net_size, ")"));\n'
)
ret += cutil.macro(
"#define VALIDATE_NET_UTF8(n)\n"
"\t{\n"
"\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"
- f'\t\t\treturn lib9p_error(ctx, {c9util.IDENT("ERRNO_L_EBADMSG")}, "message contains invalid UTF-8");\n'
+ "\t\tif (!utf8_is_valid_without_nul(&net_bytes[net_offset-len], len))\n"
+ '\t\t\treturn ERROR_NEW_ERR(size_t, error_new(E_POSIX_EILSEQ, "message contains invalid UTF-8"));\n'
"\t}\n"
)
ret += cutil.macro(
"#define RESERVE_HOST_BYTES(n)\n"
"\tif (__builtin_add_overflow(host_size, n, &host_size))\n"
- "\t\t/* If needed-host-size overflowed ssize_t, then there's\n"
+ "\t\t/* If needed-host-size overflowed size_t, then there's\n"
"\t\t * no way that actual-net-size will live up to\n"
"\t\t * that. */\n"
- f'\t\treturn lib9p_error(ctx, {c9util.IDENT("ERRNO_L_EBADMSG")}, "message is too short for content");\n'
+ '\t\treturn ERROR_NEW_ERR(size_t, error_new(E_POSIX_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"GET_U{nbits}LE({lookup_sym(f'&{child.membname}')})"
exp = f"{c9util.idl_expr(child.val, lookup_sym)}"
ret += f"{'\t'*indent_lvl()}if ({act} != {exp})\n"
- ret += f'{"\t"*(indent_lvl()+1)}return lib9p_error(ctx, {c9util.IDENT("ERRNO_L_EBADMSG")}, "{path} value is wrong: actual:", (base10, {act}), " != correct:", (base10, {exp}));\n'
+ ret += f'{"\t"*(indent_lvl()+1)}return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "{path} value is wrong: actual:", (base10, {act}), " != correct:", (base10, {exp})));\n'
if child.max:
incr_flush()
assert child.typ.static_size
@@ -207,15 +207,15 @@ def gen_c_validate(versions: set[str], typs: list[idl.UserType]) -> str:
act = f"GET_U{nbits}LE({lookup_sym(f'&{child.membname}')})"
exp = f"{c9util.idl_expr(child.max, lookup_sym)}"
ret += f"{'\t'*indent_lvl()}if ({act} > {exp})\n"
- ret += f'{"\t"*(indent_lvl()+1)}return lib9p_error(ctx, {c9util.IDENT("ERRNO_L_EBADMSG")}, "{path} value is too large: ", (base10, {act}), " > ", (base10, {exp}));\n'
+ ret += f'{"\t"*(indent_lvl()+1)}return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "{path} value is too large: ", (base10, {act}), " > ", (base10, {exp})));\n'
if isinstance(child.typ, idl.Bitfield):
incr_flush()
nbytes = child.typ.static_size
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_error(ctx, {c9util.IDENT("ERRNO_L_EBADMSG")}, "unknown bits in {child.typ.typname} bitfield: ",\n'
- ret += f"{'\t'*(indent_lvl()+2)}(base16_u{nbits}_, {act} & ~{child.typ.typname}_masks[ctx->version]));\n"
+ ret += f'{"\t"*(indent_lvl()+1)}return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in {child.typ.typname} bitfield: ",\n'
+ ret += f"{'\t'*(indent_lvl()+2)}(base16_u{nbits}_, {act} & ~{child.typ.typname}_masks[ctx->version])));\n"
def handle(
path: idlutil.Path,
@@ -271,12 +271,12 @@ def gen_c_validate(versions: set[str], typs: list[idl.UserType]) -> str:
ret += "\n"
ret += cutil.ifdef_push(1, c9util.ver_ifdef(typ.in_versions))
if typ.typname == "stat": # SPECIAL (stat)
- ret += f"static ssize_t validate_{typ.typname}(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes, uint32_t *ret_net_size) {{\n"
+ ret += f"static size_t_or_error validate_{typ.typname}(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes, uint32_t *ret_net_size) {{\n"
else:
- ret += f"static ssize_t validate_{typ.typname}(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {{\n"
+ ret += f"static size_t_or_error validate_{typ.typname}([[maybe_unused]] struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {{\n"
ret += "\tuint32_t net_offset = 0;\n"
- ret += f"\tssize_t host_size = sizeof({c9util.typename(typ)});\n"
+ ret += f"\tsize_t host_size = sizeof({c9util.typename(typ)});\n"
incr_buf = 0
indent_stack = [IndentLevel(ifdef=True)]
@@ -291,7 +291,7 @@ def gen_c_validate(versions: set[str], typs: list[idl.UserType]) -> str:
if typ.typname == "stat": # SPECIAL (stat)
ret += "\tif (ret_net_size)\n"
ret += "\t\t*ret_net_size = net_offset;\n"
- ret += "\treturn (ssize_t)host_size;\n"
+ ret += "\treturn ERROR_NEW_VAL(size_t, host_size);\n"
ret += "}\n"
ret += cutil.ifdef_pop(0)
return ret
diff --git a/lib9p/core_gen/h.py b/lib9p/core_gen/h.py
index acf8415..eba1492 100644
--- a/lib9p/core_gen/h.py
+++ b/lib9p/core_gen/h.py
@@ -162,7 +162,6 @@ def gen_h(versions: set[str], typs: list[idl.UserType]) -> str:
#ifndef _LIB9P_CORE_H_
\t#error Do not include <lib9p/_core_generated.h> directly; include <lib9p/core.h> instead
#endif
-
"""
id2typ: dict[int, idl.Message] = {}
for msg in [msg for msg in typs if isinstance(msg, idl.Message)]:
@@ -170,8 +169,6 @@ def gen_h(versions: set[str], typs: list[idl.UserType]) -> str:
ret += """
/* config *********************************************************************/
-
-#include "config.h"
"""
for ver in sorted(versions):
ret += "\n"
@@ -348,14 +345,14 @@ enum {c9util.ident('version')} {{
ret += "\n"
ret += f"struct {c9util.ident('Tmsg_send_buf')} {{\n"
ret += "\tsize_t iov_cnt;\n"
- ret += f"\tstruct iovec iov[{c9util.IDENT('TMSG_MAX_IOV')}];\n"
+ ret += f"\tstruct wr_iovec iov[{c9util.IDENT('TMSG_MAX_IOV')}];\n"
ret += f"\tuint8_t copied[{c9util.IDENT('TMSG_MAX_COPY')}];\n"
ret += "};\n"
ret += "\n"
ret += f"struct {c9util.ident('Rmsg_send_buf')} {{\n"
ret += "\tsize_t iov_cnt;\n"
- ret += f"\tstruct iovec iov[{c9util.IDENT('RMSG_MAX_IOV')}];\n"
+ ret += f"\tstruct wr_iovec iov[{c9util.IDENT('RMSG_MAX_IOV')}];\n"
ret += f"\tuint8_t copied[{c9util.IDENT('RMSG_MAX_COPY')}];\n"
ret += "};\n"
diff --git a/lib9p/core_generated.c b/lib9p/core_generated.c
index 81ace7d..5acc551 100644
--- a/lib9p/core_generated.c
+++ b/lib9p/core_generated.c
@@ -1,16 +1,15 @@
/* 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 <stddef.h> /* for size_t */
-#include <inttypes.h> /* for PRI* macros */
-#include <string.h> /* for memset() */
+#include <stddef.h> /* for size_t */
+#include <string.h> /* for memset() */
#include <libmisc/assert.h>
#include <libmisc/endian.h>
+#include <libmisc/utf8.h>
#include <lib9p/core.h>
#include "core_tables.h"
-#include "core_utf8.h"
/* utilities ******************************************************************/
#if CONFIG_9P_ENABLE_9P2000
@@ -222,27 +221,27 @@ static const lib9p_lock_flags_t lock_flags_masks[LIB9P_VER_NUM] = {
/* 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, LIB9P_ERRNO_L_EBADMSG, "message is too short for content"); \
- if (net_offset > net_size) \
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "message is too short for content (", net_offset, " > ", net_size, ")");
-#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, LIB9P_ERRNO_L_EBADMSG, "message is too short for content");
+#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 ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "message is too short for content")); \
+ if (net_offset > net_size) \
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "message is too short for content (", net_offset, " > ", net_size, ")"));
+#define VALIDATE_NET_UTF8(n) \
+ { \
+ size_t len = n; \
+ VALIDATE_NET_BYTES(len); \
+ if (!utf8_is_valid_without_nul(&net_bytes[net_offset-len], len)) \
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EILSEQ, "message contains invalid UTF-8")); \
+ }
+#define RESERVE_HOST_BYTES(n) \
+ if (__builtin_add_overflow(host_size, n, &host_size)) \
+ /* If needed-host-size overflowed size_t, then there's \
+ * no way that actual-net-size will live up to \
+ * that. */ \
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_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])
@@ -253,16 +252,16 @@ static const lib9p_lock_flags_t lock_flags_masks[LIB9P_VER_NUM] = {
#define LAST_U64LE() GET_U64LE(net_offset-8)
#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
-static ssize_t validate_stat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes, uint32_t *ret_net_size) {
+static size_t_or_error 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);
+ size_t host_size = sizeof(struct lib9p_stat);
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_qid_type) & ~qt_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: ",
- (base16_u8_, GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in qt bitfield: ",
+ (base16_u8_, 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());
@@ -281,52 +280,52 @@ 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 (GET_U32LE(offsetof__stat_size) != offsetof_end - offsetof_fstype)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "stat->_stat_size value is wrong: actual:", (base10, GET_U32LE(offsetof__stat_size)), " != correct:", (base10, offsetof_end - offsetof_fstype));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "stat->_stat_size value is wrong: actual:", (base10, GET_U32LE(offsetof__stat_size)), " != correct:", (base10, offsetof_end - offsetof_fstype)));
if (GET_U32LE(offsetof_mode) & ~dm_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in dm bitfield: ",
- (base16_u32_, GET_U32LE(offsetof_mode) & ~dm_masks[ctx->version]));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in dm bitfield: ",
+ (base16_u32_, GET_U32LE(offsetof_mode) & ~dm_masks[ctx->version])));
if (ret_net_size)
*ret_net_size = net_offset;
- return (ssize_t)host_size;
+ return ERROR_NEW_VAL(size_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 || CONFIG_9P_ENABLE_uninitialized
-static ssize_t validate_Tversion(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Tversion([[maybe_unused]] 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);
+ size_t host_size = sizeof(struct lib9p_msg_Tversion);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
VALIDATE_NET_BYTES(13);
VALIDATE_NET_UTF8(LAST_U16LE());
uint32_t offsetof_end = net_offset + 0;
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tversion->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tversion->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 100)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tversion->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 100));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tversion->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 100)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rversion(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rversion([[maybe_unused]] 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_Rversion);
+ size_t host_size = sizeof(struct lib9p_msg_Rversion);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
VALIDATE_NET_BYTES(13);
VALIDATE_NET_UTF8(LAST_U16LE());
uint32_t offsetof_end = net_offset + 0;
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rversion->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rversion->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 101)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rversion->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 101));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rversion->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 101)));
+ return ERROR_NEW_VAL(size_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_uninitialized */
#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) {
+static size_t_or_error validate_Tauth([[maybe_unused]] 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);
+ size_t host_size = sizeof(struct lib9p_msg_Tauth);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
VALIDATE_NET_BYTES(13);
@@ -340,33 +339,33 @@ 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 (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tauth->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tauth->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 102)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tauth->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 102));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tauth->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 102)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rauth(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rauth([[maybe_unused]] 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_Rauth);
+ size_t host_size = sizeof(struct lib9p_msg_Rauth);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_aqid_type = net_offset + 7;
VALIDATE_NET_BYTES(20);
if (GET_U8LE(offsetof_aqid_type) & ~qt_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: ",
- (base16_u8_, GET_U8LE(offsetof_aqid_type) & ~qt_masks[ctx->version]));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in qt bitfield: ",
+ (base16_u8_, GET_U8LE(offsetof_aqid_type) & ~qt_masks[ctx->version])));
uint32_t offsetof_end = net_offset + 0;
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rauth->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rauth->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 103)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rauth->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 103));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rauth->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 103)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Tattach(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Tattach([[maybe_unused]] 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_Tattach);
+ size_t host_size = sizeof(struct lib9p_msg_Tattach);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
VALIDATE_NET_BYTES(17);
@@ -380,35 +379,35 @@ 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 (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tattach->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tattach->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 104)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tattach->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 104));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tattach->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 104)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rattach(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rattach([[maybe_unused]] 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_Rattach);
+ size_t host_size = sizeof(struct lib9p_msg_Rattach);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_qid_type = net_offset + 7;
VALIDATE_NET_BYTES(20);
if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: ",
- (base16_u8_, GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in qt bitfield: ",
+ (base16_u8_, GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version])));
uint32_t offsetof_end = net_offset + 0;
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rattach->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rattach->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 105)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rattach->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 105));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rattach->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 105)));
+ return ERROR_NEW_VAL(size_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_uninitialized
-static ssize_t validate_Rerror(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rerror([[maybe_unused]] 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);
+ size_t host_size = sizeof(struct lib9p_msg_Rerror);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
VALIDATE_NET_BYTES(9);
@@ -420,45 +419,45 @@ 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 (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rerror->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rerror->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 107)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rerror->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 107));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rerror->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 107)));
+ return ERROR_NEW_VAL(size_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_uninitialized */
#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) {
+static size_t_or_error validate_Tflush([[maybe_unused]] 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);
+ size_t host_size = sizeof(struct lib9p_msg_Tflush);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_end = net_offset + 9;
VALIDATE_NET_BYTES(9);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tflush->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tflush->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 108)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tflush->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 108));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tflush->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 108)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rflush(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rflush([[maybe_unused]] 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_Rflush);
+ size_t host_size = sizeof(struct lib9p_msg_Rflush);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_end = net_offset + 7;
VALIDATE_NET_BYTES(7);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rflush->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rflush->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 109)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rflush->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 109));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rflush->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 109)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Twalk(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Twalk([[maybe_unused]] 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_Twalk);
+ size_t host_size = sizeof(struct lib9p_msg_Twalk);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_nwname = net_offset + 15;
@@ -470,17 +469,17 @@ static ssize_t validate_Twalk(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t
}
uint32_t offsetof_end = net_offset + 0;
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Twalk->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Twalk->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 110)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Twalk->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 110));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Twalk->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 110)));
if (GET_U16LE(offsetof_nwname) > 16)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Twalk->nwname value is too large: ", (base10, GET_U16LE(offsetof_nwname)), " > ", (base10, 16));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Twalk->nwname value is too large: ", (base10, GET_U16LE(offsetof_nwname)), " > ", (base10, 16)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rwalk(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rwalk([[maybe_unused]] 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_Rwalk);
+ size_t host_size = sizeof(struct lib9p_msg_Rwalk);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_nwqid = net_offset + 7;
@@ -490,61 +489,61 @@ 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_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: ",
- (base16_u8_, GET_U8LE(offsetof_wqid_type) & ~qt_masks[ctx->version]));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in qt bitfield: ",
+ (base16_u8_, GET_U8LE(offsetof_wqid_type) & ~qt_masks[ctx->version])));
}
uint32_t offsetof_end = net_offset + 0;
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rwalk->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rwalk->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 111)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rwalk->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 111));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rwalk->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 111)));
if (GET_U16LE(offsetof_nwqid) > 16)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rwalk->nwqid value is too large: ", (base10, GET_U16LE(offsetof_nwqid)), " > ", (base10, 16));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rwalk->nwqid value is too large: ", (base10, GET_U16LE(offsetof_nwqid)), " > ", (base10, 16)));
+ return ERROR_NEW_VAL(size_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
-static ssize_t validate_Topen(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Topen([[maybe_unused]] 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_Topen);
+ size_t host_size = sizeof(struct lib9p_msg_Topen);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_mode = net_offset + 11;
uint32_t offsetof_end = net_offset + 12;
VALIDATE_NET_BYTES(12);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Topen->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Topen->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 112)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Topen->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 112));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Topen->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 112)));
if (GET_U8LE(offsetof_mode) & ~o_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in o bitfield: ",
- (base16_u8_, GET_U8LE(offsetof_mode) & ~o_masks[ctx->version]));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in o bitfield: ",
+ (base16_u8_, GET_U8LE(offsetof_mode) & ~o_masks[ctx->version])));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Ropen(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Ropen([[maybe_unused]] 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_Ropen);
+ size_t host_size = sizeof(struct lib9p_msg_Ropen);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_qid_type = net_offset + 7;
VALIDATE_NET_BYTES(20);
if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: ",
- (base16_u8_, GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in qt bitfield: ",
+ (base16_u8_, GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version])));
uint32_t offsetof_end = net_offset + 4;
VALIDATE_NET_BYTES(4);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Ropen->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Ropen->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 113)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Ropen->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 113));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Ropen->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 113)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Tcreate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Tcreate([[maybe_unused]] 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_Tcreate);
+ size_t host_size = sizeof(struct lib9p_msg_Tcreate);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
VALIDATE_NET_BYTES(13);
@@ -554,42 +553,42 @@ 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 (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tcreate->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tcreate->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 114)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tcreate->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 114));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tcreate->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 114)));
if (GET_U32LE(offsetof_perm) & ~dm_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in dm bitfield: ",
- (base16_u32_, GET_U32LE(offsetof_perm) & ~dm_masks[ctx->version]));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in dm bitfield: ",
+ (base16_u32_, GET_U32LE(offsetof_perm) & ~dm_masks[ctx->version])));
if (GET_U8LE(offsetof_mode) & ~o_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in o bitfield: ",
- (base16_u8_, GET_U8LE(offsetof_mode) & ~o_masks[ctx->version]));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in o bitfield: ",
+ (base16_u8_, GET_U8LE(offsetof_mode) & ~o_masks[ctx->version])));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rcreate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rcreate([[maybe_unused]] 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_Rcreate);
+ size_t host_size = sizeof(struct lib9p_msg_Rcreate);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_qid_type = net_offset + 7;
VALIDATE_NET_BYTES(20);
if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: ",
- (base16_u8_, GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in qt bitfield: ",
+ (base16_u8_, GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version])));
uint32_t offsetof_end = net_offset + 4;
VALIDATE_NET_BYTES(4);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rcreate->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rcreate->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 115)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rcreate->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 115));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rcreate->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 115)));
+ return ERROR_NEW_VAL(size_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
-static ssize_t validate_Tread(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Tread([[maybe_unused]] 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_Tread);
+ size_t host_size = sizeof(struct lib9p_msg_Tread);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_offset = net_offset + 11;
@@ -597,19 +596,19 @@ 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 (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tread->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tread->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 116)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tread->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 116));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tread->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 116)));
if (GET_U64LE(offsetof_offset) > INT64_MAX)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tread->offset value is too large: ", (base10, GET_U64LE(offsetof_offset)), " > ", (base10, INT64_MAX));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tread->offset value is too large: ", (base10, GET_U64LE(offsetof_offset)), " > ", (base10, INT64_MAX)));
if (GET_U32LE(offsetof_count) > INT32_MAX)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tread->count value is too large: ", (base10, GET_U32LE(offsetof_count)), " > ", (base10, INT32_MAX));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tread->count value is too large: ", (base10, GET_U32LE(offsetof_count)), " > ", (base10, INT32_MAX)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rread(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rread([[maybe_unused]] 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_Rread);
+ size_t host_size = sizeof(struct lib9p_msg_Rread);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_count = net_offset + 7;
@@ -617,17 +616,17 @@ 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 (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rread->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rread->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 117)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rread->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 117));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rread->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 117)));
if (GET_U32LE(offsetof_count) > INT32_MAX)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rread->count value is too large: ", (base10, GET_U32LE(offsetof_count)), " > ", (base10, INT32_MAX));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rread->count value is too large: ", (base10, GET_U32LE(offsetof_count)), " > ", (base10, INT32_MAX)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Twrite(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Twrite([[maybe_unused]] 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_Twrite);
+ size_t host_size = sizeof(struct lib9p_msg_Twrite);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_offset = net_offset + 11;
@@ -636,108 +635,108 @@ 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 (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Twrite->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Twrite->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 118)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Twrite->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 118));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Twrite->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 118)));
if (GET_U64LE(offsetof_offset) > INT64_MAX)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Twrite->offset value is too large: ", (base10, GET_U64LE(offsetof_offset)), " > ", (base10, INT64_MAX));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Twrite->offset value is too large: ", (base10, GET_U64LE(offsetof_offset)), " > ", (base10, INT64_MAX)));
if (GET_U32LE(offsetof_count) > INT32_MAX)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Twrite->count value is too large: ", (base10, GET_U32LE(offsetof_count)), " > ", (base10, INT32_MAX));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Twrite->count value is too large: ", (base10, GET_U32LE(offsetof_count)), " > ", (base10, INT32_MAX)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rwrite(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rwrite([[maybe_unused]] 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_Rwrite);
+ size_t host_size = sizeof(struct lib9p_msg_Rwrite);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_count = net_offset + 7;
uint32_t offsetof_end = net_offset + 11;
VALIDATE_NET_BYTES(11);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rwrite->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rwrite->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 119)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rwrite->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 119));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rwrite->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 119)));
if (GET_U32LE(offsetof_count) > INT32_MAX)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rwrite->count value is too large: ", (base10, GET_U32LE(offsetof_count)), " > ", (base10, INT32_MAX));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rwrite->count value is too large: ", (base10, GET_U32LE(offsetof_count)), " > ", (base10, INT32_MAX)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Tclunk(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Tclunk([[maybe_unused]] 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_Tclunk);
+ size_t host_size = sizeof(struct lib9p_msg_Tclunk);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_end = net_offset + 11;
VALIDATE_NET_BYTES(11);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tclunk->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tclunk->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 120)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tclunk->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 120));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tclunk->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 120)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rclunk(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rclunk([[maybe_unused]] 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_Rclunk);
+ size_t host_size = sizeof(struct lib9p_msg_Rclunk);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_end = net_offset + 7;
VALIDATE_NET_BYTES(7);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rclunk->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rclunk->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 121)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rclunk->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 121));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rclunk->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 121)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Tremove(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Tremove([[maybe_unused]] 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_Tremove);
+ size_t host_size = sizeof(struct lib9p_msg_Tremove);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_end = net_offset + 11;
VALIDATE_NET_BYTES(11);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tremove->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tremove->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 122)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tremove->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 122));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tremove->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 122)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rremove(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rremove([[maybe_unused]] 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_Rremove);
+ size_t host_size = sizeof(struct lib9p_msg_Rremove);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_end = net_offset + 7;
VALIDATE_NET_BYTES(7);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rremove->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rremove->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 123)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rremove->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 123));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rremove->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 123)));
+ return ERROR_NEW_VAL(size_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
-static ssize_t validate_Tstat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Tstat([[maybe_unused]] 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_Tstat);
+ size_t host_size = sizeof(struct lib9p_msg_Tstat);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_end = net_offset + 11;
VALIDATE_NET_BYTES(11);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tstat->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tstat->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 124)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tstat->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 124));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tstat->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 124)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rstat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rstat([[maybe_unused]] 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_Rstat);
+ size_t host_size = sizeof(struct lib9p_msg_Rstat);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_nstat = net_offset + 7;
@@ -747,8 +746,8 @@ static ssize_t validate_Rstat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t
uint32_t offsetof_stat_qid_type = net_offset + 17;
VALIDATE_NET_BYTES(30);
if (GET_U8LE(offsetof_stat_qid_type) & ~qt_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: ",
- (base16_u8_, GET_U8LE(offsetof_stat_qid_type) & ~qt_masks[ctx->version]));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in qt bitfield: ",
+ (base16_u8_, 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());
@@ -767,23 +766,23 @@ 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 (GET_U32LE(offsetof_stat__stat_size) != offsetof_stat_end - offsetof_stat_fstype)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rstat->stat._stat_size value is wrong: actual:", (base10, GET_U32LE(offsetof_stat__stat_size)), " != correct:", (base10, offsetof_stat_end - offsetof_stat_fstype));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rstat->stat._stat_size value is wrong: actual:", (base10, GET_U32LE(offsetof_stat__stat_size)), " != correct:", (base10, offsetof_stat_end - offsetof_stat_fstype)));
if (GET_U32LE(offsetof_stat_mode) & ~dm_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in dm bitfield: ",
- (base16_u32_, GET_U32LE(offsetof_stat_mode) & ~dm_masks[ctx->version]));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in dm bitfield: ",
+ (base16_u32_, GET_U32LE(offsetof_stat_mode) & ~dm_masks[ctx->version])));
uint32_t offsetof_end = net_offset + 0;
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rstat->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rstat->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 125)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rstat->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 125));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rstat->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 125)));
if (GET_U32LE(offsetof_nstat) != offsetof_end - offsetof_stat)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rstat->nstat value is wrong: actual:", (base10, GET_U32LE(offsetof_nstat)), " != correct:", (base10, offsetof_end - offsetof_stat));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rstat->nstat value is wrong: actual:", (base10, GET_U32LE(offsetof_nstat)), " != correct:", (base10, offsetof_end - offsetof_stat)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Twstat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Twstat([[maybe_unused]] 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_Twstat);
+ size_t host_size = sizeof(struct lib9p_msg_Twstat);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_nstat = net_offset + 11;
@@ -793,8 +792,8 @@ static ssize_t validate_Twstat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t
uint32_t offsetof_stat_qid_type = net_offset + 21;
VALIDATE_NET_BYTES(34);
if (GET_U8LE(offsetof_stat_qid_type) & ~qt_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: ",
- (base16_u8_, GET_U8LE(offsetof_stat_qid_type) & ~qt_masks[ctx->version]));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in qt bitfield: ",
+ (base16_u8_, 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());
@@ -813,157 +812,157 @@ 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 (GET_U32LE(offsetof_stat__stat_size) != offsetof_stat_end - offsetof_stat_fstype)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Twstat->stat._stat_size value is wrong: actual:", (base10, GET_U32LE(offsetof_stat__stat_size)), " != correct:", (base10, offsetof_stat_end - offsetof_stat_fstype));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Twstat->stat._stat_size value is wrong: actual:", (base10, GET_U32LE(offsetof_stat__stat_size)), " != correct:", (base10, offsetof_stat_end - offsetof_stat_fstype)));
if (GET_U32LE(offsetof_stat_mode) & ~dm_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in dm bitfield: ",
- (base16_u32_, GET_U32LE(offsetof_stat_mode) & ~dm_masks[ctx->version]));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in dm bitfield: ",
+ (base16_u32_, GET_U32LE(offsetof_stat_mode) & ~dm_masks[ctx->version])));
uint32_t offsetof_end = net_offset + 0;
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Twstat->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Twstat->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 126)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Twstat->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 126));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Twstat->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 126)));
if (GET_U32LE(offsetof_nstat) != offsetof_end - offsetof_stat)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Twstat->nstat value is wrong: actual:", (base10, GET_U32LE(offsetof_nstat)), " != correct:", (base10, offsetof_end - offsetof_stat));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Twstat->nstat value is wrong: actual:", (base10, GET_U32LE(offsetof_nstat)), " != correct:", (base10, offsetof_end - offsetof_stat)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rwstat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rwstat([[maybe_unused]] 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_Rwstat);
+ size_t host_size = sizeof(struct lib9p_msg_Rwstat);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_end = net_offset + 7;
VALIDATE_NET_BYTES(7);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rwstat->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rwstat->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 127)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rwstat->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 127));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rwstat->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 127)));
+ return ERROR_NEW_VAL(size_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_p9p
-static ssize_t validate_Topenfd(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Topenfd([[maybe_unused]] 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_Topenfd);
+ size_t host_size = sizeof(struct lib9p_msg_Topenfd);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_mode = net_offset + 11;
uint32_t offsetof_end = net_offset + 12;
VALIDATE_NET_BYTES(12);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Topenfd->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Topenfd->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 98)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Topenfd->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 98));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Topenfd->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 98)));
if (GET_U8LE(offsetof_mode) & ~o_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in o bitfield: ",
- (base16_u8_, GET_U8LE(offsetof_mode) & ~o_masks[ctx->version]));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in o bitfield: ",
+ (base16_u8_, GET_U8LE(offsetof_mode) & ~o_masks[ctx->version])));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Ropenfd(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Ropenfd([[maybe_unused]] 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_Ropenfd);
+ size_t host_size = sizeof(struct lib9p_msg_Ropenfd);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_qid_type = net_offset + 7;
VALIDATE_NET_BYTES(20);
if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: ",
- (base16_u8_, GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in qt bitfield: ",
+ (base16_u8_, GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version])));
uint32_t offsetof_end = net_offset + 8;
VALIDATE_NET_BYTES(8);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Ropenfd->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Ropenfd->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 99)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Ropenfd->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 99));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Ropenfd->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 99)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
#if CONFIG_9P_ENABLE_9P2000_L
-static ssize_t validate_Rlerror(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rlerror([[maybe_unused]] 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_Rlerror);
+ size_t host_size = sizeof(struct lib9p_msg_Rlerror);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_end = net_offset + 11;
VALIDATE_NET_BYTES(11);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rlerror->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rlerror->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 7)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rlerror->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 7));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rlerror->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 7)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Tstatfs(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Tstatfs([[maybe_unused]] 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_Tstatfs);
+ size_t host_size = sizeof(struct lib9p_msg_Tstatfs);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_end = net_offset + 11;
VALIDATE_NET_BYTES(11);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tstatfs->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tstatfs->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 8)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tstatfs->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 8));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tstatfs->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 8)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rstatfs(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rstatfs([[maybe_unused]] 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_Rstatfs);
+ size_t host_size = sizeof(struct lib9p_msg_Rstatfs);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_end = net_offset + 67;
VALIDATE_NET_BYTES(67);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rstatfs->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rstatfs->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 9)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rstatfs->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 9));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rstatfs->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 9)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Tlopen(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Tlopen([[maybe_unused]] 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_Tlopen);
+ size_t host_size = sizeof(struct lib9p_msg_Tlopen);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_flags = net_offset + 11;
uint32_t offsetof_end = net_offset + 15;
VALIDATE_NET_BYTES(15);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tlopen->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tlopen->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 12)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tlopen->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 12));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tlopen->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 12)));
if (GET_U32LE(offsetof_flags) & ~lo_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in lo bitfield: ",
- (base16_u32_, GET_U32LE(offsetof_flags) & ~lo_masks[ctx->version]));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in lo bitfield: ",
+ (base16_u32_, GET_U32LE(offsetof_flags) & ~lo_masks[ctx->version])));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rlopen(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rlopen([[maybe_unused]] 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_Rlopen);
+ size_t host_size = sizeof(struct lib9p_msg_Rlopen);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_qid_type = net_offset + 7;
VALIDATE_NET_BYTES(20);
if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: ",
- (base16_u8_, GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in qt bitfield: ",
+ (base16_u8_, GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version])));
uint32_t offsetof_end = net_offset + 4;
VALIDATE_NET_BYTES(4);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rlopen->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rlopen->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 13)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rlopen->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 13));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rlopen->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 13)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Tlcreate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Tlcreate([[maybe_unused]] 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_Tlcreate);
+ size_t host_size = sizeof(struct lib9p_msg_Tlcreate);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
VALIDATE_NET_BYTES(13);
@@ -973,40 +972,40 @@ 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 (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tlcreate->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tlcreate->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 14)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tlcreate->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 14));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tlcreate->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 14)));
if (GET_U32LE(offsetof_flags) & ~lo_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in lo bitfield: ",
- (base16_u32_, GET_U32LE(offsetof_flags) & ~lo_masks[ctx->version]));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in lo bitfield: ",
+ (base16_u32_, GET_U32LE(offsetof_flags) & ~lo_masks[ctx->version])));
if (GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in mode bitfield: ",
- (base16_u32_, GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in mode bitfield: ",
+ (base16_u32_, GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version])));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rlcreate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rlcreate([[maybe_unused]] 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_Rlcreate);
+ size_t host_size = sizeof(struct lib9p_msg_Rlcreate);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_qid_type = net_offset + 7;
VALIDATE_NET_BYTES(20);
if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: ",
- (base16_u8_, GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in qt bitfield: ",
+ (base16_u8_, GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version])));
uint32_t offsetof_end = net_offset + 4;
VALIDATE_NET_BYTES(4);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rlcreate->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rlcreate->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 15)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rlcreate->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 15));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rlcreate->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 15)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Tsymlink(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Tsymlink([[maybe_unused]] 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_Tsymlink);
+ size_t host_size = sizeof(struct lib9p_msg_Tsymlink);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
VALIDATE_NET_BYTES(13);
@@ -1016,33 +1015,33 @@ 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 (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tsymlink->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tsymlink->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 16)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tsymlink->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 16));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tsymlink->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 16)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rsymlink(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rsymlink([[maybe_unused]] 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_Rsymlink);
+ size_t host_size = sizeof(struct lib9p_msg_Rsymlink);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_qid_type = net_offset + 7;
VALIDATE_NET_BYTES(20);
if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: ",
- (base16_u8_, GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in qt bitfield: ",
+ (base16_u8_, GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version])));
uint32_t offsetof_end = net_offset + 0;
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rsymlink->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rsymlink->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 17)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rsymlink->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 17));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rsymlink->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 17)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Tmknod(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Tmknod([[maybe_unused]] 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_Tmknod);
+ size_t host_size = sizeof(struct lib9p_msg_Tmknod);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
VALIDATE_NET_BYTES(13);
@@ -1051,139 +1050,139 @@ 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 (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tmknod->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tmknod->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 18)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tmknod->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 18));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tmknod->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 18)));
if (GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in mode bitfield: ",
- (base16_u32_, GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in mode bitfield: ",
+ (base16_u32_, GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version])));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rmknod(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rmknod([[maybe_unused]] 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_Rmknod);
+ size_t host_size = sizeof(struct lib9p_msg_Rmknod);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_qid_type = net_offset + 7;
VALIDATE_NET_BYTES(20);
if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: ",
- (base16_u8_, GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in qt bitfield: ",
+ (base16_u8_, GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version])));
uint32_t offsetof_end = net_offset + 0;
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rmknod->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rmknod->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 19)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rmknod->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 19));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rmknod->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 19)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Trename(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Trename([[maybe_unused]] 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_Trename);
+ size_t host_size = sizeof(struct lib9p_msg_Trename);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
VALIDATE_NET_BYTES(17);
VALIDATE_NET_UTF8(LAST_U16LE());
uint32_t offsetof_end = net_offset + 0;
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Trename->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Trename->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 20)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Trename->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 20));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Trename->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 20)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rrename(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rrename([[maybe_unused]] 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_Rrename);
+ size_t host_size = sizeof(struct lib9p_msg_Rrename);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_end = net_offset + 7;
VALIDATE_NET_BYTES(7);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rrename->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rrename->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 21)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rrename->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 21));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rrename->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 21)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Treadlink(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Treadlink([[maybe_unused]] 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_Treadlink);
+ size_t host_size = sizeof(struct lib9p_msg_Treadlink);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_end = net_offset + 11;
VALIDATE_NET_BYTES(11);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Treadlink->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Treadlink->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 22)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Treadlink->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 22));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Treadlink->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 22)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rreadlink(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rreadlink([[maybe_unused]] 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_Rreadlink);
+ size_t host_size = sizeof(struct lib9p_msg_Rreadlink);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
VALIDATE_NET_BYTES(9);
VALIDATE_NET_UTF8(LAST_U16LE());
uint32_t offsetof_end = net_offset + 0;
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rreadlink->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rreadlink->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 23)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rreadlink->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 23));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rreadlink->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 23)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Tgetattr(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Tgetattr([[maybe_unused]] 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_Tgetattr);
+ size_t host_size = sizeof(struct lib9p_msg_Tgetattr);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_request_mask = net_offset + 11;
uint32_t offsetof_end = net_offset + 19;
VALIDATE_NET_BYTES(19);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tgetattr->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tgetattr->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 24)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tgetattr->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 24));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tgetattr->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 24)));
if (GET_U64LE(offsetof_request_mask) & ~getattr_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in getattr bitfield: ",
- (base16_u64_, GET_U64LE(offsetof_request_mask) & ~getattr_masks[ctx->version]));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in getattr bitfield: ",
+ (base16_u64_, GET_U64LE(offsetof_request_mask) & ~getattr_masks[ctx->version])));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rgetattr(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rgetattr([[maybe_unused]] 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_Rgetattr);
+ size_t host_size = sizeof(struct lib9p_msg_Rgetattr);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_valid = net_offset + 7;
uint32_t offsetof_qid_type = net_offset + 15;
VALIDATE_NET_BYTES(28);
if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: ",
- (base16_u8_, GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in qt bitfield: ",
+ (base16_u8_, 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 (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rgetattr->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rgetattr->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 25)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rgetattr->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 25));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rgetattr->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 25)));
if (GET_U64LE(offsetof_valid) & ~getattr_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in getattr bitfield: ",
- (base16_u64_, GET_U64LE(offsetof_valid) & ~getattr_masks[ctx->version]));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in getattr bitfield: ",
+ (base16_u64_, GET_U64LE(offsetof_valid) & ~getattr_masks[ctx->version])));
if (GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in mode bitfield: ",
- (base16_u32_, GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in mode bitfield: ",
+ (base16_u32_, GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version])));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Tsetattr(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Tsetattr([[maybe_unused]] 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_Tsetattr);
+ size_t host_size = sizeof(struct lib9p_msg_Tsetattr);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_valid = net_offset + 11;
@@ -1191,64 +1190,64 @@ 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 (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tsetattr->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tsetattr->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 26)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tsetattr->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 26));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tsetattr->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 26)));
if (GET_U32LE(offsetof_valid) & ~setattr_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in setattr bitfield: ",
- (base16_u32_, GET_U32LE(offsetof_valid) & ~setattr_masks[ctx->version]));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in setattr bitfield: ",
+ (base16_u32_, GET_U32LE(offsetof_valid) & ~setattr_masks[ctx->version])));
if (GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in mode bitfield: ",
- (base16_u32_, GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in mode bitfield: ",
+ (base16_u32_, GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version])));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rsetattr(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rsetattr([[maybe_unused]] 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_Rsetattr);
+ size_t host_size = sizeof(struct lib9p_msg_Rsetattr);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_end = net_offset + 7;
VALIDATE_NET_BYTES(7);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rsetattr->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rsetattr->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 27)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rsetattr->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 27));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rsetattr->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 27)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Txattrwalk(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Txattrwalk([[maybe_unused]] 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_Txattrwalk);
+ size_t host_size = sizeof(struct lib9p_msg_Txattrwalk);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
VALIDATE_NET_BYTES(17);
VALIDATE_NET_UTF8(LAST_U16LE());
uint32_t offsetof_end = net_offset + 0;
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Txattrwalk->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Txattrwalk->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 30)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Txattrwalk->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 30));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Txattrwalk->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 30)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rxattrwalk(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rxattrwalk([[maybe_unused]] 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_Rxattrwalk);
+ size_t host_size = sizeof(struct lib9p_msg_Rxattrwalk);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_end = net_offset + 15;
VALIDATE_NET_BYTES(15);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rxattrwalk->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rxattrwalk->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 31)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rxattrwalk->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 31));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rxattrwalk->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 31)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Txattrcreate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Txattrcreate([[maybe_unused]] 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_Txattrcreate);
+ size_t host_size = sizeof(struct lib9p_msg_Txattrcreate);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
VALIDATE_NET_BYTES(13);
@@ -1256,86 +1255,86 @@ 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 (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Txattrcreate->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Txattrcreate->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 32)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Txattrcreate->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 32));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Txattrcreate->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 32)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rxattrcreate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rxattrcreate([[maybe_unused]] 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_Rxattrcreate);
+ size_t host_size = sizeof(struct lib9p_msg_Rxattrcreate);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_end = net_offset + 7;
VALIDATE_NET_BYTES(7);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rxattrcreate->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rxattrcreate->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 33)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rxattrcreate->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 33));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rxattrcreate->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 33)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Treaddir(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Treaddir([[maybe_unused]] 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_Treaddir);
+ size_t host_size = sizeof(struct lib9p_msg_Treaddir);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_end = net_offset + 23;
VALIDATE_NET_BYTES(23);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Treaddir->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Treaddir->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 40)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Treaddir->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 40));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Treaddir->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 40)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rreaddir(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rreaddir([[maybe_unused]] 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_Rreaddir);
+ size_t host_size = sizeof(struct lib9p_msg_Rreaddir);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
VALIDATE_NET_BYTES(11);
VALIDATE_NET_BYTES(LAST_U32LE());
uint32_t offsetof_end = net_offset + 0;
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rreaddir->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rreaddir->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 41)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rreaddir->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 41));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rreaddir->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 41)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Tfsync(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Tfsync([[maybe_unused]] 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_Tfsync);
+ size_t host_size = sizeof(struct lib9p_msg_Tfsync);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_end = net_offset + 15;
VALIDATE_NET_BYTES(15);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tfsync->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tfsync->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 50)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tfsync->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 50));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tfsync->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 50)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rfsync(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rfsync([[maybe_unused]] 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_Rfsync);
+ size_t host_size = sizeof(struct lib9p_msg_Rfsync);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_end = net_offset + 7;
VALIDATE_NET_BYTES(7);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rfsync->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rfsync->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 51)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rfsync->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 51));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rfsync->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 51)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Tlock(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Tlock([[maybe_unused]] 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_Tlock);
+ size_t host_size = sizeof(struct lib9p_msg_Tlock);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_flags = net_offset + 12;
@@ -1343,91 +1342,91 @@ 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 (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tlock->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tlock->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 52)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tlock->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 52));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tlock->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 52)));
if (GET_U32LE(offsetof_flags) & ~lock_flags_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in lock_flags bitfield: ",
- (base16_u32_, GET_U32LE(offsetof_flags) & ~lock_flags_masks[ctx->version]));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in lock_flags bitfield: ",
+ (base16_u32_, GET_U32LE(offsetof_flags) & ~lock_flags_masks[ctx->version])));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rlock(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rlock([[maybe_unused]] 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_Rlock);
+ size_t host_size = sizeof(struct lib9p_msg_Rlock);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_end = net_offset + 8;
VALIDATE_NET_BYTES(8);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rlock->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rlock->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 53)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rlock->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 53));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rlock->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 53)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Tgetlock(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Tgetlock([[maybe_unused]] 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_Tgetlock);
+ size_t host_size = sizeof(struct lib9p_msg_Tgetlock);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
VALIDATE_NET_BYTES(34);
VALIDATE_NET_UTF8(LAST_U16LE());
uint32_t offsetof_end = net_offset + 0;
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tgetlock->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tgetlock->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 54)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tgetlock->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 54));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tgetlock->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 54)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rgetlock(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rgetlock([[maybe_unused]] 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_Rgetlock);
+ size_t host_size = sizeof(struct lib9p_msg_Rgetlock);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
VALIDATE_NET_BYTES(30);
VALIDATE_NET_UTF8(LAST_U16LE());
uint32_t offsetof_end = net_offset + 0;
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rgetlock->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rgetlock->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 55)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rgetlock->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 55));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rgetlock->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 55)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Tlink(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Tlink([[maybe_unused]] 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_Tlink);
+ size_t host_size = sizeof(struct lib9p_msg_Tlink);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
VALIDATE_NET_BYTES(17);
VALIDATE_NET_UTF8(LAST_U16LE());
uint32_t offsetof_end = net_offset + 0;
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tlink->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tlink->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 70)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tlink->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 70));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tlink->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 70)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rlink(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rlink([[maybe_unused]] 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_Rlink);
+ size_t host_size = sizeof(struct lib9p_msg_Rlink);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_end = net_offset + 7;
VALIDATE_NET_BYTES(7);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rlink->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rlink->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 71)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rlink->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 71));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rlink->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 71)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Tmkdir(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Tmkdir([[maybe_unused]] 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_Tmkdir);
+ size_t host_size = sizeof(struct lib9p_msg_Tmkdir);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
VALIDATE_NET_BYTES(13);
@@ -1436,36 +1435,36 @@ 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 (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tmkdir->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tmkdir->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 72)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tmkdir->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 72));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tmkdir->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 72)));
if (GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in mode bitfield: ",
- (base16_u32_, GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in mode bitfield: ",
+ (base16_u32_, GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version])));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rmkdir(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rmkdir([[maybe_unused]] 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_Rmkdir);
+ size_t host_size = sizeof(struct lib9p_msg_Rmkdir);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_qid_type = net_offset + 7;
VALIDATE_NET_BYTES(20);
if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version])
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: ",
- (base16_u8_, GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "unknown bits in qt bitfield: ",
+ (base16_u8_, GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version])));
uint32_t offsetof_end = net_offset + 0;
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rmkdir->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rmkdir->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 73)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rmkdir->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 73));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rmkdir->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 73)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Trenameat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Trenameat([[maybe_unused]] 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_Trenameat);
+ size_t host_size = sizeof(struct lib9p_msg_Trenameat);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
VALIDATE_NET_BYTES(13);
@@ -1474,29 +1473,29 @@ 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 (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Trenameat->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Trenameat->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 74)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Trenameat->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 74));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Trenameat->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 74)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rrenameat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rrenameat([[maybe_unused]] 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_Rrenameat);
+ size_t host_size = sizeof(struct lib9p_msg_Rrenameat);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_end = net_offset + 7;
VALIDATE_NET_BYTES(7);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rrenameat->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rrenameat->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 75)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rrenameat->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 75));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rrenameat->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 75)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Tunlinkat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Tunlinkat([[maybe_unused]] 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_Tunlinkat);
+ size_t host_size = sizeof(struct lib9p_msg_Tunlinkat);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
VALIDATE_NET_BYTES(13);
@@ -1504,59 +1503,59 @@ 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 (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tunlinkat->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tunlinkat->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 76)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tunlinkat->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 76));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tunlinkat->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 76)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Runlinkat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Runlinkat([[maybe_unused]] 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_Runlinkat);
+ size_t host_size = sizeof(struct lib9p_msg_Runlinkat);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_end = net_offset + 7;
VALIDATE_NET_BYTES(7);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Runlinkat->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Runlinkat->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 77)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Runlinkat->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 77));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Runlinkat->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 77)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
#endif /* CONFIG_9P_ENABLE_9P2000_L */
#if CONFIG_9P_ENABLE_9P2000_e
-static ssize_t validate_Tsession(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Tsession([[maybe_unused]] 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_Tsession);
+ size_t host_size = sizeof(struct lib9p_msg_Tsession);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_end = net_offset + 15;
VALIDATE_NET_BYTES(15);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tsession->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tsession->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 150)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tsession->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 150));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tsession->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 150)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rsession(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rsession([[maybe_unused]] 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_Rsession);
+ size_t host_size = sizeof(struct lib9p_msg_Rsession);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_end = net_offset + 7;
VALIDATE_NET_BYTES(7);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rsession->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rsession->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 151)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rsession->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 151));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rsession->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 151)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Tsread(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Tsread([[maybe_unused]] 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_Tsread);
+ size_t host_size = sizeof(struct lib9p_msg_Tsread);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
VALIDATE_NET_BYTES(13);
@@ -1567,30 +1566,30 @@ static ssize_t validate_Tsread(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t
}
uint32_t offsetof_end = net_offset + 0;
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tsread->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tsread->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 152)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tsread->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 152));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tsread->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 152)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rsread(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rsread([[maybe_unused]] 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_Rsread);
+ size_t host_size = sizeof(struct lib9p_msg_Rsread);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
VALIDATE_NET_BYTES(11);
VALIDATE_NET_BYTES(LAST_U32LE());
uint32_t offsetof_end = net_offset + 0;
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rsread->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rsread->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 153)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rsread->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 153));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rsread->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 153)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Tswrite(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Tswrite([[maybe_unused]] 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_Tswrite);
+ size_t host_size = sizeof(struct lib9p_msg_Tswrite);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
VALIDATE_NET_BYTES(13);
@@ -1603,24 +1602,24 @@ 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 (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tswrite->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tswrite->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 154)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Tswrite->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 154));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Tswrite->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 154)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
-static ssize_t validate_Rswrite(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+static size_t_or_error validate_Rswrite([[maybe_unused]] 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_Rswrite);
+ size_t host_size = sizeof(struct lib9p_msg_Rswrite);
uint32_t offsetof_size = net_offset + 0;
uint32_t offsetof_typ = net_offset + 4;
uint32_t offsetof_end = net_offset + 11;
VALIDATE_NET_BYTES(11);
if (GET_U32LE(offsetof_size) != offsetof_end - offsetof_size)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rswrite->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size));
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rswrite->size value is wrong: actual:", (base10, GET_U32LE(offsetof_size)), " != correct:", (base10, offsetof_end - offsetof_size)));
if (GET_U8LE(offsetof_typ) != 155)
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "Rswrite->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 155));
- return (ssize_t)host_size;
+ return ERROR_NEW_ERR(size_t, error_new(E_POSIX_EBADMSG, "Rswrite->typ value is wrong: actual:", (base10, GET_U8LE(offsetof_typ)), " != correct:", (base10, 155)));
+ return ERROR_NEW_VAL(size_t, host_size);
}
#endif /* CONFIG_9P_ENABLE_9P2000_e */
@@ -2685,41 +2684,41 @@ static void unmarshal_Rswrite([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *n
/* marshal_* ******************************************************************/
-#define MARSHAL_BYTES_ZEROCOPY(ctx, data, len) \
- if (ret->net_iov[ret->net_iov_cnt-1].iov_len) \
- ret->net_iov_cnt++; \
- ret->net_iov[ret->net_iov_cnt-1].iov_base = data; \
- ret->net_iov[ret->net_iov_cnt-1].iov_len = len; \
+#define MARSHAL_BYTES_ZEROCOPY(ctx, data, len) \
+ if (ret->net_iov[ret->net_iov_cnt-1].iov_len) \
+ ret->net_iov_cnt++; \
+ ret->net_iov[ret->net_iov_cnt-1].iov_write_from = data; \
+ ret->net_iov[ret->net_iov_cnt-1].iov_len = len; \
ret->net_iov_cnt++;
-#define MARSHAL_BYTES(ctx, data, len) \
- if (!ret->net_iov[ret->net_iov_cnt-1].iov_base) \
- ret->net_iov[ret->net_iov_cnt-1].iov_base = &ret->net_copied[ret->net_copied_size]; \
- memcpy(&ret->net_copied[ret->net_copied_size], data, len); \
- ret->net_copied_size += len; \
+#define MARSHAL_BYTES(ctx, data, len) \
+ if (!ret->net_iov[ret->net_iov_cnt-1].iov_write_from) \
+ ret->net_iov[ret->net_iov_cnt-1].iov_write_from = &ret->net_copied[ret->net_copied_size]; \
+ memcpy(&ret->net_copied[ret->net_copied_size], data, len); \
+ ret->net_copied_size += len; \
ret->net_iov[ret->net_iov_cnt-1].iov_len += len;
-#define MARSHAL_U8LE(ctx, val) \
- if (!ret->net_iov[ret->net_iov_cnt-1].iov_base) \
- ret->net_iov[ret->net_iov_cnt-1].iov_base = &ret->net_copied[ret->net_copied_size]; \
- ret->net_copied[ret->net_copied_size] = val; \
- ret->net_copied_size += 1; \
+#define MARSHAL_U8LE(ctx, val) \
+ if (!ret->net_iov[ret->net_iov_cnt-1].iov_write_from) \
+ ret->net_iov[ret->net_iov_cnt-1].iov_write_from = &ret->net_copied[ret->net_copied_size]; \
+ ret->net_copied[ret->net_copied_size] = val; \
+ ret->net_copied_size += 1; \
ret->net_iov[ret->net_iov_cnt-1].iov_len += 1;
-#define MARSHAL_U16LE(ctx, val) \
- if (!ret->net_iov[ret->net_iov_cnt-1].iov_base) \
- ret->net_iov[ret->net_iov_cnt-1].iov_base = &ret->net_copied[ret->net_copied_size]; \
- uint16le_encode(&ret->net_copied[ret->net_copied_size], val); \
- ret->net_copied_size += 2; \
+#define MARSHAL_U16LE(ctx, val) \
+ if (!ret->net_iov[ret->net_iov_cnt-1].iov_write_from) \
+ ret->net_iov[ret->net_iov_cnt-1].iov_write_from = &ret->net_copied[ret->net_copied_size]; \
+ uint16le_encode(&ret->net_copied[ret->net_copied_size], val); \
+ ret->net_copied_size += 2; \
ret->net_iov[ret->net_iov_cnt-1].iov_len += 2;
-#define MARSHAL_U32LE(ctx, val) \
- if (!ret->net_iov[ret->net_iov_cnt-1].iov_base) \
- ret->net_iov[ret->net_iov_cnt-1].iov_base = &ret->net_copied[ret->net_copied_size]; \
- uint32le_encode(&ret->net_copied[ret->net_copied_size], val); \
- ret->net_copied_size += 4; \
+#define MARSHAL_U32LE(ctx, val) \
+ if (!ret->net_iov[ret->net_iov_cnt-1].iov_write_from) \
+ ret->net_iov[ret->net_iov_cnt-1].iov_write_from = &ret->net_copied[ret->net_copied_size]; \
+ uint32le_encode(&ret->net_copied[ret->net_copied_size], val); \
+ ret->net_copied_size += 4; \
ret->net_iov[ret->net_iov_cnt-1].iov_len += 4;
-#define MARSHAL_U64LE(ctx, val) \
- if (!ret->net_iov[ret->net_iov_cnt-1].iov_base) \
- ret->net_iov[ret->net_iov_cnt-1].iov_base = &ret->net_copied[ret->net_copied_size]; \
- uint64le_encode(&ret->net_copied[ret->net_copied_size], val); \
- ret->net_copied_size += 8; \
+#define MARSHAL_U64LE(ctx, val) \
+ if (!ret->net_iov[ret->net_iov_cnt-1].iov_write_from) \
+ ret->net_iov[ret->net_iov_cnt-1].iov_write_from = &ret->net_copied[ret->net_copied_size]; \
+ uint64le_encode(&ret->net_copied[ret->net_copied_size], val); \
+ ret->net_copied_size += 8; \
ret->net_iov[ret->net_iov_cnt-1].iov_len += 8;
#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
@@ -2767,13 +2766,12 @@ static bool marshal_stat(struct lib9p_ctx *ctx, struct lib9p_stat *val, struct _
#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 || CONFIG_9P_ENABLE_uninitialized
-static bool marshal_Tversion(struct lib9p_ctx *ctx, struct lib9p_msg_Tversion *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Tversion message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Tversion message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -2783,16 +2781,15 @@ static bool marshal_Tversion(struct lib9p_ctx *ctx, struct lib9p_msg_Tversion *v
MARSHAL_U32LE(ctx, val->max_msg_size);
MARSHAL_U16LE(ctx, val->version.len);
MARSHAL_BYTES_ZEROCOPY(ctx, val->version.utf8, val->version.len);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rversion(struct lib9p_ctx *ctx, struct lib9p_msg_Rversion *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rversion message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rversion message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -2802,12 +2799,12 @@ static bool marshal_Rversion(struct lib9p_ctx *ctx, struct lib9p_msg_Rversion *v
MARSHAL_U32LE(ctx, val->max_msg_size);
MARSHAL_U16LE(ctx, val->version.len);
MARSHAL_BYTES_ZEROCOPY(ctx, val->version.utf8, val->version.len);
- return false;
+ return ERROR_NULL;
}
#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_uninitialized */
#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) {
+static error 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
if ( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) ) {
@@ -2815,10 +2812,9 @@ 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Tauth message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Tauth message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -2835,16 +2831,15 @@ static bool marshal_Tauth(struct lib9p_ctx *ctx, struct lib9p_msg_Tauth *val, st
MARSHAL_U32LE(ctx, val->unum);
}
#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rauth(struct lib9p_ctx *ctx, struct lib9p_msg_Rauth *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rauth message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rauth message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -2854,10 +2849,10 @@ static bool marshal_Rauth(struct lib9p_ctx *ctx, struct lib9p_msg_Rauth *val, st
MARSHAL_U8LE(ctx, val->aqid.type & qt_masks[ctx->version]);
MARSHAL_U32LE(ctx, val->aqid.vers);
MARSHAL_U64LE(ctx, val->aqid.path);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Tattach(struct lib9p_ctx *ctx, struct lib9p_msg_Tattach *val, struct _marshal_ret *ret) {
+static error marshal_Tattach(struct lib9p_ctx *ctx, struct lib9p_msg_Tattach *val, struct _marshal_ret *ret) {
uint32_t needed_size = 19 + val->uname.len + 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) ) {
@@ -2865,10 +2860,9 @@ 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Tattach message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Tattach message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -2886,16 +2880,15 @@ static bool marshal_Tattach(struct lib9p_ctx *ctx, struct lib9p_msg_Tattach *val
MARSHAL_U32LE(ctx, val->unum);
}
#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rattach(struct lib9p_ctx *ctx, struct lib9p_msg_Rattach *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rattach message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rattach message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -2905,12 +2898,12 @@ static bool marshal_Rattach(struct lib9p_ctx *ctx, struct lib9p_msg_Rattach *val
MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->version]);
MARSHAL_U32LE(ctx, val->qid.vers);
MARSHAL_U64LE(ctx, val->qid.path);
- return false;
+ return ERROR_NULL;
}
#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_uninitialized
-static bool marshal_Rerror(struct lib9p_ctx *ctx, struct lib9p_msg_Rerror *val, struct _marshal_ret *ret) {
+static error marshal_Rerror(struct lib9p_ctx *ctx, struct lib9p_msg_Rerror *val, struct _marshal_ret *ret) {
uint32_t needed_size = 9 + val->errstr.len;
#if CONFIG_9P_ENABLE_9P2000_u
if is_ver(ctx, 9P2000_u) {
@@ -2918,10 +2911,9 @@ static bool marshal_Rerror(struct lib9p_ctx *ctx, struct lib9p_msg_Rerror *val,
}
#endif /* CONFIG_9P_ENABLE_9P2000_u */
if (needed_size > ctx->max_msg_size) {
- lib9p_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rerror message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rerror message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -2935,18 +2927,17 @@ static bool marshal_Rerror(struct lib9p_ctx *ctx, struct lib9p_msg_Rerror *val,
MARSHAL_U32LE(ctx, val->errnum);
}
#endif /* CONFIG_9P_ENABLE_9P2000_u */
- return false;
+ return ERROR_NULL;
}
#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_uninitialized */
#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) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Tflush message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Tflush message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -2954,35 +2945,33 @@ static bool marshal_Tflush(struct lib9p_ctx *ctx, struct lib9p_msg_Tflush *val,
MARSHAL_U8LE(ctx, 108);
MARSHAL_U16LE(ctx, val->tag);
MARSHAL_U16LE(ctx, val->oldtag);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rflush(struct lib9p_ctx *ctx, struct lib9p_msg_Rflush *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rflush message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rflush message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
MARSHAL_U8LE(ctx, 109);
MARSHAL_U16LE(ctx, val->tag);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Twalk(struct lib9p_ctx *ctx, struct lib9p_msg_Twalk *val, struct _marshal_ret *ret) {
+static error marshal_Twalk(struct lib9p_ctx *ctx, struct lib9p_msg_Twalk *val, struct _marshal_ret *ret) {
uint32_t needed_size = 17;
for (uint16_t i = 0; i < val->nwname; i++) {
needed_size += 2 + val->wname[i].len;
}
if (needed_size > ctx->max_msg_size) {
- lib9p_error(ctx, LIB9P_ERRNO_L_ERANGE, "Twalk message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Twalk message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -2996,16 +2985,15 @@ static bool marshal_Twalk(struct lib9p_ctx *ctx, struct lib9p_msg_Twalk *val, st
MARSHAL_U16LE(ctx, val->wname[i].len);
MARSHAL_BYTES_ZEROCOPY(ctx, val->wname[i].utf8, val->wname[i].len);
}
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rwalk(struct lib9p_ctx *ctx, struct lib9p_msg_Rwalk *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rwalk message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rwalk message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3018,18 +3006,17 @@ static bool marshal_Rwalk(struct lib9p_ctx *ctx, struct lib9p_msg_Rwalk *val, st
MARSHAL_U32LE(ctx, val->wqid[i].vers);
MARSHAL_U64LE(ctx, val->wqid[i].path);
}
- return false;
+ return ERROR_NULL;
}
#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
-static bool marshal_Topen(struct lib9p_ctx *ctx, struct lib9p_msg_Topen *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Topen message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Topen message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3038,16 +3025,15 @@ static bool marshal_Topen(struct lib9p_ctx *ctx, struct lib9p_msg_Topen *val, st
MARSHAL_U16LE(ctx, val->tag);
MARSHAL_U32LE(ctx, val->fid);
MARSHAL_U8LE(ctx, val->mode & o_masks[ctx->version]);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Ropen(struct lib9p_ctx *ctx, struct lib9p_msg_Ropen *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Ropen message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Ropen message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3058,16 +3044,15 @@ static bool marshal_Ropen(struct lib9p_ctx *ctx, struct lib9p_msg_Ropen *val, st
MARSHAL_U32LE(ctx, val->qid.vers);
MARSHAL_U64LE(ctx, val->qid.path);
MARSHAL_U32LE(ctx, val->iounit);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Tcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Tcreate *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Tcreate message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Tcreate message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3079,16 +3064,15 @@ static bool marshal_Tcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Tcreate *val
MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len);
MARSHAL_U32LE(ctx, val->perm & dm_masks[ctx->version]);
MARSHAL_U8LE(ctx, val->mode & o_masks[ctx->version]);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Rcreate *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rcreate message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rcreate message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3099,18 +3083,17 @@ static bool marshal_Rcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Rcreate *val
MARSHAL_U32LE(ctx, val->qid.vers);
MARSHAL_U64LE(ctx, val->qid.path);
MARSHAL_U32LE(ctx, val->iounit);
- return false;
+ return ERROR_NULL;
}
#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
-static bool marshal_Tread(struct lib9p_ctx *ctx, struct lib9p_msg_Tread *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Tread message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Tread message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3120,16 +3103,15 @@ static bool marshal_Tread(struct lib9p_ctx *ctx, struct lib9p_msg_Tread *val, st
MARSHAL_U32LE(ctx, val->fid);
MARSHAL_U64LE(ctx, val->offset);
MARSHAL_U32LE(ctx, val->count);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rread(struct lib9p_ctx *ctx, struct lib9p_msg_Rread *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rread message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rread message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3138,16 +3120,15 @@ static bool marshal_Rread(struct lib9p_ctx *ctx, struct lib9p_msg_Rread *val, st
MARSHAL_U16LE(ctx, val->tag);
MARSHAL_U32LE(ctx, val->count);
MARSHAL_BYTES_ZEROCOPY(ctx, val->data, val->count);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Twrite(struct lib9p_ctx *ctx, struct lib9p_msg_Twrite *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Twrite message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Twrite message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3158,16 +3139,15 @@ static bool marshal_Twrite(struct lib9p_ctx *ctx, struct lib9p_msg_Twrite *val,
MARSHAL_U64LE(ctx, val->offset);
MARSHAL_U32LE(ctx, val->count);
MARSHAL_BYTES_ZEROCOPY(ctx, val->data, val->count);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rwrite(struct lib9p_ctx *ctx, struct lib9p_msg_Rwrite *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rwrite message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rwrite message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3175,16 +3155,15 @@ static bool marshal_Rwrite(struct lib9p_ctx *ctx, struct lib9p_msg_Rwrite *val,
MARSHAL_U8LE(ctx, 119);
MARSHAL_U16LE(ctx, val->tag);
MARSHAL_U32LE(ctx, val->count);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Tclunk(struct lib9p_ctx *ctx, struct lib9p_msg_Tclunk *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Tclunk message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Tclunk message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3192,32 +3171,30 @@ static bool marshal_Tclunk(struct lib9p_ctx *ctx, struct lib9p_msg_Tclunk *val,
MARSHAL_U8LE(ctx, 120);
MARSHAL_U16LE(ctx, val->tag);
MARSHAL_U32LE(ctx, val->fid);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rclunk(struct lib9p_ctx *ctx, struct lib9p_msg_Rclunk *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rclunk message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rclunk message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
MARSHAL_U8LE(ctx, 121);
MARSHAL_U16LE(ctx, val->tag);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Tremove(struct lib9p_ctx *ctx, struct lib9p_msg_Tremove *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Tremove message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Tremove message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3225,34 +3202,32 @@ static bool marshal_Tremove(struct lib9p_ctx *ctx, struct lib9p_msg_Tremove *val
MARSHAL_U8LE(ctx, 122);
MARSHAL_U16LE(ctx, val->tag);
MARSHAL_U32LE(ctx, val->fid);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rremove(struct lib9p_ctx *ctx, struct lib9p_msg_Rremove *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rremove message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rremove message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
MARSHAL_U8LE(ctx, 123);
MARSHAL_U16LE(ctx, val->tag);
- return false;
+ return ERROR_NULL;
}
#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
-static bool marshal_Tstat(struct lib9p_ctx *ctx, struct lib9p_msg_Tstat *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Tstat message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Tstat message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3260,10 +3235,10 @@ static bool marshal_Tstat(struct lib9p_ctx *ctx, struct lib9p_msg_Tstat *val, st
MARSHAL_U8LE(ctx, 124);
MARSHAL_U16LE(ctx, val->tag);
MARSHAL_U32LE(ctx, val->fid);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rstat(struct lib9p_ctx *ctx, struct lib9p_msg_Rstat *val, struct _marshal_ret *ret) {
+static error marshal_Rstat(struct lib9p_ctx *ctx, struct lib9p_msg_Rstat *val, struct _marshal_ret *ret) {
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) {
@@ -3271,10 +3246,9 @@ static bool marshal_Rstat(struct lib9p_ctx *ctx, struct lib9p_msg_Rstat *val, st
}
#endif /* CONFIG_9P_ENABLE_9P2000_u */
if (needed_size > ctx->max_msg_size) {
- lib9p_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rstat message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rstat message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3317,10 +3291,10 @@ static bool marshal_Rstat(struct lib9p_ctx *ctx, struct lib9p_msg_Rstat *val, st
MARSHAL_U32LE(ctx, val->stat.last_modifier_unum);
}
#endif /* CONFIG_9P_ENABLE_9P2000_u */
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Twstat(struct lib9p_ctx *ctx, struct lib9p_msg_Twstat *val, struct _marshal_ret *ret) {
+static error marshal_Twstat(struct lib9p_ctx *ctx, struct lib9p_msg_Twstat *val, struct _marshal_ret *ret) {
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) {
@@ -3328,10 +3302,9 @@ static bool marshal_Twstat(struct lib9p_ctx *ctx, struct lib9p_msg_Twstat *val,
}
#endif /* CONFIG_9P_ENABLE_9P2000_u */
if (needed_size > ctx->max_msg_size) {
- lib9p_error(ctx, LIB9P_ERRNO_L_ERANGE, "Twstat message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Twstat message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3375,34 +3348,32 @@ static bool marshal_Twstat(struct lib9p_ctx *ctx, struct lib9p_msg_Twstat *val,
MARSHAL_U32LE(ctx, val->stat.last_modifier_unum);
}
#endif /* CONFIG_9P_ENABLE_9P2000_u */
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rwstat(struct lib9p_ctx *ctx, struct lib9p_msg_Rwstat *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rwstat message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rwstat message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
MARSHAL_U8LE(ctx, 127);
MARSHAL_U16LE(ctx, val->tag);
- return false;
+ return ERROR_NULL;
}
#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
-static bool marshal_Topenfd(struct lib9p_ctx *ctx, struct lib9p_msg_Topenfd *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Topenfd message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Topenfd message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3411,16 +3382,15 @@ static bool marshal_Topenfd(struct lib9p_ctx *ctx, struct lib9p_msg_Topenfd *val
MARSHAL_U16LE(ctx, val->tag);
MARSHAL_U32LE(ctx, val->fid);
MARSHAL_U8LE(ctx, val->mode & o_masks[ctx->version]);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Ropenfd(struct lib9p_ctx *ctx, struct lib9p_msg_Ropenfd *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Ropenfd message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Ropenfd message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3432,18 +3402,17 @@ static bool marshal_Ropenfd(struct lib9p_ctx *ctx, struct lib9p_msg_Ropenfd *val
MARSHAL_U64LE(ctx, val->qid.path);
MARSHAL_U32LE(ctx, val->iounit);
MARSHAL_U32LE(ctx, val->unixfd);
- return false;
+ return ERROR_NULL;
}
#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
#if CONFIG_9P_ENABLE_9P2000_L
-static bool marshal_Rlerror(struct lib9p_ctx *ctx, struct lib9p_msg_Rlerror *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rlerror message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rlerror message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3451,16 +3420,15 @@ static bool marshal_Rlerror(struct lib9p_ctx *ctx, struct lib9p_msg_Rlerror *val
MARSHAL_U8LE(ctx, 7);
MARSHAL_U16LE(ctx, val->tag);
MARSHAL_U32LE(ctx, val->errnum);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Tstatfs(struct lib9p_ctx *ctx, struct lib9p_msg_Tstatfs *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Tstatfs message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Tstatfs message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3468,16 +3436,15 @@ static bool marshal_Tstatfs(struct lib9p_ctx *ctx, struct lib9p_msg_Tstatfs *val
MARSHAL_U8LE(ctx, 8);
MARSHAL_U16LE(ctx, val->tag);
MARSHAL_U32LE(ctx, val->fid);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rstatfs(struct lib9p_ctx *ctx, struct lib9p_msg_Rstatfs *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rstatfs message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rstatfs message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3493,16 +3460,15 @@ static bool marshal_Rstatfs(struct lib9p_ctx *ctx, struct lib9p_msg_Rstatfs *val
MARSHAL_U64LE(ctx, val->ffree);
MARSHAL_U64LE(ctx, val->fsid);
MARSHAL_U32LE(ctx, val->namelen);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Tlopen(struct lib9p_ctx *ctx, struct lib9p_msg_Tlopen *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Tlopen message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Tlopen message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3511,16 +3477,15 @@ static bool marshal_Tlopen(struct lib9p_ctx *ctx, struct lib9p_msg_Tlopen *val,
MARSHAL_U16LE(ctx, val->tag);
MARSHAL_U32LE(ctx, val->fid);
MARSHAL_U32LE(ctx, val->flags & lo_masks[ctx->version]);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rlopen(struct lib9p_ctx *ctx, struct lib9p_msg_Rlopen *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rlopen message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rlopen message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3531,16 +3496,15 @@ static bool marshal_Rlopen(struct lib9p_ctx *ctx, struct lib9p_msg_Rlopen *val,
MARSHAL_U32LE(ctx, val->qid.vers);
MARSHAL_U64LE(ctx, val->qid.path);
MARSHAL_U32LE(ctx, val->iounit);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Tlcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Tlcreate *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Tlcreate message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Tlcreate message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3553,16 +3517,15 @@ static bool marshal_Tlcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Tlcreate *v
MARSHAL_U32LE(ctx, val->flags & lo_masks[ctx->version]);
MARSHAL_U32LE(ctx, val->mode & mode_masks[ctx->version]);
MARSHAL_U32LE(ctx, val->gid);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rlcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Rlcreate *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rlcreate message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rlcreate message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3573,16 +3536,15 @@ static bool marshal_Rlcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Rlcreate *v
MARSHAL_U32LE(ctx, val->qid.vers);
MARSHAL_U64LE(ctx, val->qid.path);
MARSHAL_U32LE(ctx, val->iounit);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Tsymlink(struct lib9p_ctx *ctx, struct lib9p_msg_Tsymlink *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Tsymlink message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Tsymlink message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3595,16 +3557,15 @@ static bool marshal_Tsymlink(struct lib9p_ctx *ctx, struct lib9p_msg_Tsymlink *v
MARSHAL_U16LE(ctx, val->symtgt.len);
MARSHAL_BYTES_ZEROCOPY(ctx, val->symtgt.utf8, val->symtgt.len);
MARSHAL_U32LE(ctx, val->gid);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rsymlink(struct lib9p_ctx *ctx, struct lib9p_msg_Rsymlink *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rsymlink message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rsymlink message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3614,16 +3575,15 @@ static bool marshal_Rsymlink(struct lib9p_ctx *ctx, struct lib9p_msg_Rsymlink *v
MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->version]);
MARSHAL_U32LE(ctx, val->qid.vers);
MARSHAL_U64LE(ctx, val->qid.path);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Tmknod(struct lib9p_ctx *ctx, struct lib9p_msg_Tmknod *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Tmknod message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Tmknod message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3637,16 +3597,15 @@ static bool marshal_Tmknod(struct lib9p_ctx *ctx, struct lib9p_msg_Tmknod *val,
MARSHAL_U32LE(ctx, val->major);
MARSHAL_U32LE(ctx, val->minor);
MARSHAL_U32LE(ctx, val->gid);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rmknod(struct lib9p_ctx *ctx, struct lib9p_msg_Rmknod *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rmknod message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rmknod message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3656,16 +3615,15 @@ static bool marshal_Rmknod(struct lib9p_ctx *ctx, struct lib9p_msg_Rmknod *val,
MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->version]);
MARSHAL_U32LE(ctx, val->qid.vers);
MARSHAL_U64LE(ctx, val->qid.path);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Trename(struct lib9p_ctx *ctx, struct lib9p_msg_Trename *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Trename message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Trename message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3676,32 +3634,30 @@ static bool marshal_Trename(struct lib9p_ctx *ctx, struct lib9p_msg_Trename *val
MARSHAL_U32LE(ctx, val->dfid);
MARSHAL_U16LE(ctx, val->name.len);
MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rrename(struct lib9p_ctx *ctx, struct lib9p_msg_Rrename *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rrename message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rrename message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
MARSHAL_U8LE(ctx, 21);
MARSHAL_U16LE(ctx, val->tag);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Treadlink(struct lib9p_ctx *ctx, struct lib9p_msg_Treadlink *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Treadlink message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Treadlink message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3709,16 +3665,15 @@ static bool marshal_Treadlink(struct lib9p_ctx *ctx, struct lib9p_msg_Treadlink
MARSHAL_U8LE(ctx, 22);
MARSHAL_U16LE(ctx, val->tag);
MARSHAL_U32LE(ctx, val->fid);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rreadlink(struct lib9p_ctx *ctx, struct lib9p_msg_Rreadlink *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rreadlink message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rreadlink message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3727,16 +3682,15 @@ static bool marshal_Rreadlink(struct lib9p_ctx *ctx, struct lib9p_msg_Rreadlink
MARSHAL_U16LE(ctx, val->tag);
MARSHAL_U16LE(ctx, val->target.len);
MARSHAL_BYTES_ZEROCOPY(ctx, val->target.utf8, val->target.len);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Tgetattr(struct lib9p_ctx *ctx, struct lib9p_msg_Tgetattr *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Tgetattr message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Tgetattr message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3745,16 +3699,15 @@ static bool marshal_Tgetattr(struct lib9p_ctx *ctx, struct lib9p_msg_Tgetattr *v
MARSHAL_U16LE(ctx, val->tag);
MARSHAL_U32LE(ctx, val->fid);
MARSHAL_U64LE(ctx, val->request_mask & getattr_masks[ctx->version]);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rgetattr(struct lib9p_ctx *ctx, struct lib9p_msg_Rgetattr *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rgetattr message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rgetattr message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3783,16 +3736,15 @@ static bool marshal_Rgetattr(struct lib9p_ctx *ctx, struct lib9p_msg_Rgetattr *v
MARSHAL_U64LE(ctx, val->btime_nsec);
MARSHAL_U64LE(ctx, val->gen);
MARSHAL_U64LE(ctx, val->data_version);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Tsetattr(struct lib9p_ctx *ctx, struct lib9p_msg_Tsetattr *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Tsetattr message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Tsetattr message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3809,32 +3761,30 @@ static bool marshal_Tsetattr(struct lib9p_ctx *ctx, struct lib9p_msg_Tsetattr *v
MARSHAL_U64LE(ctx, val->atime_nsec);
MARSHAL_U64LE(ctx, val->mtime_sec);
MARSHAL_U64LE(ctx, val->mtime_nsec);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rsetattr(struct lib9p_ctx *ctx, struct lib9p_msg_Rsetattr *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rsetattr message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rsetattr message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
MARSHAL_U8LE(ctx, 27);
MARSHAL_U16LE(ctx, val->tag);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Txattrwalk(struct lib9p_ctx *ctx, struct lib9p_msg_Txattrwalk *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Txattrwalk message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Txattrwalk message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3845,16 +3795,15 @@ static bool marshal_Txattrwalk(struct lib9p_ctx *ctx, struct lib9p_msg_Txattrwal
MARSHAL_U32LE(ctx, val->newfid);
MARSHAL_U16LE(ctx, val->name.len);
MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rxattrwalk(struct lib9p_ctx *ctx, struct lib9p_msg_Rxattrwalk *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rxattrwalk message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rxattrwalk message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3862,16 +3811,15 @@ static bool marshal_Rxattrwalk(struct lib9p_ctx *ctx, struct lib9p_msg_Rxattrwal
MARSHAL_U8LE(ctx, 31);
MARSHAL_U16LE(ctx, val->tag);
MARSHAL_U64LE(ctx, val->attr_size);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Txattrcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Txattrcreate *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Txattrcreate message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Txattrcreate message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3883,32 +3831,30 @@ static bool marshal_Txattrcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Txattrc
MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len);
MARSHAL_U64LE(ctx, val->attr_size);
MARSHAL_U32LE(ctx, val->flags);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rxattrcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Rxattrcreate *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rxattrcreate message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rxattrcreate message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
MARSHAL_U8LE(ctx, 33);
MARSHAL_U16LE(ctx, val->tag);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Treaddir(struct lib9p_ctx *ctx, struct lib9p_msg_Treaddir *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Treaddir message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Treaddir message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3918,16 +3864,15 @@ static bool marshal_Treaddir(struct lib9p_ctx *ctx, struct lib9p_msg_Treaddir *v
MARSHAL_U32LE(ctx, val->fid);
MARSHAL_U64LE(ctx, val->offset);
MARSHAL_U32LE(ctx, val->count);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rreaddir(struct lib9p_ctx *ctx, struct lib9p_msg_Rreaddir *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rreaddir message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rreaddir message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = (uint32_t)needed_size;
uint32_t offsetof_size = 0;
@@ -3936,16 +3881,15 @@ static bool marshal_Rreaddir(struct lib9p_ctx *ctx, struct lib9p_msg_Rreaddir *v
MARSHAL_U16LE(ctx, val->tag);
MARSHAL_U32LE(ctx, val->count);
MARSHAL_BYTES_ZEROCOPY(ctx, val->data, val->count);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Tfsync(struct lib9p_ctx *ctx, struct lib9p_msg_Tfsync *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Tfsync message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Tfsync message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3954,32 +3898,30 @@ static bool marshal_Tfsync(struct lib9p_ctx *ctx, struct lib9p_msg_Tfsync *val,
MARSHAL_U16LE(ctx, val->tag);
MARSHAL_U32LE(ctx, val->fid);
MARSHAL_U32LE(ctx, val->datasync);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rfsync(struct lib9p_ctx *ctx, struct lib9p_msg_Rfsync *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rfsync message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rfsync message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
MARSHAL_U8LE(ctx, 51);
MARSHAL_U16LE(ctx, val->tag);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Tlock(struct lib9p_ctx *ctx, struct lib9p_msg_Tlock *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Tlock message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Tlock message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3994,16 +3936,15 @@ static bool marshal_Tlock(struct lib9p_ctx *ctx, struct lib9p_msg_Tlock *val, st
MARSHAL_U32LE(ctx, val->proc_id);
MARSHAL_U16LE(ctx, val->client_id.len);
MARSHAL_BYTES_ZEROCOPY(ctx, val->client_id.utf8, val->client_id.len);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rlock(struct lib9p_ctx *ctx, struct lib9p_msg_Rlock *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rlock message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rlock message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4011,16 +3952,15 @@ static bool marshal_Rlock(struct lib9p_ctx *ctx, struct lib9p_msg_Rlock *val, st
MARSHAL_U8LE(ctx, 53);
MARSHAL_U16LE(ctx, val->tag);
MARSHAL_U8LE(ctx, val->status);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Tgetlock(struct lib9p_ctx *ctx, struct lib9p_msg_Tgetlock *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Tgetlock message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Tgetlock message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4034,16 +3974,15 @@ static bool marshal_Tgetlock(struct lib9p_ctx *ctx, struct lib9p_msg_Tgetlock *v
MARSHAL_U32LE(ctx, val->proc_id);
MARSHAL_U16LE(ctx, val->client_id.len);
MARSHAL_BYTES_ZEROCOPY(ctx, val->client_id.utf8, val->client_id.len);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rgetlock(struct lib9p_ctx *ctx, struct lib9p_msg_Rgetlock *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rgetlock message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rgetlock message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4056,16 +3995,15 @@ static bool marshal_Rgetlock(struct lib9p_ctx *ctx, struct lib9p_msg_Rgetlock *v
MARSHAL_U32LE(ctx, val->proc_id);
MARSHAL_U16LE(ctx, val->client_id.len);
MARSHAL_BYTES_ZEROCOPY(ctx, val->client_id.utf8, val->client_id.len);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Tlink(struct lib9p_ctx *ctx, struct lib9p_msg_Tlink *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Tlink message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Tlink message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4076,32 +4014,30 @@ static bool marshal_Tlink(struct lib9p_ctx *ctx, struct lib9p_msg_Tlink *val, st
MARSHAL_U32LE(ctx, val->fid);
MARSHAL_U16LE(ctx, val->name.len);
MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rlink(struct lib9p_ctx *ctx, struct lib9p_msg_Rlink *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rlink message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rlink message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
MARSHAL_U8LE(ctx, 71);
MARSHAL_U16LE(ctx, val->tag);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Tmkdir(struct lib9p_ctx *ctx, struct lib9p_msg_Tmkdir *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Tmkdir message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Tmkdir message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4113,16 +4049,15 @@ static bool marshal_Tmkdir(struct lib9p_ctx *ctx, struct lib9p_msg_Tmkdir *val,
MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len);
MARSHAL_U32LE(ctx, val->mode & mode_masks[ctx->version]);
MARSHAL_U32LE(ctx, val->gid);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rmkdir(struct lib9p_ctx *ctx, struct lib9p_msg_Rmkdir *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rmkdir message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rmkdir message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4132,16 +4067,15 @@ static bool marshal_Rmkdir(struct lib9p_ctx *ctx, struct lib9p_msg_Rmkdir *val,
MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->version]);
MARSHAL_U32LE(ctx, val->qid.vers);
MARSHAL_U64LE(ctx, val->qid.path);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Trenameat(struct lib9p_ctx *ctx, struct lib9p_msg_Trenameat *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Trenameat message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Trenameat message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4154,32 +4088,30 @@ static bool marshal_Trenameat(struct lib9p_ctx *ctx, struct lib9p_msg_Trenameat
MARSHAL_U32LE(ctx, val->newdirfid);
MARSHAL_U16LE(ctx, val->newname.len);
MARSHAL_BYTES_ZEROCOPY(ctx, val->newname.utf8, val->newname.len);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rrenameat(struct lib9p_ctx *ctx, struct lib9p_msg_Rrenameat *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rrenameat message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rrenameat message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
MARSHAL_U8LE(ctx, 75);
MARSHAL_U16LE(ctx, val->tag);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Tunlinkat(struct lib9p_ctx *ctx, struct lib9p_msg_Tunlinkat *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Tunlinkat message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Tunlinkat message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4190,34 +4122,32 @@ static bool marshal_Tunlinkat(struct lib9p_ctx *ctx, struct lib9p_msg_Tunlinkat
MARSHAL_U16LE(ctx, val->name.len);
MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len);
MARSHAL_U32LE(ctx, val->flags);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Runlinkat(struct lib9p_ctx *ctx, struct lib9p_msg_Runlinkat *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Runlinkat message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Runlinkat message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
MARSHAL_U8LE(ctx, 77);
MARSHAL_U16LE(ctx, val->tag);
- return false;
+ return ERROR_NULL;
}
#endif /* CONFIG_9P_ENABLE_9P2000_L */
#if CONFIG_9P_ENABLE_9P2000_e
-static bool marshal_Tsession(struct lib9p_ctx *ctx, struct lib9p_msg_Tsession *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Tsession message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Tsession message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4225,35 +4155,33 @@ static bool marshal_Tsession(struct lib9p_ctx *ctx, struct lib9p_msg_Tsession *v
MARSHAL_U8LE(ctx, 150);
MARSHAL_U16LE(ctx, val->tag);
MARSHAL_U64LE(ctx, val->key);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rsession(struct lib9p_ctx *ctx, struct lib9p_msg_Rsession *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rsession message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rsession message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
MARSHAL_U8LE(ctx, 151);
MARSHAL_U16LE(ctx, val->tag);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Tsread(struct lib9p_ctx *ctx, struct lib9p_msg_Tsread *val, struct _marshal_ret *ret) {
+static error marshal_Tsread(struct lib9p_ctx *ctx, struct lib9p_msg_Tsread *val, struct _marshal_ret *ret) {
uint64_t needed_size = 13;
for (uint16_t i = 0; i < val->nwname; i++) {
needed_size += 2 + val->wname[i].len;
}
if (needed_size > (uint64_t)(ctx->max_msg_size)) {
- lib9p_error(ctx, LIB9P_ERRNO_L_ERANGE, "Tsread message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Tsread message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = (uint32_t)needed_size;
uint32_t offsetof_size = 0;
@@ -4266,16 +4194,15 @@ static bool marshal_Tsread(struct lib9p_ctx *ctx, struct lib9p_msg_Tsread *val,
MARSHAL_U16LE(ctx, val->wname[i].len);
MARSHAL_BYTES_ZEROCOPY(ctx, val->wname[i].utf8, val->wname[i].len);
}
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rsread(struct lib9p_ctx *ctx, struct lib9p_msg_Rsread *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rsread message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rsread message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = (uint32_t)needed_size;
uint32_t offsetof_size = 0;
@@ -4284,19 +4211,18 @@ static bool marshal_Rsread(struct lib9p_ctx *ctx, struct lib9p_msg_Rsread *val,
MARSHAL_U16LE(ctx, val->tag);
MARSHAL_U32LE(ctx, val->count);
MARSHAL_BYTES_ZEROCOPY(ctx, val->data, val->count);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Tswrite(struct lib9p_ctx *ctx, struct lib9p_msg_Tswrite *val, struct _marshal_ret *ret) {
+static error marshal_Tswrite(struct lib9p_ctx *ctx, struct lib9p_msg_Tswrite *val, struct _marshal_ret *ret) {
uint64_t needed_size = 17 + val->count;
for (uint16_t i = 0; i < val->nwname; i++) {
needed_size += 2 + val->wname[i].len;
}
if (needed_size > (uint64_t)(ctx->max_msg_size)) {
- lib9p_error(ctx, LIB9P_ERRNO_L_ERANGE, "Tswrite message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Tswrite message too large to marshal into ",
ctx->version ? "negotiated" : "client", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = (uint32_t)needed_size;
uint32_t offsetof_size = 0;
@@ -4311,16 +4237,15 @@ static bool marshal_Tswrite(struct lib9p_ctx *ctx, struct lib9p_msg_Tswrite *val
}
MARSHAL_U32LE(ctx, val->count);
MARSHAL_BYTES_ZEROCOPY(ctx, val->data, val->count);
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Rswrite(struct lib9p_ctx *ctx, struct lib9p_msg_Rswrite *val, struct _marshal_ret *ret) {
+static error 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_error(ctx, LIB9P_ERRNO_L_ERANGE, "Rswrite message too large to marshal into ",
+ return error_new(E_POSIX_ERANGE, "Rswrite message too large to marshal into ",
ctx->version ? "negotiated" : "server", " limit",
" (", needed_size, " > ", ctx->max_msg_size, ")");
- return true;
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4328,7 +4253,7 @@ static bool marshal_Rswrite(struct lib9p_ctx *ctx, struct lib9p_msg_Rswrite *val
MARSHAL_U8LE(ctx, 155);
MARSHAL_U16LE(ctx, val->tag);
MARSHAL_U32LE(ctx, val->count);
- return false;
+ return ERROR_NULL;
}
#endif /* CONFIG_9P_ENABLE_9P2000_e */
@@ -6507,7 +6432,7 @@ static bool marshal_Rswrite(struct lib9p_ctx *ctx, struct lib9p_msg_Rswrite *val
fmt_print_tag(w, ctx, &self->tag);
fmt_print_str(w, " count=");
fmt_print_base10(w, self->count);
- if (is_valid_utf8_without_nul((uint8_t *)self->data, (size_t)self->count)) {
+ if (utf8_is_valid_without_nul((uint8_t *)self->data, (size_t)self->count)) {
fmt_print_str(w, " data=");
fmt_print_qmem(w, self->data, self->count < 50 ? self->count : 50);
if (self->count > 50)
@@ -6528,7 +6453,7 @@ static bool marshal_Rswrite(struct lib9p_ctx *ctx, struct lib9p_msg_Rswrite *val
fmt_print_base10(w, self->offset);
fmt_print_str(w, " count=");
fmt_print_base10(w, self->count);
- if (is_valid_utf8_without_nul((uint8_t *)self->data, (size_t)self->count)) {
+ if (utf8_is_valid_without_nul((uint8_t *)self->data, (size_t)self->count)) {
fmt_print_str(w, " data=");
fmt_print_qmem(w, self->data, self->count < 50 ? self->count : 50);
if (self->count > 50)
@@ -6763,7 +6688,7 @@ static bool marshal_Rswrite(struct lib9p_ctx *ctx, struct lib9p_msg_Rswrite *val
fmt_print_tag(w, ctx, &self->tag);
fmt_print_str(w, " count=");
fmt_print_base10(w, self->count);
- if (is_valid_utf8_without_nul((uint8_t *)self->data, (size_t)self->count)) {
+ if (utf8_is_valid_without_nul((uint8_t *)self->data, (size_t)self->count)) {
fmt_print_str(w, " data=");
fmt_print_qmem(w, self->data, self->count < 50 ? self->count : 50);
if (self->count > 50)
@@ -6846,7 +6771,7 @@ static bool marshal_Rswrite(struct lib9p_ctx *ctx, struct lib9p_msg_Rswrite *val
fmt_print_tag(w, ctx, &self->tag);
fmt_print_str(w, " count=");
fmt_print_base10(w, self->count);
- if (is_valid_utf8_without_nul((uint8_t *)self->data, (size_t)self->count)) {
+ if (utf8_is_valid_without_nul((uint8_t *)self->data, (size_t)self->count)) {
fmt_print_str(w, " data=");
fmt_print_qmem(w, self->data, self->count < 50 ? self->count : 50);
if (self->count > 50)
@@ -7445,7 +7370,7 @@ static bool marshal_Rswrite(struct lib9p_ctx *ctx, struct lib9p_msg_Rswrite *val
fmt_print_str(w, " ]");
fmt_print_str(w, " count=");
fmt_print_base10(w, self->count);
- if (is_valid_utf8_without_nul((uint8_t *)self->data, (size_t)self->count)) {
+ if (utf8_is_valid_without_nul((uint8_t *)self->data, (size_t)self->count)) {
fmt_print_str(w, " data=");
fmt_print_qmem(w, self->data, self->count < 50 ? self->count : 50);
if (self->count > 50)
@@ -8178,7 +8103,7 @@ const struct _lib9p_send_tentry _lib9p_table_Rmsg_send[LIB9P_VER_NUM][0x80] = {
};
#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) {
+LM_FLATTEN size_t_or_error _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);
}
LM_FLATTEN void _lib9p_stat_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out) {
diff --git a/lib9p/core_include/lib9p/_core_generated.h b/lib9p/core_include/lib9p/_core_generated.h
index 5b9a67d..3f87181 100644
--- a/lib9p/core_include/lib9p/_core_generated.h
+++ b/lib9p/core_include/lib9p/_core_generated.h
@@ -4,11 +4,8 @@
#error Do not include <lib9p/_core_generated.h> directly; include <lib9p/core.h> instead
#endif
-
/* config *********************************************************************/
-#include "config.h"
-
#ifndef CONFIG_9P_ENABLE_9P2000
#error config.h must define CONFIG_9P_ENABLE_9P2000
#endif
@@ -673,8 +670,8 @@ typedef uint8_t lib9p_lock_status_t;
#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_uninitialized
/* 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;
+ uint16_t len;
+ [[gnu::nonstring]] const char *utf8;
};
/* size = 13 ; max_iov = 1 ; max_copy = 13 */
@@ -718,18 +715,18 @@ struct 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;
- uint32_t count;
- [[gnu::nonstring]] char *data;
+ lib9p_tag_t tag;
+ uint32_t count;
+ const void *data;
};
/* 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;
+ lib9p_tag_t tag;
+ lib9p_fid_t fid;
+ uint64_t offset;
+ uint32_t count;
+ const void *data;
};
/* size = 11 ; max_iov = 1 ; max_copy = 11 */
@@ -876,9 +873,9 @@ struct 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;
- uint32_t count;
- [[gnu::nonstring]] char *data;
+ lib9p_tag_t tag;
+ uint32_t count;
+ const void *data;
};
/* size = 15 ; max_iov = 1 ; max_copy = 15 */
@@ -929,9 +926,9 @@ struct lib9p_msg_Rsession {
/* 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_Rsread {
- lib9p_tag_t tag;
- uint32_t count;
- [[gnu::nonstring]] char *data;
+ lib9p_tag_t tag;
+ uint32_t count;
+ const void *data;
};
/* size = 11 ; max_iov = 1 ; max_copy = 11 */
@@ -1294,12 +1291,12 @@ struct 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;
+ lib9p_tag_t tag;
+ uint32_t fid;
+ uint16_t nwname;
+ struct lib9p_s *wname;
+ uint32_t count;
+ const void *data;
};
#endif /* CONFIG_9P_ENABLE_9P2000_e */
@@ -1376,12 +1373,12 @@ struct lib9p_msg_Twstat {
struct lib9p_Tmsg_send_buf {
size_t iov_cnt;
- struct iovec iov[LIB9P_TMSG_MAX_IOV];
+ struct wr_iovec iov[LIB9P_TMSG_MAX_IOV];
uint8_t copied[LIB9P_TMSG_MAX_COPY];
};
struct lib9p_Rmsg_send_buf {
size_t iov_cnt;
- struct iovec iov[LIB9P_RMSG_MAX_IOV];
+ struct wr_iovec iov[LIB9P_RMSG_MAX_IOV];
uint8_t copied[LIB9P_RMSG_MAX_COPY];
};
diff --git a/lib9p/core_include/lib9p/core.h b/lib9p/core_include/lib9p/core.h
index 4941220..84ecd0f 100644
--- a/lib9p/core_include/lib9p/core.h
+++ b/lib9p/core_include/lib9p/core.h
@@ -7,21 +7,17 @@
#ifndef _LIB9P_CORE_H_
#define _LIB9P_CORE_H_
-#include <stdint.h> /* for uint{n}_t */
-#include <string.h> /* for memset() */
-#include <sys/types.h> /* for ssize_t */
+#include <stdint.h> /* for uint{n}_t */
+#include <string.h> /* for memset() */
-#include <libhw/generic/io.h> /* for struct iovec */
+#include <libhw/generic/io.h> /* for struct wr_iovec */
#include <libmisc/assert.h>
#include <libmisc/fmt.h>
#define CONFIG_9P_ENABLE_uninitialized 1
-#include <lib9p/_core_generated.h>
+#include "config.h"
-#ifndef CONFIG_9P_MAX_ERR_SIZE
- #error config.h must define CONFIG_9P_MAX_ERR_SIZE
-#endif
-static_assert(CONFIG_9P_MAX_ERR_SIZE <= UINT16_MAX);
+#include <lib9p/_core_generated.h> /* _after_ other includes, including config.h */
/* constants ******************************************************************/
@@ -35,8 +31,8 @@ enum {
const char *lib9p_version_str(enum lib9p_version);
const char *lib9p_msgtype_str(enum lib9p_version, enum lib9p_msg_type);
-struct lib9p_s lib9p_str(char *s);
-struct lib9p_s lib9p_strn(char *s, size_t maxlen);
+struct lib9p_s lib9p_str(const char *s);
+struct lib9p_s lib9p_strn(const char *s, size_t maxlen);
struct lib9p_s lib9p_str_slice(struct lib9p_s s, uint16_t beg, uint16_t end);
#define lib9p_str_sliceleft(s, beg) lib9p_str_slice(s, beg, (s).len)
bool lib9p_str_eq(struct lib9p_s a, struct lib9p_s b);
@@ -47,40 +43,8 @@ struct lib9p_ctx {
/* negotiated */
enum lib9p_version version;
uint32_t max_msg_size;
-
- /* state */
-#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];
};
-void lib9p_ctx_clear_error(struct lib9p_ctx *ctx);
-
-bool lib9p_ctx_has_error(struct lib9p_ctx *ctx);
-
-#if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L
- #define _lib9p_set_err_num(ctx, linux_errno) do { (ctx)->err_num = linux_errno; } while (0)
-#else
- #define _lib9p_set_err_num(ctx, linux_errno) do { } while (0)
-#endif
-
-/** Write a <libmisc/fmt.h>-style error into ctx, return -1. */
-#define lib9p_error(ctx, linux_errno, ...) ({ \
- if (!lib9p_ctx_has_error(ctx)) { \
- _lib9p_set_err_num(ctx, linux_errno); \
- struct fmt_buf _w = { \
- .dat = (ctx)->err_msg, \
- .cap = sizeof((ctx)->err_msg), \
- }; \
- lo_interface fmt_dest w = lo_box_fmt_buf_as_fmt_dest(&_w); \
- fmt_print(w, __VA_ARGS__); \
- if (_w.len < _w.cap) \
- memset(_w.dat + _w.len, 0, _w.cap - _w.len); \
- } \
- -1; \
-})
-
/* misc utilities *************************************************************/
uint32_t lib9p_version_min_Rerror_size(enum lib9p_version);
@@ -98,23 +62,19 @@ void fmt_print_lib9p_msg(lo_interface fmt_dest w, struct lib9p_ctx *ctx, enum li
* number may be larger than net_bytes due to (1) struct padding, (2)
* array pointers.
*
- * Emits an error (return -1, set ctx->err_num and ctx->err_msg) if
- * either the message type is unknown, or if net_bytes is too short
- * for that message type, or if an invalid string (invalid UTF-8,
- * contains a nul-byte) is encountered.
- *
+ * @param ctx : negotiated protocol parameters
* @param net_bytes : the complete request, starting with the "size[4]"
*
- * @return required size, or -1 on error
+ * @return required size, or an error
*
- * @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
+ * @errno E_POSIX_EOPNOTSUPP: message is an R-message
+ * @errno E_POSIX_EOPNOTSUPP: message has unknown type
+ * @errno E_POSIX_EBADMSG: message is wrong size for content
+ * @errno E_POSIX_EILSEQ: message contains invalid UTF-8, or the UTF-8 contains a nul-byte
+ * @errno E_POSIX_EBADMSG: message contains a bitfield with unknown bits
+ * @errno E_POSIX_EMSGSIZE: would-be return value overflows SSIZE_MAX
*/
-ssize_t lib9p_Tmsg_validate(struct lib9p_ctx *ctx, uint8_t *net_bytes);
+size_t_or_error lib9p_Tmsg_validate(struct lib9p_ctx *ctx, uint8_t *net_bytes);
/**
* Unmarshal the 9P message `net_bytes` into the C struct `ret_body`.
@@ -140,27 +100,27 @@ void lib9p_Tmsg_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes,
* marshal bitfield bits that aren't in ctx->version; it applies a
* version-specific mask to bitfields.
*
- * @param ctx : negotiated protocol parameters, where to record errors
+ * @param ctx : negotiated protocol parameters
* @param typ : the message type
- * @param msg : the message to encode
+ * @param msg : the message to encode (`struct lib9p_msg_XXXX` according to `typ`)
*
- * @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)
+ * @return ret : the buffer to encode to
+ * @return error
*
- * @errno L_ERANGE: reply does not fit in ctx->max_msg_size
+ * @errno E_POSIX_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);
+error lib9p_Tmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body,
+ struct lib9p_Tmsg_send_buf *ret);
/* main R-message functions ***************************************************/
/** Same as above, but for R-messages instead of T-messages. */
-ssize_t lib9p_Rmsg_validate(struct lib9p_ctx *ctx, uint8_t *net_bytes);
+size_t_or_error lib9p_Rmsg_validate(struct lib9p_ctx *ctx, uint8_t *net_bytes);
void lib9p_Rmsg_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes,
enum lib9p_msg_type *ret_typ, void *ret_body);
-bool lib9p_Rmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body,
- struct lib9p_Rmsg_send_buf *ret);
+error lib9p_Rmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body,
+ struct lib9p_Rmsg_send_buf *ret);
/* `struct lib9p_stat` helpers ************************************************/
@@ -172,16 +132,16 @@ void fmt_print_lib9p_stat(lo_interface fmt_dest w, struct lib9p_ctx *ctx, struct
/**
* Validate a message's `stat` structure.
*
- * @param ctx : negotiated protocol parameters, where to record errors
+ * @param ctx : negotiated protocol parameters
* @param net_bytes : network-encoded stat structure
* @param net_size : the number of net_bytes that may be read
*
* @return ret_net_size : number of bytes consumed; <=net_size
* @return ret_host_size : number of bytes that lib9p_stat_unmarshal would take
- * @return whether there was an error
+ * @return error
*/
-bool lib9p_stat_validate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes,
- uint32_t *ret_net_size, size_t *ret_host_size);
+error lib9p_stat_validate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes,
+ uint32_t *ret_net_size, size_t *ret_host_size);
/**
* Unmarshal the 9P `net_bytes` into the C struct `ret_obj`.
@@ -206,14 +166,12 @@ void lib9p_stat_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes,
* marshal bitfield bits that aren't in ctx->version; it applies a
* version-specific mask to bitfields.
*
- * @param ctx : negotiated protocol parameters, where to record errors
+ * @param ctx : negotiated protocol parameters
* @param max_net_size : the maximum network-encoded size to allow
* @param obj : the message to encode
*
* @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 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);
diff --git a/lib9p/core_tables.h b/lib9p/core_tables.h
index e3dc8f4..94cdbe1 100644
--- a/lib9p/core_tables.h
+++ b/lib9p/core_tables.h
@@ -27,7 +27,7 @@ struct _lib9p_msg_tentry {
_print_fn_t print;
};
-typedef ssize_t (*_validate_fn_t)(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes);
+typedef size_t_or_error (*_validate_fn_t)(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes);
typedef void (*_unmarshal_fn_t)(struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out);
struct _lib9p_recv_tentry {
_validate_fn_t validate;
@@ -36,11 +36,11 @@ struct _lib9p_recv_tentry {
struct _marshal_ret {
size_t net_iov_cnt;
- struct iovec *net_iov;
+ struct wr_iovec *net_iov;
size_t net_copied_size;
uint8_t *net_copied;
};
-typedef bool (*_marshal_fn_t)(struct lib9p_ctx *ctx, void *host_val, struct _marshal_ret *ret);
+typedef error (*_marshal_fn_t)(struct lib9p_ctx *ctx, void *host_val, struct _marshal_ret *ret);
struct _lib9p_send_tentry {
_marshal_fn_t marshal;
};
@@ -54,7 +54,7 @@ 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);
+size_t_or_error _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
diff --git a/lib9p/core_utf8.h b/lib9p/core_utf8.h
deleted file mode 100644
index 2c451e0..0000000
--- a/lib9p/core_utf8.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* 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_CORE_UTF8_H_
-#define _LIB9P_CORE_UTF8_H_
-
-#include <stddef.h> /* for size_t */
-#include <stdint.h> /* for uint{n}_t */
-
-static inline bool _is_valid_utf8(uint8_t *str, size_t len, bool forbid_nul) {
- uint32_t ch;
- uint8_t chlen;
- for (size_t pos = 0; pos < len;) {
- if ((str[pos] & 0b10000000) == 0b00000000) { ch = str[pos] & 0b01111111; chlen = 1; }
- else if ((str[pos] & 0b11100000) == 0b11000000) { ch = str[pos] & 0b00011111; chlen = 2; }
- else if ((str[pos] & 0b11110000) == 0b11100000) { ch = str[pos] & 0b00001111; chlen = 3; }
- else if ((str[pos] & 0b11111000) == 0b11110000) { ch = str[pos] & 0b00000111; chlen = 4; }
- else return false;
- if ((ch == 0 && (chlen != 1 || forbid_nul)) || pos + chlen > len) return false;
- for (uint8_t i = 1; i < chlen; i++) {
- if ((str[pos+i] & 0b11000000) != 0b10000000) return false;
- ch = (ch << 6) | (str[pos+i] & 0b00111111);
- }
- if (ch > 0x10FFFF) return false;
- pos += chlen;
- }
- return true;
-}
-
-#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_CORE_UTF8_H_ */
diff --git a/lib9p/idl/1992-9P0.9p.wip b/lib9p/idl/1992-9P0.9p.wip
index c9432c9..de902dd 100644
--- a/lib9p/idl/1992-9P0.9p.wip
+++ b/lib9p/idl/1992-9P0.9p.wip
@@ -137,5 +137,5 @@ msg Twstat = "typ[1,val=78] tag[tag] fid[fid] stat[stat]"
msg Rwstat = "typ[1,val=79] tag[tag] fid[fid]"
msg Tclwalk = "typ[1,val=80] tag[tag] fid[fid] newfid[fid] name[name]"
msg Rclwalk = "typ[1,val=81] tag[tag] fid[fid] qid[qid]"
-msg Tauth = "typ[1,val=82] tag[tag] fid[fid] uid[name] chal[encrypted_auth_challenge]" # chal is an encrypted
+msg Tauth = "typ[1,val=82] tag[tag] fid[fid] uid[name] chal[encrypted_auth_challenge]"
msg Rauth = "typ[1,val=83] tag[tag] fid[fid] chal[encrypted_auth_response]"
diff --git a/lib9p/idl/2010-9P2000.L.9p.gen b/lib9p/idl/2010-9P2000.L.9p.gen
index cb32585..f0bdb6b 100755
--- a/lib9p/idl/2010-9P2000.L.9p.gen
+++ b/lib9p/idl/2010-9P2000.L.9p.gen
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# lib9p/idl/2010-9P2000.L.9p.gen - Generate definitions of 9P2000.L messages
import sys
diff --git a/lib9p/srv.c b/lib9p/srv.c
index 18165e0..3e4de91 100644
--- a/lib9p/srv.c
+++ b/lib9p/srv.c
@@ -4,23 +4,16 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-#include <inttypes.h> /* for PRI* */
-#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
#include <libcr/coroutine.h>
-#include <libcr_ipc/chan.h>
#include <libcr_ipc/mutex.h>
+#include <libhw/generic/net.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
#include <libmisc/log.h>
@@ -28,6 +21,8 @@
#define IMPLEMENTATION_FOR_LIB9P_SRV_H YES
#include <lib9p/srv.h>
+#include "srv_errno.h"
+
/* config *********************************************************************/
#include "config.h"
@@ -39,7 +34,7 @@
#error config.h must define CONFIG_9P_SRV_MAX_HOSTMSG_SIZE
#endif
static_assert(CONFIG_9P_SRV_MAX_MSG_SIZE <= CONFIG_9P_SRV_MAX_HOSTMSG_SIZE);
-static_assert(CONFIG_9P_SRV_MAX_HOSTMSG_SIZE <= SSIZE_MAX);
+static_assert(CONFIG_9P_SRV_MAX_HOSTMSG_SIZE <= SIZE_MAX);
/* context ********************************************************************/
@@ -48,12 +43,6 @@ bool lib9p_srv_flush_requested(struct lib9p_srv_ctx *ctx) {
return cr_chan_can_send(&ctx->flush_ch);
}
-void lib9p_srv_acknowledge_flush(struct lib9p_srv_ctx *ctx) {
- assert(ctx);
- assert(cr_chan_can_send(&ctx->flush_ch));
- ctx->flush_acknowledged = true;
-}
-
#define req_debug(...) \
log_debugln( \
"cid=", cr_getcid(), ": ", \
@@ -62,6 +51,18 @@ void lib9p_srv_acknowledge_flush(struct lib9p_srv_ctx *ctx) {
/* structs ********************************************************************/
+#ifndef NDEBUG
+void lib9p_srv_stat_assert(const struct lib9p_srv_stat *stat) {
+ assert(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) );
+}
+#endif
+
enum srv_filetype {
SRV_FILETYPE_FILE,
SRV_FILETYPE_DIR,
@@ -115,6 +116,7 @@ struct srv_fidinfo {
} auth;
};
};
+DECLARE_ERROR_OR_(struct srv_fidinfo *, srv_fidinfop);
/* contexts **************************************
*
@@ -130,7 +132,7 @@ struct srv_conn {
/* immutable */
struct lib9p_srv *parent_srv;
lo_interface net_stream_conn fd;
- cid_t reader; /* the lib9p_srv_read_cr() coroutine */
+ cid_t reader; /* the lib9p_srv_read() coroutine */
/* mutable */
cr_mutex_t writelock;
};
@@ -145,7 +147,6 @@ struct srv_sess {
enum lib9p_version version;
uint32_t max_msg_size;
/* mutable */
- bool initialized;
bool closing;
struct srv_pathmap paths; /* srv_path_t => `lib9p_srv_file` + metadata */
struct srv_fidmap fids; /* lib9p_fid_t => `lib9p_srv_{fio,dio}` + metadata */
@@ -156,7 +157,7 @@ struct srv_sess {
/* utilities for the above types **********************************************/
-static inline enum srv_filetype srv_qid_filetype(struct lib9p_qid qid) {
+static 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)
@@ -164,7 +165,8 @@ static inline enum srv_filetype srv_qid_filetype(struct lib9p_qid qid) {
return SRV_FILETYPE_FILE;
}
-static inline bool srv_check_perm(struct srv_req *ctx, struct lib9p_srv_stat *stat, uint8_t action) {
+[[maybe_unused]]
+static bool srv_stat_check_perm(struct srv_req *ctx, struct lib9p_srv_stat *stat, uint8_t action) {
assert(ctx);
assert(stat);
assert(action);
@@ -176,20 +178,33 @@ static inline bool srv_check_perm(struct srv_req *ctx, struct lib9p_srv_stat *st
}
[[maybe_unused]]
+static ok_or_error srv_file_check_perm(struct srv_req *ctx, lo_interface lib9p_srv_file file, uint8_t action) {
+ assert(ctx);
+ assert(!LO_IS_NULL(file));
+ assert(action);
+
+ struct lib9p_srv_stat stat;
+ error err = LO_CALL(file, stat, ctx, &stat);
+ if (!ERROR_IS_NULL(err))
+ return ERROR_NEW_ERR(ok, err);
+ lib9p_srv_stat_assert(&stat);
+ return ERROR_NEW_VAL(ok, srv_stat_check_perm(ctx, &stat, action));
+}
+
+[[maybe_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;
+ struct lib9p_srv_userid *ret = (void *)heap_alloc(sizeof(struct lib9p_srv_userid) + name.len, char);
+ void *end_dat = (void *)&ret[1];
+ memcpy(end_dat, name.utf8, name.len);
#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->name.utf8 = end_dat;
ret->refcount = 1;
return ret;
}
@@ -219,9 +234,10 @@ static struct lib9p_srv_userid *srv_userid_incref(struct lib9p_srv_userid *useri
*
* 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) {
+[[maybe_unused]]
+static 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));
@@ -253,7 +269,7 @@ static inline struct srv_pathinfo *srv_path_save(struct srv_req *ctx,
* 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) {
+static void srv_path_decref(struct srv_req *ctx, srv_path_t path) {
assert(ctx);
for (;;) {
@@ -271,11 +287,13 @@ static inline void srv_path_decref(struct srv_req *ctx, srv_path_t path) {
}
}
-static inline void srv_fid_del(struct srv_req *ctx, lib9p_fid_t fid, struct srv_fidinfo *fidinfo, bool remove) {
+static error srv_fid_del(struct srv_req *ctx, lib9p_fid_t fid, struct srv_fidinfo *fidinfo, bool remove) {
assert(ctx);
assert(!ctx->user);
assert(fidinfo);
+ error err = {};
+
if (fidinfo->flags & FIDFLAG_RCLOSE)
remove = true;
ctx->user = srv_userid_incref(fidinfo->user);
@@ -284,7 +302,7 @@ static inline void srv_fid_del(struct srv_req *ctx, lib9p_fid_t fid, struct srv_
assert(pathinfo);
if (remove)
- LO_CALL(pathinfo->file, remove, ctx);
+ err = LO_CALL(pathinfo->file, remove, ctx);
if (fidinfo->flags & FIDFLAG_OPEN) {
switch (fidinfo->type) {
@@ -305,6 +323,8 @@ static inline void srv_fid_del(struct srv_req *ctx, lib9p_fid_t fid, struct srv_
map_del(&ctx->parent_sess->fids, fid);
ctx->user = srv_userid_decref(ctx->user);
+
+ return err;
}
/**
@@ -312,7 +332,8 @@ static inline void srv_fid_del(struct srv_req *ctx, lib9p_fid_t fid, struct srv_
* 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) {
+[[maybe_unused]]
+static srv_fidinfop_or_error 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);
@@ -333,9 +354,7 @@ static inline struct srv_fidinfo *srv_fid_store(struct srv_req *ctx, lib9p_fid_t
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;
+ return ERROR_NEW_ERR(srv_fidinfop, error_new(E_POSIX_EBADF, "FID already in use"));
}
}
struct srv_fidinfo *fidinfo = map_store(&ctx->parent_sess->fids, fid, (struct srv_fidinfo){
@@ -344,7 +363,7 @@ static inline struct srv_fidinfo *srv_fid_store(struct srv_req *ctx, lib9p_fid_t
.user = srv_userid_incref(ctx->user),
});
assert(fidinfo);
- return fidinfo;
+ return ERROR_NEW_VAL(srv_fidinfop, fidinfo);
}
/* base utilities *************************************************************/
@@ -358,29 +377,40 @@ static void srv_msglog(struct srv_req *req, enum lib9p_msg_type typ, void *hostm
log_infoln(typ % 2 ? "< " : "> ", (lib9p_msg, &req->basectx, typ, hostmsg));
}
-static ssize_t srv_write_Rmsg(struct srv_req *req, struct lib9p_Rmsg_send_buf *resp) {
- ssize_t r;
+#define srv_nonrespond_error log_errorln
+
+static error srv_write_Rmsg(struct srv_req *req, enum lib9p_msg_type typ, void *host) {
+ assert(req);
+ assert(typ % 2 == 1);
+ assert(host);
+
+ struct lib9p_Rmsg_send_buf net;
+ error err = lib9p_Rmsg_marshal(&req->basectx,
+ typ, host,
+ &net);
+ if (!ERROR_IS_NULL(err))
+ return err;
+
+ srv_msglog(req, typ, host);
+
cr_mutex_lock(&req->parent_sess->parent_conn->writelock);
- r = io_writev(req->parent_sess->parent_conn->fd, resp->iov, resp->iov_cnt);
+ size_t_and_error r = io_writev(req->parent_sess->parent_conn->fd, net.iov, net.iov_cnt);
cr_mutex_unlock(&req->parent_sess->parent_conn->writelock);
- return r;
+ if (!ERROR_IS_NULL(r.err)) {
+ srv_nonrespond_error("write: (", r.size_t, ", ", (error, r.err), ")");
+ error_cleanup(&r.err);
+ }
+ return ERROR_NULL;
}
-#define srv_nonrespond_error log_errorln
-
-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->basectx.err_msg[0]);
+static void srv_respond_error(struct srv_req *req, error err) {
+ assert(!ERROR_IS_NULL(err));
- ssize_t r;
struct lib9p_msg_Rerror host = {
.tag = req->tag,
- .errstr = lib9p_strn(req->basectx.err_msg,
- CONFIG_9P_MAX_ERR_SIZE),
+ .errstr = lib9p_str(error_msg(err)),
#if CONFIG_9P_ENABLE_9P2000_u
- .errnum = req->basectx.err_num,
+ .errnum = libmisc_to_linuxgeneric_errno(err.num),
#endif
};
@@ -389,39 +419,36 @@ static void srv_respond_error(struct srv_req *req) {
uint32_t overhead = lib9p_version_min_Rerror_size(sess->version);
/* Truncate the error-string if necessary to avoid needing to
- * return LIB9P_ERRNO_L_ERANGE. */
+ * return E_POSIX_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->basectx,
- LIB9P_TYP_Rerror, &host,
- &net);
+ error marshal_err = srv_write_Rmsg(req, LIB9P_TYP_Rerror, &host);
+ assert(ERROR_IS_NULL(marshal_err));
- srv_msglog(req, LIB9P_TYP_Rerror, &host);
- r = srv_write_Rmsg(req, &net);
- if (r < 0)
- srv_nonrespond_error("write: ", net_strerror(-r));
+ error_cleanup(&err);
}
/* read coroutine *************************************************************/
-static inline bool srv_read_exactly(lo_interface net_stream_conn fd, uint8_t *buf, size_t goal, size_t *done) {
+/** Return whether to `break`. */
+static 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) {
- srv_nonrespond_error("read: ", net_strerror(-r));
- return true;
- } else if (r == 0) {
- if (*done != 0)
- srv_nonrespond_error("read: unexpected EOF");
+ size_t_or_error r = io_read(fd, &buf[*done], goal - *done);
+ if (r.is_err) {
+ if (r.err.num == E_EOF) {
+ if (*done != 0)
+ srv_nonrespond_error("read: unexpected EOF");
+ } else {
+ srv_nonrespond_error("read: ", (error, r.err));
+ }
+ error_cleanup(&r.err);
return true;
}
- *done += r;
+ *done += r.size_t;
}
return false;
}
@@ -434,112 +461,126 @@ void lib9p_srv_accept_and_read_loop(struct lib9p_srv *srv, lo_interface net_stre
srv->readers++;
for (;;) {
- lo_interface net_stream_conn conn = LO_CALL(listener, accept);
- if (LO_IS_NULL(conn)) {
- srv_nonrespond_error("accept: error");
+ net_stream_conn_or_error r = LO_CALL(listener, accept);
+ if (r.is_err) {
+ srv_nonrespond_error("accept: ", (error, r.err));
+ error_cleanup(&r.err);
srv->readers--;
if (srv->readers == 0)
while (srv->writers > 0)
- cr_rpc_send_req(&srv->_reqch, NULL);
+ cr_rpc_send_req(&srv->reqch, NULL);
return;
}
- lib9p_srv_read(srv, conn);
+ lib9p_srv_read(srv, r.net_stream_conn);
}
}
+static void lib9p_srv_worker_Tversion(struct srv_req *ctx);
+
void lib9p_srv_read(struct lib9p_srv *srv, lo_interface net_stream_conn _conn) {
assert(srv);
assert(srv->rootdir);
assert(!LO_IS_NULL(_conn));
- struct srv_conn conn = {
+ struct srv_conn _conn_ = {
.parent_srv = srv,
.fd = _conn,
.reader = cr_getcid(),
};
- struct srv_sess sess = {
- .parent_conn = &conn,
+ struct srv_conn *conn = &_conn_;
+ struct srv_sess _sess_ = {
+ .parent_conn = conn,
.version = LIB9P_VER_uninitialized,
.max_msg_size = CONFIG_9P_SRV_MAX_MSG_SIZE,
- .initialized = false,
};
+ struct srv_sess *sess = &_sess_;
+ struct srv_req _req_;
+ struct srv_req *req = &_req_;
+
for (;;) {
/* Read the message. */
size_t done = 0;
uint8_t buf[7];
- if (srv_read_exactly(conn.fd, buf, 4, &done))
+ if (srv_read_exactly(conn->fd, buf, 4, &done))
break;
size_t goal = uint32le_decode(buf);
if (goal < 7) {
srv_nonrespond_error("T-message is impossibly small");
break;
}
- if (srv_read_exactly(conn.fd, buf, 7, &done))
+ if (srv_read_exactly(conn->fd, buf, 7, &done))
break;
- struct srv_req req = {
+ *req = (struct srv_req){
.basectx = {
- .version = sess.version,
- .max_msg_size = sess.max_msg_size,
+ .version = sess->version,
+ .max_msg_size = sess->max_msg_size,
},
- .parent_sess = &sess,
+ .parent_sess = sess,
.tag = uint16le_decode(&buf[5]),
.net_bytes = buf,
};
- if (goal > sess.max_msg_size) {
- lib9p_error(&req.basectx, LIB9P_ERRNO_L_EMSGSIZE,
- "T-message larger than ", sess.initialized ? "negotiated" : "server", " limit",
- " (", goal, " > ", sess.max_msg_size, ")");
- srv_respond_error(&req);
+ if (goal > sess->max_msg_size) {
+ srv_respond_error(req, error_new(E_POSIX_EMSGSIZE,
+ "T-message larger than ", sess->version == LIB9P_VER_uninitialized ? "server" : "negotiated", " limit",
+ " (", goal, " > ", sess->max_msg_size, ")"));
continue;
}
- 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);
+ req->net_bytes = heap_alloc(goal, uint8_t);
+ 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)
+ if (req->net_bytes[4] == LIB9P_TYP_Tversion)
/* ...in this coroutine for Tversion, */
- lib9p_srv_worker(&req);
+ lib9p_srv_worker_Tversion(req);
else
/* ...but usually in another coroutine. */
- cr_rpc_send_req(&srv->_reqch, &req);
+ 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;
+
+ /* Cleanup `conn` and `sess->reqs`. */
+ error err = io_close_read(conn->fd);
+ if (!ERROR_IS_NULL(err)) {
+ srv_nonrespond_error("conn close: ", (error, err));
+ error_cleanup(&err);
+ }
+ if (map_len(&sess->reqs)) {
+ sess->closing = true;
cr_pause_and_yield();
- assert(map_len(&sess.reqs) == 0);
- io_close_write(conn.fd);
}
+ assert(map_len(&sess->reqs) == 0);
+ err = io_close_write(conn->fd);
+ if (!ERROR_IS_NULL(err)) {
+ srv_nonrespond_error("conn close: ", (error, err));
+ error_cleanup(&err);
+ }
+ map_free(&sess->reqs);
- assert(map_len(&sess.reqs) == 0);
- map_free(&sess.reqs);
-
- struct srv_req pseudoreq = {
+ /* Cleanup `sess->fids`. */
+ *req = (struct srv_req){
.basectx = {
- .version = sess.version,
- .max_msg_size = sess.max_msg_size,
+ .version = sess->version,
+ .max_msg_size = sess->max_msg_size,
},
- .parent_sess = &sess,
+ .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_error("clunk: ", (strn, pseudoreq.basectx.err_msg, CONFIG_9P_MAX_ERR_SIZE));
- lib9p_ctx_clear_error(&pseudoreq.basectx);
+ MAP_FOREACH(&sess->fids, fid, fidinfo) {
+ err = srv_fid_del(req, fid, fidinfo, false);
+ if (!ERROR_IS_NULL(err)) {
+ srv_nonrespond_error("clunk: ", (error, err));
+ error_cleanup(&err);
}
}
- map_free(&sess.fids);
+ assert(map_len(&sess->fids) == 0);
+ map_free(&sess->fids);
- assert(map_len(&sess.paths) == 0);
- map_free(&sess.paths);
+ /* Cleanup `sess->paths`. */
+ assert(map_len(&sess->paths) == 0);
+ map_free(&sess->paths);
}
/* write coroutine ************************************************************/
@@ -555,7 +596,7 @@ void lib9p_srv_worker_loop(struct lib9p_srv *srv) {
for (;;) {
/* Receive the request from the reader coroutine. ************/
- rpc_handle = cr_rpc_recv_req(&srv->_reqch);
+ rpc_handle = cr_rpc_recv_req(&srv->reqch);
if (!rpc_handle.req) {
srv->writers--;
cr_rpc_send_resp(rpc_handle, 0);
@@ -604,16 +645,16 @@ _HANDLER_PROTO(swrite);
#endif
void lib9p_srv_worker(struct srv_req *ctx) {
- uint8_t *host_req = NULL;
+ [[gnu::cleanup(heap_cleanup)]] void *host_req = NULL;
/* Unmarshal it. *****************************************************/
- ssize_t host_size = lib9p_Tmsg_validate(&ctx->basectx, ctx->net_bytes);
- if (host_size < 0) {
- srv_respond_error(ctx);
+ size_t_or_error r = lib9p_Tmsg_validate(&ctx->basectx, ctx->net_bytes);
+ if (r.is_err) {
+ srv_respond_error(ctx, r.err);
goto release;
}
- host_req = calloc(1, host_size);
- assert(host_req);
+ size_t host_size = r.size_t;
+ host_req = heap_alloc(host_size, char);
enum lib9p_msg_type typ;
lib9p_Tmsg_unmarshal(&ctx->basectx, ctx->net_bytes,
&typ, host_req);
@@ -622,7 +663,6 @@ void lib9p_srv_worker(struct srv_req *ctx) {
/* Handle it. ********************************************************/
#define CASE(typ) case LIB9P_TYP_##typ: handle_##typ(ctx, (void *)host_req); break
LM_PARTIAL_SWITCH (typ) {
- CASE(Tversion);
#if _LIB9P_ENABLE_stat
CASE(Tauth);
CASE(Tattach);
@@ -662,42 +702,75 @@ void lib9p_srv_worker(struct srv_req *ctx) {
}
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);
}
-static inline void _srv_respond(struct srv_req *ctx, enum lib9p_msg_type resp_typ, void *host_resp) {
+static void lib9p_srv_worker_Tversion(struct srv_req *ctx) {
+ [[gnu::cleanup(heap_cleanup)]] void *host_req = NULL;
+
+ /* Unmarshal it. *****************************************************/
+ size_t_or_error r = lib9p_Tmsg_validate(&ctx->basectx, ctx->net_bytes);
+ if (r.is_err) {
+ srv_respond_error(ctx, r.err);
+ goto release;
+ }
+ size_t host_size = r.size_t;
+ host_req = heap_alloc(host_size, char);
+ enum lib9p_msg_type typ;
+ lib9p_Tmsg_unmarshal(&ctx->basectx, ctx->net_bytes,
+ &typ, host_req);
+ srv_msglog(ctx, typ, host_req);
+
+ /* Handle it. ********************************************************/
+ handle_Tversion(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);
+ free(ctx->net_bytes);
+}
+
+static void _srv_respond(struct srv_req *ctx, enum lib9p_msg_type resp_typ, void *host_resp, error err) {
assert(!ctx->responded);
- if (lib9p_ctx_has_error(&ctx->basectx)) {
- error:
- srv_respond_error(ctx);
- } else if (ctx->flush_acknowledged) {
- /* do nothing */
+ if (!ERROR_IS_NULL(err)) {
+ if (err.num == E_POSIX_ECANCELED && lib9p_srv_flush_requested(ctx)) {
+ error_cleanup(&err);
+ } else {
+ error:
+ srv_respond_error(ctx, err);
+ }
} else {
assert(host_resp);
- struct lib9p_Rmsg_send_buf net_resp;
- if (lib9p_Rmsg_marshal(&ctx->basectx,
- resp_typ, host_resp,
- &net_resp))
+ err = srv_write_Rmsg(ctx, resp_typ, host_resp);
+ if (!ERROR_IS_NULL(err))
goto error;
- srv_msglog(ctx, resp_typ, host_resp);
- srv_write_Rmsg(ctx, &net_resp);
}
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); \
+#define srv_respond(CTX, TYP, HOST_RESP, ERR) do { \
+ struct lib9p_msg_R##TYP *_host_resp = HOST_RESP; \
+ _srv_respond(CTX, LIB9P_TYP_R##TYP, _host_resp, ERR); \
} while (0)
/* handle_T* ******************************************************************/
-#define srv_handler_common(ctx, typ, req) \
+#define srv_handler_common_no_err(ctx, typ, req) \
assert(ctx); \
assert(req); \
struct lib9p_msg_T##typ *_typecheck_req [[maybe_unused]] = req; \
struct lib9p_msg_R##typ resp = { .tag = ctx->tag }
+#define srv_handler_common(ctx, typ, req) \
+ srv_handler_common_no_err(ctx, typ, req); \
+ error err = {}
static void handle_Tversion(struct srv_req *ctx,
struct lib9p_msg_Tversion *req) {
@@ -737,13 +810,12 @@ static void handle_Tversion(struct srv_req *ctx,
uint32_t min_msg_size = _LIB9P_MAX(lib9p_version_min_Rerror_size(ctx->basectx.version),
lib9p_version_min_Rread_size(ctx->basectx.version)+1);
if (req->max_msg_size < min_msg_size) {
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EDOM, "requested max_msg_size is less than minimum for ", lib9p_version_str(version),
- " (", req->max_msg_size, " < ", min_msg_size,")");
+ err = error_new(E_POSIX_EDOM, "requested max_msg_size is less than minimum for ", lib9p_version_str(version),
+ " (", req->max_msg_size, " < ", min_msg_size, ")");
goto tversion_return;
}
- resp.version = lib9p_str((char *)lib9p_version_str(version)); /* cast to discard "const" qualifier */
+ resp.version = lib9p_str(lib9p_version_str(version));
#if CONFIG_9P_ENABLE_9P2000_p9p
if (version == LIB9P_VER_9P2000_p9p)
resp.version = lib9p_str("9P2000");
@@ -756,7 +828,7 @@ static void handle_Tversion(struct srv_req *ctx,
if (map_len(&ctx->parent_sess->reqs)) {
/* Flush all in-progress requests, and wait for them
* to finish. */
- struct cr_select_arg *args = stack_alloc(map_len(&ctx->parent_sess->reqs), struct cr_select_arg);
+ struct cr_select_arg *args = heap_alloc(map_len(&ctx->parent_sess->reqs), struct cr_select_arg);
while (map_len(&ctx->parent_sess->reqs)) {
size_t i = 0;
MAP_FOREACH(&ctx->parent_sess->reqs, tag, reqpp) {
@@ -766,13 +838,14 @@ static void handle_Tversion(struct srv_req *ctx,
assert(i == map_len(&ctx->parent_sess->reqs));
cr_select_v(i, args);
}
+ free(args);
}
/* 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_error("clunk: ", (strn, ctx->basectx.err_msg, CONFIG_9P_MAX_ERR_SIZE));
- lib9p_ctx_clear_error(&ctx->basectx);
+ error fiderr = srv_fid_del(ctx, fid, fidinfo, false);
+ if (!ERROR_IS_NULL(fiderr)) {
+ srv_nonrespond_error("clunk: ", (error, fiderr));
+ error_cleanup(&fiderr);
}
}
@@ -781,7 +854,7 @@ static void handle_Tversion(struct srv_req *ctx,
ctx->parent_sess->max_msg_size = resp.max_msg_size;
tversion_return:
- srv_respond(ctx, version, &resp);
+ srv_respond(ctx, version, &resp, err);
}
#if _LIB9P_ENABLE_stat
@@ -791,23 +864,22 @@ static void handle_Tauth(struct srv_req *ctx,
struct lib9p_srv *srv = ctx->parent_sess->parent_conn->parent_srv;
if (!srv->auth) {
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EOPNOTSUPP, "authentication not required");
+ err = error_new(E_POSIX_EOPNOTSUPP, "authentication not required");
goto tauth_return;
}
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");
+ err = srv->auth(ctx, req->aname);
+ if (!ERROR_IS_NULL(err))
+ goto tauth_return;
- if (lib9p_ctx_has_error(&ctx->basectx))
- ctx->user = srv_userid_decref(ctx->user);
+ err = error_new(E_POSIX_EOPNOTSUPP, "TODO: auth not implemented");
tauth_return:
- srv_respond(ctx, auth, &resp);
+ if (!ERROR_IS_NULL(err) && ctx->user)
+ ctx->user = srv_userid_decref(ctx->user);
+ srv_respond(ctx, auth, &resp, err);
}
static void handle_Tattach(struct srv_req *ctx,
@@ -815,8 +887,7 @@ static void handle_Tattach(struct srv_req *ctx,
srv_handler_common(ctx, attach, req);
if (req->fid == LIB9P_FID_NOFID) {
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EBADF, "cannot assign to NOFID");
+ err = error_new(E_POSIX_EBADF, "cannot assign to NOFID");
goto tattach_return;
}
@@ -824,48 +895,43 @@ static void handle_Tattach(struct srv_req *ctx,
if (srv->auth) {
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");
+ err = error_new(E_POSIX_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");
+ err = error_new(E_POSIX_EACCES, "FID provided as auth-file is not an auth-file");
else if (!lib9p_str_eq(afid->user->name, req->uname))
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EACCES,
- "FID provided as auth-file is for user=", (qmem, afid->user->name.utf8, afid->user->name.len),
- " and cannot be used for user=", (qmem, req->uname.utf8, req->uname.len));
+ err = error_new(E_POSIX_EACCES,
+ "FID provided as auth-file is for user=", (qmem, afid->user->name.utf8, afid->user->name.len),
+ " and cannot be used for user=", (qmem, req->uname.utf8, req->uname.len));
#if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L
else if (afid->user->num != req->unum)
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EACCES,
- "FID provided as auth-file is for user=", afid->user->num,
- " and cannot be used for user=", req->unum);
+ err = error_new(E_POSIX_EACCES,
+ "FID provided as auth-file is for user=", afid->user->num,
+ " and cannot be used for user=", req->unum);
#endif
else if (!lib9p_str_eq(afid->auth.aname, req->aname))
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EACCES,
- "FID provided as auth-file is for tree=", (qmem, afid->auth.aname.utf8, afid->auth.aname.len),
- " and cannot be used for tree=", (qmem, req->aname.utf8, req->aname.len));
+ err = error_new(E_POSIX_EACCES,
+ "FID provided as auth-file is for tree=", (qmem, afid->auth.aname.utf8, afid->auth.aname.len),
+ " and cannot be used for tree=", (qmem, req->aname.utf8, req->aname.len));
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))
+ err = error_new(E_POSIX_EACCES, "FID provided as auth-file has not completed authentication");
+ if (!ERROR_IS_NULL(err))
goto tattach_return;
ctx->user = srv_userid_incref(afid->user);
} else {
if (req->afid != LIB9P_FID_NOFID) {
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EACCES, "FID provided as auth-file, but no auth-file is required");
+ err = error_new(E_POSIX_EACCES, "FID provided as auth-file, but no auth-file is required");
goto tattach_return;
}
ctx->user = srv_userid_new(req->uname, req->unum);
}
/* 1. File object */
- 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))
+ lib9p_srv_file_or_error root_file_r = srv->rootdir(ctx, req->aname);
+ if (root_file_r.is_err) {
+ err = root_file_r.err;
goto tattach_return;
+ }
+ lo_interface lib9p_srv_file root_file = root_file_r.lib9p_srv_file;
struct lib9p_qid root_qid = LO_CALL(root_file, qid);
assert(srv_qid_filetype(root_qid) == SRV_FILETYPE_DIR);
@@ -874,7 +940,9 @@ static void handle_Tattach(struct srv_req *ctx,
struct srv_pathinfo *root_pathinfo = srv_path_save(ctx, root_file, root_qid.path);
/* 3. fidinfo */
- if (!srv_fid_store(ctx, req->fid, root_pathinfo, false)) {
+ srv_fidinfop_or_error fidinfo = srv_fid_store(ctx, req->fid, root_pathinfo, false);
+ if (fidinfo.is_err) {
+ err = fidinfo.err;
srv_path_decref(ctx, root_qid.path);
goto tattach_return;
}
@@ -883,7 +951,7 @@ static void handle_Tattach(struct srv_req *ctx,
tattach_return:
if (ctx->user)
ctx->user = srv_userid_decref(ctx->user);
- srv_respond(ctx, attach, &resp);
+ srv_respond(ctx, attach, &resp, err);
}
static void handle_Tflush(struct srv_req *ctx,
@@ -898,15 +966,17 @@ static void handle_Tflush(struct srv_req *ctx,
CR_SELECT_SEND(&ctx->flush_ch, &res))) {
case 0: /* original request returned */
req_debug("original request (tag=", req->oldtag, ") returned");
- ctx->flush_acknowledged = (res == _LIB9P_SRV_FLUSH_SILENT);
+ if (res == _LIB9P_SRV_FLUSH_SILENT) {
+ ctx->responded = true;
+ return;
+ }
break;
case 1: /* flush itself got flushed */
- req_debug("flush itself flushed");
- ctx->flush_acknowledged = true;
- break;
+ ctx->responded = true;
+ return;
}
}
- srv_respond(ctx, flush, &resp);
+ srv_respond(ctx, flush, &resp, err);
}
static void handle_Twalk(struct srv_req *ctx,
@@ -914,20 +984,17 @@ static void handle_Twalk(struct srv_req *ctx,
srv_handler_common(ctx, walk, req);
if (req->newfid == LIB9P_FID_NOFID) {
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EBADF, "cannot assign to NOFID");
+ err = error_new(E_POSIX_EBADF, "cannot assign to NOFID");
goto twalk_return;
}
struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid);
if (!fidinfo) {
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EBADF, "bad file number ", req->fid);
+ err = error_new(E_POSIX_EBADF, "bad file number ", 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");
+ err = error_new(E_POSIX_EALREADY, "cannot walk on FID open for I/O");
goto twalk_return;
}
ctx->user = srv_userid_incref(fidinfo->user);
@@ -936,12 +1003,10 @@ static void handle_Twalk(struct srv_req *ctx,
assert(pathinfo);
pathinfo->gc_refcount++;
- struct lib9p_qid _resp_qid[16];
- resp.wqid = _resp_qid;
+ resp.wqid = heap_alloc(req->nwname, struct lib9p_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");
+ err = error_new(E_POSIX_ENOTDIR, "not a directory");
break;
}
@@ -951,22 +1016,22 @@ static void handle_Twalk(struct srv_req *ctx,
assert(new_pathinfo);
new_pathinfo->gc_refcount++;
} else {
- 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))
+ lib9p_srv_file_or_error member_file = LO_CALL(pathinfo->file, dwalk, ctx, req->wname[resp.nwqid]);
+ if (member_file.is_err) {
+ err = member_file.err;
break;
- new_pathinfo = srv_path_save(ctx, member_file, LO_CALL(pathinfo->file, qid).path);
+ }
+ new_pathinfo = srv_path_save(ctx, member_file.lib9p_srv_file, LO_CALL(pathinfo->file, qid).path);
assert(new_pathinfo);
}
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))
+ ok_or_error have_perm = srv_file_check_perm(ctx, new_pathinfo->file, 0b001);
+ if (have_perm.is_err) {
+ err = have_perm.err;
break;
- 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");
+ } else if (!have_perm.ok) {
+ err = error_new(E_POSIX_EACCES, "you do not have execute permission on that directory");
srv_path_decref(ctx, LO_CALL(new_pathinfo->file, qid).path);
break;
}
@@ -978,18 +1043,23 @@ static void handle_Twalk(struct srv_req *ctx,
pathinfo = new_pathinfo;
}
if (resp.nwqid == req->nwname) {
- if (!srv_fid_store(ctx, req->newfid, pathinfo, req->newfid == req->fid))
+ srv_fidinfop_or_error fidinfo = srv_fid_store(ctx, req->newfid, pathinfo, req->newfid == req->fid);
+ if (fidinfo.is_err) {
+ err = fidinfo.err;
srv_path_decref(ctx, LO_CALL(pathinfo->file, qid).path);
+ }
} else {
- assert(lib9p_ctx_has_error(&ctx->basectx));
+ assert(!ERROR_IS_NULL(err));
srv_path_decref(ctx, LO_CALL(pathinfo->file, qid).path);
if (resp.nwqid > 0)
- lib9p_ctx_clear_error(&ctx->basectx);
+ error_cleanup(&err);
}
twalk_return:
if (ctx->user)
ctx->user = srv_userid_decref(ctx->user);
- srv_respond(ctx, walk, &resp);
+ srv_respond(ctx, walk, &resp, err);
+ if (resp.wqid)
+ free(resp.wqid);
}
static void handle_Topen(struct srv_req *ctx,
@@ -999,21 +1069,18 @@ static void handle_Topen(struct srv_req *ctx,
/* Check that the FID is valid for this. */
struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid);
if (!fidinfo) {
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EBADF, "bad file number ", req->fid);
+ err = error_new(E_POSIX_EBADF, "bad file number ", req->fid);
goto topen_return;
}
if (fidinfo->flags & FIDFLAG_OPEN) {
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EALREADY, "FID is already open");
+ err = error_new(E_POSIX_EALREADY, "FID is already open");
goto topen_return;
}
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->basectx,
- LIB9P_ERRNO_L_EISDIR, "directories cannot be written, executed, truncated, or removed-on-close");
+ err = error_new(E_POSIX_EISDIR, "directories cannot be written, executed, truncated, or removed-on-close");
goto topen_return;
}
}
@@ -1029,24 +1096,23 @@ static void handle_Topen(struct srv_req *ctx,
if (reqmode & LIB9P_O_RCLOSE) {
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))
+ ok_or_error have_perm = srv_file_check_perm(ctx, parent->file, 0b010);
+ if (have_perm.is_err) {
+ err = have_perm.err;
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");
+ } else if (!have_perm.ok) {
+ err = error_new(E_POSIX_EACCES, "permission denied to remove-on-close");
goto topen_return;
}
fidflags |= FIDFLAG_RCLOSE;
}
- struct lib9p_srv_stat stat = LO_CALL(pathinfo->file, stat, ctx);
- if (lib9p_ctx_has_error(&ctx->basectx))
+ struct lib9p_srv_stat stat;
+ err = LO_CALL(pathinfo->file, stat, ctx, &stat);
+ if (!ERROR_IS_NULL(err))
goto topen_return;
- lib9p_srv_stat_assert(stat);
+ 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");
+ err = error_new(E_POSIX_EEXIST, "exclusive file is already opened");
goto topen_return;
}
if (stat.mode & LIB9P_DM_APPEND) {
@@ -1073,9 +1139,8 @@ static void handle_Topen(struct srv_req *ctx,
rd = true;
break;
}
- if (!srv_check_perm(ctx, &stat, perm_bits)) {
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EACCES, "permission denied");
+ if (!srv_stat_check_perm(ctx, &stat, perm_bits)) {
+ err = error_new(E_POSIX_EACCES, "permission denied");
goto topen_return;
}
@@ -1084,23 +1149,29 @@ static void handle_Topen(struct srv_req *ctx,
struct lib9p_qid qid;
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))
+ lib9p_srv_dio_or_error dio_r =
+ LO_CALL(pathinfo->file, dopen, ctx);
+ if (dio_r.is_err) {
+ err = dio_r.err;
goto topen_return;
+ }
+ fidinfo->dir.io = dio_r.lib9p_srv_dio;
fidinfo->dir.idx = 0;
fidinfo->dir.off = 0;
- qid = LO_CALL(fidinfo->dir.io, qid);
+ qid = LO_CALL(fidinfo->dir.io, ioqid);
iounit = 0;
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->basectx));
- if (lib9p_ctx_has_error(&ctx->basectx))
+ lib9p_srv_fio_or_error fio_r =
+ LO_CALL(pathinfo->file, fopen, ctx,
+ rd, wr,
+ reqmode & LIB9P_O_TRUNC);
+ if (fio_r.is_err) {
+ err = fio_r.err;
goto topen_return;
- qid = LO_CALL(fidinfo->file.io, qid);
+ }
+ fidinfo->file.io = fio_r.lib9p_srv_fio;
+ qid = LO_CALL(fidinfo->file.io, ioqid);
iounit = LO_CALL(fidinfo->file.io, iounit);
break;
case SRV_FILETYPE_AUTH:
@@ -1123,60 +1194,66 @@ static void handle_Topen(struct srv_req *ctx,
topen_return:
if (ctx->user)
ctx->user = srv_userid_decref(ctx->user);
- srv_respond(ctx, open, &resp);
+ srv_respond(ctx, open, &resp, err);
}
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");
+ err = error_new(E_POSIX_EOPNOTSUPP, "create not (yet?) implemented");
- srv_respond(ctx, create, &resp);
+ srv_respond(ctx, create, &resp, err);
}
-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,
+static void srv_stat_to_net_stat(struct lib9p_stat *out, const struct lib9p_srv_stat *in) {
+ lib9p_srv_stat_assert(in);
+ *out = (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,
+ .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_read_file(struct srv_req *ctx, struct srv_fidinfo *fidinfo, uint64_t offset, uint32_t count);
+static void handle_read_dir(struct srv_req *ctx, struct srv_fidinfo *fidinfo, uint64_t offset, uint32_t count);
+
static void handle_Tread(struct srv_req *ctx,
struct lib9p_msg_Tread *req) {
- srv_handler_common(ctx, read, req);
- char *heap = NULL;
+ assert(ctx);
+ assert(req);
/* TODO: serialize simultaneous reads to the same FID */
+ /* req->count <= CONFIG_9P_SRV_MAX_MSG_SIZE <= CONFIG_9P_SRV_MAX_HOSTMSG_SIZE <= SIZE_MAX */
+ assert(req->count <= SIZE_MAX);
+ /* req->offset is u64, uoff is u64 */
+ static_assert(req->offset <= UOFF_MAX);
+
if (req->count > ctx->basectx.max_msg_size - lib9p_version_min_Rread_size(ctx->basectx.version))
req->count = ctx->basectx.max_msg_size - lib9p_version_min_Rread_size(ctx->basectx.version);
/* Check that the FID is valid for this. */
struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid);
if (!fidinfo) {
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EBADF, "bad file number ", req->fid);
- goto tread_return;
+ srv_respond(ctx, read, NULL, error_new(E_POSIX_EBADF, "bad file number ", req->fid));
+ return;
}
if (!(fidinfo->flags & FIDFLAG_OPEN_R)) {
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EINVAL, "FID not open for reading");
- goto tread_return;
+ srv_respond(ctx, read, NULL, error_new(E_POSIX_EINVAL, "FID not open for reading"));
+ return;
}
/* Do it. */
@@ -1184,102 +1261,190 @@ static void handle_Tread(struct srv_req *ctx,
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_error(&ctx->basectx,
- LIB9P_ERRNO_L_EINVAL, "invalid offset (must be 0 or ", fidinfo->dir.off, "): ", req->offset);
- goto tread_return;
- }
- /* Read. */
- resp.data = heap = malloc(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);
+ handle_read_dir(ctx, fidinfo, req->offset, req->count);
+#else
+ assert_notreached("Tread for directory on protocol version without that");
+#endif
+ break;
+ case SRV_FILETYPE_FILE:
+ handle_read_file(ctx, fidinfo, req->offset, req->count);
+ break;
+ case SRV_FILETYPE_AUTH:
+ assert_notreached("TODO: auth not yet implemented");
+ break;
+ }
+ ctx->user = srv_userid_decref(ctx->user);
+}
+
+struct rread_writer {
+ struct srv_req *ctx;
+ size_t count;
+ bool written;
+
+};
+LO_IMPLEMENTATION_STATIC(io_writer, struct rread_writer, rread);
+
+static size_t_and_error rread_writev(struct rread_writer *self, const struct wr_iovec *iov, int iovcnt) {
+ assert(self);
+ assert(!self->written);
+ assert(iovcnt == 1);
+ assert(iov);
+ assert(iov->iov_len <= self->count);
+
+ struct lib9p_msg_Rread resp = {
+ .tag = self->ctx->tag,
+ .count = iov->iov_len,
+ .data = iov->iov_write_from,
+ };
+
+ srv_respond(self->ctx, read, &resp, ERROR_NULL);
+
+ self->written = true;
+ return ERROR_AND(size_t, iov->iov_len, ERROR_NULL);
+}
+
+static void handle_read_file(struct srv_req *ctx, struct srv_fidinfo *fidinfo, uint64_t offset, uint32_t count) {
+ struct rread_writer _writer = {
+ .ctx = ctx,
+ .count = (size_t) count,
+ .written = false,
+ };
+ lo_interface io_writer writer = LO_BOX(io_writer, &_writer);
+ error err = LO_CALL(fidinfo->file.io, pread, ctx, writer, offset, count);
+ assert(ERROR_IS_NULL(err) == _writer.written);
+ if (!ERROR_IS_NULL(err))
+ srv_respond(ctx, read, NULL, err);
+}
+
+#if _LIB9P_ENABLE_stat
+
+static error stat_and_convert(struct lib9p_stat *out, struct srv_req *ctx, lo_interface lib9p_srv_file file) {
+ struct lib9p_srv_stat hoststat;
+ error err = LO_CALL(file, stat, ctx, &hoststat);
+ if (!ERROR_IS_NULL(err))
+ return err;
+
+ srv_stat_to_net_stat(out, &hoststat);
+ return ERROR_NULL;
+}
+
+static uint32_t_or_error stat_and_encode(struct srv_req *ctx, lo_interface lib9p_srv_file file, void *out, size_t out_len) {
+ struct lib9p_srv_stat hoststat;
+ struct lib9p_stat netstat;
+ error err;
+
+ err = LO_CALL(file, stat, ctx, &hoststat);
+
+ if (!ERROR_IS_NULL(err))
+ return ERROR_NEW_ERR(uint32_t, err);
+ srv_stat_to_net_stat(&netstat, &hoststat);
+ return ERROR_NEW_VAL(uint32_t, lib9p_stat_marshal(&ctx->basectx, out_len, &netstat, (uint8_t *)out));
+}
+
+static void handle_read_dir(struct srv_req *ctx, struct srv_fidinfo *fidinfo, uint64_t offset, uint32_t count) {
+ /* Seek. */
+ if (offset == 0) {
+ fidinfo->dir.idx = 0;
+ fidinfo->dir.off = 0;
+ fidinfo->dir.buffered_dirent = (struct lib9p_srv_dirent){};
+ } else if (offset != fidinfo->dir.off) {
+ srv_respond(ctx, read, NULL, error_new(E_POSIX_EINVAL, "invalid offset (must be 0 or ", fidinfo->dir.off, "): ", offset));
+ return;
+ }
+
+ /* Allocate. */
+ [[gnu::cleanup(heap_cleanup)]] char *heap = NULL;
+ struct lib9p_msg_Rread resp = {
+ .tag = ctx->tag,
+ .data = heap = heap_alloc(count, char),
+ .count = 0,
+ };
+
+ /* Read. */
+ struct srv_pathinfo *dir_pathinfo = NULL;
+ for (;;) {
+ /* 1. Call ->dread() to get `member_dirent`. */
+ struct lib9p_srv_dirent member_dirent;
+ if (fidinfo->dir.buffered_dirent.name.len) {
+ member_dirent = fidinfo->dir.buffered_dirent;
+ } else {
+ lib9p_srv_dirent_or_error r = LO_CALL(fidinfo->dir.io, dread, ctx, fidinfo->dir.idx);
+ if (r.is_err) {
+ if (resp.count) {
+ /* Just do a short-read; discard the error. */
+ error_cleanup(&r.err);
break;
}
+ srv_respond(ctx, read, NULL, r.err);
+ return;
}
- if (!member_dirent.name.len)
- break;
- struct lib9p_srv_stat member_stat;
+ member_dirent = r.lib9p_srv_dirent;
+ }
+ if (!member_dirent.name.len)
+ /* end-of-directory */
+ break;
+
+ /* 2. Call ->dwalk() to get the `member_file` object to call ->stat() on. */
+ lo_interface lib9p_srv_file member_file;
+ bool free_member_file;
+ {
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);
+ member_file = member_pathinfo->file;
+ free_member_file = false;
} 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);
+ lib9p_srv_file_or_error r = LO_CALL(dir_pathinfo->file, dwalk, ctx, member_dirent.name);
+ if (r.is_err) {
+ if (resp.count) {
+ /* Just do a short-read; discard the error. */
+ error_cleanup(&r.err);
+ break;
+ }
+ srv_respond(ctx, read, NULL, r.err);
+ return;
+ }
+ member_file = r.lib9p_srv_file;
+ free_member_file = true;
}
- 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);
+ }
+
+ /* 3. Call ->stat() to get `member_stat``. */
+ /* 4. Encode `member_stat` into `resp.data`/`heap` and increment `resp.count`. */
+ uint32_t_or_error r = stat_and_encode(ctx, member_file, &heap[resp.count], count - resp.count);
+ if (free_member_file)
+ LO_CALL(member_file, free);
+ if (r.is_err) {
+ if (resp.count) {
+ /* Just do a short-read; discard the error. */
+ error_cleanup(&r.err);
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;
- }
+ srv_respond(ctx, read, NULL, r.err);
+ return;
+ }
+ uint32_t nbytes = r.uint32_t;
+ if (!nbytes) {
+ if (resp.count) {
+ /* Just do a short-read; discard the error.
+ * But save the member_dirent for next time. */
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){};
- }
-#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, 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;
+ srv_respond(ctx, read, NULL,
+ error_new(E_POSIX_ERANGE, "stat object does not fit into negotiated max message size"));
+ return;
}
- break;
- case SRV_FILETYPE_AUTH:
- assert_notreached("TODO: auth not yet implemented");
- break;
+ resp.count += nbytes;
+ fidinfo->dir.idx++;
+ fidinfo->dir.off += nbytes;
+ fidinfo->dir.buffered_dirent = (struct lib9p_srv_dirent){};
}
- tread_return:
- if (ctx->user)
- ctx->user = srv_userid_decref(ctx->user);
- srv_respond(ctx, read, &resp);
- if (heap)
- free(heap);
+ srv_respond(ctx, read, &resp, ERROR_NULL);
}
+#endif
static void handle_Twrite(struct srv_req *ctx,
struct lib9p_msg_Twrite *req) {
@@ -1290,13 +1455,11 @@ static void handle_Twrite(struct srv_req *ctx,
/* Check that the FID is valid for this. */
struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid);
if (!fidinfo) {
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EBADF, "bad file number ", req->fid);
+ err = error_new(E_POSIX_EBADF, "bad file number ", req->fid);
goto twrite_return;
}
if (!(fidinfo->flags & FIDFLAG_OPEN_W)) {
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EINVAL, "FID not open for writing");
+ err = error_new(E_POSIX_EINVAL, "FID not open for writing");
goto twrite_return;
}
if (fidinfo->flags & FIDFLAG_APPEND)
@@ -1304,28 +1467,30 @@ static void handle_Twrite(struct srv_req *ctx,
/* Do it. */
ctx->user = srv_userid_incref(fidinfo->user);
- resp.count = LO_CALL(fidinfo->file.io, pwrite, ctx, req->data, req->count, req->offset);
+ uint32_t_or_error count = LO_CALL(fidinfo->file.io, pwrite, ctx, req->data, req->count, req->offset);
+ if (count.is_err)
+ err = count.err;
+ else
+ resp.count = count.uint32_t;
twrite_return:
if (ctx->user)
ctx->user = srv_userid_decref(ctx->user);
- srv_respond(ctx, write, &resp);
+ srv_respond(ctx, write, &resp, err);
}
static void handle_Tclunk(struct srv_req *ctx,
struct lib9p_msg_Tclunk *req) {
- srv_handler_common(ctx, clunk, req);
+ srv_handler_common_no_err(ctx, clunk, req);
struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid);
if (!fidinfo) {
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EBADF, "bad file number ", req->fid);
- goto tclunk_return;
+ srv_respond(ctx, clunk, NULL, error_new(E_POSIX_EBADF, "bad file number ", req->fid));
+ return;
}
+ srv_respond(ctx, clunk, &resp, ERROR_NULL);
+ /* Yes, don't actually perform the clunk until *after* we send Rclunk. */
srv_fid_del(ctx, req->fid, fidinfo, false);
-
- tclunk_return:
- srv_respond(ctx, clunk, &resp);
}
static void handle_Tremove(struct srv_req *ctx,
@@ -1334,8 +1499,7 @@ static void handle_Tremove(struct srv_req *ctx,
struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid);
if (!fidinfo) {
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EBADF, "bad file number ", req->fid);
+ err = error_new(E_POSIX_EBADF, "bad file number ", req->fid);
goto tremove_return;
}
@@ -1343,17 +1507,19 @@ static void handle_Tremove(struct srv_req *ctx,
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");
+ err = error_new(E_POSIX_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");
+ ok_or_error have_perm = srv_file_check_perm(ctx, parent->file, 0b010);
+ if (have_perm.is_err) {
+ err = have_perm.err;
+ remove = false;
+ goto tremove_main;
+ } else if (!have_perm.ok) {
+ err = error_new(E_POSIX_EACCES, "you do not have write permission on the parent directory");
remove = false;
goto tremove_main;
}
@@ -1361,7 +1527,7 @@ static void handle_Tremove(struct srv_req *ctx,
tremove_main:
srv_fid_del(ctx, req->fid, fidinfo, remove);
tremove_return:
- srv_respond(ctx, remove, &resp);
+ srv_respond(ctx, remove, &resp, err);
}
static void handle_Tstat(struct srv_req *ctx,
@@ -1370,33 +1536,27 @@ static void handle_Tstat(struct srv_req *ctx,
struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid);
if (!fidinfo) {
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EBADF, "bad file number ", req->fid);
+ err = error_new(E_POSIX_EBADF, "bad file number ", req->fid);
goto tstat_return;
}
struct srv_pathinfo *pathinfo = map_load(&ctx->parent_sess->paths, fidinfo->path);
assert(pathinfo);
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);
+ err = stat_and_convert(&resp.stat, ctx, pathinfo->file);
tstat_return:
if (ctx->user)
ctx->user = srv_userid_decref(ctx->user);
- srv_respond(ctx, stat, &resp);
+ srv_respond(ctx, stat, &resp, err);
}
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");
+ err = error_new(E_POSIX_EOPNOTSUPP, "wstat not (yet?) implemented");
- srv_respond(ctx, wstat, &resp);
+ srv_respond(ctx, wstat, &resp, err);
}
#endif
@@ -1405,10 +1565,9 @@ 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");
+ err = error_new(E_POSIX_EOPNOTSUPP, "openfd not (yet?) implemented");
- srv_respond(ctx, openfd, &resp);
+ srv_respond(ctx, openfd, &resp, err);
}
#endif
@@ -1417,29 +1576,26 @@ 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");
+ err = error_new(E_POSIX_EOPNOTSUPP, "session not (yet?) implemented");
- srv_respond(ctx, session, &resp);
+ srv_respond(ctx, session, &resp, err);
}
static void handle_Tsread(struct srv_req *ctx,
struct lib9p_msg_Tsread *req) {
srv_handler_common(ctx, sread, req);
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EOPNOTSUPP, "sread not (yet?) implemented");
+ err = error_new(E_POSIX_EOPNOTSUPP, "sread not (yet?) implemented");
- srv_respond(ctx, sread, &resp);
+ srv_respond(ctx, sread, &resp, err);
}
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");
+ err = error_new(E_POSIX_EOPNOTSUPP, "swrite not (yet?) implemented");
- srv_respond(ctx, swrite, &resp);
+ srv_respond(ctx, swrite, &resp, err);
}
#endif
diff --git a/lib9p/srv_errno.h b/lib9p/srv_errno.h
new file mode 100644
index 0000000..1384f97
--- /dev/null
+++ b/lib9p/srv_errno.h
@@ -0,0 +1,14 @@
+/* lib9p/srv_errno.h - TODO
+ *
+ * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#ifndef _LIB9P_SRV_ERRNO_H_
+#define _LIB9P_SRV_ERRNO_H_
+
+#if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L
+lib9p_errno_t libmisc_to_linuxgeneric_errno(_errnum);
+#endif
+
+#endif /* _LIB9P_SRV_ERRNO_H_ */
diff --git a/lib9p/srv_generated.c b/lib9p/srv_generated.c
new file mode 100644
index 0000000..26989c5
--- /dev/null
+++ b/lib9p/srv_generated.c
@@ -0,0 +1,91 @@
+/* lib9p/srv_generated.c - Generated by lib9p/srv_generated.c.gen. DO NOT EDIT! */
+
+#include <libmisc/error.h>
+#include <lib9p/core.h>
+#include "srv_errno.h"
+
+#if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L
+lib9p_errno_t libmisc_to_linuxgeneric_errno(_errnum errnum) {
+ LM_PARTIAL_SWITCH (errnum) {
+ case E_POSIX_E2BIG: return LIB9P_ERRNO_L_E2BIG;
+ case E_POSIX_EACCES: return LIB9P_ERRNO_L_EACCES;
+ case E_POSIX_EADDRINUSE: return LIB9P_ERRNO_L_EADDRINUSE;
+ case E_POSIX_EADDRNOTAVAIL: return LIB9P_ERRNO_L_EADDRNOTAVAIL;
+ case E_POSIX_EAFNOSUPPORT: return LIB9P_ERRNO_L_EAFNOSUPPORT;
+ case E_POSIX_EAGAIN: return LIB9P_ERRNO_L_EAGAIN;
+ case E_POSIX_EALREADY: return LIB9P_ERRNO_L_EALREADY;
+ case E_POSIX_EBADF: return LIB9P_ERRNO_L_EBADF;
+ case E_POSIX_EBADMSG: return LIB9P_ERRNO_L_EBADMSG;
+ case E_POSIX_EBUSY: return LIB9P_ERRNO_L_EBUSY;
+ case E_POSIX_ECANCELED: return LIB9P_ERRNO_L_ECANCELED;
+ case E_POSIX_ECHILD: return LIB9P_ERRNO_L_ECHILD;
+ case E_POSIX_ECONNABORTED: return LIB9P_ERRNO_L_ECONNABORTED;
+ case E_POSIX_ECONNREFUSED: return LIB9P_ERRNO_L_ECONNREFUSED;
+ case E_POSIX_ECONNRESET: return LIB9P_ERRNO_L_ECONNRESET;
+ case E_POSIX_EDEADLK: return LIB9P_ERRNO_L_EDEADLK;
+ case E_POSIX_EDESTADDRREQ: return LIB9P_ERRNO_L_EDESTADDRREQ;
+ case E_POSIX_EDOM: return LIB9P_ERRNO_L_EDOM;
+ case E_POSIX_EDQUOT: return LIB9P_ERRNO_L_EDQUOT;
+ case E_POSIX_EEXIST: return LIB9P_ERRNO_L_EEXIST;
+ case E_POSIX_EFAULT: return LIB9P_ERRNO_L_EFAULT;
+ case E_POSIX_EFBIG: return LIB9P_ERRNO_L_EFBIG;
+ case E_POSIX_EHOSTUNREACH: return LIB9P_ERRNO_L_EHOSTUNREACH;
+ case E_POSIX_EIDRM: return LIB9P_ERRNO_L_EIDRM;
+ case E_POSIX_EILSEQ: return LIB9P_ERRNO_L_EILSEQ;
+ case E_POSIX_EINPROGRESS: return LIB9P_ERRNO_L_EINPROGRESS;
+ case E_POSIX_EINTR: return LIB9P_ERRNO_L_EINTR;
+ case E_POSIX_EINVAL: return LIB9P_ERRNO_L_EINVAL;
+ case E_POSIX_EIO: return LIB9P_ERRNO_L_EIO;
+ case E_POSIX_EISCONN: return LIB9P_ERRNO_L_EISCONN;
+ case E_POSIX_EISDIR: return LIB9P_ERRNO_L_EISDIR;
+ case E_POSIX_ELOOP: return LIB9P_ERRNO_L_ELOOP;
+ case E_POSIX_EMFILE: return LIB9P_ERRNO_L_EMFILE;
+ case E_POSIX_EMLINK: return LIB9P_ERRNO_L_EMLINK;
+ case E_POSIX_EMSGSIZE: return LIB9P_ERRNO_L_EMSGSIZE;
+ case E_POSIX_EMULTIHOP: return LIB9P_ERRNO_L_EMULTIHOP;
+ case E_POSIX_ENAMETOOLONG: return LIB9P_ERRNO_L_ENAMETOOLONG;
+ case E_POSIX_ENETDOWN: return LIB9P_ERRNO_L_ENETDOWN;
+ case E_POSIX_ENETRESET: return LIB9P_ERRNO_L_ENETRESET;
+ case E_POSIX_ENETUNREACH: return LIB9P_ERRNO_L_ENETUNREACH;
+ case E_POSIX_ENFILE: return LIB9P_ERRNO_L_ENFILE;
+ case E_POSIX_ENOBUFS: return LIB9P_ERRNO_L_ENOBUFS;
+ case E_POSIX_ENODEV: return LIB9P_ERRNO_L_ENODEV;
+ case E_POSIX_ENOENT: return LIB9P_ERRNO_L_ENOENT;
+ case E_POSIX_ENOEXEC: return LIB9P_ERRNO_L_ENOEXEC;
+ case E_POSIX_ENOLCK: return LIB9P_ERRNO_L_ENOLCK;
+ case E_POSIX_ENOLINK: return LIB9P_ERRNO_L_ENOLINK;
+ case E_POSIX_ENOMEM: return LIB9P_ERRNO_L_ENOMEM;
+ case E_POSIX_ENOMSG: return LIB9P_ERRNO_L_ENOMSG;
+ case E_POSIX_ENOPROTOOPT: return LIB9P_ERRNO_L_ENOPROTOOPT;
+ case E_POSIX_ENOSPC: return LIB9P_ERRNO_L_ENOSPC;
+ case E_POSIX_ENOSYS: return LIB9P_ERRNO_L_ENOSYS;
+ case E_POSIX_ENOTCONN: return LIB9P_ERRNO_L_ENOTCONN;
+ case E_POSIX_ENOTDIR: return LIB9P_ERRNO_L_ENOTDIR;
+ case E_POSIX_ENOTEMPTY: return LIB9P_ERRNO_L_ENOTEMPTY;
+ case E_POSIX_ENOTRECOVERABLE: return LIB9P_ERRNO_L_ENOTRECOVERABLE;
+ case E_POSIX_ENOTSOCK: return LIB9P_ERRNO_L_ENOTSOCK;
+ case E_POSIX_ENOTTY: return LIB9P_ERRNO_L_ENOTTY;
+ case E_POSIX_ENXIO: return LIB9P_ERRNO_L_ENXIO;
+ case E_POSIX_EOPNOTSUPP: return LIB9P_ERRNO_L_EOPNOTSUPP;
+ case E_POSIX_EOVERFLOW: return LIB9P_ERRNO_L_EOVERFLOW;
+ case E_POSIX_EOWNERDEAD: return LIB9P_ERRNO_L_EOWNERDEAD;
+ case E_POSIX_EPERM: return LIB9P_ERRNO_L_EPERM;
+ case E_POSIX_EPIPE: return LIB9P_ERRNO_L_EPIPE;
+ case E_POSIX_EPROTO: return LIB9P_ERRNO_L_EPROTO;
+ case E_POSIX_EPROTONOSUPPORT: return LIB9P_ERRNO_L_EPROTONOSUPPORT;
+ case E_POSIX_EPROTOTYPE: return LIB9P_ERRNO_L_EPROTOTYPE;
+ case E_POSIX_ERANGE: return LIB9P_ERRNO_L_ERANGE;
+ case E_POSIX_EROFS: return LIB9P_ERRNO_L_EROFS;
+ case E_POSIX_ESOCKTNOSUPPORT: return LIB9P_ERRNO_L_ESOCKTNOSUPPORT;
+ case E_POSIX_ESPIPE: return LIB9P_ERRNO_L_ESPIPE;
+ case E_POSIX_ESRCH: return LIB9P_ERRNO_L_ESRCH;
+ case E_POSIX_ESTALE: return LIB9P_ERRNO_L_ESTALE;
+ case E_POSIX_ETIMEDOUT: return LIB9P_ERRNO_L_ETIMEDOUT;
+ case E_POSIX_ETXTBSY: return LIB9P_ERRNO_L_ETXTBSY;
+ case E_POSIX_EXDEV: return LIB9P_ERRNO_L_EXDEV;
+ case E_POSIX_ENOTSUP: return LIB9P_ERRNO_L_EOPNOTSUPP;
+ case E_POSIX_EWOULDBLOCK: return LIB9P_ERRNO_L_EAGAIN;
+ default: return LIB9P_ERRNO_L_EIO;
+ }
+}
+#endif
diff --git a/lib9p/srv_generated.c.gen b/lib9p/srv_generated.c.gen
new file mode 100755
index 0000000..6a6335a
--- /dev/null
+++ b/lib9p/srv_generated.c.gen
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+# lib9p/srv_generated.c.gen - Generate errno translation tables
+#
+# Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+error_h=$1
+outfile=$2
+
+{
+ echo "/* ${outfile} - Generated by $0. DO NOT EDIT! */"
+ echo
+ echo '#include <libmisc/error.h>'
+ echo '#include <lib9p/core.h>'
+ echo '#include "srv_errno.h"'
+ echo
+ echo '#if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L'
+ echo 'lib9p_errno_t libmisc_to_linuxgeneric_errno(_errnum errnum) {'
+ echo $'\tLM_PARTIAL_SWITCH (errnum) {'
+ sed -nE \
+ -e 's@^(#define)?\s+(E_POSIX_([_A-Z0-9]+))[ ,][^/]*/\* ([^*(]+) (\*/|\().*@'$'\tcase \\2: return LIB9P_ERRNO_L_\\3;''@p' \
+ -- "$error_h" |
+ grep -v -e '_ENOTSUP' -e '_EWOULDBLOCK'
+ echo $'\tcase E_POSIX_ENOTSUP: return LIB9P_ERRNO_L_EOPNOTSUPP;'
+ echo $'\tcase E_POSIX_EWOULDBLOCK: return LIB9P_ERRNO_L_EAGAIN;'
+ echo $'\tdefault: return LIB9P_ERRNO_L_EIO;'
+ echo $'\t}'
+ echo '}'
+ echo '#endif'
+} >"$outfile"
diff --git a/lib9p/srv_include/lib9p/srv.h b/lib9p/srv_include/lib9p/srv.h
index c40c85a..cea1d79 100644
--- a/lib9p/srv_include/lib9p/srv.h
+++ b/lib9p/srv_include/lib9p/srv.h
@@ -7,7 +7,6 @@
#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>
@@ -17,6 +16,11 @@
#include <lib9p/core.h>
+#ifndef CONFIG_9P_SRV_MAX_ERR_SIZE
+ #error config.h must define CONFIG_9P_SRV_MAX_ERR_SIZE
+#endif
+static_assert(CONFIG_9P_SRV_MAX_ERR_SIZE <= UINT16_MAX);
+
/* context ********************************************************************/
struct lib9p_srv_userid {
@@ -45,8 +49,7 @@ struct lib9p_srv_ctx {
struct _lib9p_srv_sess *parent_sess;
lib9p_tag_t tag;
uint8_t *net_bytes;
- _lib9p_srv_flush_ch_t flush_ch;
- bool flush_acknowledged;
+ _lib9p_srv_flush_ch_t flush_ch; /* flushers for this req _read_ from here */
bool responded;
END_PRIVATE(LIB9P_SRV_H);
};
@@ -55,20 +58,13 @@ struct lib9p_srv_ctx {
* 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.
+ *
+ * As a special case, returning E_POSIX_ECANCELED indicates that the
+ * flush has been observed, and a Rerror should not be sent ot the
+ * client.
*/
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 {
@@ -96,14 +92,11 @@ struct lib9p_srv_stat {
#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) );
-}
+#ifdef NDEBUG
+#define lib9p_srv_stat_assert(stat) ((void)0)
+#else
+void lib9p_srv_stat_assert(const struct lib9p_srv_stat *stat);
+#endif
/* interface definitions ******************************************************/
@@ -111,16 +104,58 @@ struct lib9p_srv_dirent {
struct lib9p_qid qid;
struct lib9p_s name;
};
+DECLARE_ERROR_OR_(struct lib9p_srv_dirent, lib9p_srv_dirent);
-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.
+/* FIXME: It would be nice if pread() could return more than 1 iovec. This
+ * API allows it, but for the "just-1-iovec" requirement inherited from
+ * io_preader_to. We enforce this requirement because otherwise we wouldn't
+ * know at compile-time how big the iovec array in lib9p_Rmsg_send_buf needs
+ * to be.
*/
+#define lib9p_srv_fio_LO_IFACE /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ \
+ LO_FUNC(struct lib9p_qid , ioqid ) \
+ LO_FUNC(void , iofree ) \
+ LO_FUNC(uint32_t , iounit ) \
+ /** \
+ * This is similar to io_preader_to->pread_to, and must follow the \
+ * same requirements. \
+ */ \
+ LO_FUNC(error , pread , struct lib9p_srv_ctx *, \
+ lo_interface io_writer dst, \
+ uint64_t src_offset, \
+ uint32_t count) \
+ /** \
+ * If the file was append-only when fopen()ed, then byte_offset will \
+ * always be 0. \
+ * \
+ * This similar to io_pwrite, but a short-write is not an error. \
+ */ \
+ LO_FUNC(uint32_t_or_error , pwrite , struct lib9p_srv_ctx *, \
+ const void *buf, \
+ uint32_t byte_count, \
+ uint64_t byte_offset)
+LO_INTERFACE(lib9p_srv_fio); /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+DECLARE_ERROR_OR_(lo_interface lib9p_srv_fio, lib9p_srv_fio);
+
+#define lib9p_srv_dio_LO_IFACE /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ \
+ LO_FUNC(struct lib9p_qid , ioqid ) \
+ LO_FUNC(void , iofree ) \
+ /** \
+ * Return the idx-th dirent. idx will always be either 0 or \
+ * prev_idx+1. A dirent with an empty name signals EOF. The string \
+ * must remain valid until the next dread() call or iofree(). \
+ */ \
+ LO_FUNC(lib9p_srv_dirent_or_error , dread , struct lib9p_srv_ctx *, \
+ size_t idx)
+LO_INTERFACE(lib9p_srv_dio); /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+DECLARE_ERROR_OR_(lo_interface lib9p_srv_dio, lib9p_srv_dio);
+
+struct _lo_lib9p_srv_file_vtable;
+lo_interface lib9p_srv_file {
+ void *self;
+ const struct _lo_lib9p_srv_file_vtable *vtable;
+};
+DECLARE_ERROR_OR_(lo_interface lib9p_srv_file, lib9p_srv_file);
#define lib9p_srv_file_LO_IFACE /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ \
/* resource management **********************************************/ \
\
@@ -146,16 +181,17 @@ lo_interface lib9p_srv_dio;
/* 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 *, \
+ LO_FUNC(error , stat , struct lib9p_srv_ctx *, \
+ struct lib9p_srv_stat * ret) \
+ LO_FUNC(error , wstat , struct lib9p_srv_ctx *, \
struct lib9p_srv_stat) \
- LO_FUNC(void , remove , struct lib9p_srv_ctx *) \
+ LO_FUNC(error , remove , struct lib9p_srv_ctx *) \
\
/* non-"opened" directory I/O ***************************************/ \
\
- LO_FUNC(lo_interface lib9p_srv_file, dwalk , struct lib9p_srv_ctx *, \
+ LO_FUNC(lib9p_srv_file_or_error , dwalk , struct lib9p_srv_ctx *, \
struct lib9p_s childname) \
- LO_FUNC(lo_interface lib9p_srv_file, dcreate, struct lib9p_srv_ctx *, \
+ LO_FUNC(lib9p_srv_file_or_error , dcreate, struct lib9p_srv_ctx *, \
struct lib9p_s childname, \
struct lib9p_srv_userid *user, \
struct lib9p_srv_userid *group, \
@@ -163,50 +199,22 @@ lo_interface lib9p_srv_dio;
\
/* open() for I/O ***************************************************/ \
\
- LO_FUNC(lo_interface lib9p_srv_fio , fopen , struct lib9p_srv_ctx *, \
+ LO_FUNC(lib9p_srv_fio_or_error , fopen , struct lib9p_srv_ctx *, \
bool rd, bool wr, \
bool trunc) \
- LO_FUNC(lo_interface lib9p_srv_dio , dopen , struct lib9p_srv_ctx *)
+ LO_FUNC(lib9p_srv_dio_or_error , 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_NOTDIR(QUALS, TYP, NAM) \
+ QUALS lib9p_srv_file_or_error NAM##_dwalk (TYP *, struct lib9p_srv_ctx *, struct lib9p_s) { assert_notreached("not a directory"); } \
+ QUALS lib9p_srv_file_or_error 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"); } \
+ QUALS lib9p_srv_dio_or_error NAM##_dopen (TYP *, struct lib9p_srv_ctx *) { assert_notreached("not a directory"); } \
+ LM_FORCE_SEMICOLON
-#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"); }
+#define LIB9P_SRV_NOTFILE(QUALS, TYP, NAM) \
+ QUALS lib9p_srv_fio_or_error NAM##_fopen (TYP *, struct lib9p_srv_ctx *, bool, bool, bool) { assert_notreached("not a file"); } \
+ LM_FORCE_SEMICOLON
/* main server entrypoints ****************************************************/
@@ -222,9 +230,9 @@ LO_INTERFACE(net_stream_conn_unix);
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 */
+ error /*TODO*/ (*auth )(struct lib9p_srv_ctx *, struct lib9p_s treename); /* optional */
+ lib9p_srv_file_or_error (*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
@@ -233,7 +241,7 @@ struct lib9p_srv {
BEGIN_PRIVATE(LIB9P_SRV_H);
unsigned int readers;
unsigned int writers;
- _lib9p_srv_reqch_t _reqch;
+ _lib9p_srv_reqch_t reqch;
END_PRIVATE(LIB9P_SRV_H);
};
@@ -270,10 +278,10 @@ void lib9p_srv_accept_and_read_loop(struct lib9p_srv *srv, lo_interface net_stre
*
* 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
+ * @errno E_POSIX_EMSGSIZE T-message has size[4] bigger than max_msg_size
+ * @errno E_POSIX_EDOM Tversion specified an impossibly small max_msg_size
+ * @errno E_POSIX_EOPNOTSUPP T-message has an R-message type, or an unrecognized T-message type
+ * @errno E_POSIX_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);
@@ -298,7 +306,7 @@ void lib9p_srv_worker_loop(struct lib9p_srv *srv);
*
* Errors that this function itself may send to clients:
*
- * @errno L_ERANGE R-message does not fit into max_msg_size
+ * @errno E_POSIX_ERANGE R-message does not fit into max_msg_size
*/
void lib9p_srv_worker(struct lib9p_srv_ctx *req);
diff --git a/lib9p/tests/client_config/config.h b/lib9p/tests/client_config/config.h
index bcf030d..afcf49f 100644
--- a/lib9p/tests/client_config/config.h
+++ b/lib9p/tests/client_config/config.h
@@ -1,4 +1,4 @@
-/* config.h - Compile-time configuration for lib9p test clients
+/* lib9p/tests/client_config/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
@@ -7,7 +7,6 @@
#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 */
diff --git a/lib9p/tests/test_compile.c b/lib9p/tests/test_compile.c
index e814bf9..6d7fb50 100644
--- a/lib9p/tests/test_compile.c
+++ b/lib9p/tests/test_compile.c
@@ -2,1254 +2,1254 @@
#include <lib9p/core.h>
int main(void) {
- [[maybe_unused]] uint64_t x;
+ [[maybe_unused]] uint64_t x;
#ifdef LIB9P_B4_FALSE
- x = LIB9P_B4_FALSE;
+ x = LIB9P_B4_FALSE;
#endif
#ifdef LIB9P_B4_TRUE
- x = LIB9P_B4_TRUE;
+ x = LIB9P_B4_TRUE;
#endif
#ifdef LIB9P_DM_APPEND
- x = LIB9P_DM_APPEND;
+ x = LIB9P_DM_APPEND;
#endif
#ifdef LIB9P_DM_AUTH
- x = LIB9P_DM_AUTH;
+ x = LIB9P_DM_AUTH;
#endif
#ifdef LIB9P_DM_DEVICE
- x = LIB9P_DM_DEVICE;
+ x = LIB9P_DM_DEVICE;
#endif
#ifdef LIB9P_DM_DIR
- x = LIB9P_DM_DIR;
+ x = LIB9P_DM_DIR;
#endif
#ifdef LIB9P_DM_EXCL
- x = LIB9P_DM_EXCL;
+ x = LIB9P_DM_EXCL;
#endif
#ifdef LIB9P_DM_GROUP_R
- x = LIB9P_DM_GROUP_R;
+ x = LIB9P_DM_GROUP_R;
#endif
#ifdef LIB9P_DM_GROUP_W
- x = LIB9P_DM_GROUP_W;
+ x = LIB9P_DM_GROUP_W;
#endif
#ifdef LIB9P_DM_GROUP_X
- x = LIB9P_DM_GROUP_X;
+ x = LIB9P_DM_GROUP_X;
#endif
#ifdef LIB9P_DM_OTHER_R
- x = LIB9P_DM_OTHER_R;
+ x = LIB9P_DM_OTHER_R;
#endif
#ifdef LIB9P_DM_OTHER_W
- x = LIB9P_DM_OTHER_W;
+ x = LIB9P_DM_OTHER_W;
#endif
#ifdef LIB9P_DM_OTHER_X
- x = LIB9P_DM_OTHER_X;
+ x = LIB9P_DM_OTHER_X;
#endif
#ifdef LIB9P_DM_OWNER_R
- x = LIB9P_DM_OWNER_R;
+ x = LIB9P_DM_OWNER_R;
#endif
#ifdef LIB9P_DM_OWNER_W
- x = LIB9P_DM_OWNER_W;
+ x = LIB9P_DM_OWNER_W;
#endif
#ifdef LIB9P_DM_OWNER_X
- x = LIB9P_DM_OWNER_X;
+ x = LIB9P_DM_OWNER_X;
#endif
#ifdef LIB9P_DM_PERM_MASK
- x = LIB9P_DM_PERM_MASK;
+ x = LIB9P_DM_PERM_MASK;
#endif
#ifdef LIB9P_DM_PIPE
- x = LIB9P_DM_PIPE;
+ x = LIB9P_DM_PIPE;
#endif
#ifdef LIB9P_DM_SETGID
- x = LIB9P_DM_SETGID;
+ x = LIB9P_DM_SETGID;
#endif
#ifdef LIB9P_DM_SETUID
- x = LIB9P_DM_SETUID;
+ x = LIB9P_DM_SETUID;
#endif
#ifdef LIB9P_DM_SOCKET
- x = LIB9P_DM_SOCKET;
+ x = LIB9P_DM_SOCKET;
#endif
#ifdef LIB9P_DM_TMP
- x = LIB9P_DM_TMP;
+ x = LIB9P_DM_TMP;
#endif
#ifdef LIB9P_DT_BLOCK_DEV
- x = LIB9P_DT_BLOCK_DEV;
+ x = LIB9P_DT_BLOCK_DEV;
#endif
#ifdef LIB9P_DT_CHAR_DEV
- x = LIB9P_DT_CHAR_DEV;
+ x = LIB9P_DT_CHAR_DEV;
#endif
#ifdef LIB9P_DT_DIRECTORY
- x = LIB9P_DT_DIRECTORY;
+ x = LIB9P_DT_DIRECTORY;
#endif
#ifdef LIB9P_DT_PIPE
- x = LIB9P_DT_PIPE;
+ x = LIB9P_DT_PIPE;
#endif
#ifdef LIB9P_DT_REGULAR
- x = LIB9P_DT_REGULAR;
+ x = LIB9P_DT_REGULAR;
#endif
#ifdef LIB9P_DT_SOCKET
- x = LIB9P_DT_SOCKET;
+ x = LIB9P_DT_SOCKET;
#endif
#ifdef LIB9P_DT_SYMLINK
- x = LIB9P_DT_SYMLINK;
+ x = LIB9P_DT_SYMLINK;
#endif
#ifdef LIB9P_DT_UNKNOWN
- x = LIB9P_DT_UNKNOWN;
+ x = LIB9P_DT_UNKNOWN;
#endif
#ifdef LIB9P_ERRNO_L_E2BIG
- x = LIB9P_ERRNO_L_E2BIG;
+ x = LIB9P_ERRNO_L_E2BIG;
#endif
#ifdef LIB9P_ERRNO_L_EACCES
- x = LIB9P_ERRNO_L_EACCES;
+ x = LIB9P_ERRNO_L_EACCES;
#endif
#ifdef LIB9P_ERRNO_L_EADDRINUSE
- x = LIB9P_ERRNO_L_EADDRINUSE;
+ x = LIB9P_ERRNO_L_EADDRINUSE;
#endif
#ifdef LIB9P_ERRNO_L_EADDRNOTAVAIL
- x = LIB9P_ERRNO_L_EADDRNOTAVAIL;
+ x = LIB9P_ERRNO_L_EADDRNOTAVAIL;
#endif
#ifdef LIB9P_ERRNO_L_EADV
- x = LIB9P_ERRNO_L_EADV;
+ x = LIB9P_ERRNO_L_EADV;
#endif
#ifdef LIB9P_ERRNO_L_EAFNOSUPPORT
- x = LIB9P_ERRNO_L_EAFNOSUPPORT;
+ x = LIB9P_ERRNO_L_EAFNOSUPPORT;
#endif
#ifdef LIB9P_ERRNO_L_EAGAIN
- x = LIB9P_ERRNO_L_EAGAIN;
+ x = LIB9P_ERRNO_L_EAGAIN;
#endif
#ifdef LIB9P_ERRNO_L_EALREADY
- x = LIB9P_ERRNO_L_EALREADY;
+ x = LIB9P_ERRNO_L_EALREADY;
#endif
#ifdef LIB9P_ERRNO_L_EBADE
- x = LIB9P_ERRNO_L_EBADE;
+ x = LIB9P_ERRNO_L_EBADE;
#endif
#ifdef LIB9P_ERRNO_L_EBADF
- x = LIB9P_ERRNO_L_EBADF;
+ x = LIB9P_ERRNO_L_EBADF;
#endif
#ifdef LIB9P_ERRNO_L_EBADFD
- x = LIB9P_ERRNO_L_EBADFD;
+ x = LIB9P_ERRNO_L_EBADFD;
#endif
#ifdef LIB9P_ERRNO_L_EBADMSG
- x = LIB9P_ERRNO_L_EBADMSG;
+ x = LIB9P_ERRNO_L_EBADMSG;
#endif
#ifdef LIB9P_ERRNO_L_EBADR
- x = LIB9P_ERRNO_L_EBADR;
+ x = LIB9P_ERRNO_L_EBADR;
#endif
#ifdef LIB9P_ERRNO_L_EBADRQC
- x = LIB9P_ERRNO_L_EBADRQC;
+ x = LIB9P_ERRNO_L_EBADRQC;
#endif
#ifdef LIB9P_ERRNO_L_EBADSLT
- x = LIB9P_ERRNO_L_EBADSLT;
+ x = LIB9P_ERRNO_L_EBADSLT;
#endif
#ifdef LIB9P_ERRNO_L_EBFONT
- x = LIB9P_ERRNO_L_EBFONT;
+ x = LIB9P_ERRNO_L_EBFONT;
#endif
#ifdef LIB9P_ERRNO_L_EBUSY
- x = LIB9P_ERRNO_L_EBUSY;
+ x = LIB9P_ERRNO_L_EBUSY;
#endif
#ifdef LIB9P_ERRNO_L_ECANCELED
- x = LIB9P_ERRNO_L_ECANCELED;
+ x = LIB9P_ERRNO_L_ECANCELED;
#endif
#ifdef LIB9P_ERRNO_L_ECHILD
- x = LIB9P_ERRNO_L_ECHILD;
+ x = LIB9P_ERRNO_L_ECHILD;
#endif
#ifdef LIB9P_ERRNO_L_ECHRNG
- x = LIB9P_ERRNO_L_ECHRNG;
+ x = LIB9P_ERRNO_L_ECHRNG;
#endif
#ifdef LIB9P_ERRNO_L_ECOMM
- x = LIB9P_ERRNO_L_ECOMM;
+ x = LIB9P_ERRNO_L_ECOMM;
#endif
#ifdef LIB9P_ERRNO_L_ECONNABORTED
- x = LIB9P_ERRNO_L_ECONNABORTED;
+ x = LIB9P_ERRNO_L_ECONNABORTED;
#endif
#ifdef LIB9P_ERRNO_L_ECONNREFUSED
- x = LIB9P_ERRNO_L_ECONNREFUSED;
+ x = LIB9P_ERRNO_L_ECONNREFUSED;
#endif
#ifdef LIB9P_ERRNO_L_ECONNRESET
- x = LIB9P_ERRNO_L_ECONNRESET;
+ x = LIB9P_ERRNO_L_ECONNRESET;
#endif
#ifdef LIB9P_ERRNO_L_EDEADLK
- x = LIB9P_ERRNO_L_EDEADLK;
+ x = LIB9P_ERRNO_L_EDEADLK;
#endif
#ifdef LIB9P_ERRNO_L_EDESTADDRREQ
- x = LIB9P_ERRNO_L_EDESTADDRREQ;
+ x = LIB9P_ERRNO_L_EDESTADDRREQ;
#endif
#ifdef LIB9P_ERRNO_L_EDOM
- x = LIB9P_ERRNO_L_EDOM;
+ x = LIB9P_ERRNO_L_EDOM;
#endif
#ifdef LIB9P_ERRNO_L_EDOTDOT
- x = LIB9P_ERRNO_L_EDOTDOT;
+ x = LIB9P_ERRNO_L_EDOTDOT;
#endif
#ifdef LIB9P_ERRNO_L_EDQUOT
- x = LIB9P_ERRNO_L_EDQUOT;
+ x = LIB9P_ERRNO_L_EDQUOT;
#endif
#ifdef LIB9P_ERRNO_L_EEXIST
- x = LIB9P_ERRNO_L_EEXIST;
+ x = LIB9P_ERRNO_L_EEXIST;
#endif
#ifdef LIB9P_ERRNO_L_EFAULT
- x = LIB9P_ERRNO_L_EFAULT;
+ x = LIB9P_ERRNO_L_EFAULT;
#endif
#ifdef LIB9P_ERRNO_L_EFBIG
- x = LIB9P_ERRNO_L_EFBIG;
+ x = LIB9P_ERRNO_L_EFBIG;
#endif
#ifdef LIB9P_ERRNO_L_EHOSTDOWN
- x = LIB9P_ERRNO_L_EHOSTDOWN;
+ x = LIB9P_ERRNO_L_EHOSTDOWN;
#endif
#ifdef LIB9P_ERRNO_L_EHOSTUNREACH
- x = LIB9P_ERRNO_L_EHOSTUNREACH;
+ x = LIB9P_ERRNO_L_EHOSTUNREACH;
#endif
#ifdef LIB9P_ERRNO_L_EHWPOISON
- x = LIB9P_ERRNO_L_EHWPOISON;
+ x = LIB9P_ERRNO_L_EHWPOISON;
#endif
#ifdef LIB9P_ERRNO_L_EIDRM
- x = LIB9P_ERRNO_L_EIDRM;
+ x = LIB9P_ERRNO_L_EIDRM;
#endif
#ifdef LIB9P_ERRNO_L_EILSEQ
- x = LIB9P_ERRNO_L_EILSEQ;
+ x = LIB9P_ERRNO_L_EILSEQ;
#endif
#ifdef LIB9P_ERRNO_L_EINPROGRESS
- x = LIB9P_ERRNO_L_EINPROGRESS;
+ x = LIB9P_ERRNO_L_EINPROGRESS;
#endif
#ifdef LIB9P_ERRNO_L_EINTR
- x = LIB9P_ERRNO_L_EINTR;
+ x = LIB9P_ERRNO_L_EINTR;
#endif
#ifdef LIB9P_ERRNO_L_EINVAL
- x = LIB9P_ERRNO_L_EINVAL;
+ x = LIB9P_ERRNO_L_EINVAL;
#endif
#ifdef LIB9P_ERRNO_L_EIO
- x = LIB9P_ERRNO_L_EIO;
+ x = LIB9P_ERRNO_L_EIO;
#endif
#ifdef LIB9P_ERRNO_L_EISCONN
- x = LIB9P_ERRNO_L_EISCONN;
+ x = LIB9P_ERRNO_L_EISCONN;
#endif
#ifdef LIB9P_ERRNO_L_EISDIR
- x = LIB9P_ERRNO_L_EISDIR;
+ x = LIB9P_ERRNO_L_EISDIR;
#endif
#ifdef LIB9P_ERRNO_L_EISNAM
- x = LIB9P_ERRNO_L_EISNAM;
+ x = LIB9P_ERRNO_L_EISNAM;
#endif
#ifdef LIB9P_ERRNO_L_EKEYEXPIRED
- x = LIB9P_ERRNO_L_EKEYEXPIRED;
+ x = LIB9P_ERRNO_L_EKEYEXPIRED;
#endif
#ifdef LIB9P_ERRNO_L_EKEYREJECTED
- x = LIB9P_ERRNO_L_EKEYREJECTED;
+ x = LIB9P_ERRNO_L_EKEYREJECTED;
#endif
#ifdef LIB9P_ERRNO_L_EKEYREVOKED
- x = LIB9P_ERRNO_L_EKEYREVOKED;
+ x = LIB9P_ERRNO_L_EKEYREVOKED;
#endif
#ifdef LIB9P_ERRNO_L_EL2HLT
- x = LIB9P_ERRNO_L_EL2HLT;
+ x = LIB9P_ERRNO_L_EL2HLT;
#endif
#ifdef LIB9P_ERRNO_L_EL2NSYNC
- x = LIB9P_ERRNO_L_EL2NSYNC;
+ x = LIB9P_ERRNO_L_EL2NSYNC;
#endif
#ifdef LIB9P_ERRNO_L_EL3HLT
- x = LIB9P_ERRNO_L_EL3HLT;
+ x = LIB9P_ERRNO_L_EL3HLT;
#endif
#ifdef LIB9P_ERRNO_L_EL3RST
- x = LIB9P_ERRNO_L_EL3RST;
+ x = LIB9P_ERRNO_L_EL3RST;
#endif
#ifdef LIB9P_ERRNO_L_ELIBACC
- x = LIB9P_ERRNO_L_ELIBACC;
+ x = LIB9P_ERRNO_L_ELIBACC;
#endif
#ifdef LIB9P_ERRNO_L_ELIBBAD
- x = LIB9P_ERRNO_L_ELIBBAD;
+ x = LIB9P_ERRNO_L_ELIBBAD;
#endif
#ifdef LIB9P_ERRNO_L_ELIBEXEC
- x = LIB9P_ERRNO_L_ELIBEXEC;
+ x = LIB9P_ERRNO_L_ELIBEXEC;
#endif
#ifdef LIB9P_ERRNO_L_ELIBMAX
- x = LIB9P_ERRNO_L_ELIBMAX;
+ x = LIB9P_ERRNO_L_ELIBMAX;
#endif
#ifdef LIB9P_ERRNO_L_ELIBSCN
- x = LIB9P_ERRNO_L_ELIBSCN;
+ x = LIB9P_ERRNO_L_ELIBSCN;
#endif
#ifdef LIB9P_ERRNO_L_ELNRNG
- x = LIB9P_ERRNO_L_ELNRNG;
+ x = LIB9P_ERRNO_L_ELNRNG;
#endif
#ifdef LIB9P_ERRNO_L_ELOOP
- x = LIB9P_ERRNO_L_ELOOP;
+ x = LIB9P_ERRNO_L_ELOOP;
#endif
#ifdef LIB9P_ERRNO_L_EMEDIUMTYPE
- x = LIB9P_ERRNO_L_EMEDIUMTYPE;
+ x = LIB9P_ERRNO_L_EMEDIUMTYPE;
#endif
#ifdef LIB9P_ERRNO_L_EMFILE
- x = LIB9P_ERRNO_L_EMFILE;
+ x = LIB9P_ERRNO_L_EMFILE;
#endif
#ifdef LIB9P_ERRNO_L_EMLINK
- x = LIB9P_ERRNO_L_EMLINK;
+ x = LIB9P_ERRNO_L_EMLINK;
#endif
#ifdef LIB9P_ERRNO_L_EMSGSIZE
- x = LIB9P_ERRNO_L_EMSGSIZE;
+ x = LIB9P_ERRNO_L_EMSGSIZE;
#endif
#ifdef LIB9P_ERRNO_L_EMULTIHOP
- x = LIB9P_ERRNO_L_EMULTIHOP;
+ x = LIB9P_ERRNO_L_EMULTIHOP;
#endif
#ifdef LIB9P_ERRNO_L_ENAMETOOLONG
- x = LIB9P_ERRNO_L_ENAMETOOLONG;
+ x = LIB9P_ERRNO_L_ENAMETOOLONG;
#endif
#ifdef LIB9P_ERRNO_L_ENAVAIL
- x = LIB9P_ERRNO_L_ENAVAIL;
+ x = LIB9P_ERRNO_L_ENAVAIL;
#endif
#ifdef LIB9P_ERRNO_L_ENETDOWN
- x = LIB9P_ERRNO_L_ENETDOWN;
+ x = LIB9P_ERRNO_L_ENETDOWN;
#endif
#ifdef LIB9P_ERRNO_L_ENETRESET
- x = LIB9P_ERRNO_L_ENETRESET;
+ x = LIB9P_ERRNO_L_ENETRESET;
#endif
#ifdef LIB9P_ERRNO_L_ENETUNREACH
- x = LIB9P_ERRNO_L_ENETUNREACH;
+ x = LIB9P_ERRNO_L_ENETUNREACH;
#endif
#ifdef LIB9P_ERRNO_L_ENFILE
- x = LIB9P_ERRNO_L_ENFILE;
+ x = LIB9P_ERRNO_L_ENFILE;
#endif
#ifdef LIB9P_ERRNO_L_ENOANO
- x = LIB9P_ERRNO_L_ENOANO;
+ x = LIB9P_ERRNO_L_ENOANO;
#endif
#ifdef LIB9P_ERRNO_L_ENOBUFS
- x = LIB9P_ERRNO_L_ENOBUFS;
+ x = LIB9P_ERRNO_L_ENOBUFS;
#endif
#ifdef LIB9P_ERRNO_L_ENOCSI
- x = LIB9P_ERRNO_L_ENOCSI;
+ x = LIB9P_ERRNO_L_ENOCSI;
#endif
#ifdef LIB9P_ERRNO_L_ENODATA
- x = LIB9P_ERRNO_L_ENODATA;
+ x = LIB9P_ERRNO_L_ENODATA;
#endif
#ifdef LIB9P_ERRNO_L_ENODEV
- x = LIB9P_ERRNO_L_ENODEV;
+ x = LIB9P_ERRNO_L_ENODEV;
#endif
#ifdef LIB9P_ERRNO_L_ENOENT
- x = LIB9P_ERRNO_L_ENOENT;
+ x = LIB9P_ERRNO_L_ENOENT;
#endif
#ifdef LIB9P_ERRNO_L_ENOEXEC
- x = LIB9P_ERRNO_L_ENOEXEC;
+ x = LIB9P_ERRNO_L_ENOEXEC;
#endif
#ifdef LIB9P_ERRNO_L_ENOKEY
- x = LIB9P_ERRNO_L_ENOKEY;
+ x = LIB9P_ERRNO_L_ENOKEY;
#endif
#ifdef LIB9P_ERRNO_L_ENOLCK
- x = LIB9P_ERRNO_L_ENOLCK;
+ x = LIB9P_ERRNO_L_ENOLCK;
#endif
#ifdef LIB9P_ERRNO_L_ENOLINK
- x = LIB9P_ERRNO_L_ENOLINK;
+ x = LIB9P_ERRNO_L_ENOLINK;
#endif
#ifdef LIB9P_ERRNO_L_ENOMEDIUM
- x = LIB9P_ERRNO_L_ENOMEDIUM;
+ x = LIB9P_ERRNO_L_ENOMEDIUM;
#endif
#ifdef LIB9P_ERRNO_L_ENOMEM
- x = LIB9P_ERRNO_L_ENOMEM;
+ x = LIB9P_ERRNO_L_ENOMEM;
#endif
#ifdef LIB9P_ERRNO_L_ENOMSG
- x = LIB9P_ERRNO_L_ENOMSG;
+ x = LIB9P_ERRNO_L_ENOMSG;
#endif
#ifdef LIB9P_ERRNO_L_ENONET
- x = LIB9P_ERRNO_L_ENONET;
+ x = LIB9P_ERRNO_L_ENONET;
#endif
#ifdef LIB9P_ERRNO_L_ENOPKG
- x = LIB9P_ERRNO_L_ENOPKG;
+ x = LIB9P_ERRNO_L_ENOPKG;
#endif
#ifdef LIB9P_ERRNO_L_ENOPROTOOPT
- x = LIB9P_ERRNO_L_ENOPROTOOPT;
+ x = LIB9P_ERRNO_L_ENOPROTOOPT;
#endif
#ifdef LIB9P_ERRNO_L_ENOSPC
- x = LIB9P_ERRNO_L_ENOSPC;
+ x = LIB9P_ERRNO_L_ENOSPC;
#endif
#ifdef LIB9P_ERRNO_L_ENOSR
- x = LIB9P_ERRNO_L_ENOSR;
+ x = LIB9P_ERRNO_L_ENOSR;
#endif
#ifdef LIB9P_ERRNO_L_ENOSTR
- x = LIB9P_ERRNO_L_ENOSTR;
+ x = LIB9P_ERRNO_L_ENOSTR;
#endif
#ifdef LIB9P_ERRNO_L_ENOSYS
- x = LIB9P_ERRNO_L_ENOSYS;
+ x = LIB9P_ERRNO_L_ENOSYS;
#endif
#ifdef LIB9P_ERRNO_L_ENOTBLK
- x = LIB9P_ERRNO_L_ENOTBLK;
+ x = LIB9P_ERRNO_L_ENOTBLK;
#endif
#ifdef LIB9P_ERRNO_L_ENOTCONN
- x = LIB9P_ERRNO_L_ENOTCONN;
+ x = LIB9P_ERRNO_L_ENOTCONN;
#endif
#ifdef LIB9P_ERRNO_L_ENOTDIR
- x = LIB9P_ERRNO_L_ENOTDIR;
+ x = LIB9P_ERRNO_L_ENOTDIR;
#endif
#ifdef LIB9P_ERRNO_L_ENOTEMPTY
- x = LIB9P_ERRNO_L_ENOTEMPTY;
+ x = LIB9P_ERRNO_L_ENOTEMPTY;
#endif
#ifdef LIB9P_ERRNO_L_ENOTNAM
- x = LIB9P_ERRNO_L_ENOTNAM;
+ x = LIB9P_ERRNO_L_ENOTNAM;
#endif
#ifdef LIB9P_ERRNO_L_ENOTRECOVERABLE
- x = LIB9P_ERRNO_L_ENOTRECOVERABLE;
+ x = LIB9P_ERRNO_L_ENOTRECOVERABLE;
#endif
#ifdef LIB9P_ERRNO_L_ENOTSOCK
- x = LIB9P_ERRNO_L_ENOTSOCK;
+ x = LIB9P_ERRNO_L_ENOTSOCK;
#endif
#ifdef LIB9P_ERRNO_L_ENOTTY
- x = LIB9P_ERRNO_L_ENOTTY;
+ x = LIB9P_ERRNO_L_ENOTTY;
#endif
#ifdef LIB9P_ERRNO_L_ENOTUNIQ
- x = LIB9P_ERRNO_L_ENOTUNIQ;
+ x = LIB9P_ERRNO_L_ENOTUNIQ;
#endif
#ifdef LIB9P_ERRNO_L_ENXIO
- x = LIB9P_ERRNO_L_ENXIO;
+ x = LIB9P_ERRNO_L_ENXIO;
#endif
#ifdef LIB9P_ERRNO_L_EOPNOTSUPP
- x = LIB9P_ERRNO_L_EOPNOTSUPP;
+ x = LIB9P_ERRNO_L_EOPNOTSUPP;
#endif
#ifdef LIB9P_ERRNO_L_EOVERFLOW
- x = LIB9P_ERRNO_L_EOVERFLOW;
+ x = LIB9P_ERRNO_L_EOVERFLOW;
#endif
#ifdef LIB9P_ERRNO_L_EOWNERDEAD
- x = LIB9P_ERRNO_L_EOWNERDEAD;
+ x = LIB9P_ERRNO_L_EOWNERDEAD;
#endif
#ifdef LIB9P_ERRNO_L_EPERM
- x = LIB9P_ERRNO_L_EPERM;
+ x = LIB9P_ERRNO_L_EPERM;
#endif
#ifdef LIB9P_ERRNO_L_EPFNOSUPPORT
- x = LIB9P_ERRNO_L_EPFNOSUPPORT;
+ x = LIB9P_ERRNO_L_EPFNOSUPPORT;
#endif
#ifdef LIB9P_ERRNO_L_EPIPE
- x = LIB9P_ERRNO_L_EPIPE;
+ x = LIB9P_ERRNO_L_EPIPE;
#endif
#ifdef LIB9P_ERRNO_L_EPROTO
- x = LIB9P_ERRNO_L_EPROTO;
+ x = LIB9P_ERRNO_L_EPROTO;
#endif
#ifdef LIB9P_ERRNO_L_EPROTONOSUPPORT
- x = LIB9P_ERRNO_L_EPROTONOSUPPORT;
+ x = LIB9P_ERRNO_L_EPROTONOSUPPORT;
#endif
#ifdef LIB9P_ERRNO_L_EPROTOTYPE
- x = LIB9P_ERRNO_L_EPROTOTYPE;
+ x = LIB9P_ERRNO_L_EPROTOTYPE;
#endif
#ifdef LIB9P_ERRNO_L_ERANGE
- x = LIB9P_ERRNO_L_ERANGE;
+ x = LIB9P_ERRNO_L_ERANGE;
#endif
#ifdef LIB9P_ERRNO_L_EREMCHG
- x = LIB9P_ERRNO_L_EREMCHG;
+ x = LIB9P_ERRNO_L_EREMCHG;
#endif
#ifdef LIB9P_ERRNO_L_EREMOTE
- x = LIB9P_ERRNO_L_EREMOTE;
+ x = LIB9P_ERRNO_L_EREMOTE;
#endif
#ifdef LIB9P_ERRNO_L_EREMOTEIO
- x = LIB9P_ERRNO_L_EREMOTEIO;
+ x = LIB9P_ERRNO_L_EREMOTEIO;
#endif
#ifdef LIB9P_ERRNO_L_ERESTART
- x = LIB9P_ERRNO_L_ERESTART;
+ x = LIB9P_ERRNO_L_ERESTART;
#endif
#ifdef LIB9P_ERRNO_L_ERFKILL
- x = LIB9P_ERRNO_L_ERFKILL;
+ x = LIB9P_ERRNO_L_ERFKILL;
#endif
#ifdef LIB9P_ERRNO_L_EROFS
- x = LIB9P_ERRNO_L_EROFS;
+ x = LIB9P_ERRNO_L_EROFS;
#endif
#ifdef LIB9P_ERRNO_L_ESHUTDOWN
- x = LIB9P_ERRNO_L_ESHUTDOWN;
+ x = LIB9P_ERRNO_L_ESHUTDOWN;
#endif
#ifdef LIB9P_ERRNO_L_ESOCKTNOSUPPORT
- x = LIB9P_ERRNO_L_ESOCKTNOSUPPORT;
+ x = LIB9P_ERRNO_L_ESOCKTNOSUPPORT;
#endif
#ifdef LIB9P_ERRNO_L_ESPIPE
- x = LIB9P_ERRNO_L_ESPIPE;
+ x = LIB9P_ERRNO_L_ESPIPE;
#endif
#ifdef LIB9P_ERRNO_L_ESRCH
- x = LIB9P_ERRNO_L_ESRCH;
+ x = LIB9P_ERRNO_L_ESRCH;
#endif
#ifdef LIB9P_ERRNO_L_ESRMNT
- x = LIB9P_ERRNO_L_ESRMNT;
+ x = LIB9P_ERRNO_L_ESRMNT;
#endif
#ifdef LIB9P_ERRNO_L_ESTALE
- x = LIB9P_ERRNO_L_ESTALE;
+ x = LIB9P_ERRNO_L_ESTALE;
#endif
#ifdef LIB9P_ERRNO_L_ESTRPIPE
- x = LIB9P_ERRNO_L_ESTRPIPE;
+ x = LIB9P_ERRNO_L_ESTRPIPE;
#endif
#ifdef LIB9P_ERRNO_L_ETIME
- x = LIB9P_ERRNO_L_ETIME;
+ x = LIB9P_ERRNO_L_ETIME;
#endif
#ifdef LIB9P_ERRNO_L_ETIMEDOUT
- x = LIB9P_ERRNO_L_ETIMEDOUT;
+ x = LIB9P_ERRNO_L_ETIMEDOUT;
#endif
#ifdef LIB9P_ERRNO_L_ETOOMANYREFS
- x = LIB9P_ERRNO_L_ETOOMANYREFS;
+ x = LIB9P_ERRNO_L_ETOOMANYREFS;
#endif
#ifdef LIB9P_ERRNO_L_ETXTBSY
- x = LIB9P_ERRNO_L_ETXTBSY;
+ x = LIB9P_ERRNO_L_ETXTBSY;
#endif
#ifdef LIB9P_ERRNO_L_EUCLEAN
- x = LIB9P_ERRNO_L_EUCLEAN;
+ x = LIB9P_ERRNO_L_EUCLEAN;
#endif
#ifdef LIB9P_ERRNO_L_EUNATCH
- x = LIB9P_ERRNO_L_EUNATCH;
+ x = LIB9P_ERRNO_L_EUNATCH;
#endif
#ifdef LIB9P_ERRNO_L_EUSERS
- x = LIB9P_ERRNO_L_EUSERS;
+ x = LIB9P_ERRNO_L_EUSERS;
#endif
#ifdef LIB9P_ERRNO_L_EXDEV
- x = LIB9P_ERRNO_L_EXDEV;
+ x = LIB9P_ERRNO_L_EXDEV;
#endif
#ifdef LIB9P_ERRNO_L_EXFULL
- x = LIB9P_ERRNO_L_EXFULL;
+ x = LIB9P_ERRNO_L_EXFULL;
#endif
#ifdef LIB9P_ERRNO_NOERROR
- x = LIB9P_ERRNO_NOERROR;
+ x = LIB9P_ERRNO_NOERROR;
#endif
#ifdef LIB9P_FID_NOFID
- x = LIB9P_FID_NOFID;
+ x = LIB9P_FID_NOFID;
#endif
#ifdef LIB9P_GETATTR_ALL
- x = LIB9P_GETATTR_ALL;
+ x = LIB9P_GETATTR_ALL;
#endif
#ifdef LIB9P_GETATTR_ATIME
- x = LIB9P_GETATTR_ATIME;
+ x = LIB9P_GETATTR_ATIME;
#endif
#ifdef LIB9P_GETATTR_BASIC
- x = LIB9P_GETATTR_BASIC;
+ x = LIB9P_GETATTR_BASIC;
#endif
#ifdef LIB9P_GETATTR_BLOCKS
- x = LIB9P_GETATTR_BLOCKS;
+ x = LIB9P_GETATTR_BLOCKS;
#endif
#ifdef LIB9P_GETATTR_BTIME
- x = LIB9P_GETATTR_BTIME;
+ x = LIB9P_GETATTR_BTIME;
#endif
#ifdef LIB9P_GETATTR_CTIME
- x = LIB9P_GETATTR_CTIME;
+ x = LIB9P_GETATTR_CTIME;
#endif
#ifdef LIB9P_GETATTR_DATA_VERSION
- x = LIB9P_GETATTR_DATA_VERSION;
+ x = LIB9P_GETATTR_DATA_VERSION;
#endif
#ifdef LIB9P_GETATTR_GEN
- x = LIB9P_GETATTR_GEN;
+ x = LIB9P_GETATTR_GEN;
#endif
#ifdef LIB9P_GETATTR_GID
- x = LIB9P_GETATTR_GID;
+ x = LIB9P_GETATTR_GID;
#endif
#ifdef LIB9P_GETATTR_INO
- x = LIB9P_GETATTR_INO;
+ x = LIB9P_GETATTR_INO;
#endif
#ifdef LIB9P_GETATTR_MODE
- x = LIB9P_GETATTR_MODE;
+ x = LIB9P_GETATTR_MODE;
#endif
#ifdef LIB9P_GETATTR_MTIME
- x = LIB9P_GETATTR_MTIME;
+ x = LIB9P_GETATTR_MTIME;
#endif
#ifdef LIB9P_GETATTR_NLINK
- x = LIB9P_GETATTR_NLINK;
+ x = LIB9P_GETATTR_NLINK;
#endif
#ifdef LIB9P_GETATTR_RDEV
- x = LIB9P_GETATTR_RDEV;
+ x = LIB9P_GETATTR_RDEV;
#endif
#ifdef LIB9P_GETATTR_SIZE
- x = LIB9P_GETATTR_SIZE;
+ x = LIB9P_GETATTR_SIZE;
#endif
#ifdef LIB9P_GETATTR_UID
- x = LIB9P_GETATTR_UID;
+ x = LIB9P_GETATTR_UID;
#endif
#ifdef LIB9P_LOCK_FLAGS_BLOCK
- x = LIB9P_LOCK_FLAGS_BLOCK;
+ x = LIB9P_LOCK_FLAGS_BLOCK;
#endif
#ifdef LIB9P_LOCK_FLAGS_RECLAIM
- x = LIB9P_LOCK_FLAGS_RECLAIM;
+ x = LIB9P_LOCK_FLAGS_RECLAIM;
#endif
#ifdef LIB9P_LOCK_STATUS_BLOCKED
- x = LIB9P_LOCK_STATUS_BLOCKED;
+ x = LIB9P_LOCK_STATUS_BLOCKED;
#endif
#ifdef LIB9P_LOCK_STATUS_ERROR
- x = LIB9P_LOCK_STATUS_ERROR;
+ x = LIB9P_LOCK_STATUS_ERROR;
#endif
#ifdef LIB9P_LOCK_STATUS_GRACE
- x = LIB9P_LOCK_STATUS_GRACE;
+ x = LIB9P_LOCK_STATUS_GRACE;
#endif
#ifdef LIB9P_LOCK_STATUS_SUCCESS
- x = LIB9P_LOCK_STATUS_SUCCESS;
+ x = LIB9P_LOCK_STATUS_SUCCESS;
#endif
#ifdef LIB9P_LOCK_TYPE_RDLCK
- x = LIB9P_LOCK_TYPE_RDLCK;
+ x = LIB9P_LOCK_TYPE_RDLCK;
#endif
#ifdef LIB9P_LOCK_TYPE_UNLCK
- x = LIB9P_LOCK_TYPE_UNLCK;
+ x = LIB9P_LOCK_TYPE_UNLCK;
#endif
#ifdef LIB9P_LOCK_TYPE_WRLCK
- x = LIB9P_LOCK_TYPE_WRLCK;
+ x = LIB9P_LOCK_TYPE_WRLCK;
#endif
#ifdef LIB9P_LO_APPEND
- x = LIB9P_LO_APPEND;
+ x = LIB9P_LO_APPEND;
#endif
#ifdef LIB9P_LO_BSD_FASYNC
- x = LIB9P_LO_BSD_FASYNC;
+ x = LIB9P_LO_BSD_FASYNC;
#endif
#ifdef LIB9P_LO_CLOEXEC
- x = LIB9P_LO_CLOEXEC;
+ x = LIB9P_LO_CLOEXEC;
#endif
#ifdef LIB9P_LO_CREATE
- x = LIB9P_LO_CREATE;
+ x = LIB9P_LO_CREATE;
#endif
#ifdef LIB9P_LO_DIRECT
- x = LIB9P_LO_DIRECT;
+ x = LIB9P_LO_DIRECT;
#endif
#ifdef LIB9P_LO_DIRECTORY
- x = LIB9P_LO_DIRECTORY;
+ x = LIB9P_LO_DIRECTORY;
#endif
#ifdef LIB9P_LO_DSYNC
- x = LIB9P_LO_DSYNC;
+ x = LIB9P_LO_DSYNC;
#endif
#ifdef LIB9P_LO_EXCL
- x = LIB9P_LO_EXCL;
+ x = LIB9P_LO_EXCL;
#endif
#ifdef LIB9P_LO_FLAG_MASK
- x = LIB9P_LO_FLAG_MASK;
+ x = LIB9P_LO_FLAG_MASK;
#endif
#ifdef LIB9P_LO_LARGEFILE
- x = LIB9P_LO_LARGEFILE;
+ x = LIB9P_LO_LARGEFILE;
#endif
#ifdef LIB9P_LO_MODE_MASK
- x = LIB9P_LO_MODE_MASK;
+ x = LIB9P_LO_MODE_MASK;
#endif
#ifdef LIB9P_LO_MODE_NOACCESS
- x = LIB9P_LO_MODE_NOACCESS;
+ x = LIB9P_LO_MODE_NOACCESS;
#endif
#ifdef LIB9P_LO_MODE_RDONLY
- x = LIB9P_LO_MODE_RDONLY;
+ x = LIB9P_LO_MODE_RDONLY;
#endif
#ifdef LIB9P_LO_MODE_RDWR
- x = LIB9P_LO_MODE_RDWR;
+ x = LIB9P_LO_MODE_RDWR;
#endif
#ifdef LIB9P_LO_MODE_WRONLY
- x = LIB9P_LO_MODE_WRONLY;
+ x = LIB9P_LO_MODE_WRONLY;
#endif
#ifdef LIB9P_LO_NOATIME
- x = LIB9P_LO_NOATIME;
+ x = LIB9P_LO_NOATIME;
#endif
#ifdef LIB9P_LO_NOCTTY
- x = LIB9P_LO_NOCTTY;
+ x = LIB9P_LO_NOCTTY;
#endif
#ifdef LIB9P_LO_NOFOLLOW
- x = LIB9P_LO_NOFOLLOW;
+ x = LIB9P_LO_NOFOLLOW;
#endif
#ifdef LIB9P_LO_NONBLOCK
- x = LIB9P_LO_NONBLOCK;
+ x = LIB9P_LO_NONBLOCK;
#endif
#ifdef LIB9P_LO_SYNC
- x = LIB9P_LO_SYNC;
+ x = LIB9P_LO_SYNC;
#endif
#ifdef LIB9P_LO_TRUNC
- x = LIB9P_LO_TRUNC;
+ x = LIB9P_LO_TRUNC;
#endif
#ifdef LIB9P_MODE_FMT_BLOCK_DEV
- x = LIB9P_MODE_FMT_BLOCK_DEV;
+ x = LIB9P_MODE_FMT_BLOCK_DEV;
#endif
#ifdef LIB9P_MODE_FMT_CHAR_DEV
- x = LIB9P_MODE_FMT_CHAR_DEV;
+ x = LIB9P_MODE_FMT_CHAR_DEV;
#endif
#ifdef LIB9P_MODE_FMT_DIRECTORY
- x = LIB9P_MODE_FMT_DIRECTORY;
+ x = LIB9P_MODE_FMT_DIRECTORY;
#endif
#ifdef LIB9P_MODE_FMT_MASK
- x = LIB9P_MODE_FMT_MASK;
+ x = LIB9P_MODE_FMT_MASK;
#endif
#ifdef LIB9P_MODE_FMT_PIPE
- x = LIB9P_MODE_FMT_PIPE;
+ x = LIB9P_MODE_FMT_PIPE;
#endif
#ifdef LIB9P_MODE_FMT_REGULAR
- x = LIB9P_MODE_FMT_REGULAR;
+ x = LIB9P_MODE_FMT_REGULAR;
#endif
#ifdef LIB9P_MODE_FMT_SOCKET
- x = LIB9P_MODE_FMT_SOCKET;
+ x = LIB9P_MODE_FMT_SOCKET;
#endif
#ifdef LIB9P_MODE_FMT_SYMLINK
- x = LIB9P_MODE_FMT_SYMLINK;
+ x = LIB9P_MODE_FMT_SYMLINK;
#endif
#ifdef LIB9P_MODE_PERM_GROUP_R
- x = LIB9P_MODE_PERM_GROUP_R;
+ x = LIB9P_MODE_PERM_GROUP_R;
#endif
#ifdef LIB9P_MODE_PERM_GROUP_W
- x = LIB9P_MODE_PERM_GROUP_W;
+ x = LIB9P_MODE_PERM_GROUP_W;
#endif
#ifdef LIB9P_MODE_PERM_GROUP_X
- x = LIB9P_MODE_PERM_GROUP_X;
+ x = LIB9P_MODE_PERM_GROUP_X;
#endif
#ifdef LIB9P_MODE_PERM_MASK
- x = LIB9P_MODE_PERM_MASK;
+ x = LIB9P_MODE_PERM_MASK;
#endif
#ifdef LIB9P_MODE_PERM_OTHER_R
- x = LIB9P_MODE_PERM_OTHER_R;
+ x = LIB9P_MODE_PERM_OTHER_R;
#endif
#ifdef LIB9P_MODE_PERM_OTHER_W
- x = 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_OTHER_X;
#endif
#ifdef LIB9P_MODE_PERM_OWNER_R
- x = LIB9P_MODE_PERM_OWNER_R;
+ x = LIB9P_MODE_PERM_OWNER_R;
#endif
#ifdef LIB9P_MODE_PERM_OWNER_W
- x = LIB9P_MODE_PERM_OWNER_W;
+ x = LIB9P_MODE_PERM_OWNER_W;
#endif
#ifdef LIB9P_MODE_PERM_OWNER_X
- x = LIB9P_MODE_PERM_OWNER_X;
+ x = LIB9P_MODE_PERM_OWNER_X;
#endif
#ifdef LIB9P_MODE_PERM_SETGROUP
- x = LIB9P_MODE_PERM_SETGROUP;
+ x = LIB9P_MODE_PERM_SETGROUP;
#endif
#ifdef LIB9P_MODE_PERM_SETUSER
- x = LIB9P_MODE_PERM_SETUSER;
+ x = LIB9P_MODE_PERM_SETUSER;
#endif
#ifdef LIB9P_MODE_PERM_STICKY
- x = LIB9P_MODE_PERM_STICKY;
+ x = LIB9P_MODE_PERM_STICKY;
#endif
#ifdef LIB9P_NUID_NONUID
- x = LIB9P_NUID_NONUID;
+ x = LIB9P_NUID_NONUID;
#endif
#ifdef LIB9P_O_FLAG_MASK
- x = LIB9P_O_FLAG_MASK;
+ x = LIB9P_O_FLAG_MASK;
#endif
#ifdef LIB9P_O_MODE_EXEC
- x = LIB9P_O_MODE_EXEC;
+ x = LIB9P_O_MODE_EXEC;
#endif
#ifdef LIB9P_O_MODE_MASK
- x = LIB9P_O_MODE_MASK;
+ x = LIB9P_O_MODE_MASK;
#endif
#ifdef LIB9P_O_MODE_RDWR
- x = LIB9P_O_MODE_RDWR;
+ x = LIB9P_O_MODE_RDWR;
#endif
#ifdef LIB9P_O_MODE_READ
- x = LIB9P_O_MODE_READ;
+ x = LIB9P_O_MODE_READ;
#endif
#ifdef LIB9P_O_MODE_WRITE
- x = LIB9P_O_MODE_WRITE;
+ x = LIB9P_O_MODE_WRITE;
#endif
#ifdef LIB9P_O_RCLOSE
- x = LIB9P_O_RCLOSE;
+ x = LIB9P_O_RCLOSE;
#endif
#ifdef LIB9P_O_TRUNC
- x = LIB9P_O_TRUNC;
+ x = LIB9P_O_TRUNC;
#endif
#ifdef LIB9P_QT_APPEND
- x = LIB9P_QT_APPEND;
+ x = LIB9P_QT_APPEND;
#endif
#ifdef LIB9P_QT_AUTH
- x = LIB9P_QT_AUTH;
+ x = LIB9P_QT_AUTH;
#endif
#ifdef LIB9P_QT_DIR
- x = LIB9P_QT_DIR;
+ x = LIB9P_QT_DIR;
#endif
#ifdef LIB9P_QT_EXCL
- x = LIB9P_QT_EXCL;
+ x = LIB9P_QT_EXCL;
#endif
#ifdef LIB9P_QT_FILE
- x = LIB9P_QT_FILE;
+ x = LIB9P_QT_FILE;
#endif
#ifdef LIB9P_QT_SYMLINK
- x = LIB9P_QT_SYMLINK;
+ x = LIB9P_QT_SYMLINK;
#endif
#ifdef LIB9P_QT_TMP
- x = LIB9P_QT_TMP;
+ x = LIB9P_QT_TMP;
#endif
#ifdef LIB9P_RMSG_MAX_COPY
- x = LIB9P_RMSG_MAX_COPY;
+ x = LIB9P_RMSG_MAX_COPY;
#endif
#ifdef LIB9P_RMSG_MAX_IOV
- x = LIB9P_RMSG_MAX_IOV;
+ x = LIB9P_RMSG_MAX_IOV;
#endif
#ifdef LIB9P_SETATTR_ATIME
- x = LIB9P_SETATTR_ATIME;
+ x = LIB9P_SETATTR_ATIME;
#endif
#ifdef LIB9P_SETATTR_ATIME_SET
- x = LIB9P_SETATTR_ATIME_SET;
+ x = LIB9P_SETATTR_ATIME_SET;
#endif
#ifdef LIB9P_SETATTR_CTIME
- x = LIB9P_SETATTR_CTIME;
+ x = LIB9P_SETATTR_CTIME;
#endif
#ifdef LIB9P_SETATTR_GID
- x = LIB9P_SETATTR_GID;
+ x = LIB9P_SETATTR_GID;
#endif
#ifdef LIB9P_SETATTR_MODE
- x = LIB9P_SETATTR_MODE;
+ x = LIB9P_SETATTR_MODE;
#endif
#ifdef LIB9P_SETATTR_MTIME
- x = LIB9P_SETATTR_MTIME;
+ x = LIB9P_SETATTR_MTIME;
#endif
#ifdef LIB9P_SETATTR_MTIME_SET
- x = LIB9P_SETATTR_MTIME_SET;
+ x = LIB9P_SETATTR_MTIME_SET;
#endif
#ifdef LIB9P_SETATTR_SIZE
- x = LIB9P_SETATTR_SIZE;
+ x = LIB9P_SETATTR_SIZE;
#endif
#ifdef LIB9P_SETATTR_UID
- x = LIB9P_SETATTR_UID;
+ x = LIB9P_SETATTR_UID;
#endif
#ifdef LIB9P_SUPER_MAGIC_V9FS_MAGIC
- x = LIB9P_SUPER_MAGIC_V9FS_MAGIC;
+ x = LIB9P_SUPER_MAGIC_V9FS_MAGIC;
#endif
#ifdef LIB9P_TAG_NOTAG
- x = LIB9P_TAG_NOTAG;
+ x = LIB9P_TAG_NOTAG;
#endif
#ifdef LIB9P_TMSG_MAX_COPY
- x = LIB9P_TMSG_MAX_COPY;
+ x = LIB9P_TMSG_MAX_COPY;
#endif
#ifdef LIB9P_TMSG_MAX_IOV
- x = LIB9P_TMSG_MAX_IOV;
+ x = LIB9P_TMSG_MAX_IOV;
#endif
#ifdef _LIB9P_DM_PLAN9_MOUNT
- x = _LIB9P_DM_PLAN9_MOUNT;
+ x = _LIB9P_DM_PLAN9_MOUNT;
#endif
#ifdef _LIB9P_DM_UNUSED_10
- x = _LIB9P_DM_UNUSED_10;
+ x = _LIB9P_DM_UNUSED_10;
#endif
#ifdef _LIB9P_DM_UNUSED_11
- x = _LIB9P_DM_UNUSED_11;
+ x = _LIB9P_DM_UNUSED_11;
#endif
#ifdef _LIB9P_DM_UNUSED_12
- x = _LIB9P_DM_UNUSED_12;
+ x = _LIB9P_DM_UNUSED_12;
#endif
#ifdef _LIB9P_DM_UNUSED_13
- x = _LIB9P_DM_UNUSED_13;
+ x = _LIB9P_DM_UNUSED_13;
#endif
#ifdef _LIB9P_DM_UNUSED_14
- x = _LIB9P_DM_UNUSED_14;
+ x = _LIB9P_DM_UNUSED_14;
#endif
#ifdef _LIB9P_DM_UNUSED_15
- x = _LIB9P_DM_UNUSED_15;
+ x = _LIB9P_DM_UNUSED_15;
#endif
#ifdef _LIB9P_DM_UNUSED_16
- x = _LIB9P_DM_UNUSED_16;
+ x = _LIB9P_DM_UNUSED_16;
#endif
#ifdef _LIB9P_DM_UNUSED_17
- x = _LIB9P_DM_UNUSED_17;
+ x = _LIB9P_DM_UNUSED_17;
#endif
#ifdef _LIB9P_DM_UNUSED_22
- x = _LIB9P_DM_UNUSED_22;
+ x = _LIB9P_DM_UNUSED_22;
#endif
#ifdef _LIB9P_DM_UNUSED_24
- x = _LIB9P_DM_UNUSED_24;
+ x = _LIB9P_DM_UNUSED_24;
#endif
#ifdef _LIB9P_DM_UNUSED_25
- x = _LIB9P_DM_UNUSED_25;
+ x = _LIB9P_DM_UNUSED_25;
#endif
#ifdef _LIB9P_DM_UNUSED_9
- x = _LIB9P_DM_UNUSED_9;
+ x = _LIB9P_DM_UNUSED_9;
#endif
#ifdef _LIB9P_DT_WHITEOUT
- x = _LIB9P_DT_WHITEOUT;
+ x = _LIB9P_DT_WHITEOUT;
#endif
#ifdef _LIB9P_ENABLE_stat
- x = _LIB9P_ENABLE_stat;
+ x = _LIB9P_ENABLE_stat;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_14
- x = _LIB9P_GETATTR_UNUSED_14;
+ x = _LIB9P_GETATTR_UNUSED_14;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_15
- x = _LIB9P_GETATTR_UNUSED_15;
+ x = _LIB9P_GETATTR_UNUSED_15;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_16
- x = _LIB9P_GETATTR_UNUSED_16;
+ x = _LIB9P_GETATTR_UNUSED_16;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_17
- x = _LIB9P_GETATTR_UNUSED_17;
+ x = _LIB9P_GETATTR_UNUSED_17;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_18
- x = _LIB9P_GETATTR_UNUSED_18;
+ x = _LIB9P_GETATTR_UNUSED_18;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_19
- x = _LIB9P_GETATTR_UNUSED_19;
+ x = _LIB9P_GETATTR_UNUSED_19;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_20
- x = _LIB9P_GETATTR_UNUSED_20;
+ x = _LIB9P_GETATTR_UNUSED_20;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_21
- x = _LIB9P_GETATTR_UNUSED_21;
+ x = _LIB9P_GETATTR_UNUSED_21;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_22
- x = _LIB9P_GETATTR_UNUSED_22;
+ x = _LIB9P_GETATTR_UNUSED_22;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_23
- x = _LIB9P_GETATTR_UNUSED_23;
+ x = _LIB9P_GETATTR_UNUSED_23;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_24
- x = _LIB9P_GETATTR_UNUSED_24;
+ x = _LIB9P_GETATTR_UNUSED_24;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_25
- x = _LIB9P_GETATTR_UNUSED_25;
+ x = _LIB9P_GETATTR_UNUSED_25;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_26
- x = _LIB9P_GETATTR_UNUSED_26;
+ x = _LIB9P_GETATTR_UNUSED_26;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_27
- x = _LIB9P_GETATTR_UNUSED_27;
+ x = _LIB9P_GETATTR_UNUSED_27;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_28
- x = _LIB9P_GETATTR_UNUSED_28;
+ x = _LIB9P_GETATTR_UNUSED_28;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_29
- x = _LIB9P_GETATTR_UNUSED_29;
+ x = _LIB9P_GETATTR_UNUSED_29;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_30
- x = _LIB9P_GETATTR_UNUSED_30;
+ x = _LIB9P_GETATTR_UNUSED_30;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_31
- x = _LIB9P_GETATTR_UNUSED_31;
+ x = _LIB9P_GETATTR_UNUSED_31;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_32
- x = _LIB9P_GETATTR_UNUSED_32;
+ x = _LIB9P_GETATTR_UNUSED_32;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_33
- x = _LIB9P_GETATTR_UNUSED_33;
+ x = _LIB9P_GETATTR_UNUSED_33;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_34
- x = _LIB9P_GETATTR_UNUSED_34;
+ x = _LIB9P_GETATTR_UNUSED_34;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_35
- x = _LIB9P_GETATTR_UNUSED_35;
+ x = _LIB9P_GETATTR_UNUSED_35;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_36
- x = _LIB9P_GETATTR_UNUSED_36;
+ x = _LIB9P_GETATTR_UNUSED_36;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_37
- x = _LIB9P_GETATTR_UNUSED_37;
+ x = _LIB9P_GETATTR_UNUSED_37;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_38
- x = _LIB9P_GETATTR_UNUSED_38;
+ x = _LIB9P_GETATTR_UNUSED_38;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_39
- x = _LIB9P_GETATTR_UNUSED_39;
+ x = _LIB9P_GETATTR_UNUSED_39;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_40
- x = _LIB9P_GETATTR_UNUSED_40;
+ x = _LIB9P_GETATTR_UNUSED_40;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_41
- x = _LIB9P_GETATTR_UNUSED_41;
+ x = _LIB9P_GETATTR_UNUSED_41;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_42
- x = _LIB9P_GETATTR_UNUSED_42;
+ x = _LIB9P_GETATTR_UNUSED_42;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_43
- x = _LIB9P_GETATTR_UNUSED_43;
+ x = _LIB9P_GETATTR_UNUSED_43;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_44
- x = _LIB9P_GETATTR_UNUSED_44;
+ x = _LIB9P_GETATTR_UNUSED_44;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_45
- x = _LIB9P_GETATTR_UNUSED_45;
+ x = _LIB9P_GETATTR_UNUSED_45;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_46
- x = _LIB9P_GETATTR_UNUSED_46;
+ x = _LIB9P_GETATTR_UNUSED_46;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_47
- x = _LIB9P_GETATTR_UNUSED_47;
+ x = _LIB9P_GETATTR_UNUSED_47;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_48
- x = _LIB9P_GETATTR_UNUSED_48;
+ x = _LIB9P_GETATTR_UNUSED_48;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_49
- x = _LIB9P_GETATTR_UNUSED_49;
+ x = _LIB9P_GETATTR_UNUSED_49;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_50
- x = _LIB9P_GETATTR_UNUSED_50;
+ x = _LIB9P_GETATTR_UNUSED_50;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_51
- x = _LIB9P_GETATTR_UNUSED_51;
+ x = _LIB9P_GETATTR_UNUSED_51;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_52
- x = _LIB9P_GETATTR_UNUSED_52;
+ x = _LIB9P_GETATTR_UNUSED_52;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_53
- x = _LIB9P_GETATTR_UNUSED_53;
+ x = _LIB9P_GETATTR_UNUSED_53;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_54
- x = _LIB9P_GETATTR_UNUSED_54;
+ x = _LIB9P_GETATTR_UNUSED_54;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_55
- x = _LIB9P_GETATTR_UNUSED_55;
+ x = _LIB9P_GETATTR_UNUSED_55;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_56
- x = _LIB9P_GETATTR_UNUSED_56;
+ x = _LIB9P_GETATTR_UNUSED_56;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_57
- x = _LIB9P_GETATTR_UNUSED_57;
+ x = _LIB9P_GETATTR_UNUSED_57;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_58
- x = _LIB9P_GETATTR_UNUSED_58;
+ x = _LIB9P_GETATTR_UNUSED_58;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_59
- x = _LIB9P_GETATTR_UNUSED_59;
+ x = _LIB9P_GETATTR_UNUSED_59;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_60
- x = _LIB9P_GETATTR_UNUSED_60;
+ x = _LIB9P_GETATTR_UNUSED_60;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_61
- x = _LIB9P_GETATTR_UNUSED_61;
+ x = _LIB9P_GETATTR_UNUSED_61;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_62
- x = _LIB9P_GETATTR_UNUSED_62;
+ x = _LIB9P_GETATTR_UNUSED_62;
#endif
#ifdef _LIB9P_GETATTR_UNUSED_63
- x = _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_10;
#endif
#ifdef _LIB9P_LOCK_FLAGS_UNUSED_11
- x = _LIB9P_LOCK_FLAGS_UNUSED_11;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_11;
#endif
#ifdef _LIB9P_LOCK_FLAGS_UNUSED_12
- x = _LIB9P_LOCK_FLAGS_UNUSED_12;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_12;
#endif
#ifdef _LIB9P_LOCK_FLAGS_UNUSED_13
- x = _LIB9P_LOCK_FLAGS_UNUSED_13;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_13;
#endif
#ifdef _LIB9P_LOCK_FLAGS_UNUSED_14
- x = _LIB9P_LOCK_FLAGS_UNUSED_14;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_14;
#endif
#ifdef _LIB9P_LOCK_FLAGS_UNUSED_15
- x = _LIB9P_LOCK_FLAGS_UNUSED_15;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_15;
#endif
#ifdef _LIB9P_LOCK_FLAGS_UNUSED_16
- x = _LIB9P_LOCK_FLAGS_UNUSED_16;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_16;
#endif
#ifdef _LIB9P_LOCK_FLAGS_UNUSED_17
- x = _LIB9P_LOCK_FLAGS_UNUSED_17;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_17;
#endif
#ifdef _LIB9P_LOCK_FLAGS_UNUSED_18
- x = _LIB9P_LOCK_FLAGS_UNUSED_18;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_18;
#endif
#ifdef _LIB9P_LOCK_FLAGS_UNUSED_19
- x = _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_UNUSED_2;
#endif
#ifdef _LIB9P_LOCK_FLAGS_UNUSED_20
- x = _LIB9P_LOCK_FLAGS_UNUSED_20;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_20;
#endif
#ifdef _LIB9P_LOCK_FLAGS_UNUSED_21
- x = _LIB9P_LOCK_FLAGS_UNUSED_21;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_21;
#endif
#ifdef _LIB9P_LOCK_FLAGS_UNUSED_22
- x = _LIB9P_LOCK_FLAGS_UNUSED_22;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_22;
#endif
#ifdef _LIB9P_LOCK_FLAGS_UNUSED_23
- x = _LIB9P_LOCK_FLAGS_UNUSED_23;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_23;
#endif
#ifdef _LIB9P_LOCK_FLAGS_UNUSED_24
- x = _LIB9P_LOCK_FLAGS_UNUSED_24;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_24;
#endif
#ifdef _LIB9P_LOCK_FLAGS_UNUSED_25
- x = _LIB9P_LOCK_FLAGS_UNUSED_25;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_25;
#endif
#ifdef _LIB9P_LOCK_FLAGS_UNUSED_26
- x = _LIB9P_LOCK_FLAGS_UNUSED_26;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_26;
#endif
#ifdef _LIB9P_LOCK_FLAGS_UNUSED_27
- x = _LIB9P_LOCK_FLAGS_UNUSED_27;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_27;
#endif
#ifdef _LIB9P_LOCK_FLAGS_UNUSED_28
- x = _LIB9P_LOCK_FLAGS_UNUSED_28;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_28;
#endif
#ifdef _LIB9P_LOCK_FLAGS_UNUSED_29
- x = _LIB9P_LOCK_FLAGS_UNUSED_29;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_29;
#endif
#ifdef _LIB9P_LOCK_FLAGS_UNUSED_3
- x = _LIB9P_LOCK_FLAGS_UNUSED_3;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_3;
#endif
#ifdef _LIB9P_LOCK_FLAGS_UNUSED_30
- x = _LIB9P_LOCK_FLAGS_UNUSED_30;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_30;
#endif
#ifdef _LIB9P_LOCK_FLAGS_UNUSED_31
- x = _LIB9P_LOCK_FLAGS_UNUSED_31;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_31;
#endif
#ifdef _LIB9P_LOCK_FLAGS_UNUSED_4
- x = _LIB9P_LOCK_FLAGS_UNUSED_4;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_4;
#endif
#ifdef _LIB9P_LOCK_FLAGS_UNUSED_5
- x = _LIB9P_LOCK_FLAGS_UNUSED_5;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_5;
#endif
#ifdef _LIB9P_LOCK_FLAGS_UNUSED_6
- x = _LIB9P_LOCK_FLAGS_UNUSED_6;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_6;
#endif
#ifdef _LIB9P_LOCK_FLAGS_UNUSED_7
- x = _LIB9P_LOCK_FLAGS_UNUSED_7;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_7;
#endif
#ifdef _LIB9P_LOCK_FLAGS_UNUSED_8
- x = _LIB9P_LOCK_FLAGS_UNUSED_8;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_8;
#endif
#ifdef _LIB9P_LOCK_FLAGS_UNUSED_9
- x = _LIB9P_LOCK_FLAGS_UNUSED_9;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_9;
#endif
#ifdef _LIB9P_LO_UNUSED_2
- x = _LIB9P_LO_UNUSED_2;
+ x = _LIB9P_LO_UNUSED_2;
#endif
#ifdef _LIB9P_LO_UNUSED_21
- x = _LIB9P_LO_UNUSED_21;
+ x = _LIB9P_LO_UNUSED_21;
#endif
#ifdef _LIB9P_LO_UNUSED_22
- x = _LIB9P_LO_UNUSED_22;
+ x = _LIB9P_LO_UNUSED_22;
#endif
#ifdef _LIB9P_LO_UNUSED_23
- x = _LIB9P_LO_UNUSED_23;
+ x = _LIB9P_LO_UNUSED_23;
#endif
#ifdef _LIB9P_LO_UNUSED_24
- x = _LIB9P_LO_UNUSED_24;
+ x = _LIB9P_LO_UNUSED_24;
#endif
#ifdef _LIB9P_LO_UNUSED_25
- x = _LIB9P_LO_UNUSED_25;
+ x = _LIB9P_LO_UNUSED_25;
#endif
#ifdef _LIB9P_LO_UNUSED_26
- x = _LIB9P_LO_UNUSED_26;
+ x = _LIB9P_LO_UNUSED_26;
#endif
#ifdef _LIB9P_LO_UNUSED_27
- x = _LIB9P_LO_UNUSED_27;
+ x = _LIB9P_LO_UNUSED_27;
#endif
#ifdef _LIB9P_LO_UNUSED_28
- x = _LIB9P_LO_UNUSED_28;
+ x = _LIB9P_LO_UNUSED_28;
#endif
#ifdef _LIB9P_LO_UNUSED_29
- x = _LIB9P_LO_UNUSED_29;
+ x = _LIB9P_LO_UNUSED_29;
#endif
#ifdef _LIB9P_LO_UNUSED_3
- x = _LIB9P_LO_UNUSED_3;
+ x = _LIB9P_LO_UNUSED_3;
#endif
#ifdef _LIB9P_LO_UNUSED_30
- x = _LIB9P_LO_UNUSED_30;
+ x = _LIB9P_LO_UNUSED_30;
#endif
#ifdef _LIB9P_LO_UNUSED_31
- x = _LIB9P_LO_UNUSED_31;
+ x = _LIB9P_LO_UNUSED_31;
#endif
#ifdef _LIB9P_LO_UNUSED_4
- x = _LIB9P_LO_UNUSED_4;
+ x = _LIB9P_LO_UNUSED_4;
#endif
#ifdef _LIB9P_LO_UNUSED_5
- x = _LIB9P_LO_UNUSED_5;
+ x = _LIB9P_LO_UNUSED_5;
#endif
#ifdef _LIB9P_MODE_UNUSED_16
- x = _LIB9P_MODE_UNUSED_16;
+ x = _LIB9P_MODE_UNUSED_16;
#endif
#ifdef _LIB9P_MODE_UNUSED_17
- x = _LIB9P_MODE_UNUSED_17;
+ x = _LIB9P_MODE_UNUSED_17;
#endif
#ifdef _LIB9P_MODE_UNUSED_18
- x = _LIB9P_MODE_UNUSED_18;
+ x = _LIB9P_MODE_UNUSED_18;
#endif
#ifdef _LIB9P_MODE_UNUSED_19
- x = _LIB9P_MODE_UNUSED_19;
+ x = _LIB9P_MODE_UNUSED_19;
#endif
#ifdef _LIB9P_MODE_UNUSED_20
- x = _LIB9P_MODE_UNUSED_20;
+ x = _LIB9P_MODE_UNUSED_20;
#endif
#ifdef _LIB9P_MODE_UNUSED_21
- x = _LIB9P_MODE_UNUSED_21;
+ x = _LIB9P_MODE_UNUSED_21;
#endif
#ifdef _LIB9P_MODE_UNUSED_22
- x = _LIB9P_MODE_UNUSED_22;
+ x = _LIB9P_MODE_UNUSED_22;
#endif
#ifdef _LIB9P_MODE_UNUSED_23
- x = _LIB9P_MODE_UNUSED_23;
+ x = _LIB9P_MODE_UNUSED_23;
#endif
#ifdef _LIB9P_MODE_UNUSED_24
- x = _LIB9P_MODE_UNUSED_24;
+ x = _LIB9P_MODE_UNUSED_24;
#endif
#ifdef _LIB9P_MODE_UNUSED_25
- x = _LIB9P_MODE_UNUSED_25;
+ x = _LIB9P_MODE_UNUSED_25;
#endif
#ifdef _LIB9P_MODE_UNUSED_26
- x = _LIB9P_MODE_UNUSED_26;
+ x = _LIB9P_MODE_UNUSED_26;
#endif
#ifdef _LIB9P_MODE_UNUSED_27
- x = _LIB9P_MODE_UNUSED_27;
+ x = _LIB9P_MODE_UNUSED_27;
#endif
#ifdef _LIB9P_MODE_UNUSED_28
- x = _LIB9P_MODE_UNUSED_28;
+ x = _LIB9P_MODE_UNUSED_28;
#endif
#ifdef _LIB9P_MODE_UNUSED_29
- x = _LIB9P_MODE_UNUSED_29;
+ x = _LIB9P_MODE_UNUSED_29;
#endif
#ifdef _LIB9P_MODE_UNUSED_30
- x = _LIB9P_MODE_UNUSED_30;
+ x = _LIB9P_MODE_UNUSED_30;
#endif
#ifdef _LIB9P_MODE_UNUSED_31
- x = _LIB9P_MODE_UNUSED_31;
+ x = _LIB9P_MODE_UNUSED_31;
#endif
#ifdef _LIB9P_O_RESERVED_CEXEC
- x = _LIB9P_O_RESERVED_CEXEC;
+ x = _LIB9P_O_RESERVED_CEXEC;
#endif
#ifdef _LIB9P_O_UNUSED_2
- x = _LIB9P_O_UNUSED_2;
+ x = _LIB9P_O_UNUSED_2;
#endif
#ifdef _LIB9P_O_UNUSED_3
- x = _LIB9P_O_UNUSED_3;
+ x = _LIB9P_O_UNUSED_3;
#endif
#ifdef _LIB9P_O_UNUSED_7
- x = _LIB9P_O_UNUSED_7;
+ x = _LIB9P_O_UNUSED_7;
#endif
#ifdef _LIB9P_QT_PLAN9_MOUNT
- x = _LIB9P_QT_PLAN9_MOUNT;
+ x = _LIB9P_QT_PLAN9_MOUNT;
#endif
#ifdef _LIB9P_QT_UNUSED_0
- x = _LIB9P_QT_UNUSED_0;
+ x = _LIB9P_QT_UNUSED_0;
#endif
#ifdef _LIB9P_SETATTR_UNUSED_10
- x = _LIB9P_SETATTR_UNUSED_10;
+ x = _LIB9P_SETATTR_UNUSED_10;
#endif
#ifdef _LIB9P_SETATTR_UNUSED_11
- x = _LIB9P_SETATTR_UNUSED_11;
+ x = _LIB9P_SETATTR_UNUSED_11;
#endif
#ifdef _LIB9P_SETATTR_UNUSED_12
- x = _LIB9P_SETATTR_UNUSED_12;
+ x = _LIB9P_SETATTR_UNUSED_12;
#endif
#ifdef _LIB9P_SETATTR_UNUSED_13
- x = _LIB9P_SETATTR_UNUSED_13;
+ x = _LIB9P_SETATTR_UNUSED_13;
#endif
#ifdef _LIB9P_SETATTR_UNUSED_14
- x = _LIB9P_SETATTR_UNUSED_14;
+ x = _LIB9P_SETATTR_UNUSED_14;
#endif
#ifdef _LIB9P_SETATTR_UNUSED_15
- x = _LIB9P_SETATTR_UNUSED_15;
+ x = _LIB9P_SETATTR_UNUSED_15;
#endif
#ifdef _LIB9P_SETATTR_UNUSED_16
- x = _LIB9P_SETATTR_UNUSED_16;
+ x = _LIB9P_SETATTR_UNUSED_16;
#endif
#ifdef _LIB9P_SETATTR_UNUSED_17
- x = _LIB9P_SETATTR_UNUSED_17;
+ x = _LIB9P_SETATTR_UNUSED_17;
#endif
#ifdef _LIB9P_SETATTR_UNUSED_18
- x = _LIB9P_SETATTR_UNUSED_18;
+ x = _LIB9P_SETATTR_UNUSED_18;
#endif
#ifdef _LIB9P_SETATTR_UNUSED_19
- x = _LIB9P_SETATTR_UNUSED_19;
+ x = _LIB9P_SETATTR_UNUSED_19;
#endif
#ifdef _LIB9P_SETATTR_UNUSED_20
- x = _LIB9P_SETATTR_UNUSED_20;
+ x = _LIB9P_SETATTR_UNUSED_20;
#endif
#ifdef _LIB9P_SETATTR_UNUSED_21
- x = _LIB9P_SETATTR_UNUSED_21;
+ x = _LIB9P_SETATTR_UNUSED_21;
#endif
#ifdef _LIB9P_SETATTR_UNUSED_22
- x = _LIB9P_SETATTR_UNUSED_22;
+ x = _LIB9P_SETATTR_UNUSED_22;
#endif
#ifdef _LIB9P_SETATTR_UNUSED_23
- x = _LIB9P_SETATTR_UNUSED_23;
+ x = _LIB9P_SETATTR_UNUSED_23;
#endif
#ifdef _LIB9P_SETATTR_UNUSED_24
- x = _LIB9P_SETATTR_UNUSED_24;
+ x = _LIB9P_SETATTR_UNUSED_24;
#endif
#ifdef _LIB9P_SETATTR_UNUSED_25
- x = _LIB9P_SETATTR_UNUSED_25;
+ x = _LIB9P_SETATTR_UNUSED_25;
#endif
#ifdef _LIB9P_SETATTR_UNUSED_26
- x = _LIB9P_SETATTR_UNUSED_26;
+ x = _LIB9P_SETATTR_UNUSED_26;
#endif
#ifdef _LIB9P_SETATTR_UNUSED_27
- x = _LIB9P_SETATTR_UNUSED_27;
+ x = _LIB9P_SETATTR_UNUSED_27;
#endif
#ifdef _LIB9P_SETATTR_UNUSED_28
- x = _LIB9P_SETATTR_UNUSED_28;
+ x = _LIB9P_SETATTR_UNUSED_28;
#endif
#ifdef _LIB9P_SETATTR_UNUSED_29
- x = _LIB9P_SETATTR_UNUSED_29;
+ x = _LIB9P_SETATTR_UNUSED_29;
#endif
#ifdef _LIB9P_SETATTR_UNUSED_30
- x = _LIB9P_SETATTR_UNUSED_30;
+ x = _LIB9P_SETATTR_UNUSED_30;
#endif
#ifdef _LIB9P_SETATTR_UNUSED_31
- x = _LIB9P_SETATTR_UNUSED_31;
+ x = _LIB9P_SETATTR_UNUSED_31;
#endif
#ifdef _LIB9P_SETATTR_UNUSED_9
- x = _LIB9P_SETATTR_UNUSED_9;
+ x = _LIB9P_SETATTR_UNUSED_9;
#endif
- return 0;
+ return 0;
}
diff --git a/lib9p/tests/test_compile.c.gen b/lib9p/tests/test_compile.c.gen
index c57ce9f..ef2aee6 100755
--- a/lib9p/tests/test_compile.c.gen
+++ b/lib9p/tests/test_compile.c.gen
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/usr/bin/env bash
# lib9p/tests/test_compile.c.gen - Generate code to make sure all generated macros work
#
# Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
@@ -12,8 +12,8 @@ outfile=$2
echo
echo "#include <lib9p/core.h>"
echo 'int main(void) {'
- echo ' [[maybe_unused]] uint64_t x;'
- <"$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 $'\t[[maybe_unused]] uint64_t x;'
+ <"$generated_h" sed -nE 's/^\s*#\s*define\s*(\S[^ (]*)\s.*/\1/p' | LC_COLLATE=C sort -u | sed $'s/.*/#ifdef &\\n\tx = &;\\n#endif/'
+ echo $'\treturn 0;'
echo '}'
} >"$outfile"
diff --git a/lib9p/tests/test_compile_config/config.h b/lib9p/tests/test_compile_config/config.h
index 02cb8e5..c0846ef 100644
--- a/lib9p/tests/test_compile_config/config.h
+++ b/lib9p/tests/test_compile_config/config.h
@@ -1,4 +1,4 @@
-/* config.h - Compile-time configuration for lib9p/test/test_compile
+/* lib9p/tests/test_compile_config/config.h - Compile-time configuration for lib9p/test/test_compile
*
* Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
@@ -9,23 +9,18 @@
/* 9P *************************************************************************/
-#define CONFIG_9P_MAX_ERR_SIZE 128
#define CONFIG_9P_MAX_9P2000_e_WELEM 16
/* 9P_SRV *********************************************************************/
+#define CONFIG_9P_SRV_DEBUG 1
+#define CONFIG_9P_SRV_MAX_ERR_SIZE 128
#define CONFIG_9P_SRV_MAX_MSG_SIZE ((4*1024)+24)
#define CONFIG_9P_SRV_MAX_HOSTMSG_SIZE CONFIG_9P_SRV_MAX_MSG_SIZE+16
/* COROUTINE ******************************************************************/
-#define CONFIG_COROUTINE_STACK_SIZE_DEFAULT (32*1024)
#define CONFIG_COROUTINE_NAME_LEN 16
#define CONFIG_COROUTINE_MEASURE_STACK 1 /* bool */
-#define CONFIG_COROUTINE_PROTECT_STACK 1 /* bool */
-#define CONFIG_COROUTINE_DEBUG 0 /* bool */
-#define CONFIG_COROUTINE_VALGRIND 1 /* bool */
-#define CONFIG_COROUTINE_GDB 1 /* bool */
-#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 c61d344..76b6ff3 100644
--- a/lib9p/tests/test_server/CMakeLists.txt
+++ b/lib9p/tests/test_server/CMakeLists.txt
@@ -5,17 +5,15 @@
if (PICO_PLATFORM STREQUAL "host")
-# Compile ######################################################################
-
-add_library(test_server_objs OBJECT
+add_executable(test_server
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})
-target_link_libraries(test_server_objs
+target_include_directories(test_server PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/config)
+target_include_directories(test_server PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) # for static.h
+target_link_libraries(test_server
libcr
libcr_ipc
libmisc
@@ -23,21 +21,7 @@ target_link_libraries(test_server_objs
libhw_cr
)
-# Analyze the stack ############################################################
-
-add_stack_analysis(test_server_stack.c test_server_objs)
-
-# Link #########################################################################
-
-add_executable(test_server)
-target_sources(test_server PRIVATE
- test_server_stack.c
- "$<TARGET_OBJECTS:test_server_objs>"
-)
-
-# Embed ########################################################################
-
-target_embed_sources(test_server_objs test_server static.h
+target_embed_sources(test_server test_server static.h
static/README.md
static/Documentation/x.txt
)
diff --git a/lib9p/tests/test_server/config/config.h b/lib9p/tests/test_server/config/config.h
index f49894b..1af0213 100644
--- a/lib9p/tests/test_server/config/config.h
+++ b/lib9p/tests/test_server/config/config.h
@@ -1,4 +1,4 @@
-/* config.h - Compile-time configuration for lib9p/test/test_server
+/* lib9p/tests/test_server/config/config.h - Compile-time configuration for lib9p/tests/test_server
*
* Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
@@ -12,8 +12,6 @@
/* 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 */
@@ -42,6 +40,7 @@
* (8*1024)+160 in 2e and 3e.
*/
#define CONFIG_9P_SRV_MAX_MSG_SIZE ((4*1024)+24)
+#define CONFIG_9P_SRV_MAX_ERR_SIZE 128 /* 128 is what Plan 9 4e uses */
/**
* Maximum host-data-structure size. A message may be larger in
* unmarshaled-host-structures than marshaled-net-bytes due to (1)
@@ -58,10 +57,9 @@
#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_9P_MAX_CONNS /* accept+read */ + \
- _CONFIG_9P_MAX_REQS /* work+write */ )
+#define CONFIG_COROUTINE_NUM ( \
+ 1 /* init_cr */ + \
+ _CONFIG_9P_MAX_CONNS /* read_cr */ + \
+ _CONFIG_9P_MAX_REQS /* write_cr */ )
#endif /* _CONFIG_H_ */
diff --git a/lib9p/tests/test_server/fs_flush.c b/lib9p/tests/test_server/fs_flush.c
index e6408d7..c8152d4 100644
--- a/lib9p/tests/test_server/fs_flush.c
+++ b/lib9p/tests/test_server/fs_flush.c
@@ -9,20 +9,19 @@
#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);
+LO_IMPLEMENTATION_C(lib9p_srv_file, struct flush_file, flush_file);
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);
+LO_IMPLEMENTATION_STATIC(lib9p_srv_fio, struct flush_fio, flush_fio);
/* srv_file *******************************************************************/
-static void flush_file_free(struct flush_file *self) {
+void flush_file_free(struct flush_file *self) {
assert(self);
}
-static struct lib9p_qid flush_file_qid(struct flush_file *self) {
+struct lib9p_qid flush_file_qid(struct flush_file *self) {
assert(self);
return (struct lib9p_qid){
.type = LIB9P_QT_FILE,
@@ -31,10 +30,12 @@ static struct lib9p_qid flush_file_qid(struct flush_file *self) {
};
}
-static struct lib9p_srv_stat flush_file_stat(struct flush_file *self, struct lib9p_srv_ctx *ctx) {
+error flush_file_stat(struct flush_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_srv_stat *out) {
assert(self);
assert(ctx);
- return (struct lib9p_srv_stat){
+ assert(out);
+
+ *out = ((struct lib9p_srv_stat){
.qid = flush_file_qid(self),
.mode = 0444,
.atime_sec = UTIL9P_ATIME,
@@ -45,29 +46,30 @@ static struct lib9p_srv_stat flush_file_stat(struct flush_file *self, struct lib
.owner_gid = { .name = lib9p_str("root"), .num = 0 },
.last_modifier_uid = { .name = lib9p_str("root"), .num = 0 },
.extension = lib9p_str(NULL),
- };
+ });
+ return ERROR_NULL;
}
-static void flush_file_wstat(struct flush_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_srv_stat) {
+error 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");
+ return error_new(E_POSIX_EROFS, "cannot wstat API file");
}
-static void flush_file_remove(struct flush_file *self, struct lib9p_srv_ctx *ctx) {
+error 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");
+ return error_new(E_POSIX_EROFS, "cannot remove API file");
}
-LIB9P_SRV_NOTDIR(struct flush_file, flush_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) {
+lib9p_srv_fio_or_error 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);
+ return ERROR_NEW_VAL(lib9p_srv_fio, LO_BOX(lib9p_srv_fio, ret));
}
/* srv_fio ********************************************************************/
@@ -77,7 +79,7 @@ static void flush_fio_iofree(struct flush_fio *self) {
free(self);
}
-static struct lib9p_qid flush_fio_qid(struct flush_fio *self) {
+static struct lib9p_qid flush_fio_ioqid(struct flush_fio *self) {
assert(self);
return flush_file_qid(self->parent);
}
@@ -87,19 +89,17 @@ static uint32_t flush_fio_iounit(struct flush_fio *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)) {
+static uint32_t_or_error flush_fio_pwrite(struct flush_fio *LM_UNUSED(self), struct lib9p_srv_ctx *LM_UNUSED(ctx),
+ const 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) {
+static error flush_fio_pread(struct flush_fio *self, struct lib9p_srv_ctx *ctx,
+ lo_interface io_writer dst, uint64_t LM_UNUSED(src_offset), uint32_t byte_count) {
assert(self);
assert(ctx);
- assert(ret);
/* Wait for first Tflush */
while (!lib9p_srv_flush_requested(ctx))
@@ -111,21 +111,18 @@ static void flush_fio_pread(struct flush_fio *self, struct lib9p_srv_ctx *ctx,
while (cr_chan_num_waiters(&ctx->flush_ch) != self->parent->flush_cnt)
cr_yield();
+ /* Yield one more time, just because. */
+ 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;
+ return io_write(dst, "Sloth\n", 6 < byte_count ? 6 : byte_count).err;
case FLUSH_ERROR:
- lib9p_srv_acknowledge_flush(ctx);
- lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_ECANCELED, "request canceled by flush");
- break;
+ return error_new(E_POSIX_EAGAIN, "request canceled by flush");
case FLUSH_SILENT:
- lib9p_srv_acknowledge_flush(ctx);
- break;
+ return error_new(E_POSIX_ECANCELED, "request canceled by flush");
+ default:
+ assert_notreached("invalid flush_behavior");
}
- cr_yield();
}
diff --git a/lib9p/tests/test_server/fs_flush.h b/lib9p/tests/test_server/fs_flush.h
index a509c4a..023434b 100644
--- a/lib9p/tests/test_server/fs_flush.h
+++ b/lib9p/tests/test_server/fs_flush.h
@@ -7,8 +7,8 @@
#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>
+#include <util9p/static.h>
struct flush_file {
char *name;
@@ -22,6 +22,5 @@ struct flush_file {
} 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
index d4ae67e..53a243b 100644
--- a/lib9p/tests/test_server/fs_shutdown.c
+++ b/lib9p/tests/test_server/fs_shutdown.c
@@ -8,20 +8,19 @@
#include "fs_shutdown.h"
-LO_IMPLEMENTATION_C(lib9p_srv_file, struct shutdown_file, shutdown_file, static);
+LO_IMPLEMENTATION_C(lib9p_srv_file, struct shutdown_file, shutdown_file);
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);
+LO_IMPLEMENTATION_STATIC(lib9p_srv_fio, struct shutdown_fio, shutdown_fio);
/* srv_file *******************************************************************/
-static void shutdown_file_free(struct shutdown_file *self) {
+void shutdown_file_free(struct shutdown_file *self) {
assert(self);
}
-static struct lib9p_qid shutdown_file_qid(struct shutdown_file *self) {
+struct lib9p_qid shutdown_file_qid(struct shutdown_file *self) {
assert(self);
return (struct lib9p_qid){
.type = LIB9P_QT_FILE | LIB9P_QT_APPEND,
@@ -30,10 +29,12 @@ static struct lib9p_qid shutdown_file_qid(struct shutdown_file *self) {
};
}
-static struct lib9p_srv_stat shutdown_file_stat(struct shutdown_file *self, struct lib9p_srv_ctx *ctx) {
+error shutdown_file_stat(struct shutdown_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_srv_stat *out) {
assert(self);
assert(ctx);
- return (struct lib9p_srv_stat){
+ assert(out);
+
+ *out = ((struct lib9p_srv_stat){
.qid = shutdown_file_qid(self),
.mode = 0222 | LIB9P_DM_APPEND,
.atime_sec = UTIL9P_ATIME,
@@ -44,29 +45,30 @@ static struct lib9p_srv_stat shutdown_file_stat(struct shutdown_file *self, stru
.owner_gid = { .name=lib9p_str("root"), .num=0 },
.last_modifier_uid = { .name=lib9p_str("root"), .num=0 },
.extension = lib9p_str(NULL),
- };
+ });
+ return ERROR_NULL;
}
-static void shutdown_file_wstat(struct shutdown_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_srv_stat) {
+error 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");
+ return error_new(E_POSIX_EROFS, "cannot wstat API file");
}
-static void shutdown_file_remove(struct shutdown_file *self, struct lib9p_srv_ctx *ctx) {
+error 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");
+ return error_new(E_POSIX_EROFS, "cannot remove API file");
}
-LIB9P_SRV_NOTDIR(struct shutdown_file, shutdown_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) {
+lib9p_srv_fio_or_error 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);
+ return ERROR_NEW_VAL(lib9p_srv_fio, LO_BOX(lib9p_srv_fio, ret));
}
/* srv_fio ********************************************************************/
@@ -76,7 +78,7 @@ static void shutdown_fio_iofree(struct shutdown_fio *self) {
free(self);
}
-static struct lib9p_qid shutdown_fio_qid(struct shutdown_fio *self) {
+static struct lib9p_qid shutdown_fio_ioqid(struct shutdown_fio *self) {
assert(self);
return shutdown_file_qid(self->parent);
}
@@ -86,19 +88,21 @@ static uint32_t shutdown_fio_iounit(struct shutdown_fio *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) {
+static uint32_t_or_error shutdown_fio_pwrite(struct shutdown_fio *self, struct lib9p_srv_ctx *ctx,
+ const void *buf,
+ uint32_t byte_count,
+ uint64_t offset) {
assert(self);
assert(ctx);
assert(buf);
assert(offset == 0);
if (byte_count == 0)
- return 0;
+ return ERROR_NEW_VAL(uint32_t, 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;
+ LO_CALL(LO_BOX(net_stream_listener, &self->parent->listeners[i]), close);
+ return ERROR_NEW_VAL(uint32_t, 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)) {
+static error shutdown_fio_pread(struct shutdown_fio *LM_UNUSED(self), struct lib9p_srv_ctx *LM_UNUSED(ctx),
+ lo_interface io_writer LM_UNUSED(dst), uint64_t LM_UNUSED(src_offset), uint32_t LM_UNUSED(count)) {
assert_notreached("not readable");
}
diff --git a/lib9p/tests/test_server/fs_shutdown.h b/lib9p/tests/test_server/fs_shutdown.h
index 65956db..7b8d327 100644
--- a/lib9p/tests/test_server/fs_shutdown.h
+++ b/lib9p/tests/test_server/fs_shutdown.h
@@ -7,8 +7,8 @@
#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>
+#include <util9p/static.h>
struct shutdown_file {
char *name;
@@ -18,6 +18,5 @@ struct shutdown_file {
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
index 8d9752a..a07fdba 100644
--- a/lib9p/tests/test_server/fs_whoami.c
+++ b/lib9p/tests/test_server/fs_whoami.c
@@ -4,22 +4,22 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-#include <stdio.h> /* for snprintf() */
-#include <stdlib.h> /* for realloc(), free() */
+#include <inttypes.h> /* for PRI* */
+#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);
+LO_IMPLEMENTATION_C(lib9p_srv_file, struct whoami_file, whoami_file);
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);
+LO_IMPLEMENTATION_STATIC(lib9p_srv_fio, struct whoami_fio, whoami_fio);
size_t whoami_len(struct lib9p_srv_ctx *ctx) {
assert(ctx);
@@ -40,10 +40,10 @@ size_t whoami_len(struct lib9p_srv_ctx *ctx) {
/* srv_file *******************************************************************/
-static void whoami_file_free(struct whoami_file *self) {
+void whoami_file_free(struct whoami_file *self) {
assert(self);
}
-static struct lib9p_qid whoami_file_qid(struct whoami_file *self) {
+struct lib9p_qid whoami_file_qid(struct whoami_file *self) {
assert(self);
return (struct lib9p_qid){
.type = LIB9P_QT_FILE,
@@ -52,11 +52,12 @@ static struct lib9p_qid whoami_file_qid(struct whoami_file *self) {
};
}
-static struct lib9p_srv_stat whoami_file_stat(struct whoami_file *self, struct lib9p_srv_ctx *ctx) {
+error whoami_file_stat(struct whoami_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_srv_stat *out) {
assert(self);
assert(ctx);
+ assert(out);
- return (struct lib9p_srv_stat){
+ *out = ((struct lib9p_srv_stat){
.qid = whoami_file_qid(self),
.mode = 0444,
.atime_sec = UTIL9P_ATIME,
@@ -67,22 +68,23 @@ static struct lib9p_srv_stat whoami_file_stat(struct whoami_file *self, struct l
.owner_gid = { .name=lib9p_str("root"), .num=0 },
.last_modifier_uid = { .name=lib9p_str("root"), .num=0 },
.extension = lib9p_str(NULL),
- };
+ });
+ return ERROR_NULL;
}
-static void whoami_file_wstat(struct whoami_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_srv_stat) {
+error 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");
+ return error_new(E_POSIX_EROFS, "cannot wstat API file");
}
-static void whoami_file_remove(struct whoami_file *self, struct lib9p_srv_ctx *ctx) {
+error 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");
+ return error_new(E_POSIX_EROFS, "cannot remove API file");
}
-LIB9P_SRV_NOTDIR(struct whoami_file, whoami_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) {
+lib9p_srv_fio_or_error whoami_file_fopen(struct whoami_file *self, struct lib9p_srv_ctx *ctx, bool, bool, bool) {
assert(self);
assert(ctx);
@@ -91,7 +93,7 @@ static lo_interface lib9p_srv_fio whoami_file_fopen(struct whoami_file *self, st
ret->buf_len = 0;
ret->buf = NULL;
- return lo_box_whoami_fio_as_lib9p_srv_fio(ret);
+ return ERROR_NEW_VAL(lib9p_srv_fio, LO_BOX(lib9p_srv_fio, ret));
}
/* srv_fio ********************************************************************/
@@ -103,7 +105,7 @@ static void whoami_fio_iofree(struct whoami_fio *self) {
free(self);
}
-static struct lib9p_qid whoami_fio_qid(struct whoami_fio *self) {
+static struct lib9p_qid whoami_fio_ioqid(struct whoami_fio *self) {
assert(self);
assert(self->parent);
return whoami_file_qid(self->parent);
@@ -114,18 +116,16 @@ static uint32_t whoami_fio_iounit(struct whoami_fio *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)) {
+static uint32_t_or_error whoami_fio_pwrite(struct whoami_fio *LM_UNUSED(self), struct lib9p_srv_ctx *LM_UNUSED(ctx),
+ const 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) {
+static error whoami_fio_pread(struct whoami_fio *self, struct lib9p_srv_ctx *ctx,
+ lo_interface io_writer dst, uint64_t byte_offset, uint32_t byte_count) {
assert(self);
assert(ctx);
- assert(ret);
size_t data_size = whoami_len(ctx);
if (self->buf_len < data_size+1) {
@@ -135,19 +135,13 @@ static void whoami_fio_pread(struct whoami_fio *self, struct lib9p_srv_ctx *ctx,
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;
- }
+ if (byte_offset > (uint64_t)data_size)
+ return error_new(E_POSIX_EINVAL, "offset is past end-of-file length");
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,
- };
+ return io_write(dst, &self->buf[beg_off], end_off-beg_off).err;
}
diff --git a/lib9p/tests/test_server/fs_whoami.h b/lib9p/tests/test_server/fs_whoami.h
index 0d3d311..518e11d 100644
--- a/lib9p/tests/test_server/fs_whoami.h
+++ b/lib9p/tests/test_server/fs_whoami.h
@@ -7,14 +7,13 @@
#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>
+#include <util9p/static.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 4caff16..0016d21 100644
--- a/lib9p/tests/test_server/main.c
+++ b/lib9p/tests/test_server/main.c
@@ -4,21 +4,26 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-#include <error.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h> /* for atoi() */
+#define error __error
+#include <error.h>
+#undef error
+
#include <lib9p/srv.h>
#include <libcr/coroutine.h>
-#include <libhw/generic/net.h>
#include <libhw/generic/alarmclock.h>
+#include <libhw/generic/net.h>
#include <libhw/host_alarmclock.h>
#include <libhw/host_net.h>
#include <libmisc/macro.h>
-#include <util9p/static.h>
#include "static.h"
+
+/* 9P files */
+#include <util9p/static.h>
#include "fs_flush.h"
#include "fs_shutdown.h"
#include "fs_whoami.h"
@@ -36,7 +41,7 @@
/* globals ********************************************************************/
-static lo_interface lib9p_srv_file get_root(struct lib9p_srv_ctx *, struct lib9p_s);
+static lib9p_srv_file_or_error get_root(struct lib9p_srv_ctx *, struct lib9p_s);
static const char *hexdig = "0123456789abcdef";
@@ -84,8 +89,8 @@ static struct lib9p_srv_file root =
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)) {
- return root;
+static lib9p_srv_file_or_error get_root(struct lib9p_srv_ctx *LM_UNUSED(ctx), struct lib9p_s LM_UNUSED(treename)) {
+ return ERROR_NEW_VAL(lib9p_srv_file, root);
}
/* main ***********************************************************************/
@@ -96,7 +101,7 @@ static COROUTINE read_cr(void *_i) {
hostnet_tcp_listener_init(&globals.listeners[i], globals.port);
- lib9p_srv_accept_and_read_loop(&globals.srv, lo_box_hostnet_tcplist_as_net_stream_listener(&globals.listeners[i]));
+ lib9p_srv_accept_and_read_loop(&globals.srv, LO_BOX(net_stream_listener, &globals.listeners[i]));
cr_end();
}
@@ -117,20 +122,19 @@ static COROUTINE init_cr(void *) {
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)");
+ __error(1, 0, "coroutine_add(read_cr, &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, write_cr, NULL))
- error(1, 0, "coroutine_add(write_cr, NULL)");
+ __error(1, 0, "coroutine_add(write_cr, NULL)");
}
cr_exit();
}
struct tstlog_stdout {};
-LO_IMPLEMENTATION_H(fmt_dest, struct tstlog_stdout, tstlog_stdout);
-LO_IMPLEMENTATION_C(fmt_dest, struct tstlog_stdout, tstlog_stdout, static);
+LO_IMPLEMENTATION_STATIC(fmt_dest, struct tstlog_stdout, tstlog_stdout);
static size_t tstlog_bytes = 0;
@@ -153,18 +157,18 @@ static void tstlog_msg(struct lib9p_srv_ctx *ctx, enum lib9p_msg_type typ, void
int main(int argc, char *argv[]) {
if (argc != 3)
- error(2, 0, "usage: %s PORT_NUMBER LOGFILE", argv[0]);
+ __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");
+ __error(2, errno, "fopen");
globals.srv.msglog = tstlog_msg;
struct hostclock clock_monotonic = {
.clock_id = CLOCK_MONOTONIC,
};
- bootclock = lo_box_hostclock_as_alarmclock(&clock_monotonic);
+ bootclock = LO_BOX(alarmclock, &clock_monotonic);
coroutine_add("init", init_cr, NULL);
coroutine_main();
fclose(globals.logstream);
diff --git a/lib9p/tests/testclient-hangup.c b/lib9p/tests/testclient-hangup.c
new file mode 100644
index 0000000..c59d647
--- /dev/null
+++ b/lib9p/tests/testclient-hangup.c
@@ -0,0 +1,100 @@
+/* lib9p/tests/testclient-hangup.c - Test the 9P `test_server`'s handling of TCP hangups
+ *
+ * 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 <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() */
+
+#define error __error
+#include <error.h>
+#undef error
+
+#include <lib9p/core.h>
+#include <libmisc/assert.h>
+#include <libmisc/endian.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;
+ error err = lib9p_Tmsg_marshal(ctx, typ, body, &buf);
+ assert(ERROR_IS_NULL(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, (const struct iovec *)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];
+
+ /**********************************************************************/
+
+ 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 */
+ 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");
+ return 0; /* Hang up without waiting for Rwrite. */
+}
diff --git a/lib9p/tests/testclient-hangup.explog b/lib9p/tests/testclient-hangup.explog
new file mode 100644
index 0000000..568b0fc
--- /dev/null
+++ b/lib9p/tests/testclient-hangup.explog
@@ -0,0 +1,14 @@
+# lib9p/tests/testclient-hangup.explog - Expected 9P logfile of testclient-hangup
+#
+# Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+> 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/tests/testclient-sess.c b/lib9p/tests/testclient-sess.c
index 7cb7f97..e90c94a 100644
--- a/lib9p/tests/testclient-sess.c
+++ b/lib9p/tests/testclient-sess.c
@@ -4,31 +4,34 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-#include <arpa/inet.h> /* for htons(), inet_addr() */
+#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 <stdlib.h> /* for atoi() */
#include <sys/socket.h> /* for socket(), connect() */
-#include <sys/uio.h> /* for writev() */
-#include <unistd.h> /* for read() */
+#include <sys/uio.h> /* for writev() */
+#include <unistd.h> /* for read() */
+
+#define error __error
+#include <error.h>
+#undef error
+#include <lib9p/core.h>
#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);
+ error err = lib9p_Tmsg_marshal(ctx, typ, body, &buf);
+ assert(ERROR_IS_NULL(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);
+ ssize_t act = writev(fd, (const struct iovec *)buf.iov, buf.iov_cnt);
if (act < 0)
- error(1, errno, "writev");
+ __error(1, errno, "writev");
assert((size_t)act == exp);
}
@@ -41,7 +44,7 @@ static void _recv9p(int fd) {
while (done < goal) {
ssize_t n = read(fd, &buf[done], goal-done);
if (n < 0)
- error(1, errno, "read");
+ __error(1, errno, "read");
done += n;
}
goal = uint32le_decode(buf);
@@ -49,7 +52,7 @@ static void _recv9p(int fd) {
while (done < goal) {
ssize_t n = read(fd, &buf[done], goal-done);
if (n < 0)
- error(1, errno, "read");
+ __error(1, errno, "read");
done += n;
}
}
@@ -58,7 +61,7 @@ static void _recv9p(int fd) {
int main(int argc, char *argv[]) {
if (argc != 2)
- error(2, 0, "Usage: %s SERVER_PORT", argv[0]);
+ __error(2, 0, "Usage: %s SERVER_PORT", argv[0]);
uint16_t server_port = atoi(argv[1]);
union {
@@ -71,9 +74,9 @@ int main(int argc, char *argv[]) {
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0)
- error(1, errno, "socket");
+ __error(1, errno, "socket");
if (connect(fd, &server_addr.gen, sizeof(server_addr)) < 0)
- error(1, errno, "connect");
+ __error(1, errno, "connect");
struct lib9p_ctx ctx = {
.max_msg_size = 16*1024,
diff --git a/lib9p/tests/testclient-sess.explog b/lib9p/tests/testclient-sess.explog
index a3838ac..ec8d9c9 100644
--- a/lib9p/tests/testclient-sess.explog
+++ b/lib9p/tests/testclient-sess.explog
@@ -103,7 +103,7 @@
< 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 }
+< Rerror { tag=0 errstr="request canceled by flush" errnum=L_EAGAIN }
< Rflush { tag=1 }
# flush, original request is aborted without error
diff --git a/lib9p_util/include/util9p/static.h b/lib9p_util/include/util9p/static.h
index 5454c24..4bb24c4 100644
--- a/lib9p_util/include/util9p/static.h
+++ b/lib9p_util/include/util9p/static.h
@@ -9,12 +9,6 @@
#include <lib9p/srv.h>
-#define util9p_box(nam, obj) \
- ((struct lib9p_srv_file){ \
- .self = obj, \
- .vtable = (void*)&_lo_##nam##_lib9p_srv_file_vtable, \
- })
-
#define UTIL9P_ATIME 1728337905
#define UTIL9P_MTIME 1728337904
@@ -56,7 +50,6 @@ struct util9p_static_dir {
lo_interface lib9p_srv_file members[];
};
LO_IMPLEMENTATION_H(lib9p_srv_file, struct util9p_static_dir, util9p_static_dir);
-#define lo_box_util9p_static_dir_as_lib9p_srv_file(obj) util9p_box(util9p_static_dir, obj)
#define UTIL9P_STATIC_DIR(PATH, STRNAME, ...) \
lo_box_util9p_static_dir_as_lib9p_srv_file(&((struct util9p_static_dir){ \
@@ -74,7 +67,6 @@ struct util9p_static_file {
size_t data_size; /* only used if .data_end==NULL */
};
LO_IMPLEMENTATION_H(lib9p_srv_file, struct util9p_static_file, util9p_static_file);
-#define lo_box_util9p_static_file_as_lib9p_srv_file(obj) util9p_box(util9p_static_file, obj)
#define UTIL9P_STATIC_FILE(PATH, STRNAME, ...) \
lo_box_util9p_static_file_as_lib9p_srv_file(&((struct util9p_static_file){ \
diff --git a/lib9p_util/static.c b/lib9p_util/static.c
index c35d28c..338e9c9 100644
--- a/lib9p_util/static.c
+++ b/lib9p_util/static.c
@@ -9,21 +9,18 @@
#include <util9p/static.h>
-LO_IMPLEMENTATION_C(lib9p_srv_file, struct util9p_static_dir, util9p_static_dir, static);
-LO_IMPLEMENTATION_C(lib9p_srv_file, struct util9p_static_file, util9p_static_file, static);
+LO_IMPLEMENTATION_C(lib9p_srv_file, struct util9p_static_dir, util9p_static_dir);
+LO_IMPLEMENTATION_C(lib9p_srv_file, struct util9p_static_file, util9p_static_file);
-LO_IMPLEMENTATION_H(lib9p_srv_dio, struct util9p_static_dir, util9p_static_dir);
-LO_IMPLEMENTATION_C(lib9p_srv_dio, struct util9p_static_dir, util9p_static_dir, static);
-
-LO_IMPLEMENTATION_H(lib9p_srv_fio, struct util9p_static_file, util9p_static_file);
-LO_IMPLEMENTATION_C(lib9p_srv_fio, struct util9p_static_file, util9p_static_file, static);
+LO_IMPLEMENTATION_STATIC(lib9p_srv_dio, struct util9p_static_dir, util9p_static_dio);
+LO_IMPLEMENTATION_STATIC(lib9p_srv_fio, struct util9p_static_file, util9p_static_fio);
/* dir ************************************************************************/
-static void util9p_static_dir_free(struct util9p_static_dir *self) {
+void util9p_static_dir_free(struct util9p_static_dir *self) {
assert(self);
}
-static struct lib9p_qid util9p_static_dir_qid(struct util9p_static_dir *self) {
+struct lib9p_qid util9p_static_dir_qid(struct util9p_static_dir *self) {
assert(self);
return (struct lib9p_qid){
@@ -33,11 +30,11 @@ static struct lib9p_qid util9p_static_dir_qid(struct util9p_static_dir *self) {
};
}
-static struct lib9p_srv_stat util9p_static_dir_stat(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx) {
+error util9p_static_dir_stat(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx, struct lib9p_srv_stat *out) {
assert(self);
assert(ctx);
- return (struct lib9p_srv_stat){
+ *out = ((struct lib9p_srv_stat){
.qid = util9p_static_dir_qid(self),
.mode = LIB9P_DM_DIR | (self->c.perm & 0555),
.atime_sec = self->c.atime,
@@ -48,88 +45,92 @@ static struct lib9p_srv_stat util9p_static_dir_stat(struct util9p_static_dir *se
.owner_gid = { .name = lib9p_str(self->c.g_name), .num = self->c.g_num },
.last_modifier_uid = { .name = lib9p_str(self->c.m_name), .num = self->c.m_num },
.extension = lib9p_str(NULL),
- };
+ });
+ return ERROR_NULL;
}
-static void util9p_static_dir_wstat(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx,
- struct lib9p_srv_stat) {
+error util9p_static_dir_wstat(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx,
+ struct lib9p_srv_stat) {
assert(self);
assert(ctx);
- lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "read-only part of filesystem");
+ return error_new(E_POSIX_EROFS, "read-only part of filesystem");
}
-static void util9p_static_dir_remove(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx) {
+error util9p_static_dir_remove(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx) {
assert(self);
assert(ctx);
- lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "read-only part of filesystem");
+ return error_new(E_POSIX_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,
- struct lib9p_s childname) {
+lib9p_srv_file_or_error util9p_static_dir_dwalk(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx,
+ struct lib9p_s childname) {
assert(self);
assert(ctx);
for (size_t i = 0; !LO_IS_NULL(self->members[i]); i++) {
lo_interface lib9p_srv_file file = self->members[i];
- struct lib9p_srv_stat stat = LO_CALL(file, stat, ctx);
- if (lib9p_ctx_has_error(&ctx->basectx))
- break;
- lib9p_srv_stat_assert(stat);
+ struct lib9p_srv_stat stat;
+ error err = LO_CALL(file, stat, ctx, &stat);
+ if (!ERROR_IS_NULL(err))
+ return ERROR_NEW_ERR(lib9p_srv_file, err);
+ lib9p_srv_stat_assert(&stat);
if (lib9p_str_eq(stat.name, childname))
- return file;
+ return ERROR_NEW_VAL(lib9p_srv_file, file);
}
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_ENOENT, "no such file or directory");
- return LO_NULL(lib9p_srv_file);
+ return ERROR_NEW_ERR(lib9p_srv_file, error_new(E_POSIX_ENOENT, "no such file or directory"));
}
-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),
- struct lib9p_srv_userid *LM_UNUSED(user),
- struct lib9p_srv_userid *LM_UNUSED(group),
- lib9p_dm_t LM_UNUSED(perm)) {
+lib9p_srv_file_or_error util9p_static_dir_dcreate(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx,
+ struct lib9p_s LM_UNUSED(childname),
+ 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, LIB9P_ERRNO_L_EROFS, "read-only part of filesystem");
- return LO_NULL(lib9p_srv_file);
+ return ERROR_NEW_ERR(lib9p_srv_file, error_new(E_POSIX_EROFS, "read-only part of filesystem"));
}
-LIB9P_SRV_NOTFILE(struct util9p_static_dir, util9p_static_dir);
+LIB9P_SRV_NOTFILE(, struct util9p_static_dir, util9p_static_dir);
-static lo_interface lib9p_srv_dio util9p_static_dir_dopen(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx) {
+lib9p_srv_dio_or_error util9p_static_dir_dopen(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx) {
assert(self);
assert(ctx);
- return lo_box_util9p_static_dir_as_lib9p_srv_dio(self);
+ return ERROR_NEW_VAL(lib9p_srv_dio, LO_BOX(lib9p_srv_dio, self));
}
-static void util9p_static_dir_iofree(struct util9p_static_dir *self) {
+
+static struct lib9p_qid util9p_static_dio_ioqid(struct util9p_static_dir *self) {
+ return util9p_static_dir_qid(self);
+}
+static void util9p_static_dio_iofree(struct util9p_static_dir *self) {
assert(self);
}
-static struct lib9p_srv_dirent util9p_static_dir_dread(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx, size_t idx) {
+static lib9p_srv_dirent_or_error util9p_static_dio_dread(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx, size_t idx) {
assert(self);
assert(ctx);
lo_interface lib9p_srv_file file = self->members[idx];
if (LO_IS_NULL(file))
- return (struct lib9p_srv_dirent){};
+ return ERROR_NEW_VAL(lib9p_srv_dirent, (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);
+ struct lib9p_srv_stat stat;
+ error err = LO_CALL(file, stat, ctx, &stat);
+ if (!ERROR_IS_NULL(err))
+ return ERROR_NEW_ERR(lib9p_srv_dirent, err);
+ lib9p_srv_stat_assert(&stat);
- return (struct lib9p_srv_dirent){
+ return ERROR_NEW_VAL(lib9p_srv_dirent, ((struct lib9p_srv_dirent){
.qid = stat.qid,
.name = stat.name,
- };
+ }));
}
/* file ***********************************************************************/
-static void util9p_static_file_free(struct util9p_static_file *self) {
+void util9p_static_file_free(struct util9p_static_file *self) {
assert(self);
}
-static struct lib9p_qid util9p_static_file_qid(struct util9p_static_file *self) {
+struct lib9p_qid util9p_static_file_qid(struct util9p_static_file *self) {
assert(self);
return (struct lib9p_qid){
@@ -151,11 +152,12 @@ static inline size_t util9p_static_file_size(struct util9p_static_file *file) {
}
-static struct lib9p_srv_stat util9p_static_file_stat(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx) {
+error util9p_static_file_stat(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_srv_stat *out) {
assert(self);
assert(ctx);
+ assert(out);
- return (struct lib9p_srv_stat){
+ *out = ((struct lib9p_srv_stat){
.qid = util9p_static_file_qid(self),
.mode = self->c.perm & 0444,
.atime_sec = self->c.atime,
@@ -166,69 +168,67 @@ static struct lib9p_srv_stat util9p_static_file_stat(struct util9p_static_file *
.owner_gid = { .name = lib9p_str(self->c.g_name), .num = self->c.g_num },
.last_modifier_uid = { .name = lib9p_str(self->c.m_name), .num = self->c.m_num },
.extension = lib9p_str(NULL),
- };
+ });
+ return ERROR_NULL;
}
-static void util9p_static_file_wstat(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx,
+error util9p_static_file_wstat(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx,
struct lib9p_srv_stat) {
assert(self);
assert(ctx);
- lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "read-only part of filesystem");
+ return error_new(E_POSIX_EROFS, "read-only part of filesystem");
}
-static void util9p_static_file_remove(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx) {
+error util9p_static_file_remove(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx) {
assert(self);
assert(ctx);
- lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "read-only part of filesystem");
+ return error_new(E_POSIX_EROFS, "read-only part of filesystem");
}
-LIB9P_SRV_NOTDIR(struct util9p_static_file, util9p_static_file);
+LIB9P_SRV_NOTDIR(, struct util9p_static_file, util9p_static_file);
-static lo_interface lib9p_srv_fio util9p_static_file_fopen(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx,
- bool rd, bool wr, bool trunc) {
+lib9p_srv_fio_or_error util9p_static_file_fopen(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx,
+ bool rd, bool wr, bool trunc) {
assert(self);
assert(ctx);
assert(rd);
assert(!wr);
assert(!trunc);
- return lo_box_util9p_static_file_as_lib9p_srv_fio(self);
+ return ERROR_NEW_VAL(lib9p_srv_fio, LO_BOX(lib9p_srv_fio, self));
+}
+
+static struct lib9p_qid util9p_static_fio_ioqid(struct util9p_static_file *self) {
+ return util9p_static_file_qid(self);
}
-static void util9p_static_file_iofree(struct util9p_static_file *self) {
+static void util9p_static_fio_iofree(struct util9p_static_file *self) {
assert(self);
}
-static uint32_t util9p_static_file_iounit(struct util9p_static_file *self) {
+static uint32_t util9p_static_fio_iounit(struct util9p_static_file *self) {
assert(self);
return 0;
}
-static void util9p_static_file_pread(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx,
- uint32_t byte_count, uint64_t byte_offset,
- struct iovec *ret) {
+static error util9p_static_fio_pread(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx,
+ lo_interface io_writer dst, uint64_t byte_offset, uint32_t byte_count) {
assert(self);
assert(ctx);
- assert(ret);
size_t data_size = util9p_static_file_size(self);
- if (byte_offset > (uint64_t)data_size) {
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EINVAL, "offset is past end-of-file length");
- return;
- }
+ if (byte_offset > (uint64_t)data_size)
+ return error_new(E_POSIX_EINVAL, "offset is past end-of-file length");
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->iov_base = &self->data_start[beg_off];
- ret->iov_len = end_off-beg_off;
+ return io_write(dst, &self->data_start[beg_off], end_off-beg_off).err;
}
-static uint32_t util9p_static_file_pwrite(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx,
- void *LM_UNUSED(buf),
- uint32_t LM_UNUSED(byte_count),
- uint64_t LM_UNUSED(byte_offset)) {
+static uint32_t_or_error util9p_static_fio_pwrite(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx,
+ const void *LM_UNUSED(buf),
+ uint32_t LM_UNUSED(byte_count),
+ uint64_t LM_UNUSED(byte_offset)) {
assert(self);
assert(ctx);
- lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "read-only part of filesystem");
- return 0;
+ return ERROR_NEW_ERR(uint32_t, error_new(E_POSIX_EROFS, "read-only part of filesystem"));
}
diff --git a/libcr/CMakeLists.txt b/libcr/CMakeLists.txt
index 2e66020..472820c 100644
--- a/libcr/CMakeLists.txt
+++ b/libcr/CMakeLists.txt
@@ -3,8 +3,11 @@
# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
# SPDX-License-Identifier: AGPL-3.0-or-later
+add_library(libcr_headers INTERFACE)
+target_include_directories(libcr_headers PUBLIC INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
+
add_library(libcr INTERFACE)
-target_include_directories(libcr PUBLIC INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
+target_link_libraries(libcr INTERFACE libcr_headers)
target_sources(libcr INTERFACE
coroutine.c
)
diff --git a/libcr/coroutine.c b/libcr/coroutine.c
index 920c371..182e85c 100644
--- a/libcr/coroutine.c
+++ b/libcr/coroutine.c
@@ -399,6 +399,7 @@ struct coroutine {
#if CONFIG_COROUTINE_VALGRIND
unsigned stack_id;
#endif
+ bool stack_free;
/* 4. env ***************************************************/
cr_plat_jmp_buf env;
@@ -547,16 +548,15 @@ cid_t coroutine_allocate_cid(void) {
return 0;
}
-cid_t coroutine_add_with_stack_size(size_t stack_size,
- const char *name,
- cr_fn_t fn, void *args) {
+static cid_t _coroutine_add(void *stack, size_t full_stack_size,
+ const char *name,
+ cr_fn_t fn, void *args) {
cid_t parent = coroutine_running;
if (parent)
assert_cid_state(parent, state == CR_RUNNING);
- assert(stack_size);
+ assert(full_stack_size > 2*CR_STACK_GUARD_SIZE);
assert(fn);
- log_debugln("coroutine_add_with_stack_size(", stack_size, ", ", (qstr, name), ", ", (ptr, fn), ", ", (ptr, args), ")...");
if (!coroutine_initialized) {
cr_plat_init();
@@ -577,24 +577,36 @@ cid_t coroutine_add_with_stack_size(size_t stack_size,
else
memset(coroutine_table[child-1].name, 0, sizeof(coroutine_table[child-1].name));
+ log_infoln("starting cid ", child,
+ " ", (qstrn, coroutine_table[child-1].name, sizeof(coroutine_table[child-1].name)),
+ ":");
+
/* 3. stack *************************************************/
- coroutine_table[child-1].stack_size = stack_size + 2*CR_STACK_GUARD_SIZE;
- log_infoln("allocing ", (qstr, name), " stack with size ",
- stack_size, "+2*", (base10, CR_STACK_GUARD_SIZE), "=", coroutine_table[child-1].stack_size);
- coroutine_table[child-1].stack =
- aligned_alloc(CR_PLAT_STACK_ALIGNMENT, coroutine_table[child-1].stack_size);
- log_infoln("... done, stack is [",
+ coroutine_table[child-1].stack_size = full_stack_size;
+ coroutine_table[child-1].stack_free = (stack == NULL);
+ if (!stack) {
+ log_infoln("allocing stack with size ", full_stack_size, "...");
+ stack = aligned_alloc(CR_PLAT_STACK_ALIGNMENT, full_stack_size);
+ log_infoln("...done");
+ }
+ coroutine_table[child-1].stack = stack;
+ log_infoln(" -> full stack is [",
+ (ptr, coroutine_table[child-1].stack), ",",
+ (ptr, coroutine_table[child-1].stack + full_stack_size), ")",
+ " ; size=", full_stack_size);
+ log_infoln(" -> usable stack is [",
(ptr, coroutine_table[child-1].stack + CR_STACK_GUARD_SIZE), ",",
- (ptr, coroutine_table[child-1].stack + CR_STACK_GUARD_SIZE + stack_size), ")");
+ (ptr, coroutine_table[child-1].stack + full_stack_size - CR_STACK_GUARD_SIZE), ")",
+ " ; size=", full_stack_size - 2*CR_STACK_GUARD_SIZE);
#if CONFIG_COROUTINE_MEASURE_STACK || CONFIG_COROUTINE_PROTECT_STACK
- for (size_t i = 0; i < coroutine_table[child-1].stack_size; i++)
+ for (size_t i = 0; i < full_stack_size; i++)
((uint8_t *)coroutine_table[child-1].stack)[i] =
stack_pattern[i%sizeof(stack_pattern)];
#endif
#if CONFIG_COROUTINE_VALGRIND
coroutine_table[child-1].stack_id = VALGRIND_STACK_REGISTER(
coroutine_table[child-1].stack + CR_STACK_GUARD_SIZE,
- coroutine_table[child-1].stack + CR_STACK_GUARD_SIZE + stack_size);
+ coroutine_table[child-1].stack + full_stack_size - CR_STACK_GUARD_SIZE);
#endif
/* 4. env ***************************************************/
@@ -602,12 +614,12 @@ cid_t coroutine_add_with_stack_size(size_t stack_size,
coroutine_cnt++;
if (!cr_setjmp(&coroutine_add_env)) { /* point=a */
void *stack_base = coroutine_table[child-1].stack
- + CR_STACK_GUARD_SIZE
#if CR_PLAT_STACK_GROWS_DOWNWARD
- + stack_size
+ + full_stack_size - CR_STACK_GUARD_SIZE
+#else
+ + CR_STACK_GUARD_SIZE
#endif
;
- log_debugln("...stack =", (ptr, coroutine_table[child-1].stack));
log_debugln("...stack_base=", (ptr, stack_base));
/* run until cr_begin() */
cr_plat_call_with_stack(stack_base, fn, args);
@@ -622,10 +634,33 @@ cid_t coroutine_add_with_stack_size(size_t stack_size,
* didn't actually check. */
cr_restore_interrupts(true);
coroutine_running = parent;
+ log_infoln(" -> done");
return child;
}
+cid_t coroutine_add_with_stack(void *stack, size_t full_stack_size,
+ const char *name,
+ cr_fn_t fn, void *args) {
+ if (name)
+ log_debugln("coroutine_add_with_stack(", (ptr, stack), full_stack_size, ", ", (qstr, name), ", ", (ptr, fn), ", ", (ptr, args), ")...");
+ else
+ log_debugln("coroutine_add_with_stack(", (ptr, stack), full_stack_size, ", ", (ptr, name), ", ", (ptr, fn), ", ", (ptr, args), ")...");
+
+ return _coroutine_add(stack, full_stack_size, name, fn, args);
+}
+
+cid_t coroutine_add_with_stack_size(size_t usable_stack_size,
+ const char *name,
+ cr_fn_t fn, void *args) {
+ if (name)
+ log_debugln("coroutine_add_with_stack_size(", usable_stack_size, ", ", (qstr, name), ", ", (ptr, fn), ", ", (ptr, args), ")...");
+ else
+ log_debugln("coroutine_add_with_stack_size(", usable_stack_size, ", ", (ptr, name), ", ", (ptr, fn), ", ", (ptr, args), ")...");
+
+ return _coroutine_add(NULL, usable_stack_size + 2*CR_STACK_GUARD_SIZE, name, fn, args);
+}
+
/* coroutine_main() ***********************************************************/
void coroutine_main(void) {
@@ -663,7 +698,8 @@ void coroutine_main(void) {
#if CONFIG_COROUTINE_VALGRIND
VALGRIND_STACK_DEREGISTER(coroutine_table[coroutine_running-1].stack_id);
#endif
- free(coroutine_table[coroutine_running-1].stack);
+ if (coroutine_table[coroutine_running-1].stack_free)
+ free(coroutine_table[coroutine_running-1].stack);
coroutine_table[coroutine_running-1] = (struct coroutine){};
coroutine_cnt--;
}
@@ -685,7 +721,7 @@ void cr_begin(void) {
cr_restore_interrupts(saved);
}
-static inline void _cr_yield() {
+static inline void _cr_yield(void) {
cid_t next;
while ( !((next = coroutine_ringbuf_pop())) ) {
/* No coroutines are runnable, wait for an interrupt
diff --git a/libcr/include/libcr/coroutine.h b/libcr/include/libcr/coroutine.h
index f72dc96..f0e6e61 100644
--- a/libcr/include/libcr/coroutine.h
+++ b/libcr/include/libcr/coroutine.h
@@ -26,7 +26,7 @@
#ifndef _LIBCR_COROUTINE_H_
#define _LIBCR_COROUTINE_H_
-#include <stddef.h> /* for size_t */
+#include <stddef.h> /* for size_t */
/* Configuration **************************************************************/
@@ -35,6 +35,9 @@
#ifndef CONFIG_COROUTINE_MEASURE_STACK
#error config.h must define CONFIG_COROUTINE_MEASURE_STACK (bool)
#endif
+#ifndef CONFIG_COROUTINE_NAME_LEN
+ #error config.h must define CONFIG_COROUTINE_NAME_LEN (non-negative integer)
+#endif
/* typedefs *******************************************************************/
@@ -80,7 +83,15 @@ typedef void (*cr_fn_t)(void *args);
/* managing coroutines ********************************************************/
/**
- * Call `fn(args)` in a new coroutine with stack size `stack_size`.
+ * Call `fn(args)` in a new coroutine with the `full_stack_size`-sized
+ * block of memory `stack` as the coroutine stack.
+ *
+ * There may be CPU-specific requirements on the alignment of the
+ * `stack` pointer.
+ *
+ * If CONFIG_COROUTINE_PROTECT_STACK: The usable stack size will be
+ * slightly less than `full_stack_size`, in order to make room for a
+ * stack guard at each end.
*
* See the doc comment on c_fn_t for the requirements imposed on fn.
*
@@ -91,17 +102,35 @@ typedef void (*cr_fn_t)(void *args);
* Returns the cid of the newly-created coroutine. May return 0 if
* there are already COROUTINE_NUM active coroutines.
*/
-cid_t coroutine_add_with_stack_size(size_t stack_size, const char *name, cr_fn_t fn, void *args);
+cid_t coroutine_add_with_stack(void *stack, size_t full_stack_size, const char *name, cr_fn_t fn, void *args);
+
+/**
+ * Like coroutine_add_with_stack(), but will use aligned_alloc() to
+ * allocate a block of memory to use as the stack.
+ *
+ * If CONFIG_COROUTINE_PROTECT_STACK: `usable_stack_size` does *not*
+ * include the size of the stack guard at each end; the amount of
+ * memory allocated for the stack will be slightly larger than
+ * `usable_stack_size`.
+ */
+cid_t coroutine_add_with_stack_size(size_t usable_stack_size, const char *name, cr_fn_t fn, void *args);
/**
* Like coroutine_add_with_stack_size(), but uses a default stack size so
* you don't need to think about it.
*
- * Either define CONFIG_COROUTINE_STACK_SIZE_DEFAULT to use for all
- * coroutines, or CONFIG_COROUTINE_STACK_SIZE_{fn} for each COROUTINE
- * function.
+ * Either:
+ * - define CONFIG_COROUTINE_STACK_SIZE_DEFAULT to use for all
+ * coroutines; or
+ * - define/declare CONFIG_COROUTINE_STACK_SIZE_{fn} for each COROUTINE
+ * function; or
+ * - define CONFIG_COROUTINE_STACK_PREALLOCATE and then
+ * define/declare COROUTINE_STACK_{fn} and COROUTINE_STACK_{fn}_len
+ * for each COROUTINE function.
*/
-#ifdef CONFIG_COROUTINE_STACK_SIZE_DEFAULT
+#if defined(CONFIG_COROUTINE_STACK_PREALLOCATE)
+#define coroutine_add(name, fn, args) coroutine_add_with_stack(COROUTINE_STACK_##fn, COROUTINE_STACK_##fn##_len, name, fn, args)
+#elif defined(CONFIG_COROUTINE_STACK_SIZE_DEFAULT)
#define coroutine_add(name, fn, args) coroutine_add_with_stack_size(CONFIG_COROUTINE_STACK_SIZE_DEFAULT, name, fn, args)
#else
#define coroutine_add(name, fn, args) coroutine_add_with_stack_size(CONFIG_COROUTINE_STACK_SIZE_##fn, name, fn, args)
diff --git a/libcr/tests/test_matrix/config.h b/libcr/tests/test_matrix/config.h
index 978b9ac..decd6de 100644
--- a/libcr/tests/test_matrix/config.h
+++ b/libcr/tests/test_matrix/config.h
@@ -1,4 +1,4 @@
-/* config.h - Compile-time configuration for libcr test_matrix
+/* libcr/tests/test_matrix/config.h - Compile-time configuration for libcr test_matrix
*
* Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/libcr_ipc/CMakeLists.txt b/libcr_ipc/CMakeLists.txt
index 60d3f2d..ed7c0a9 100644
--- a/libcr_ipc/CMakeLists.txt
+++ b/libcr_ipc/CMakeLists.txt
@@ -3,8 +3,15 @@
# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
# SPDX-License-Identifier: AGPL-3.0-or-later
+add_library(libcr_ipc_headers INTERFACE)
+target_include_directories(libcr_ipc_headers PUBLIC INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
+target_link_libraries(libcr_ipc_headers INTERFACE
+ libcr_headers
+ libmisc_headers
+)
+
add_library(libcr_ipc INTERFACE)
-target_include_directories(libcr_ipc PUBLIC INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
+target_link_libraries(libcr_ipc INTERFACE libcr_ipc_headers)
target_sources(libcr_ipc INTERFACE
chan.c
mutex.c
@@ -22,9 +29,9 @@ set(ipc_tests
mutex
rpc
rwmutex
- select
sema
)
foreach(test IN LISTS ipc_tests)
add_lib_test(libcr_ipc "test_${test}")
+ add_lib_test(libcr_ipc "test_${test}_compile")
endforeach()
diff --git a/libcr_ipc/chan.c b/libcr_ipc/chan.c
index b7ecfc8..b52dab1 100644
--- a/libcr_ipc/chan.c
+++ b/libcr_ipc/chan.c
@@ -4,7 +4,7 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-#include <string.h> /* for memcpy() */
+#include <string.h> /* for memcpy() */
#include <libcr/coroutine.h> /* for cid_t, cr_* */
#include <libmisc/assert.h>
diff --git a/libcr_ipc/include/libcr_ipc/chan.h b/libcr_ipc/include/libcr_ipc/chan.h
index 09d269f..1755a97 100644
--- a/libcr_ipc/include/libcr_ipc/chan.h
+++ b/libcr_ipc/include/libcr_ipc/chan.h
@@ -7,7 +7,7 @@
#ifndef _LIBCR_IPC_CHAN_H_
#define _LIBCR_IPC_CHAN_H_
-#include <stddef.h> /* for size_t */
+#include <stddef.h> /* for size_t */
#include <libmisc/linkedlist.h> /* for DLIST_DECLARE() */
#include <libmisc/private.h>
diff --git a/libcr_ipc/include/libcr_ipc/rpc.h b/libcr_ipc/include/libcr_ipc/rpc.h
index c5336cd..85ebdb3 100644
--- a/libcr_ipc/include/libcr_ipc/rpc.h
+++ b/libcr_ipc/include/libcr_ipc/rpc.h
@@ -7,6 +7,7 @@
#ifndef _LIBCR_IPC_RPC_H_
#define _LIBCR_IPC_RPC_H_
+#include <libcr/coroutine.h> /* for cid_t */
#include <libmisc/linkedlist.h> /* for SLIST_DECLARE() */
/**
diff --git a/libcr_ipc/rpc.c b/libcr_ipc/rpc.c
index fcf51ba..b1b7674 100644
--- a/libcr_ipc/rpc.c
+++ b/libcr_ipc/rpc.c
@@ -4,7 +4,7 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-#include <string.h> /* for memcpy() */
+#include <string.h> /* for memcpy() */
#include <libcr/coroutine.h> /* for cid_t, cr_* */
#include <libmisc/assert.h>
diff --git a/libcr_ipc/tests/config.h b/libcr_ipc/tests/config.h
index a648589..a16df1d 100644
--- a/libcr_ipc/tests/config.h
+++ b/libcr_ipc/tests/config.h
@@ -1,4 +1,4 @@
-/* config.h - Compile-time configuration for the libcr_ipc tests
+/* libcr_ipc/tests/config.h - Compile-time configuration for the libcr_ipc tests
*
* Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/libcr_ipc/tests/test_chan.c b/libcr_ipc/tests/test_chan.c
index a6eba82..ee1751f 100644
--- a/libcr_ipc/tests/test_chan.c
+++ b/libcr_ipc/tests/test_chan.c
@@ -11,7 +11,9 @@
CR_CHAN_DECLARE(intchan, int);
-COROUTINE producer_cr(void *_ch) {
+/* test 1 *********************************************************************/
+
+COROUTINE test1_producer_cr(void *_ch) {
intchan_t *ch = _ch;
cr_begin();
@@ -22,11 +24,10 @@ COROUTINE producer_cr(void *_ch) {
cr_chan_send(ch, 2);
-
cr_end();
}
-COROUTINE consumer_cr(void *_ch) {
+COROUTINE test1_consumer_cr(void *_ch) {
int x;
intchan_t *ch = _ch;
cr_begin();
@@ -40,10 +41,91 @@ COROUTINE consumer_cr(void *_ch) {
cr_end();
}
+/* test 2 *********************************************************************/
+
+intchan_t test2_ch[10] = {};
+intchan_t test2_fch = {};
+
+COROUTINE test2_consumer_cr(void *) {
+ cr_begin();
+
+ struct cr_select_arg args[11];
+
+ bool chdone[10] = {};
+ 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(&test2_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(&test2_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(&test2_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(&test2_fch, &send),
+ CR_SELECT_DEFAULT);
+ test_assert(ret_arg == 1);
+
+ cr_end();
+}
+
+COROUTINE test2_producer_cr(void *_n) {
+ int n = *(int *)_n;
+ cr_begin();
+
+ cr_chan_send(&test2_ch[n], n);
+
+ cr_end();
+}
+
+COROUTINE test2_final_cr(void *) {
+ cr_begin();
+
+ int ret = cr_chan_recv(&test2_fch);
+ printf("ret=%d\n", ret);
+ test_assert(ret == 567);
+
+ cr_end();
+}
+
+/******************************************************************************/
+
int main() {
+ printf("== test 1 =========================================\n");
intchan_t ch = {};
- coroutine_add("producer", producer_cr, &ch);
- coroutine_add("consumer", consumer_cr, &ch);
+ coroutine_add("producer", test1_producer_cr, &ch);
+ coroutine_add("consumer", test1_consumer_cr, &ch);
coroutine_main();
+
+ printf("== test 2 =========================================\n");
+ for (int i = 0; i < 10; i++)
+ coroutine_add("producer", test2_producer_cr, &i);
+ coroutine_add("consumer", test2_consumer_cr, NULL);
+ coroutine_add("final", test2_final_cr, NULL);
+ coroutine_main();
+
return 0;
}
diff --git a/libcr_ipc/tests/test_chan_compile.c b/libcr_ipc/tests/test_chan_compile.c
new file mode 100644
index 0000000..00f3bdc
--- /dev/null
+++ b/libcr_ipc/tests/test_chan_compile.c
@@ -0,0 +1,13 @@
+/* libcr_ipc/tests/test_chan_compile.c - Test that <libcr_ipc/chan.h> compiles
+ *
+ * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <libcr_ipc/chan.h>
+
+CR_CHAN_DECLARE(intchan, int);
+
+int main() {
+ return 0;
+}
diff --git a/libcr_ipc/tests/test_mutex_compile.c b/libcr_ipc/tests/test_mutex_compile.c
new file mode 100644
index 0000000..c119ee3
--- /dev/null
+++ b/libcr_ipc/tests/test_mutex_compile.c
@@ -0,0 +1,11 @@
+/* libcr_ipc/tests/test_mutex_compile.c - Test that <libcr_ipc/mutex.h> compiles
+ *
+ * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <libcr_ipc/mutex.h>
+
+int main() {
+ return 0;
+}
diff --git a/libcr_ipc/tests/test_rpc_compile.c b/libcr_ipc/tests/test_rpc_compile.c
new file mode 100644
index 0000000..ed0e0c1
--- /dev/null
+++ b/libcr_ipc/tests/test_rpc_compile.c
@@ -0,0 +1,13 @@
+/* libcr_ipc/tests/test_rpc_compile.c - Test that <libcr_ipc/rpc.h> compiles
+ *
+ * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <libcr_ipc/rpc.h>
+
+CR_RPC_DECLARE(intrpc, int, int);
+
+int main() {
+ return 0;
+}
diff --git a/libcr_ipc/tests/test_rwmutex_compile.c b/libcr_ipc/tests/test_rwmutex_compile.c
new file mode 100644
index 0000000..358a535
--- /dev/null
+++ b/libcr_ipc/tests/test_rwmutex_compile.c
@@ -0,0 +1,11 @@
+/* libcr_ipc/tests/test_rwmutex_compile.c - Test that <libcr_ipc/rwmutex.h> compiles
+ *
+ * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <libcr_ipc/rwmutex.h>
+
+int main() {
+ return 0;
+}
diff --git a/libcr_ipc/tests/test_select.c b/libcr_ipc/tests/test_select.c
deleted file mode 100644
index 3107155..0000000
--- a/libcr_ipc/tests/test_select.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/* 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] = {};
-intchan_t fch = {};
-
-COROUTINE consumer_cr(void *) {
- cr_begin();
-
- struct cr_select_arg args[11];
-
- bool chdone[10] = {};
- 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_compile.c b/libcr_ipc/tests/test_sema_compile.c
new file mode 100644
index 0000000..8a635b2
--- /dev/null
+++ b/libcr_ipc/tests/test_sema_compile.c
@@ -0,0 +1,11 @@
+/* libcr_ipc/tests/test_sema_compile.c - Test that <libcr_ipc/sema.h> compiles
+ *
+ * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <libcr_ipc/sema.h>
+
+int main() {
+ return 0;
+}
diff --git a/libdhcp/CMakeLists.txt b/libdhcp/CMakeLists.txt
index dee7cb6..f14e46d 100644
--- a/libdhcp/CMakeLists.txt
+++ b/libdhcp/CMakeLists.txt
@@ -7,7 +7,14 @@ add_library(libdhcp INTERFACE)
target_include_directories(libdhcp PUBLIC INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_sources(libdhcp INTERFACE
dhcp_client.c
+ dhcp_common.c
)
target_link_libraries(libdhcp INTERFACE
libmisc
+ libhw_generic
)
+
+if (ENABLE_TESTS)
+ add_lib_test(libdhcp test_client)
+ target_link_libraries(test_client libcr libhw_cr)
+endif()
diff --git a/libdhcp/dhcp_client.c b/libdhcp/dhcp_client.c
index 8e8361d..1164355 100644
--- a/libdhcp/dhcp_client.c
+++ b/libdhcp/dhcp_client.c
@@ -86,8 +86,8 @@
#include <string.h> /* for strlen(), memcpy(), memset() */
-#include <libmisc/rand.h>
#include <libhw/generic/alarmclock.h>
+#include <libmisc/rand.h>
#define LOG_NAME DHCP
#include <libmisc/log.h>
@@ -179,9 +179,10 @@ static const char *state_strs[] = {
};
/**
- * For convenience in switch blocks, a list of the states that, when
- * msgtyp==DHCP_MSGTYP_REQUEST, dhcp_client_send() has assert()ed the state is
- * not.
+ * IMPOSSIBLE_REQUEST_STATES is a convenience macro for use in switch
+ * blocks; it is a list of the states that (when
+ * msgtyp==DHCP_MSGTYP_REQUEST) dhcp_client_send() has assert()ed the
+ * state is not.
*/
#define IMPOSSIBLE_REQUEST_STATES \
STATE_INIT: \
@@ -251,11 +252,8 @@ static inline enum requirement dhcp_table5(typeof((struct dhcp_client){}.state)
* @param client->lease_client_addr (sometimes)
* @param client->lease_server_id (sometimes)
* @param client->sock
- *
- * @return client->last_sent_msgtyp
- * @return whether there was an error
*/
-static bool dhcp_client_send(struct dhcp_client *client, uint8_t msgtyp, const char *errstr, struct dhcp_msg *scratch_msg) {
+static error dhcp_client_send(struct dhcp_client *client, uint8_t msgtyp, const char *errstr, struct dhcp_msg *scratch_msg) {
/**********************************************************************\
* Preconditions *
\**********************************************************************/
@@ -461,14 +459,14 @@ static bool dhcp_client_send(struct dhcp_client *client, uint8_t msgtyp, const c
* Send *
\**********************************************************************/
log_debugln("state ", state_strs[client->state], ": sending DHCP ", dhcp_msgtyp_str(msgtyp));
- ssize_t r = LO_CALL(client->sock, sendto, scratch_msg, DHCP_MSG_BASE_SIZE + optlen,
- client_broadcasts ? net_ip4_addr_broadcast : client->lease_server_id, DHCP_PORT_SERVER);
- if (r < 0) {
- log_debugln("error: sendto: ", r);
- return true;
+ error err = LO_CALL(client->sock, sendto, scratch_msg, DHCP_MSG_BASE_SIZE + optlen,
+ client_broadcasts ? net_ip4_addr_broadcast : client->lease_server_id, DHCP_PORT_SERVER);
+ if (!ERROR_IS_NULL(err)) {
+ log_debugln("error: sendto: ", (error, err));
+ return err;
}
client->last_sent_msgtyp = msgtyp;
- return false;
+ return ERROR_NULL;
}
struct dhcp_recv_msg {
@@ -564,24 +562,20 @@ static inline enum requirement dhcp_table3(uint8_t req_msgtyp, uint8_t resp_msgt
* @param client->self_eth_addr
* @param client->xid
* @param client->lease_server_id
- *
- * @return
- * - <0: -errno
- * - 0: success
- * - >0: should not happen
*/
-static ssize_t dhcp_client_recv(struct dhcp_client *client, struct dhcp_recv_msg *ret) {
+static error dhcp_client_recv(struct dhcp_client *client, struct dhcp_recv_msg *ret) {
struct net_ip4_addr srv_addr;
uint16_t srv_port;
- ssize_t msg_len;
+ size_t msg_len;
assert(client);
ignore:
- msg_len = LO_CALL(client->sock, recvfrom, &ret->raw, sizeof(ret->raw), &srv_addr, &srv_port);
- if (msg_len < 0)
+ size_t_or_error r = LO_CALL(client->sock, recvfrom, &ret->raw, sizeof(ret->raw), &srv_addr, &srv_port);
+ if (r.is_err)
/* msg_len is -errno */
- return msg_len;
+ return r.err;
+ msg_len = r.size_t;
/* Validate L3: IP */
/* Don't validate that srv_addr matches client->server_id
@@ -594,10 +588,10 @@ static ssize_t dhcp_client_recv(struct dhcp_client *client, struct dhcp_recv_msg
goto ignore;
/* Validate L5: DHCP. */
- if ((size_t)msg_len < DHCP_MSG_BASE_SIZE + sizeof(dhcp_magic_cookie))
+ if (msg_len < DHCP_MSG_BASE_SIZE + sizeof(dhcp_magic_cookie))
/* ignore impossibly short message */
goto ignore;
- if ((size_t)msg_len > sizeof(ret->raw))
+ if (msg_len > sizeof(ret->raw))
/* ignore message that is larger than the specified
* DHCP_OPT_DHCP_MAX_MSG_SIZE */
goto ignore;
@@ -697,15 +691,7 @@ static ssize_t dhcp_client_recv(struct dhcp_client *client, struct dhcp_recv_msg
goto ignore;
}
- return 0;
-}
-
-/** @return true if there's a conflict, false if the addr appears to be unused */
-static bool dhcp_check_conflict(lo_interface net_packet_conn sock, struct net_ip4_addr addr) {
- assert(!LO_IS_NULL(sock));
- ssize_t v = LO_CALL(sock, sendto, "CHECK_IP_CONFLICT", 17, addr, 5000);
- log_debugln("check_ip_conflict => ", v);
- return v != -NET_EARP_TIMEOUT;
+ return ERROR_NULL;
}
static void dhcp_client_take_lease(struct dhcp_client *client, struct dhcp_recv_msg *msg, bool ifup) {
@@ -755,18 +741,19 @@ static void dhcp_client_take_lease(struct dhcp_client *client, struct dhcp_recv_
static void dhcp_client_setstate(struct dhcp_client *client,
typeof((struct dhcp_client){}.state) newstate,
uint8_t send_msgtyp, const char *errstr, struct dhcp_recv_msg *scratch_msg) {
- if (send_msgtyp)
- (void)dhcp_client_send(client, send_msgtyp, errstr, &scratch_msg->raw);
+ if (send_msgtyp) {
+ error err = dhcp_client_send(client, send_msgtyp, errstr, &scratch_msg->raw);
+ error_cleanup(&err);
+ }
client->state = newstate;
}
[[noreturn]] static void dhcp_client_run(struct dhcp_client *client, struct dhcp_recv_msg *scratch_msg) {
assert(client);
- ssize_t r;
-
/* State transition diagram: https://datatracker.ietf.org/doc/html/rfc2131#page-35 */
for (;;) {
+ [[gnu::cleanup(error_cleanup)]] error err = {};
log_debugln("loop: state=", state_strs[client->state]);
switch (client->state) {
case STATE_INIT:
@@ -776,8 +763,8 @@ static void dhcp_client_setstate(struct dhcp_client *client,
break;
case STATE_SELECTING:
LO_CALL(client->sock, set_recv_deadline, client->time_ns_init+CONFIG_DHCP_SELECTING_NS);
- switch ((r = dhcp_client_recv(client, scratch_msg))) {
- case 0:
+ LM_PARTIAL_SWITCH ((err = dhcp_client_recv(client, scratch_msg)).num) {
+ case E_NOERROR:
switch (scratch_msg->option_dat[scratch_msg->options[DHCP_OPT_DHCP_MSG_TYPE].off]) {
case DHCP_MSGTYP_OFFER:
/* Accept the first offer. */
@@ -788,24 +775,23 @@ static void dhcp_client_setstate(struct dhcp_client *client,
/* ignore */
}
break;
- case -NET_ERECV_TIMEOUT:
+ case E_NET_ERECV_TIMEOUT:
dhcp_client_setstate(client, STATE_INIT, 0, NULL, scratch_msg);
break;
default:
- assert(r < 0);
- log_debugln("error: recvfrom: ", r);
+ log_debugln("error: recvfrom: ", (error, err));
}
break;
case STATE_REQUESTING:
LO_CALL(client->sock, set_recv_deadline, 0);
- switch ((r = dhcp_client_recv(client, scratch_msg))) {
- case 0:
+ LM_PARTIAL_SWITCH ((err = dhcp_client_recv(client, scratch_msg)).num) {
+ case E_NOERROR:
switch (scratch_msg->option_dat[scratch_msg->options[DHCP_OPT_DHCP_MSG_TYPE].off]) {
case DHCP_MSGTYP_NAK:
dhcp_client_setstate(client, STATE_INIT, 0, NULL, scratch_msg);
break;
case DHCP_MSGTYP_ACK:
- if (dhcp_check_conflict(client->sock, client->lease_client_addr)) {
+ if (LO_CALL(client->iface, arp_ping, client->lease_client_addr)) {
log_debugln("IP ", (net_ip4_addr, client->lease_client_addr), " is already in use");
dhcp_client_setstate(client, STATE_INIT, DHCP_MSGTYP_DECLINE, "IP is already in use", scratch_msg);
} else {
@@ -818,22 +804,20 @@ static void dhcp_client_setstate(struct dhcp_client *client,
}
break;
default:
- assert(r < 0);
- log_debugln("error: recvfrom: ", r);
+ log_debugln("error: recvfrom: ", (error, err));
}
break;
case STATE_BOUND:
LO_CALL(client->sock, set_recv_deadline, client->lease_time_ns_t1);
- switch ((r = dhcp_client_recv(client, scratch_msg))) {
- case 0:
+ LM_PARTIAL_SWITCH ((err = dhcp_client_recv(client, scratch_msg)).num) {
+ case E_NOERROR:
/* discard */
break;
- case -NET_ERECV_TIMEOUT:
+ case E_NET_ERECV_TIMEOUT:
dhcp_client_setstate(client, STATE_RENEWING, DHCP_MSGTYP_REQUEST, NULL, scratch_msg);
break;
default:
- assert(r < 0);
- log_debugln("error: recvfrom: ", r);
+ log_debugln("error: recvfrom: ", (error, err));
}
break;
case STATE_RENEWING:
@@ -841,8 +825,8 @@ static void dhcp_client_setstate(struct dhcp_client *client,
client->time_ns_init = LO_CALL(bootclock, get_time_ns);
LO_CALL(client->sock, set_recv_deadline, client->lease_time_ns_t2);
- switch ((r = dhcp_client_recv(client, scratch_msg))) {
- case 0:
+ LM_PARTIAL_SWITCH ((err = dhcp_client_recv(client, scratch_msg)).num) {
+ case E_NOERROR:
switch (scratch_msg->option_dat[scratch_msg->options[DHCP_OPT_DHCP_MSG_TYPE].off]) {
case DHCP_MSGTYP_NAK:
LO_CALL(client->iface, ifdown);
@@ -856,19 +840,18 @@ static void dhcp_client_setstate(struct dhcp_client *client,
/* ignore */
}
break;
- case -NET_ERECV_TIMEOUT:
+ case E_NET_ERECV_TIMEOUT:
client->lease_server_id = net_ip4_addr_zero;
dhcp_client_setstate(client, STATE_REBINDING, DHCP_MSGTYP_REQUEST, NULL, scratch_msg);
break;
default:
- assert(r < 0);
- log_debugln("error: recvfrom: ", r);
+ log_debugln("error: recvfrom: ", (error, err));
}
break;
case STATE_REBINDING:
LO_CALL(client->sock, set_recv_deadline, client->lease_time_ns_end);
- switch ((r = dhcp_client_recv(client, scratch_msg))) {
- case 0:
+ LM_PARTIAL_SWITCH ((err = dhcp_client_recv(client, scratch_msg)).num) {
+ case E_NOERROR:
switch (scratch_msg->option_dat[scratch_msg->options[DHCP_OPT_DHCP_MSG_TYPE].off]) {
case DHCP_MSGTYP_NAK:
LO_CALL(client->iface, ifdown);
@@ -882,13 +865,12 @@ static void dhcp_client_setstate(struct dhcp_client *client,
/* ignore */
}
break;
- case -NET_ERECV_TIMEOUT:
+ case E_NET_ERECV_TIMEOUT:
LO_CALL(client->iface, ifdown);
dhcp_client_setstate(client, STATE_BOUND, 0, NULL, scratch_msg);
break;
default:
- assert(r < 0);
- log_debugln("error: recvfrom: ", r);
+ log_debugln("error: recvfrom: ", (error, err));
}
break;
case STATE_INIT_REBOOT:
diff --git a/libdhcp/dhcp_common.c b/libdhcp/dhcp_common.c
new file mode 100644
index 0000000..d691836
--- /dev/null
+++ b/libdhcp/dhcp_common.c
@@ -0,0 +1,104 @@
+/* libdhcp/dhcp_common.c - Base definitions for the DHCP protocol
+ *
+ * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include "dhcp_common.h"
+
+/**
+ * DHCP Options
+ * https://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xhtml#options
+ */
+bool dhcp_opt_length_is_valid(uint8_t opt, uint16_t len) {
+ switch (opt) {
+ /* RFC 2132 */
+ case DHCP_OPT_PAD: return len == 0;
+ case DHCP_OPT_SUBNET_MASK: return len == 4;
+ case DHCP_OPT_TIME_OFFSET: return len == 4;
+ case DHCP_OPT_ROUTER: return len >= 4 && len % 4 == 0;
+ case DHCP_OPT_TIME_SERVER: return len >= 4 && len % 4 == 0;
+ case DHCP_OPT_NAME_SERVER: return len >= 4 && len % 4 == 0;
+ case DHCP_OPT_DOMAIN_SERVER: return len >= 4 && len % 4 == 0;
+ case DHCP_OPT_LOG_SERVER: return len >= 4 && len % 4 == 0;
+ case DHCP_OPT_QUOTES_SERVER: return len >= 4 && len % 4 == 0;
+ case DHCP_OPT_LPR_SERVER: return len >= 4 && len % 4 == 0;
+ case DHCP_OPT_IMPRESS_SERVER: return len >= 4 && len % 4 == 0;
+ case DHCP_OPT_RLP_SERVER: return len >= 4 && len % 4 == 0;
+ case DHCP_OPT_HOSTNAME: return len >= 1;
+ case DHCP_OPT_BOOT_FILE_SIZE: return len == 2;
+ case DHCP_OPT_MERIT_DUMP_FILE: return len >= 1;
+ case DHCP_OPT_DOMAIN_NAME: return len >= 1;
+ case DHCP_OPT_SWAP_SERVER: return len == 4; /* IANA says length is "N", but RFC 2132 says "length is 4"; likely releated to errata ID 487 */
+ case DHCP_OPT_ROOT_PATH: return len >= 1;
+ case DHCP_OPT_EXTENSION_FILE: return len >= 1;
+ case DHCP_OPT_FORWARD_ONOFF: return len == 1;
+ case DHCP_OPT_SRCRTE_ONOFF: return len == 1;
+ case DHCP_OPT_POLICY_FILTER: return len >= 8 && len % 8 == 0;
+ case DHCP_OPT_MAX_DG_ASSEMBLY: return len == 2;
+ case DHCP_OPT_DEFAULT_IP_TTL: return len == 1;
+ case DHCP_OPT_MTU_TIMEOUT: return len == 4;
+ case DHCP_OPT_MTU_PLATEAU: return len >= 2 && len % 2 == 0;
+ case DHCP_OPT_MTU_INTERFACE: return len == 2;
+ case DHCP_OPT_MTU_SUBNET: return len == 1;
+ case DHCP_OPT_BROADCAST_ADDRESS: return len == 4;
+ case DHCP_OPT_MASK_DISCOVERY: return len == 1;
+ case DHCP_OPT_MASK_SUPPLIER: return len == 1;
+ case DHCP_OPT_ROUTER_DISCOVERY: return len == 1;
+ case DHCP_OPT_ROUTER_REQUEST: return len == 4;
+ case DHCP_OPT_STATIC_ROUTE: return len >= 8 && len % 8 == 0;
+ case DHCP_OPT_TRAILERS: return len == 1;
+ case DHCP_OPT_ARP_TIMEOUT: return len == 4;
+ case DHCP_OPT_ETHERNET: return len == 1;
+ case DHCP_OPT_DEFAULT_TCP_TTL: return len == 1;
+ case DHCP_OPT_KEEPALIVE_TIME: return len == 4;
+ case DHCP_OPT_KEEPALIVE_DATA: return len == 1;
+ case DHCP_OPT_NIS_DOMAIN: return len >= 1;
+ case DHCP_OPT_NIS_SERVERS: return len >= 4 && len % 4 == 0;
+ case DHCP_OPT_NTP_SERVERS: return len >= 4 && len % 4 == 0;
+ case DHCP_OPT_VENDOR_SPECIFIC: return len >= 1;
+ case DHCP_OPT_NETBIOS_NAME_SRV: return len >= 4 && len % 4 == 0;
+ case DHCP_OPT_NETBIOS_DIST_SRV: return len >= 4 && len % 4 == 0;
+ case DHCP_OPT_NETBIOS_NODE_TYPE: return len == 1;
+ case DHCP_OPT_NETBIOS_SCOPE: return len >= 1;
+ case DHCP_OPT_X_WINDOW_FONT: return len >= 4 && len % 4 == 0;
+ case DHCP_OPT_X_WINDOW_MANAGER: return len >= 4 && len % 4 == 0;
+ case DHCP_OPT_ADDRESS_REQUEST: return len == 4;
+ case DHCP_OPT_ADDRESS_TIME: return len == 4;
+ case DHCP_OPT_OVERLOAD: return len == 1;
+ case DHCP_OPT_DHCP_MSG_TYPE: return len == 1;
+ case DHCP_OPT_DHCP_SERVER_ID: return len == 4;
+ case DHCP_OPT_PARAMETER_LIST: return len >= 1;
+ case DHCP_OPT_DHCP_MESSAGE: return len >= 1;
+ case DHCP_OPT_DHCP_MAX_MSG_SIZE: return len == 2;
+ case DHCP_OPT_RENEWAL_TIME: return len == 4;
+ case DHCP_OPT_REBINDING_TIME: return len == 4;
+ case DHCP_OPT_CLASS_ID: return len >= 1;
+ case DHCP_OPT_CLIENT_ID: return len >= 2;
+
+ /* RFC 2132 */
+ case DHCP_OPT_END: return len == 0;
+
+ /* Unrecognized */
+ default:
+ return true;
+ }
+}
+
+/**
+ * DHCP Message Type 53 Values
+ * https://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xhtml#message-type-53
+ */
+const char *dhcp_msgtyp_str(uint8_t typ) {
+ switch (typ) {
+ case DHCP_MSGTYP_DISCOVER: return "DHCP_MSGTYP_DISCOVER";
+ case DHCP_MSGTYP_OFFER: return "DHCP_MSGTYP_OFFER";
+ case DHCP_MSGTYP_REQUEST: return "DHCP_MSGTYP_REQUEST";
+ case DHCP_MSGTYP_DECLINE: return "DHCP_MSGTYP_DECLINE";
+ case DHCP_MSGTYP_ACK: return "DHCP_MSGTYP_ACK";
+ case DHCP_MSGTYP_NAK: return "DHCP_MSGTYP_NAK";
+ case DHCP_MSGTYP_RELEASE: return "DHCP_MSGTYP_RELEASE";
+ case DHCP_MSGTYP_INFORM: return "DHCP_MSGTYP_INFORM";
+ default: return const_byte_str(typ);
+ }
+}
diff --git a/libdhcp/dhcp_common.h b/libdhcp/dhcp_common.h
index 5b51ce2..a0cdd3c 100644
--- a/libdhcp/dhcp_common.h
+++ b/libdhcp/dhcp_common.h
@@ -1,6 +1,6 @@
/* libdhcp/dhcp_common.h - Base definitions for the DHCP protocol
*
- * 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
*
* -----------------------------------------------------------------------------
@@ -67,8 +67,9 @@
#ifndef _LIBDHCP_DHCP_COMMON_H_
#define _LIBDHCP_DHCP_COMMON_H_
-#include <libmisc/endian.h>
-#include <libmisc/log.h> /* for const_byte_str() */
+#include <libhw/generic/net.h> /* for struct net_ip4_addr */
+#include <libmisc/endian.h> /* for uint{n}be_t */
+#include <libmisc/log.h> /* for const_byte_str() */
/* Config *********************************************************************/
@@ -215,80 +216,7 @@ static const uint8_t dhcp_magic_cookie[] = {99, 130, 83, 99};
/* ... */
#define DHCP_OPT_END ((uint8_t)255) /* RFC2132: length: 0; meaning: None */
-static inline bool dhcp_opt_length_is_valid(uint8_t opt, uint16_t len) {
- switch (opt) {
- /* RFC 2132 */
- case DHCP_OPT_PAD: return len == 0;
- case DHCP_OPT_SUBNET_MASK: return len == 4;
- case DHCP_OPT_TIME_OFFSET: return len == 4;
- case DHCP_OPT_ROUTER: return len >= 4 && len % 4 == 0;
- case DHCP_OPT_TIME_SERVER: return len >= 4 && len % 4 == 0;
- case DHCP_OPT_NAME_SERVER: return len >= 4 && len % 4 == 0;
- case DHCP_OPT_DOMAIN_SERVER: return len >= 4 && len % 4 == 0;
- case DHCP_OPT_LOG_SERVER: return len >= 4 && len % 4 == 0;
- case DHCP_OPT_QUOTES_SERVER: return len >= 4 && len % 4 == 0;
- case DHCP_OPT_LPR_SERVER: return len >= 4 && len % 4 == 0;
- case DHCP_OPT_IMPRESS_SERVER: return len >= 4 && len % 4 == 0;
- case DHCP_OPT_RLP_SERVER: return len >= 4 && len % 4 == 0;
- case DHCP_OPT_HOSTNAME: return len >= 1;
- case DHCP_OPT_BOOT_FILE_SIZE: return len == 2;
- case DHCP_OPT_MERIT_DUMP_FILE: return len >= 1;
- case DHCP_OPT_DOMAIN_NAME: return len >= 1;
- case DHCP_OPT_SWAP_SERVER: return len == 4; /* IANA says length is "N", but RFC 2132 says "length is 4"; likely releated to errata ID 487 */
- case DHCP_OPT_ROOT_PATH: return len >= 1;
- case DHCP_OPT_EXTENSION_FILE: return len >= 1;
- case DHCP_OPT_FORWARD_ONOFF: return len == 1;
- case DHCP_OPT_SRCRTE_ONOFF: return len == 1;
- case DHCP_OPT_POLICY_FILTER: return len >= 8 && len % 8 == 0;
- case DHCP_OPT_MAX_DG_ASSEMBLY: return len == 2;
- case DHCP_OPT_DEFAULT_IP_TTL: return len == 1;
- case DHCP_OPT_MTU_TIMEOUT: return len == 4;
- case DHCP_OPT_MTU_PLATEAU: return len >= 2 && len % 2 == 0;
- case DHCP_OPT_MTU_INTERFACE: return len == 2;
- case DHCP_OPT_MTU_SUBNET: return len == 1;
- case DHCP_OPT_BROADCAST_ADDRESS: return len == 4;
- case DHCP_OPT_MASK_DISCOVERY: return len == 1;
- case DHCP_OPT_MASK_SUPPLIER: return len == 1;
- case DHCP_OPT_ROUTER_DISCOVERY: return len == 1;
- case DHCP_OPT_ROUTER_REQUEST: return len == 4;
- case DHCP_OPT_STATIC_ROUTE: return len >= 8 && len % 8 == 0;
- case DHCP_OPT_TRAILERS: return len == 1;
- case DHCP_OPT_ARP_TIMEOUT: return len == 4;
- case DHCP_OPT_ETHERNET: return len == 1;
- case DHCP_OPT_DEFAULT_TCP_TTL: return len == 1;
- case DHCP_OPT_KEEPALIVE_TIME: return len == 4;
- case DHCP_OPT_KEEPALIVE_DATA: return len == 1;
- case DHCP_OPT_NIS_DOMAIN: return len >= 1;
- case DHCP_OPT_NIS_SERVERS: return len >= 4 && len % 4 == 0;
- case DHCP_OPT_NTP_SERVERS: return len >= 4 && len % 4 == 0;
- case DHCP_OPT_VENDOR_SPECIFIC: return len >= 1;
- case DHCP_OPT_NETBIOS_NAME_SRV: return len >= 4 && len % 4 == 0;
- case DHCP_OPT_NETBIOS_DIST_SRV: return len >= 4 && len % 4 == 0;
- case DHCP_OPT_NETBIOS_NODE_TYPE: return len == 1;
- case DHCP_OPT_NETBIOS_SCOPE: return len >= 1;
- case DHCP_OPT_X_WINDOW_FONT: return len >= 4 && len % 4 == 0;
- case DHCP_OPT_X_WINDOW_MANAGER: return len >= 4 && len % 4 == 0;
- case DHCP_OPT_ADDRESS_REQUEST: return len == 4;
- case DHCP_OPT_ADDRESS_TIME: return len == 4;
- case DHCP_OPT_OVERLOAD: return len == 1;
- case DHCP_OPT_DHCP_MSG_TYPE: return len == 1;
- case DHCP_OPT_DHCP_SERVER_ID: return len == 4;
- case DHCP_OPT_PARAMETER_LIST: return len >= 1;
- case DHCP_OPT_DHCP_MESSAGE: return len >= 1;
- case DHCP_OPT_DHCP_MAX_MSG_SIZE: return len == 2;
- case DHCP_OPT_RENEWAL_TIME: return len == 4;
- case DHCP_OPT_REBINDING_TIME: return len == 4;
- case DHCP_OPT_CLASS_ID: return len >= 1;
- case DHCP_OPT_CLIENT_ID: return len >= 2;
-
- /* RFC 2132 */
- case DHCP_OPT_END: return len == 0;
-
- /* Unrecognized */
- default:
- return true;
- }
-};
+bool dhcp_opt_length_is_valid(uint8_t opt, uint16_t len);
/**
* DHCP Message Type 53 Values
@@ -303,18 +231,6 @@ static inline bool dhcp_opt_length_is_valid(uint8_t opt, uint16_t len) {
#define DHCP_MSGTYP_RELEASE ((uint8_t) 7) /* RFC2132, client->server */
#define DHCP_MSGTYP_INFORM ((uint8_t) 8) /* RFC2132, client->server */
-static const char *dhcp_msgtyp_str(uint8_t typ) {
- switch (typ) {
- case DHCP_MSGTYP_DISCOVER: return "DHCP_MSGTYP_DISCOVER";
- case DHCP_MSGTYP_OFFER: return "DHCP_MSGTYP_OFFER";
- case DHCP_MSGTYP_REQUEST: return "DHCP_MSGTYP_REQUEST";
- case DHCP_MSGTYP_DECLINE: return "DHCP_MSGTYP_DECLINE";
- case DHCP_MSGTYP_ACK: return "DHCP_MSGTYP_ACK";
- case DHCP_MSGTYP_NAK: return "DHCP_MSGTYP_NAK";
- case DHCP_MSGTYP_RELEASE: return "DHCP_MSGTYP_RELEASE";
- case DHCP_MSGTYP_INFORM: return "DHCP_MSGTYP_INFORM";
- default: return const_byte_str(typ);
- }
-}
+const char *dhcp_msgtyp_str(uint8_t typ);
#endif /* _LIBDHCP_DHCP_COMMON_H_ */
diff --git a/libdhcp/include/libdhcp/client.h b/libdhcp/include/libdhcp/client.h
index f81e9b1..d1711b2 100644
--- a/libdhcp/include/libdhcp/client.h
+++ b/libdhcp/include/libdhcp/client.h
@@ -2,66 +2,6 @@
*
* Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
- *
- * -----------------------------------------------------------------------------
- * https://github.com/Wiznet/ioLibrary_Driver/blob/b981401e7f3d07015619adf44c13998e13e777f9/Internet/DHCP/dhcp.h
- *
- * Copyright (c) 2013, WIZnet Co., LTD.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of the <ORGANIZATION> nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * -----------------------------------------------------------------------------
- * https://github.com/Wiznet/ioLibrary_Driver/blob/b981401e7f3d07015619adf44c13998e13e777f9/license.txt
- *
- * Copyright (c) 2014 WIZnet Co.,Ltd.
- * Copyright (c) WIZnet ioLibrary Project.
- * All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * SPDX-License-Identifier: MIT
*/
#ifndef _LIBDHCP_CLIENT_H_
diff --git a/libdhcp/tests/config.h b/libdhcp/tests/config.h
new file mode 100644
index 0000000..299d020
--- /dev/null
+++ b/libdhcp/tests/config.h
@@ -0,0 +1,25 @@
+/* libdhcp/tests/config.h - Compile-time configuration for the libdhcp tests
+ *
+ * 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_COROUTINE_STACK_SIZE_DEFAULT (16*1024)
+#define CONFIG_COROUTINE_NAME_LEN 16
+#define CONFIG_COROUTINE_NUM 16
+
+#define CONFIG_COROUTINE_MEASURE_STACK 1
+#define CONFIG_COROUTINE_PROTECT_STACK 1
+#define CONFIG_COROUTINE_DEBUG 1
+#define CONFIG_COROUTINE_VALGRIND 1
+#define CONFIG_COROUTINE_GDB 1
+
+#define CONFIG_DHCP_CAN_RECV_UNICAST_IP_WITHOUT_IP 0 /* bool */
+#define CONFIG_DHCP_DEBUG 1 /* bool */
+#define CONFIG_DHCP_OPT_SIZE 312 /* minimum of 312 */
+#define CONFIG_DHCP_SELECTING_NS (5*NS_PER_S)
+
+#endif /* _CONFIG_H_ */
diff --git a/libdhcp/tests/test.h b/libdhcp/tests/test.h
new file mode 120000
index 0000000..2fb1bd5
--- /dev/null
+++ b/libdhcp/tests/test.h
@@ -0,0 +1 @@
+../../libmisc/tests/test.h \ No newline at end of file
diff --git a/libdhcp/tests/test_client.c b/libdhcp/tests/test_client.c
new file mode 100644
index 0000000..6446cef
--- /dev/null
+++ b/libdhcp/tests/test_client.c
@@ -0,0 +1,120 @@
+/* libdhcp/tests/test_client.c - Tests for libdhcp client
+ *
+ * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <string.h> /* for memcpy() */
+
+#include <libcr/coroutine.h>
+#include <libhw/generic/net.h>
+#include <libhw/host_alarmclock.h>
+
+#include <libdhcp/client.h>
+
+#include "test.h"
+
+/******************************************************************************/
+
+struct test_udp {
+};
+LO_IMPLEMENTATION_STATIC(io_closer, struct test_udp, test_udp);
+LO_IMPLEMENTATION_STATIC(net_packet_conn, struct test_udp, test_udp);
+
+static error test_udp_sendto(struct test_udp *LM_UNUSED(self), void *LM_UNUSED(buf), size_t LM_UNUSED(len), struct net_ip4_addr LM_UNUSED(node), uint16_t LM_UNUSED(port)) {
+ static unsigned cnt = 0;
+ if (cnt++ % 2 == 0)
+ return error_new(E_EUNKNOWN);
+ return ERROR_NULL;
+}
+
+static size_t_or_error test_udp_recvfrom(struct test_udp *LM_UNUSED(self), void *buf, size_t len, struct net_ip4_addr *ret_node, uint16_t *ret_port) {
+ static const uint8_t resp_offer[] = {0x02,0x01,0x06,0x00,0xE8,0x40,0xC6,0x79,0x00,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0xC0,0xA8,0x0A,0x78,0xC0,0xA8,0x0A,0x01,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x63,0x82,0x53,0x63,0x35,0x01,0x02,0x36,0x04,0xC0,0xA8,0x0A,0x01,0x33,0x04,0x00,0x00,0xA8,0xC0,0x3A,0x04,0x00,0x00,0x54,0x60,0x3B,0x04,0x00,0x00,0x93,0xA8,0x01,0x04,0xFF,0xFF,0xFF,0x00,0x1C,0x04,0xC0,0xA8,0x0A,0xFF,0x03,0x04,0xC0,0xA8,0x0A,0x01,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+ static const uint8_t resp_ack[] = {0x02,0x01,0x06,0x00,0xE8,0x40,0xC6,0x79,0x00,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0xC0,0xA8,0x0A,0x78,0xC0,0xA8,0x0A,0x01,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x63,0x82,0x53,0x63,0x35,0x01,0x05,0x36,0x04,0xC0,0xA8,0x0A,0x01,0x33,0x04,0x00,0x00,0xA8,0xC0,0x3A,0x04,0x00,0x00,0x54,0x60,0x3B,0x04,0x00,0x00,0x93,0xA8,0x01,0x04,0xFF,0xFF,0xFF,0x00,0x1C,0x04,0xC0,0xA8,0x0A,0xFF,0x03,0x04,0xC0,0xA8,0x0A,0x01,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+
+ static unsigned cnt = 0;
+ const void *resp;
+ size_t resp_len;
+ switch (cnt++) {
+ case 0: return ERROR_NEW_ERR(size_t, error_new(E_EUNKNOWN));
+ case 1: resp = resp_offer; resp_len = sizeof(resp_offer); break;
+ case 2: return ERROR_NEW_ERR(size_t, error_new(E_EUNKNOWN));
+ case 3: resp = resp_ack; resp_len = sizeof(resp_ack); break;
+ default: return ERROR_NEW_ERR(size_t, error_new(E_NET_ERECV_TIMEOUT));
+ }
+ test_assert(len >= resp_len);
+ memcpy(buf, resp, resp_len);
+ *ret_node = ((struct net_ip4_addr){{192,168,10,1}});
+ *ret_port = 67;
+ return ERROR_NEW_VAL(size_t, resp_len);
+}
+
+static void test_udp_set_recv_deadline(struct test_udp *LM_UNUSED(self), uint64_t LM_UNUSED(ns_since_boot)) {
+ /* Do nothing? */
+}
+
+static error test_udp_close(struct test_udp *LM_UNUSED(self)) {
+ assert_notreached("not implemented");
+}
+
+/******************************************************************************/
+
+struct test_iface {
+ struct net_iface_config cfg;
+
+ struct test_udp conn;
+};
+LO_IMPLEMENTATION_STATIC(net_iface, struct test_iface, test);
+
+static struct net_eth_addr test_hwaddr(struct test_iface *LM_UNUSED(self)) {
+ struct net_eth_addr ret = {{1, 2, 3, 4, 5, 6}};
+ return ret;
+}
+
+static void test_ifup(struct test_iface *LM_UNUSED(self), struct net_iface_config LM_UNUSED(cfg)) {
+ cr_exit();
+}
+
+static void test_ifdown(struct test_iface *LM_UNUSED(self)) {
+ assert_notreached("not implemented");
+}
+
+static bool test_arp_ping(struct test_iface *LM_UNUSED(self), struct net_ip4_addr LM_UNUSED(addr)) {
+ return false;
+}
+
+static lo_interface net_stream_listener test_tcp_listen(struct test_iface *LM_UNUSED(self), uint16_t LM_UNUSED(local_port)) {
+ assert_notreached("not implemented");
+}
+
+static net_stream_conn_or_error test_tcp_dial(struct test_iface *LM_UNUSED(self), struct net_ip4_addr LM_UNUSED(remote_node), uint16_t LM_UNUSED(remote_port)) {
+ assert_notreached("not implemented");
+}
+
+static lo_interface net_packet_conn test_udp_conn(struct test_iface *self, uint16_t local_port) {
+ bool once = false;
+ test_assert(local_port == 68);
+ test_assert(!once);
+ once = true;
+ return LO_BOX(net_packet_conn, &self->conn);
+}
+
+/******************************************************************************/
+
+COROUTINE dhcp_cr(void *) {
+ cr_begin();
+ struct test_iface iface = {};
+ dhcp_client_main(LO_BOX(net_iface, &iface), "test-client");
+ cr_end();
+}
+
+int main() {
+ struct hostclock clock_monotonic = {
+ .clock_id = CLOCK_MONOTONIC,
+ };
+ bootclock = LO_BOX(alarmclock, &clock_monotonic);
+
+ coroutine_add("dhcp", dhcp_cr, NULL);
+ coroutine_main();
+ return 0;
+}
diff --git a/libhw_cr/CMakeLists.txt b/libhw_cr/CMakeLists.txt
index ba20b26..9dd6a27 100644
--- a/libhw_cr/CMakeLists.txt
+++ b/libhw_cr/CMakeLists.txt
@@ -24,6 +24,7 @@ if (PICO_PLATFORM STREQUAL "rp2040")
rp2040_hwspi.c
rp2040_hwtimer.c
w5500.c
+ w5500_ll.c
)
target_link_libraries(libhw_cr INTERFACE
hardware_gpio
diff --git a/libhw_cr/host_alarmclock.c b/libhw_cr/host_alarmclock.c
index ac2093c..0c42677 100644
--- a/libhw_cr/host_alarmclock.c
+++ b/libhw_cr/host_alarmclock.c
@@ -5,9 +5,12 @@
*/
#include <errno.h>
-#include <error.h>
#include <signal.h>
+#define error __error
+#include <error.h>
+#undef error
+
#include <libcr/coroutine.h>
#include <libmisc/assert.h>
@@ -19,15 +22,15 @@
#include "host_util.h" /* for host_sigrt_alloc(), ns_to_host_ns_time() */
-LO_IMPLEMENTATION_C(alarmclock, struct hostclock, hostclock, static);
+LO_IMPLEMENTATION_C(alarmclock, struct hostclock, hostclock);
-static uint64_t hostclock_get_time_ns(struct hostclock *alarmclock) {
+uint64_t hostclock_get_time_ns(struct hostclock *alarmclock) {
assert(alarmclock);
struct timespec ts;
if (clock_gettime(alarmclock->clock_id, &ts) != 0)
- error(1, errno, "clock_gettime(%d)", (int)alarmclock->clock_id);
+ __error(1, errno, "clock_gettime(%d)", (int)alarmclock->clock_id);
return ns_from_host_ns_time(ts);
}
@@ -52,15 +55,15 @@ static void hostclock_handle_sig_alarm(int LM_UNUSED(sig), siginfo_t *info, void
.it_interval = {},
};
if (timer_settime(alarmclock->timer_id, TIMER_ABSTIME, &alarmspec, NULL) != 0)
- error(1, errno, "timer_settime");
+ __error(1, errno, "timer_settime");
}
}
-static bool hostclock_add_trigger(struct hostclock *alarmclock,
- struct alarmclock_trigger *trigger,
- uint64_t fire_at_ns,
- void (*cb)(void *),
- void *cb_arg) {
+void hostclock_add_trigger(struct hostclock *alarmclock,
+ struct alarmclock_trigger *trigger,
+ uint64_t fire_at_ns,
+ void (*cb)(void *),
+ void *cb_arg) {
assert(alarmclock);
assert(trigger);
assert(fire_at_ns);
@@ -72,6 +75,7 @@ static bool hostclock_add_trigger(struct hostclock *alarmclock,
trigger->cb_arg = cb_arg;
bool saved = cr_save_and_disable_interrupts();
+
struct alarmclock_trigger **dst = &alarmclock->queue;
while (*dst && fire_at_ns >= (*dst)->fire_at_ns)
dst = &(*dst)->next;
@@ -80,6 +84,7 @@ static bool hostclock_add_trigger(struct hostclock *alarmclock,
if (*dst)
(*dst)->prev = trigger;
*dst = trigger;
+
if (!alarmclock->initialized) {
struct sigevent how_to_notify = {
.sigev_notify = SIGEV_SIGNAL,
@@ -93,26 +98,26 @@ static bool hostclock_add_trigger(struct hostclock *alarmclock,
.sa_sigaction = hostclock_handle_sig_alarm,
};
if (sigaction(how_to_notify.sigev_signo, &action, NULL) != 0)
- error(1, errno, "sigaction");
+ __error(1, errno, "sigaction");
if (timer_create(alarmclock->clock_id, &how_to_notify, &alarmclock->timer_id) != 0)
- error(1, errno, "timer_create(%d)", (int)alarmclock->clock_id);
+ __error(1, errno, "timer_create(%d)", (int)alarmclock->clock_id);
alarmclock->initialized = true;
}
+
if (alarmclock->queue == trigger) {
struct itimerspec alarmspec = {
.it_value = ns_to_host_ns_time(trigger->fire_at_ns),
.it_interval = {},
};
if (timer_settime(alarmclock->timer_id, TIMER_ABSTIME, &alarmspec, NULL) != 0)
- error(1, errno, "timer_settime");
+ __error(1, errno, "timer_settime");
}
- cr_restore_interrupts(saved);
- return false;
+ cr_restore_interrupts(saved);
}
-static void hostclock_del_trigger(struct hostclock *alarmclock,
- struct alarmclock_trigger *trigger) {
+ void hostclock_del_trigger(struct hostclock *alarmclock,
+ struct alarmclock_trigger *trigger) {
assert(alarmclock);
assert(trigger);
diff --git a/libhw_cr/host_include/libhw/host_alarmclock.h b/libhw_cr/host_include/libhw/host_alarmclock.h
index 3cc43c1..2ddb054 100644
--- a/libhw_cr/host_include/libhw/host_alarmclock.h
+++ b/libhw_cr/host_include/libhw/host_alarmclock.h
@@ -7,10 +7,10 @@
#ifndef _LIBHW_HOST_ALARMCLOCK_H_
#define _LIBHW_HOST_ALARMCLOCK_H_
-#include <time.h> /* for clockid_t, timer_t */
+#include <time.h> /* for clockid_t, timer_t */
-#include <libmisc/private.h>
#include <libhw/generic/alarmclock.h>
+#include <libmisc/private.h>
struct hostclock {
clockid_t clock_id;
diff --git a/libhw_cr/host_include/libhw/host_net.h b/libhw_cr/host_include/libhw/host_net.h
index a16ed01..6ff2779 100644
--- a/libhw_cr/host_include/libhw/host_net.h
+++ b/libhw_cr/host_include/libhw/host_net.h
@@ -13,13 +13,16 @@
#include <libhw/generic/net.h>
+/* TCP connection *************************************************************/
+
struct _hostnet_tcp_conn {
BEGIN_PRIVATE(LIBHW_HOST_NET_H);
int fd;
uint64_t read_deadline_ns;
END_PRIVATE(LIBHW_HOST_NET_H);
};
-LO_IMPLEMENTATION_H(net_stream_conn, struct _hostnet_tcp_conn, hostnet_tcp);
+
+/* TCP listener ***************************************************************/
struct hostnet_tcp_listener {
BEGIN_PRIVATE(LIBHW_HOST_NET_H);
@@ -27,16 +30,20 @@ struct hostnet_tcp_listener {
struct _hostnet_tcp_conn active_conn;
END_PRIVATE(LIBHW_HOST_NET_H);
};
+LO_IMPLEMENTATION_H(io_closer, struct hostnet_tcp_listener, hostnet_tcplist);
LO_IMPLEMENTATION_H(net_stream_listener, struct hostnet_tcp_listener, hostnet_tcplist);
void hostnet_tcp_listener_init(struct hostnet_tcp_listener *self, uint16_t port);
+/* UDP connection *************************************************************/
+
struct hostnet_udp_conn {
BEGIN_PRIVATE(LIBHW_HOST_NET_H);
int fd;
uint64_t read_deadline_ns;
END_PRIVATE(LIBHW_HOST_NET_H);
};
+LO_IMPLEMENTATION_H(io_closer, struct hostnet_udp_conn, hostnet_udp);
LO_IMPLEMENTATION_H(net_packet_conn, struct hostnet_udp_conn, hostnet_udp);
void hostnet_udp_conn_init(struct hostnet_udp_conn *self, uint16_t port);
diff --git a/libhw_cr/host_net.c b/libhw_cr/host_net.c
index 4a2e65f..e68ccf8 100644
--- a/libhw_cr/host_net.c
+++ b/libhw_cr/host_net.c
@@ -7,11 +7,13 @@
#define _GNU_SOURCE /* for pthread_sigqueue(3gnu) */
/* misc */
#include <errno.h> /* for errno, EAGAIN, EINVAL */
+#define error __error
#include <error.h> /* for error(3gnu) */
+#undef error
#include <stdlib.h> /* for abs(), shutdown(), SHUT_RD, SHUT_WR, SHUT_RDWR */
-#include <unistd.h> /* for read(), write() */
+#include <sys/uio.h> /* for readv(), writev(), struct iovec */
/* net */
-#include <arpa/inet.h> /* for htons(3p) */
+#include <arpa/inet.h> /* for htons() */
#include <netinet/in.h> /* for struct sockaddr_in */
#include <sys/socket.h> /* for struct sockaddr{,_storage}, SOCK_*, SOL_*, SO_*, socket(), setsockopt(), bind(), listen(), accept() */
/* async */
@@ -31,18 +33,18 @@
#include "host_util.h" /* for host_sigrt_alloc(), ns_to_host_us_time() */
-LO_IMPLEMENTATION_C(io_closer, struct hostnet_tcp_listener, hostnet_tcplist, static);
-LO_IMPLEMENTATION_C(net_stream_listener, struct hostnet_tcp_listener, hostnet_tcplist, static);
+LO_IMPLEMENTATION_C(io_closer, struct hostnet_tcp_listener, hostnet_tcplist);
+LO_IMPLEMENTATION_C(net_stream_listener, struct hostnet_tcp_listener, hostnet_tcplist);
-LO_IMPLEMENTATION_C(io_reader, struct _hostnet_tcp_conn, hostnet_tcp, static);
-LO_IMPLEMENTATION_C(io_writer, struct _hostnet_tcp_conn, hostnet_tcp, static);
-LO_IMPLEMENTATION_C(io_readwriter, struct _hostnet_tcp_conn, hostnet_tcp, static);
-LO_IMPLEMENTATION_C(io_closer, struct _hostnet_tcp_conn, hostnet_tcp, static);
-LO_IMPLEMENTATION_C(io_bidi_closer, struct _hostnet_tcp_conn, hostnet_tcp, static);
-LO_IMPLEMENTATION_C(net_stream_conn, struct _hostnet_tcp_conn, hostnet_tcp, static);
+LO_IMPLEMENTATION_STATIC(io_reader, struct _hostnet_tcp_conn, hostnet_tcp);
+LO_IMPLEMENTATION_STATIC(io_writer, struct _hostnet_tcp_conn, hostnet_tcp);
+LO_IMPLEMENTATION_STATIC(io_readwriter, struct _hostnet_tcp_conn, hostnet_tcp);
+LO_IMPLEMENTATION_STATIC(io_closer, struct _hostnet_tcp_conn, hostnet_tcp);
+LO_IMPLEMENTATION_STATIC(io_bidi_closer, struct _hostnet_tcp_conn, hostnet_tcp);
+LO_IMPLEMENTATION_STATIC(net_stream_conn, struct _hostnet_tcp_conn, hostnet_tcp);
-LO_IMPLEMENTATION_C(io_closer, struct hostnet_udp_conn, hostnet_udp, static);
-LO_IMPLEMENTATION_C(net_packet_conn, struct hostnet_udp_conn, hostnet_udp, static);
+LO_IMPLEMENTATION_C(io_closer, struct hostnet_udp_conn, hostnet_udp);
+LO_IMPLEMENTATION_C(net_packet_conn, struct hostnet_udp_conn, hostnet_udp);
/* common *********************************************************************/
@@ -63,7 +65,7 @@ static void hostnet_init(void) {
action.sa_flags = SA_SIGINFO;
action.sa_sigaction = hostnet_handle_sig_io;
if (sigaction(hostnet_sig_io, &action, NULL) < 0)
- error(1, errno, "sigaction");
+ __error(1, errno, "sigaction");
}
#define WAKE_COROUTINE(args) do { \
@@ -78,46 +80,47 @@ static void hostnet_init(void) {
} while (r == EAGAIN); \
} while (0)
-static inline bool RUN_PTHREAD(void *(*fn)(void *), void *args) {
+static inline host_errno_t RUN_PTHREAD(void *(*fn)(void *), void *args) {
pthread_t thread;
+ host_errno_t r;
bool saved = cr_save_and_disable_interrupts();
- if (pthread_create(&thread, NULL, fn, args))
- return true;
+ r = pthread_create(&thread, NULL, fn, args);
+ if (r) {
+ cr_restore_interrupts(saved);
+ return r;
+ }
cr_pause_and_yield();
cr_restore_interrupts(saved);
- if (pthread_join(thread, NULL))
- return true;
- return false;
+ return pthread_join(thread, NULL);
}
enum hostnet_timeout_op {
- OP_NONE,
+ OP_CLOSE,
OP_SEND,
OP_RECV,
};
-static inline ssize_t hostnet_map_negerrno(ssize_t v, enum hostnet_timeout_op op) {
- if (v >= 0)
- return v;
- switch (v) {
- case -EHOSTUNREACH:
- return -NET_EARP_TIMEOUT;
- case -ETIMEDOUT:
+static inline error hostnet_error(host_errno_t errnum, enum hostnet_timeout_op op) {
+ assert(errnum > 0);
+ switch (errnum) {
+ case EHOSTUNREACH:
+ return error_new(E_NET_EARP_TIMEOUT);
+ case ETIMEDOUT:
switch (op) {
- case OP_NONE:
+ case OP_CLOSE:
assert_notreached("impossible ETIMEDOUT");
case OP_SEND:
- return -NET_EACK_TIMEOUT;
+ return error_new(E_NET_EACK_TIMEOUT);
case OP_RECV:
- return -NET_ERECV_TIMEOUT;
+ return error_new(E_NET_ERECV_TIMEOUT);
}
assert_notreached("invalid timeout op");
- case -EBADF:
- return -NET_ECLOSED;
- case -EMSGSIZE:
- return -NET_EMSGSIZE;
+ case EBADF:
+ return error_new(E_NET_ECLOSED);
+ case EMSGSIZE:
+ return error_new(E_POSIX_EMSGSIZE);
default:
- return -NET_EOTHER;
+ return errno2lm(errnum);
}
}
@@ -136,15 +139,15 @@ void hostnet_tcp_listener_init(struct hostnet_tcp_listener *self, uint16_t port)
addr.in.sin_port = htons(port);
listenerfd = socket(AF_INET, SOCK_STREAM, 0);
if (listenerfd < 0)
- error(1, errno, "socket");
+ __error(1, errno, "socket");
if (setsockopt(listenerfd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) < 0)
- error(1, errno, "setsockopt(fd=%d, SO_REUSEADDR=1)", listenerfd);
+ __error(1, errno, "setsockopt(fd=%d, SO_REUSEADDR=1)", listenerfd);
if (setsockopt(listenerfd, SOL_SOCKET, SO_REUSEPORT, &(int){1}, sizeof(int)) < 0)
- error(1, errno, "setsockopt(fd=%d, SO_REUSEPORT=1)", listenerfd);
+ __error(1, errno, "setsockopt(fd=%d, SO_REUSEPORT=1)", listenerfd);
if (bind(listenerfd, &addr.gen, sizeof addr) < 0)
- error(1, errno, "bind(fd=%d)", listenerfd);
+ __error(1, errno, "bind(fd=%d)", listenerfd);
if (listen(listenerfd, 0) < 0)
- error(1, errno, "listen(fd=%d)", listenerfd);
+ __error(1, errno, "listen(fd=%d)", listenerfd);
self->fd = listenerfd;
}
@@ -158,44 +161,48 @@ struct hostnet_pthread_accept_args {
int listenerfd;
int *ret_connfd;
+ host_errno_t *ret_errno;
};
static void *hostnet_pthread_accept(void *_args) {
struct hostnet_pthread_accept_args *args = _args;
*(args->ret_connfd) = accept(args->listenerfd, NULL, NULL);
- if (*(args->ret_connfd) < 0)
- *(args->ret_connfd) = -errno;
+ *(args->ret_errno) = errno;
WAKE_COROUTINE(args);
return NULL;
}
-static lo_interface net_stream_conn hostnet_tcplist_accept(struct hostnet_tcp_listener *listener) {
+net_stream_conn_or_error hostnet_tcplist_accept(struct hostnet_tcp_listener *listener) {
assert(listener);
int ret_connfd;
+ host_errno_t ret_errno;
struct hostnet_pthread_accept_args args = {
.cr_thread = pthread_self(),
.cr_coroutine = cr_getcid(),
.listenerfd = listener->fd,
.ret_connfd = &ret_connfd,
+ .ret_errno = &ret_errno,
};
- if (RUN_PTHREAD(hostnet_pthread_accept, &args))
- return LO_NULL(net_stream_conn);
-
+ host_errno_t thread_errno = RUN_PTHREAD(hostnet_pthread_accept, &args);
+ if (thread_errno)
+ return ERROR_NEW_ERR(net_stream_conn, errno2lm(thread_errno));
if (ret_connfd < 0)
- return LO_NULL(net_stream_conn);
+ return ERROR_NEW_ERR(net_stream_conn, hostnet_error(ret_errno, OP_RECV));
listener->active_conn.fd = ret_connfd;
listener->active_conn.read_deadline_ns = 0;
- return lo_box_hostnet_tcp_as_net_stream_conn(&listener->active_conn);
+ return ERROR_NEW_VAL(net_stream_conn, LO_BOX(net_stream_conn, &listener->active_conn));
}
/* TCP listener close() *******************************************************/
-static int hostnet_tcplist_close(struct hostnet_tcp_listener *listener) {
+error hostnet_tcplist_close(struct hostnet_tcp_listener *listener) {
assert(listener);
- return hostnet_map_negerrno(shutdown(listener->fd, SHUT_RDWR) ? -errno : 0, OP_NONE);
+ if (shutdown(listener->fd, SHUT_RDWR))
+ return hostnet_error(errno, OP_CLOSE);
+ return ERROR_NULL;
}
/* TCP read() *****************************************************************/
@@ -215,29 +222,36 @@ struct hostnet_pthread_readv_args {
const struct iovec *iov;
int iovcnt;
- ssize_t *ret;
+ size_t *ret_size;
+ host_errno_t *ret_errno;
};
static void *hostnet_pthread_readv(void *_args) {
struct hostnet_pthread_readv_args *args = _args;
- *(args->ret) = setsockopt(args->connfd, SOL_SOCKET, SO_RCVTIMEO,
- &args->timeout, sizeof(args->timeout));
- if (*(args->ret) < 0)
+ int r_i = setsockopt(args->connfd, SOL_SOCKET, SO_RCVTIMEO,
+ &args->timeout, sizeof(args->timeout));
+ if (r_i) {
+ *args->ret_size = 0;
+ *args->ret_errno = errno;
goto end;
+ }
- *(args->ret) = readv(args->connfd, args->iov, args->iovcnt);
- if (*(args->ret) < 0)
+ ssize_t r_ss = readv(args->connfd, args->iov, args->iovcnt);
+ if (r_ss < 0) {
+ *args->ret_size = 0;
+ *args->ret_errno = errno;
goto end;
+ }
+ *args->ret_size = r_ss;
+ *args->ret_errno = 0;
end:
- if (*(args->ret) < 0)
- *(args->ret) = hostnet_map_negerrno(-errno, OP_SEND);
WAKE_COROUTINE(args);
return NULL;
}
-static ssize_t hostnet_tcp_readv(struct _hostnet_tcp_conn *conn, const struct iovec *iov, int iovcnt) {
+static size_t_or_error hostnet_tcp_readv(struct _hostnet_tcp_conn *conn, const struct rd_iovec *iov, int iovcnt) {
assert(conn);
assert(iov);
assert(iovcnt > 0);
@@ -246,29 +260,36 @@ static ssize_t hostnet_tcp_readv(struct _hostnet_tcp_conn *conn, const struct io
count += iov[i].iov_len;
assert(count);
- ssize_t ret;
+ size_t ret_size;
+ host_errno_t ret_errno;
struct hostnet_pthread_readv_args args = {
.cr_thread = pthread_self(),
.cr_coroutine = cr_getcid(),
.connfd = conn->fd,
- .iov = iov,
+ .iov = (const struct iovec *)iov,
.iovcnt = iovcnt,
- .ret = &ret,
+ .ret_size = &ret_size,
+ .ret_errno = &ret_errno,
};
if (conn->read_deadline_ns) {
uint64_t now_ns = LO_CALL(bootclock, get_time_ns);
if (conn->read_deadline_ns < now_ns)
- return -NET_ERECV_TIMEOUT;
+ return ERROR_NEW_ERR(size_t, error_new(E_NET_ERECV_TIMEOUT));
args.timeout = ns_to_host_us_time(conn->read_deadline_ns-now_ns);
} else {
args.timeout = (host_us_time_t){};
}
- if (RUN_PTHREAD(hostnet_pthread_readv, &args))
- return -NET_ETHREAD;
- return ret;
+ host_errno_t thread_errno = RUN_PTHREAD(hostnet_pthread_readv, &args);
+ if (thread_errno)
+ return ERROR_NEW_ERR(size_t, errno2lm(thread_errno));
+ if (ret_errno)
+ return ERROR_NEW_ERR(size_t, hostnet_error(ret_errno, OP_RECV));
+ if (!ret_size)
+ return ERROR_NEW_ERR(size_t, error_new(E_EOF));
+ return ERROR_NEW_VAL(size_t, ret_size);
}
/* TCP write() ****************************************************************/
@@ -281,7 +302,8 @@ struct hostnet_pthread_writev_args {
const struct iovec *iov;
int iovcnt;
- ssize_t *ret;
+ size_t *ret_size;
+ host_errno_t *ret_errno;
};
static void *hostnet_pthread_writev(void *_args) {
@@ -299,7 +321,7 @@ static void *hostnet_pthread_writev(void *_args) {
while (done < count) {
ssize_t r = writev(args->connfd, iov, iovcnt);
if (r < 0) {
- hostnet_map_negerrno(-errno, OP_RECV);
+ *args->ret_errno = errno;
break;
}
done += r;
@@ -314,12 +336,13 @@ static void *hostnet_pthread_writev(void *_args) {
}
}
if (done == count)
- *(args->ret) = done;
+ *args->ret_errno = 0;
+ *args->ret_size = done;
WAKE_COROUTINE(args);
return NULL;
}
-static ssize_t hostnet_tcp_writev(struct _hostnet_tcp_conn *conn, const struct iovec *iov, int iovcnt) {
+static size_t_and_error hostnet_tcp_writev(struct _hostnet_tcp_conn *conn, const struct wr_iovec *iov, int iovcnt) {
assert(conn);
assert(iov);
assert(iovcnt > 0);
@@ -328,35 +351,44 @@ static ssize_t hostnet_tcp_writev(struct _hostnet_tcp_conn *conn, const struct i
count += iov[i].iov_len;
assert(count);
- ssize_t ret;
+ size_t ret_size;
+ host_errno_t ret_errno;
struct hostnet_pthread_writev_args args = {
.cr_thread = pthread_self(),
.cr_coroutine = cr_getcid(),
.connfd = conn->fd,
- .iov = iov,
+ .iov = (const struct iovec *)iov,
.iovcnt = iovcnt,
- .ret = &ret,
+ .ret_size = &ret_size,
+ .ret_errno = &ret_errno,
};
- if (RUN_PTHREAD(hostnet_pthread_writev, &args))
- return -NET_ETHREAD;
- return ret;
+ int thread_errno = RUN_PTHREAD(hostnet_pthread_writev, &args);
+ if (thread_errno)
+ return ERROR_AND(size_t, 0, errno2lm(thread_errno));
+ return ERROR_AND(size_t, ret_size, ret_errno ? hostnet_error(ret_errno, OP_SEND) : ERROR_NULL);
}
/* TCP close() ****************************************************************/
-static int hostnet_tcp_close(struct _hostnet_tcp_conn *conn) {
+static error hostnet_tcp_close(struct _hostnet_tcp_conn *conn) {
assert(conn);
- return hostnet_map_negerrno(shutdown(conn->fd, SHUT_RDWR) ? -errno : 0, OP_NONE);
+ if (shutdown(conn->fd, SHUT_RDWR))
+ return hostnet_error(errno, OP_CLOSE);
+ return ERROR_NULL;
}
-static int hostnet_tcp_close_read(struct _hostnet_tcp_conn *conn) {
+static error hostnet_tcp_close_read(struct _hostnet_tcp_conn *conn) {
assert(conn);
- return hostnet_map_negerrno(shutdown(conn->fd, SHUT_RD) ? -errno : 0, OP_NONE);
+ if (shutdown(conn->fd, SHUT_RD))
+ return hostnet_error(errno, OP_CLOSE);
+ return ERROR_NULL;
}
-static int hostnet_tcp_close_write(struct _hostnet_tcp_conn *conn) {
+static error hostnet_tcp_close_write(struct _hostnet_tcp_conn *conn) {
assert(conn);
- return hostnet_map_negerrno(shutdown(conn->fd, SHUT_WR) ? -errno : 0, OP_NONE);
+ if (shutdown(conn->fd, SHUT_WR))
+ return hostnet_error(errno, OP_CLOSE);
+ return ERROR_NULL;
}
/* UDP init() *****************************************************************/
@@ -375,9 +407,11 @@ void hostnet_udp_conn_init(struct hostnet_udp_conn *self, uint16_t port) {
addr.in.sin_port = htons(port);
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0)
- error(1, errno, "socket");
+ __error(1, errno, "socket");
+ if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &(int){1}, sizeof(int)) < 0)
+ __error(1, errno, "setsockopt(fd=%d, SO_BROADCAST=1)", fd);
if (bind(fd, &addr.gen, sizeof addr) < 0)
- error(1, errno, "bind");
+ __error(1, errno, "bind");
self->fd = fd;
self->read_deadline_ns = 0;
@@ -395,7 +429,8 @@ struct hostnet_pthread_sendto_args {
struct net_ip4_addr node;
uint16_t port;
- ssize_t *ret;
+ size_t *ret_size;
+ host_errno_t *ret_errno;
};
static void *hostnet_pthread_sendto(void *_args) {
@@ -408,23 +443,29 @@ static void *hostnet_pthread_sendto(void *_args) {
addr.in.sin_family = AF_INET;
addr.in.sin_addr.s_addr =
- (((uint32_t)args->node.octets[0])<<24) |
- (((uint32_t)args->node.octets[1])<<16) |
- (((uint32_t)args->node.octets[2])<< 8) |
- (((uint32_t)args->node.octets[3])<< 0) ;
+ (((uint32_t)args->node.octets[3])<<24) |
+ (((uint32_t)args->node.octets[2])<<16) |
+ (((uint32_t)args->node.octets[1])<< 8) |
+ (((uint32_t)args->node.octets[0])<< 0) ;
addr.in.sin_port = htons(args->port);
- *(args->ret) = sendto(args->connfd, args->buf, args->count, 0, &addr.gen, sizeof(addr));
- if (*(args->ret) < 0)
- *(args->ret) = hostnet_map_negerrno(-errno, OP_SEND);
+ ssize_t r = sendto(args->connfd, args->buf, args->count, 0, &addr.gen, sizeof(addr));
+ if (r < 0) {
+ *args->ret_size = 0;
+ *args->ret_errno = errno;
+ } else {
+ *args->ret_size = r;
+ *args->ret_errno = 0;
+ }
WAKE_COROUTINE(args);
return NULL;
}
-static ssize_t hostnet_udp_sendto(struct hostnet_udp_conn *conn, void *buf, size_t count,
- struct net_ip4_addr node, uint16_t port) {
+error hostnet_udp_sendto(struct hostnet_udp_conn *conn, void *buf, size_t count,
+ struct net_ip4_addr node, uint16_t port) {
assert(conn);
- ssize_t ret;
+ size_t ret_size;
+ host_errno_t ret_errno;
struct hostnet_pthread_sendto_args args = {
.cr_thread = pthread_self(),
.cr_coroutine = cr_getcid(),
@@ -435,17 +476,21 @@ static ssize_t hostnet_udp_sendto(struct hostnet_udp_conn *conn, void *buf, size
.node = node,
.port = port,
- .ret = &ret,
+ .ret_size = &ret_size,
+ .ret_errno = &ret_errno,
};
- if (RUN_PTHREAD(hostnet_pthread_sendto, &args))
- return -NET_ETHREAD;
- return ret;
+ int thread_errno = RUN_PTHREAD(hostnet_pthread_sendto, &args);
+ if (thread_errno)
+ return errno2lm(thread_errno);
+ if (ret_errno)
+ return hostnet_error(ret_errno, OP_SEND);
+ return ERROR_NULL;
}
/* UDP recvfrom() *************************************************************/
-static void hostnet_udp_set_recv_deadline(struct hostnet_udp_conn *conn,
- uint64_t ts_ns) {
+void hostnet_udp_set_recv_deadline(struct hostnet_udp_conn *conn,
+ uint64_t ts_ns) {
assert(conn);
conn->read_deadline_ns = ts_ns;
@@ -460,7 +505,8 @@ struct hostnet_pthread_recvfrom_args {
void *buf;
size_t count;
- ssize_t *ret_size;
+ size_t *ret_size;
+ host_errno_t *ret_errno;
struct net_ip4_addr *ret_node;
uint16_t *ret_port;
};
@@ -473,41 +519,48 @@ static void *hostnet_pthread_recvfrom(void *_args) {
struct sockaddr gen;
struct sockaddr_storage stor;
} addr = {};
- socklen_t addr_size;
+ socklen_t addr_size = sizeof(addr);
- *(args->ret_size) = setsockopt(args->connfd, SOL_SOCKET, SO_RCVTIMEO,
- &args->timeout, sizeof(args->timeout));
- if (*(args->ret_size) < 0)
+ int r_i = setsockopt(args->connfd, SOL_SOCKET, SO_RCVTIMEO,
+ &args->timeout, sizeof(args->timeout));
+ if (r_i) {
+ *args->ret_size = 0;
+ *args->ret_errno = errno;
goto end;
+ }
- *(args->ret_size) = recvfrom(args->connfd, args->buf, args->count,
- MSG_TRUNC, &addr.gen, &addr_size);
- if (*(args->ret_size) < 0)
+ ssize_t r_ss = recvfrom(args->connfd, args->buf, args->count,
+ MSG_TRUNC, &addr.gen, &addr_size);
+ if (r_ss < 0) {
+ *args->ret_size = 0;
+ *args->ret_errno = errno;
goto end;
+ }
+ *args->ret_size = r_ss;
+ *args->ret_errno = 0;
assert(addr.in.sin_family == AF_INET);
if (args->ret_node) {
- args->ret_node->octets[0] = (addr.in.sin_addr.s_addr >> 24) & 0xFF;
- args->ret_node->octets[1] = (addr.in.sin_addr.s_addr >> 16) & 0xFF;
- args->ret_node->octets[2] = (addr.in.sin_addr.s_addr >> 8) & 0xFF;
- args->ret_node->octets[3] = (addr.in.sin_addr.s_addr >> 0) & 0xFF;
+ args->ret_node->octets[3] = (addr.in.sin_addr.s_addr >> 24) & 0xFF;
+ args->ret_node->octets[2] = (addr.in.sin_addr.s_addr >> 16) & 0xFF;
+ args->ret_node->octets[1] = (addr.in.sin_addr.s_addr >> 8) & 0xFF;
+ args->ret_node->octets[0] = (addr.in.sin_addr.s_addr >> 0) & 0xFF;
}
if (args->ret_port) {
(*args->ret_port) = ntohs(addr.in.sin_port);
}
end:
- if (*(args->ret_size) < 0)
- *(args->ret_size) = hostnet_map_negerrno(-errno, OP_RECV);
WAKE_COROUTINE(args);
return NULL;
}
-static ssize_t hostnet_udp_recvfrom(struct hostnet_udp_conn *conn, void *buf, size_t count,
- struct net_ip4_addr *ret_node, uint16_t *ret_port) {
+size_t_or_error hostnet_udp_recvfrom(struct hostnet_udp_conn *conn, void *buf, size_t count,
+ struct net_ip4_addr *ret_node, uint16_t *ret_port) {
assert(conn);
- ssize_t ret;
+ size_t ret_size;
+ host_errno_t ret_errno;
struct hostnet_pthread_recvfrom_args args = {
.cr_thread = pthread_self(),
.cr_coroutine = cr_getcid(),
@@ -516,28 +569,34 @@ static ssize_t hostnet_udp_recvfrom(struct hostnet_udp_conn *conn, void *buf, si
.buf = buf,
.count = count,
- .ret_size = &ret,
+ .ret_size = &ret_size,
+ .ret_errno = &ret_errno,
.ret_node = ret_node,
.ret_port = ret_port,
};
if (conn->read_deadline_ns) {
uint64_t now_ns = LO_CALL(bootclock, get_time_ns);
if (conn->read_deadline_ns < now_ns)
- return -NET_ERECV_TIMEOUT;
+ return ERROR_NEW_ERR(size_t, error_new(E_NET_ERECV_TIMEOUT));
args.timeout = ns_to_host_us_time(conn->read_deadline_ns-now_ns);
} else {
args.timeout = (host_us_time_t){};
}
- if (RUN_PTHREAD(hostnet_pthread_recvfrom, &args))
- return -NET_ETHREAD;
- return ret;
+ host_errno_t thread_errno = RUN_PTHREAD(hostnet_pthread_recvfrom, &args);
+ if (thread_errno)
+ return ERROR_NEW_ERR(size_t, errno2lm(thread_errno));
+ if (ret_errno)
+ return ERROR_NEW_ERR(size_t, hostnet_error(ret_errno, OP_RECV));
+ return ERROR_NEW_VAL(size_t, ret_size);
}
/* UDP close() ****************************************************************/
-static int hostnet_udp_close(struct hostnet_udp_conn *conn) {
+error hostnet_udp_close(struct hostnet_udp_conn *conn) {
assert(conn);
- return hostnet_map_negerrno(close(conn->fd) ? -errno : 0, OP_NONE);
+ if (close(conn->fd))
+ return hostnet_error(errno, OP_CLOSE);
+ return ERROR_NULL;
}
diff --git a/libhw_cr/host_util.c b/libhw_cr/host_util.c
index 7b3200c..2d45490 100644
--- a/libhw_cr/host_util.c
+++ b/libhw_cr/host_util.c
@@ -4,9 +4,15 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-#include <error.h> /* for error(3gnu) */
+#include <errno.h> /* for E* */
#include <signal.h> /* for SIGRTMIN, SIGRTMAX */
+#define error __error
+#include <error.h>
+#undef error
+
+#include <libhw/generic/alarmclock.h> /* for {X}S_PER_S */
+
#include "host_util.h"
int host_sigrt_alloc(void) {
@@ -16,6 +22,124 @@ int host_sigrt_alloc(void) {
next = SIGRTMIN;
int ret = next++;
if (ret > SIGRTMAX)
- error(1, 0, "SIGRTMAX exceeded");
+ __error(1, 0, "SIGRTMAX exceeded");
+ return ret;
+}
+
+host_us_time_t ns_to_host_us_time(uint64_t time_ns) {
+ host_us_time_t ret;
+ ret.tv_sec = time_ns
+ /NS_PER_S;
+ ret.tv_usec = (time_ns - ((uint64_t)ret.tv_sec)*NS_PER_S)
+ /(NS_PER_S/US_PER_S);
+ return ret;
+}
+
+host_ns_time_t ns_to_host_ns_time(uint64_t time_ns) {
+ host_ns_time_t ret;
+ ret.tv_sec = time_ns
+ /NS_PER_S;
+ ret.tv_nsec = time_ns - ((uint64_t)ret.tv_sec)*NS_PER_S;
return ret;
}
+
+uint64_t ns_from_host_us_time(host_us_time_t host_time) {
+ return (((uint64_t)host_time.tv_sec) * NS_PER_S) +
+ ((uint64_t)host_time.tv_usec * (NS_PER_S/US_PER_S));
+}
+
+uint64_t ns_from_host_ns_time(host_ns_time_t host_time) {
+ return (((uint64_t)host_time.tv_sec) * NS_PER_S) +
+ ((uint64_t)host_time.tv_nsec);
+}
+
+_errnum errno_host2lm(host_errno_t host) {
+ switch (host) {
+ case E2BIG: return E_POSIX_E2BIG;
+ case EACCES: return E_POSIX_EACCES;
+ case EADDRINUSE: return E_POSIX_EADDRINUSE;
+ case EADDRNOTAVAIL: return E_POSIX_EADDRNOTAVAIL;
+ case EAFNOSUPPORT: return E_POSIX_EAFNOSUPPORT;
+ case EAGAIN: return E_POSIX_EAGAIN;
+ case EALREADY: return E_POSIX_EALREADY;
+ case EBADF: return E_POSIX_EBADF;
+ case EBADMSG: return E_POSIX_EBADMSG;
+ case EBUSY: return E_POSIX_EBUSY;
+ case ECANCELED: return E_POSIX_ECANCELED;
+ case ECHILD: return E_POSIX_ECHILD;
+ case ECONNABORTED: return E_POSIX_ECONNABORTED;
+ case ECONNREFUSED: return E_POSIX_ECONNREFUSED;
+ case ECONNRESET: return E_POSIX_ECONNRESET;
+ case EDEADLK: return E_POSIX_EDEADLK;
+ case EDESTADDRREQ: return E_POSIX_EDESTADDRREQ;
+ case EDOM: return E_POSIX_EDOM;
+ case EDQUOT: return E_POSIX_EDQUOT;
+ case EEXIST: return E_POSIX_EEXIST;
+ case EFAULT: return E_POSIX_EFAULT;
+ case EFBIG: return E_POSIX_EFBIG;
+ case EHOSTUNREACH: return E_POSIX_EHOSTUNREACH;
+ case EIDRM: return E_POSIX_EIDRM;
+ case EILSEQ: return E_POSIX_EILSEQ;
+ case EINPROGRESS: return E_POSIX_EINPROGRESS;
+ case EINTR: return E_POSIX_EINTR;
+ case EINVAL: return E_POSIX_EINVAL;
+ case EIO: return E_POSIX_EIO;
+ case EISCONN: return E_POSIX_EISCONN;
+ case EISDIR: return E_POSIX_EISDIR;
+ case ELOOP: return E_POSIX_ELOOP;
+ case EMFILE: return E_POSIX_EMFILE;
+ case EMLINK: return E_POSIX_EMLINK;
+ case EMSGSIZE: return E_POSIX_EMSGSIZE;
+ case EMULTIHOP: return E_POSIX_EMULTIHOP;
+ case ENAMETOOLONG: return E_POSIX_ENAMETOOLONG;
+ case ENETDOWN: return E_POSIX_ENETDOWN;
+ case ENETRESET: return E_POSIX_ENETRESET;
+ case ENETUNREACH: return E_POSIX_ENETUNREACH;
+ case ENFILE: return E_POSIX_ENFILE;
+ case ENOBUFS: return E_POSIX_ENOBUFS;
+ case ENODEV: return E_POSIX_ENODEV;
+ case ENOENT: return E_POSIX_ENOENT;
+ case ENOEXEC: return E_POSIX_ENOEXEC;
+ case ENOLCK: return E_POSIX_ENOLCK;
+ case ENOLINK: return E_POSIX_ENOLINK;
+ case ENOMEM: return E_POSIX_ENOMEM;
+ case ENOMSG: return E_POSIX_ENOMSG;
+ case ENOPROTOOPT: return E_POSIX_ENOPROTOOPT;
+ case ENOSPC: return E_POSIX_ENOSPC;
+ case ENOSYS: return E_POSIX_ENOSYS;
+ case ENOTCONN: return E_POSIX_ENOTCONN;
+ case ENOTDIR: return E_POSIX_ENOTDIR;
+ case ENOTEMPTY: return E_POSIX_ENOTEMPTY;
+ case ENOTRECOVERABLE: return E_POSIX_ENOTRECOVERABLE;
+ case ENOTSOCK: return E_POSIX_ENOTSOCK;
+ case ENOTSUP: return E_POSIX_ENOTSUP;
+ case ENOTTY: return E_POSIX_ENOTTY;
+ case ENXIO: return E_POSIX_ENXIO;
+ case EOVERFLOW: return E_POSIX_EOVERFLOW;
+ case EOWNERDEAD: return E_POSIX_EOWNERDEAD;
+ case EPERM: return E_POSIX_EPERM;
+ case EPIPE: return E_POSIX_EPIPE;
+ case EPROTO: return E_POSIX_EPROTO;
+ case EPROTONOSUPPORT: return E_POSIX_EPROTONOSUPPORT;
+ case EPROTOTYPE: return E_POSIX_EPROTOTYPE;
+ case ERANGE: return E_POSIX_ERANGE;
+ case EROFS: return E_POSIX_EROFS;
+ case ESOCKTNOSUPPORT: return E_POSIX_ESOCKTNOSUPPORT;
+ case ESPIPE: return E_POSIX_ESPIPE;
+ case ESRCH: return E_POSIX_ESRCH;
+ case ESTALE: return E_POSIX_ESTALE;
+ case ETIMEDOUT: return E_POSIX_ETIMEDOUT;
+ case ETXTBSY: return E_POSIX_ETXTBSY;
+ case EXDEV: return E_POSIX_EXDEV;
+ default:
+ switch (host) {
+ case EOPNOTSUPP: return E_POSIX_EOPNOTSUPP;
+ case EWOULDBLOCK: return E_POSIX_EWOULDBLOCK;
+ default: return E_EUNKNOWN;
+ }
+ }
+}
+
+error errno2lm(host_errno_t host) {
+ return error_new(errno_host2lm(host));
+}
diff --git a/libhw_cr/host_util.h b/libhw_cr/host_util.h
index 02c04dc..7e559ef 100644
--- a/libhw_cr/host_util.h
+++ b/libhw_cr/host_util.h
@@ -7,41 +7,24 @@
#ifndef _LIBHW_CR_HOST_UTIL_H_
#define _LIBHW_CR_HOST_UTIL_H_
-#include <time.h> /* for struct timespec */
-#include <sys/time.h> /* for struct timeval */
+#include <stdint.h> /* for uint{n}_t */
+#include <sys/time.h> /* for struct timeval */
+#include <time.h> /* for struct timespec */
-#include <libhw/generic/alarmclock.h> /* for {X}S_PER_S */
+#include <libmisc/error.h> /* for _errnum, error */
int host_sigrt_alloc(void);
typedef struct timeval host_us_time_t;
typedef struct timespec host_ns_time_t;
-static inline host_us_time_t ns_to_host_us_time(uint64_t time_ns) {
- host_us_time_t ret;
- ret.tv_sec = time_ns
- /NS_PER_S;
- ret.tv_usec = (time_ns - ((uint64_t)ret.tv_sec)*NS_PER_S)
- /(NS_PER_S/US_PER_S);
- return ret;
-}
-
-static inline host_ns_time_t ns_to_host_ns_time(uint64_t time_ns) {
- host_ns_time_t ret;
- ret.tv_sec = time_ns
- /NS_PER_S;
- ret.tv_nsec = time_ns - ((uint64_t)ret.tv_sec)*NS_PER_S;
- return ret;
-}
-
-static inline uint64_t ns_from_host_us_time(host_us_time_t host_time) {
- return (((uint64_t)host_time.tv_sec) * NS_PER_S) +
- ((uint64_t)host_time.tv_usec * (NS_PER_S/US_PER_S));
-}
-
-static inline uint64_t ns_from_host_ns_time(host_ns_time_t host_time) {
- return (((uint64_t)host_time.tv_sec) * NS_PER_S) +
- ((uint64_t)host_time.tv_nsec);
-}
+host_us_time_t ns_to_host_us_time(uint64_t time_ns);
+host_ns_time_t ns_to_host_ns_time(uint64_t time_ns);
+uint64_t ns_from_host_us_time(host_us_time_t host_time);
+uint64_t ns_from_host_ns_time(host_ns_time_t host_time);
+
+#define host_errno_t int
+_errnum errno_host2lm(host_errno_t host);
+error errno2lm(host_errno_t host);
#endif /* _LIBHW_CR_HOST_UTIL_H_ */
diff --git a/libhw_cr/rp2040_dma.c b/libhw_cr/rp2040_dma.c
index e117c19..0248f23 100644
--- a/libhw_cr/rp2040_dma.c
+++ b/libhw_cr/rp2040_dma.c
@@ -1,5 +1,8 @@
/* libhw_cr/rp2040_dma.c - Utilities for sharing the DMA IRQs
*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
* Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
@@ -8,6 +11,21 @@
#include "rp2040_dma.h"
+/* Borrowed from <hardware/dma.h> *********************************************/
+
+dma_channel_hw_t *dma_channel_hw_addr(uint channel) {
+ assert(channel < NUM_DMA_CHANNELS);
+ return &dma_hw->ch[channel];
+}
+
+enum dma_channel_transfer_size {
+ DMA_SIZE_8 = 0, ///< Byte transfer (8 bits)
+ DMA_SIZE_16 = 1, ///< Half word transfer (16 bits)
+ DMA_SIZE_32 = 2 ///< Word transfer (32 bits)
+};
+
+/* Our own code ***************************************************************/
+
struct dmairq_handler_entry {
dmairq_handler_t fn;
void *arg;
@@ -22,6 +40,7 @@ static void dmairq_handler(void) {
assert(irq_idx < NUM_DMA_IRQS);
uint32_t regval = dma_hw->irq_ctrl[irq_idx].ints;
+ dma_hw->intr = regval; /* acknowledge irq */
for (uint channel = 0; channel < NUM_DMA_CHANNELS; channel++) {
if (regval & 1u<<channel) {
struct dmairq_handler_entry *handler = &dmairq_handlers[channel];
@@ -29,8 +48,6 @@ static void dmairq_handler(void) {
handler->fn(handler->arg, irq, channel);
}
}
- /* acknowledge irq */
- dma_hw->intr = regval;
}
void dmairq_set_and_enable_exclusive_handler(enum dmairq irq, uint channel, dmairq_handler_t fn, void *arg) {
diff --git a/libhw_cr/rp2040_dma.h b/libhw_cr/rp2040_dma.h
index c7f5a8f..13862d0 100644
--- a/libhw_cr/rp2040_dma.h
+++ b/libhw_cr/rp2040_dma.h
@@ -21,15 +21,12 @@
/* Borrowed from <hardware/dma.h> *********************************************/
-static inline dma_channel_hw_t *dma_channel_hw_addr(uint channel) {
- assert(channel < NUM_DMA_CHANNELS);
- return &dma_hw->ch[channel];
-}
+dma_channel_hw_t *dma_channel_hw_addr(uint channel);
enum dma_channel_transfer_size {
- DMA_SIZE_8 = 0, ///< Byte transfer (8 bits)
- DMA_SIZE_16 = 1, ///< Half word transfer (16 bits)
- DMA_SIZE_32 = 2 ///< Word transfer (32 bits)
+ DMA_SIZE_8 = 0, ///< Byte transfer (8 bits)
+ DMA_SIZE_16 = 1, ///< Half word transfer (16 bits)
+ DMA_SIZE_32 = 2 ///< Word transfer (32 bits)
};
/* Our own code ***************************************************************/
@@ -46,26 +43,26 @@ typedef void (*dmairq_handler_t)(void *arg, enum dmairq irq, uint channel);
* has a NULL trigger (depending on the channel's configuration).
*
* Your handler does not need to acknowledge the IRQ; that will be
- * done for you after your handler is called.
+ * done for you before your handler is called.
*
* It is illegal to enable the same channel on more than one IRQ.
*/
void dmairq_set_and_enable_exclusive_handler(enum dmairq irq, uint channel, dmairq_handler_t fn, void *arg);
-#define DMA_CTRL_ENABLE (1<<0)
-#define DMA_CTRL_HI_PRIO (1<<1)
-#define DMA_CTRL_DATA_SIZE(sz) ((sz)<<2)
-#define DMA_CTRL_INCR_READ (1<<4)
-#define DMA_CTRL_INCR_WRITE (1<<5)
-#define _DMA_CTRL_RING_BITS(b) ((b)<<6)
-#define _DMA_CTRL_RING_RD (0)
-#define _DMA_CTRL_RING_WR (1<<10)
+#define DMA_CTRL_ENABLE (1<<0)
+#define DMA_CTRL_HI_PRIO (1<<1)
+#define DMA_CTRL_DATA_SIZE(sz) ((sz)<<2)
+#define DMA_CTRL_INCR_READ (1<<4)
+#define DMA_CTRL_INCR_WRITE (1<<5)
+#define _DMA_CTRL_RING_BITS(b) ((b)<<6)
+#define _DMA_CTRL_RING_RD (0)
+#define _DMA_CTRL_RING_WR (1<<10)
#define DMA_CTRL_RING(rdwr, bits) (_DMA_CTRL_RING_##rdwr | _DMA_CTRL_RING_BITS(bits))
-#define DMA_CTRL_CHAIN_TO(ch) ((ch)<<11)
-#define DMA_CTRL_TREQ_SEL(dreq) ((dreq)<<15)
-#define DMA_CTRL_IRQ_QUIET (1<<21)
-#define DMA_CTRL_BSWAP (1<<22)
-#define DMA_CTRL_SNIFF_EN (1<<23)
+#define DMA_CTRL_CHAIN_TO(ch) ((ch)<<11)
+#define DMA_CTRL_TREQ_SEL(dreq) ((dreq)<<15)
+#define DMA_CTRL_IRQ_QUIET (1<<21)
+#define DMA_CTRL_BSWAP (1<<22)
+#define DMA_CTRL_SNIFF_EN (1<<23)
/* | elem | val | name */
#define READ_ADDR /*|*/volatile const void/*|*/ * /*|*/read_addr
diff --git a/libhw_cr/rp2040_gpioirq.c b/libhw_cr/rp2040_gpioirq.c
index 5b3d616..ecbdb04 100644
--- a/libhw_cr/rp2040_gpioirq.c
+++ b/libhw_cr/rp2040_gpioirq.c
@@ -4,8 +4,8 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
+#include <hardware/irq.h> /* for irq_set_exclusive_handler() */
#include <hardware/structs/io_bank0.h> /* for io_bank0_hw */
-#include <hardware/irq.h> /* for irq_set_exclusive_handler() */
#include <libmisc/macro.h>
diff --git a/libhw_cr/rp2040_hwspi.c b/libhw_cr/rp2040_hwspi.c
index 75acd58..6b0d1f5 100644
--- a/libhw_cr/rp2040_hwspi.c
+++ b/libhw_cr/rp2040_hwspi.c
@@ -4,8 +4,6 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-#include <inttypes.h> /* for PRIu{n} */
-
#include <hardware/clocks.h> /* for clock_get_hz() and clk_peri */
#include <hardware/gpio.h>
#include <hardware/spi.h>
@@ -30,8 +28,8 @@
#error config.h must define CONFIG_RP2040_SPI_DEBUG (bool)
#endif
-LO_IMPLEMENTATION_C(io_duplex_readwriter, struct rp2040_hwspi, rp2040_hwspi, static);
-LO_IMPLEMENTATION_C(spi, struct rp2040_hwspi, rp2040_hwspi, static);
+LO_IMPLEMENTATION_C(io_duplex_readwriter, struct rp2040_hwspi, rp2040_hwspi);
+LO_IMPLEMENTATION_C(spi, struct rp2040_hwspi, rp2040_hwspi);
static void rp2040_hwspi_intrhandler(void *_self, enum dmairq LM_UNUSED(irq), uint LM_UNUSED(channel)) {
struct rp2040_hwspi *self = _self;
@@ -96,6 +94,7 @@ void _rp2040_hwspi_init(struct rp2040_hwspi *self,
assert_notreached("invalid hwspi instance number");
}
+ /* Initialize the PL022. */
actual_baudrate_hz = spi_init(inst, baudrate_hz);
log_debugln("baudrate = ", actual_baudrate_hz, "Hz");
assert(actual_baudrate_hz == baudrate_hz);
@@ -138,7 +137,7 @@ void _rp2040_hwspi_init(struct rp2040_hwspi *self,
dmairq_set_and_enable_exclusive_handler(DMAIRQ_0, self->dma_rx_data, rp2040_hwspi_intrhandler, self);
}
-static void rp2040_hwspi_readwritev(struct rp2040_hwspi *self, const struct duplex_iovec *iov, int iovcnt) {
+size_t_and_error rp2040_hwspi_readwritev(struct rp2040_hwspi *self, const struct duplex_iovec *iov, int iovcnt) {
assert(self);
assert(self->inst);
assert(iov);
@@ -200,8 +199,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 = stack_alloc(pruned_iovcnt+1, struct dma_alias1);
- struct dma_alias0 *rx_data_blocks = stack_alloc(pruned_iovcnt+1, struct dma_alias0);
+ [[gnu::cleanup(heap_cleanup)]] struct dma_alias1 *tx_data_blocks = heap_alloc(pruned_iovcnt+1, struct dma_alias1);
+ [[gnu::cleanup(heap_cleanup)]] struct dma_alias0 *rx_data_blocks = heap_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));
@@ -270,4 +269,5 @@ static void rp2040_hwspi_readwritev(struct rp2040_hwspi *self, const struct dupl
cr_restore_interrupts(saved);
cr_sema_wait(&self->sema);
self->dead_until_ns = LO_CALL(bootclock, get_time_ns) + self->min_delay_ns;
+ return ERROR_AND(size_t, count, ERROR_NULL);
}
diff --git a/libhw_cr/rp2040_hwtimer.c b/libhw_cr/rp2040_hwtimer.c
index 8227abb..6d7e868 100644
--- a/libhw_cr/rp2040_hwtimer.c
+++ b/libhw_cr/rp2040_hwtimer.c
@@ -27,8 +27,7 @@ struct rp2040_hwtimer {
bool initialized;
struct alarmclock_trigger *queue;
};
-LO_IMPLEMENTATION_H(alarmclock, struct rp2040_hwtimer, rp2040_hwtimer);
-LO_IMPLEMENTATION_C(alarmclock, struct rp2040_hwtimer, rp2040_hwtimer, static);
+LO_IMPLEMENTATION_STATIC(alarmclock, struct rp2040_hwtimer, rp2040_hwtimer);
/* Globals ********************************************************************/
@@ -44,7 +43,7 @@ static_assert(sizeof(hwtimers)/sizeof(hwtimers[0]) == _RP2040_HWALARM_NUM);
lo_interface alarmclock rp2040_hwtimer(enum rp2040_hwalarm_instance alarm_num) {
assert(alarm_num < _RP2040_HWALARM_NUM);
- return lo_box_rp2040_hwtimer_as_alarmclock(&hwtimers[alarm_num]);
+ return LO_BOX(alarmclock, &hwtimers[alarm_num]);
}
@@ -52,7 +51,11 @@ static uint64_t rp2040_hwtimer_get_time_ns(struct rp2040_hwtimer *) {
return timer_time_us_64(timer_hw) * (NS_PER_S/US_PER_S);
}
-#define NS_TO_US_ROUNDUP(x) LM_CEILDIV(x, NS_PER_S/US_PER_S)
+static uint32_t ns_to_us_roundup_and_cap(uint64_t ns) {
+ if (ns >= ((uint64_t)(UINT32_MAX))*1000)
+ return UINT32_MAX;
+ return (ns+999)/1000;
+}
static void rp2040_hwtimer_intrhandler(void) {
uint irq_num = __get_current_exception() - VTABLE_FIRST_IRQ;
@@ -62,7 +65,7 @@ static void rp2040_hwtimer_intrhandler(void) {
struct rp2040_hwtimer *alarmclock = &hwtimers[alarm_num];
while (alarmclock->queue &&
- NS_TO_US_ROUNDUP(alarmclock->queue->fire_at_ns) <= timer_time_us_64(timer_hw)) {
+ alarmclock->queue->fire_at_ns <= timer_time_us_64(timer_hw)*1000) {
struct alarmclock_trigger *trigger = alarmclock->queue;
trigger->cb(trigger->cb_arg);
alarmclock->queue = trigger->next;
@@ -74,10 +77,10 @@ static void rp2040_hwtimer_intrhandler(void) {
hw_clear_bits(&timer_hw->intf, 1 << alarm_num); /* Clear "force"ing the interrupt. */
hw_clear_bits(&timer_hw->intr, 1 << alarm_num); /* Clear natural firing of the alarm. */
if (alarmclock->queue)
- timer_hw->alarm[alarm_num] = (uint32_t)NS_TO_US_ROUNDUP(alarmclock->queue->fire_at_ns);
+ timer_hw->alarm[alarm_num] = ns_to_us_roundup_and_cap(alarmclock->queue->fire_at_ns);
}
-static bool rp2040_hwtimer_add_trigger(struct rp2040_hwtimer *alarmclock,
+static void rp2040_hwtimer_add_trigger(struct rp2040_hwtimer *alarmclock,
struct alarmclock_trigger *trigger,
uint64_t fire_at_ns,
void (*cb)(void *),
@@ -87,18 +90,13 @@ static bool rp2040_hwtimer_add_trigger(struct rp2040_hwtimer *alarmclock,
assert(fire_at_ns);
assert(cb);
- uint64_t now_us = timer_time_us_64(timer_hw);
- if (NS_TO_US_ROUNDUP(fire_at_ns) > now_us &&
- (NS_TO_US_ROUNDUP(fire_at_ns) - now_us) > UINT32_MAX)
- /* Too far in the future. */
- return true;
-
trigger->alarmclock = alarmclock;
trigger->fire_at_ns = fire_at_ns;
trigger->cb = cb;
trigger->cb_arg = cb_arg;
bool saved = cr_save_and_disable_interrupts();
+
struct alarmclock_trigger **dst = &alarmclock->queue;
while (*dst && fire_at_ns >= (*dst)->fire_at_ns)
dst = &(*dst)->next;
@@ -107,6 +105,7 @@ static bool rp2040_hwtimer_add_trigger(struct rp2040_hwtimer *alarmclock,
if (*dst)
(*dst)->prev = trigger;
*dst = trigger;
+
if (!alarmclock->initialized) {
hw_set_bits(&timer_hw->inte, 1 << alarmclock->alarm_num);
irq_set_exclusive_handler(TIMER_ALARM_IRQ_NUM(timer_hw, alarmclock->alarm_num),
@@ -114,6 +113,7 @@ static bool rp2040_hwtimer_add_trigger(struct rp2040_hwtimer *alarmclock,
irq_set_enabled(TIMER_ALARM_IRQ_NUM(timer_hw, alarmclock->alarm_num), true);
alarmclock->initialized = true;
}
+
if (alarmclock->queue == trigger) {
/* "Force" the interrupt handler to trigger as soon as
* we enable interrupts. This handles the case of
@@ -126,9 +126,8 @@ static bool rp2040_hwtimer_add_trigger(struct rp2040_hwtimer *alarmclock,
* fire. */
hw_set_bits(&timer_hw->intf, 1 << alarmclock->alarm_num);
}
- cr_restore_interrupts(saved);
- return false;
+ cr_restore_interrupts(saved);
}
static void rp2040_hwtimer_del_trigger(struct rp2040_hwtimer *alarmclock,
diff --git a/libhw_cr/rp2040_include/libhw/w5500.h b/libhw_cr/rp2040_include/libhw/w5500.h
index 8dda1a1..43c58a3 100644
--- a/libhw_cr/rp2040_include/libhw/w5500.h
+++ b/libhw_cr/rp2040_include/libhw/w5500.h
@@ -41,19 +41,6 @@ struct _w5500_socket {
END_PRIVATE(LIBHW_W5500_H);
};
-LO_IMPLEMENTATION_H(io_closer, struct _w5500_socket, w5500_tcplist);
-LO_IMPLEMENTATION_H(net_stream_listener, struct _w5500_socket, w5500_tcplist);
-
-LO_IMPLEMENTATION_H(io_reader, struct _w5500_socket, w5500_tcp);
-LO_IMPLEMENTATION_H(io_writer, struct _w5500_socket, w5500_tcp);
-LO_IMPLEMENTATION_H(io_readwriter, struct _w5500_socket, w5500_tcp);
-LO_IMPLEMENTATION_H(io_closer, struct _w5500_socket, w5500_tcp);
-LO_IMPLEMENTATION_H(io_bidi_closer, struct _w5500_socket, w5500_tcp);
-LO_IMPLEMENTATION_H(net_stream_conn, struct _w5500_socket, w5500_tcp);
-
-LO_IMPLEMENTATION_H(io_closer, struct _w5500_socket, w5500_udp);
-LO_IMPLEMENTATION_H(net_packet_conn, struct _w5500_socket, w5500_udp);
-
struct w5500 {
BEGIN_PRIVATE(LIBHW_W5500_H);
/* const-after-init */
diff --git a/libhw_cr/w5500.c b/libhw_cr/w5500.c
index 6f3f302..dc11ef9 100644
--- a/libhw_cr/w5500.c
+++ b/libhw_cr/w5500.c
@@ -8,6 +8,7 @@
* https://github.com/Wiznet/ioLibrary_Driver/blob/b981401e7f3d07015619adf44c13998e13e777f9/Ethernet/W5500/w5500.h
* https://github.com/Wiznet/ioLibrary_Driver/blob/b981401e7f3d07015619adf44c13998e13e777f9/Ethernet/W5500/w5500.c
* https://github.com/Wiznet/ioLibrary_Driver/blob/b981401e7f3d07015619adf44c13998e13e777f9/Ethernet/socket.c
+ * https://github.com/Wiznet/ioLibrary_Driver/blob/b981401e7f3d07015619adf44c13998e13e777f9/Internet/DHCP/dhcp.c
*
* Copyright (c) 2013, WIZnet Co., LTD.
* All rights reserved.
@@ -67,12 +68,12 @@
* SPDX-License-Identifier: MIT
*/
-#include <inttypes.h> /* for PRIu{n} */
+#include <string.h> /* for memcmp() */
/* TODO: Write a <libhw/generic/gpio.h> to avoid w5500.c being
* pico-sdk-specific. */
-#include <hardware/gpio.h> /* pico-sdk:hardware_gpio */
#include "rp2040_gpioirq.h"
+#include <hardware/gpio.h> /* pico-sdk:hardware_gpio */
#include <libcr/coroutine.h> /* for cr_yield() */
@@ -126,20 +127,20 @@ static const char *w5500_state_str(uint8_t state) {
/* libmisc/obj.h **************************************************************/
-LO_IMPLEMENTATION_C(io_closer, struct _w5500_socket, w5500_tcplist, static);
-LO_IMPLEMENTATION_C(net_stream_listener, struct _w5500_socket, w5500_tcplist, static);
+LO_IMPLEMENTATION_STATIC(io_closer, struct _w5500_socket, w5500_tcplist);
+LO_IMPLEMENTATION_STATIC(net_stream_listener, struct _w5500_socket, w5500_tcplist);
-LO_IMPLEMENTATION_C(io_reader, struct _w5500_socket, w5500_tcp, static);
-LO_IMPLEMENTATION_C(io_writer, struct _w5500_socket, w5500_tcp, static);
-LO_IMPLEMENTATION_C(io_readwriter, struct _w5500_socket, w5500_tcp, static);
-LO_IMPLEMENTATION_C(io_closer, struct _w5500_socket, w5500_tcp, static);
-LO_IMPLEMENTATION_C(io_bidi_closer, struct _w5500_socket, w5500_tcp, static);
-LO_IMPLEMENTATION_C(net_stream_conn, struct _w5500_socket, w5500_tcp, static);
+LO_IMPLEMENTATION_STATIC(io_reader, struct _w5500_socket, w5500_tcp);
+LO_IMPLEMENTATION_STATIC(io_writer, struct _w5500_socket, w5500_tcp);
+LO_IMPLEMENTATION_STATIC(io_readwriter, struct _w5500_socket, w5500_tcp);
+LO_IMPLEMENTATION_STATIC(io_closer, struct _w5500_socket, w5500_tcp);
+LO_IMPLEMENTATION_STATIC(io_bidi_closer, struct _w5500_socket, w5500_tcp);
+LO_IMPLEMENTATION_STATIC(net_stream_conn, struct _w5500_socket, w5500_tcp);
-LO_IMPLEMENTATION_C(io_closer, struct _w5500_socket, w5500_udp, static);
-LO_IMPLEMENTATION_C(net_packet_conn, struct _w5500_socket, w5500_udp, static);
+LO_IMPLEMENTATION_STATIC(io_closer, struct _w5500_socket, w5500_udp);
+LO_IMPLEMENTATION_STATIC(net_packet_conn, struct _w5500_socket, w5500_udp);
-LO_IMPLEMENTATION_C(net_iface, struct w5500, w5500_if, static);
+LO_IMPLEMENTATION_C(net_iface, struct w5500, w5500_if);
/* mid-level utilities ********************************************************/
@@ -337,7 +338,8 @@ void _w5500_init(struct w5500 *chip,
w5500_hard_reset(chip);
/* Finally, wire in the interrupt handler. */
- coroutine_add("w5500_irq", w5500_irq_cr, chip);
+ cid_t cid = coroutine_add("w5500_irq", w5500_irq_cr, chip);
+ assert(cid);
}
/* chip methods ***************************************************************/
@@ -408,7 +410,7 @@ void w5500_soft_reset(struct w5500 *chip) {
cr_mutex_unlock(&chip->mu);
}
-static struct net_eth_addr w5500_if_hwaddr(struct w5500 *chip) {
+struct net_eth_addr w5500_if_hwaddr(struct w5500 *chip) {
assert(chip);
return chip->hwaddr;
@@ -426,7 +428,7 @@ static void _w5500_if_up(struct w5500 *chip, struct net_iface_config cfg) {
cr_mutex_unlock(&chip->mu);
}
-static void w5500_if_ifup(struct w5500 *chip, struct net_iface_config cfg) {
+void w5500_if_ifup(struct w5500 *chip, struct net_iface_config cfg) {
log_debugln("if_up()");
log_debugln(":: addr = ", (net_ip4_addr, cfg.addr));
log_debugln(":: gateway_addr = ", (net_ip4_addr, cfg.gateway_addr));
@@ -434,12 +436,12 @@ static void w5500_if_ifup(struct w5500 *chip, struct net_iface_config cfg) {
_w5500_if_up(chip, cfg);
}
-static void w5500_if_ifdown(struct w5500 *chip) {
+void w5500_if_ifdown(struct w5500 *chip) {
log_debugln("if_down()");
_w5500_if_up(chip, (struct net_iface_config){});
}
-static lo_interface net_stream_listener w5500_if_tcp_listen(struct w5500 *chip, uint16_t local_port) {
+lo_interface net_stream_listener w5500_if_tcp_listen(struct w5500 *chip, uint16_t local_port) {
assert(chip);
struct _w5500_socket *sock = w5500_alloc_socket(chip);
@@ -458,11 +460,11 @@ static lo_interface net_stream_listener w5500_if_tcp_listen(struct w5500 *chip,
sock->read_deadline_ns = 0;
sock->list_open = true;
- return lo_box_w5500_tcplist_as_net_stream_listener(sock);
+ return LO_BOX(net_stream_listener, sock);
}
-static lo_interface net_stream_conn w5500_if_tcp_dial(struct w5500 *chip,
- struct net_ip4_addr node, uint16_t port) {
+net_stream_conn_or_error w5500_if_tcp_dial(struct w5500 *chip,
+ struct net_ip4_addr node, uint16_t port) {
assert(chip);
assert(memcmp(node.octets, net_ip4_addr_zero.octets, 4));
assert(memcmp(node.octets, net_ip4_addr_broadcast.octets, 4));
@@ -471,7 +473,7 @@ static lo_interface net_stream_conn w5500_if_tcp_dial(struct w5500 *chip,
struct _w5500_socket *socket = w5500_alloc_socket(chip);
if (!socket) {
log_debugln("tcp_dial() => no sock");
- return LO_NULL(net_stream_conn);
+ return ERROR_NEW_ERR(net_stream_conn, error_new(E_POSIX_ENOTSOCK));
}
uint8_t socknum = socket->socknum;
log_debugln("tcp_dial() => sock[", socknum, "]");
@@ -508,14 +510,14 @@ static lo_interface net_stream_conn w5500_if_tcp_dial(struct w5500 *chip,
cr_yield();
break;
case STATE_TCP_ESTABLISHED:
- return lo_box_w5500_tcp_as_net_stream_conn(socket);
+ return ERROR_NEW_VAL(net_stream_conn, LO_BOX(net_stream_conn, socket));
default:
goto restart;
}
}
}
-static lo_interface net_packet_conn w5500_if_udp_conn(struct w5500 *chip, uint16_t local_port) {
+lo_interface net_packet_conn w5500_if_udp_conn(struct w5500 *chip, uint16_t local_port) {
assert(chip);
struct _w5500_socket *socket = w5500_alloc_socket(chip);
@@ -544,18 +546,34 @@ static lo_interface net_packet_conn w5500_if_udp_conn(struct w5500 *chip, uint16
cr_yield();
cr_mutex_unlock(&chip->mu);
- return lo_box_w5500_udp_as_net_packet_conn(socket);
+ return LO_BOX(net_packet_conn, socket);
+}
+
+bool w5500_if_arp_ping(struct w5500 *chip, struct net_ip4_addr addr) {
+ /* FIXME: This arp_ping implementation is really bad (and
+ * assumes that a UDP socket is open, which is "safe" because
+ * I only use it from inside of a DHCP client). */
+ assert(chip);
+ struct _w5500_socket *sock = NULL;
+ for (size_t i = 0; i < LM_ARRAY_LEN(chip->sockets) && !sock; i++) {
+ if (chip->sockets[i].mode == W5500_MODE_UDP)
+ sock = &chip->sockets[i];
+ }
+ assert(sock);
+ error err = w5500_udp_sendto(sock, "BOGUS_PACKET_TO_TRIGGER_AN_ARP", 17, addr, 5000);
+ log_debugln("arp_ping => ", (error, err));
+ return err.num != E_NET_EARP_TIMEOUT;
}
/* tcp_listener methods *******************************************************/
-static lo_interface net_stream_conn w5500_tcplist_accept(struct _w5500_socket *socket) {
+static net_stream_conn_or_error w5500_tcplist_accept(struct _w5500_socket *socket) {
ASSERT_SELF(stream_listener, TCP);
restart:
if (!socket->list_open) {
log_debugln("tcp_listener.accept() => already closed");
- return LO_NULL(net_stream_conn);
+ return ERROR_NEW_ERR(net_stream_conn, error_new(E_NET_ECLOSED));
}
cr_mutex_lock(&chip->mu);
@@ -581,28 +599,28 @@ static lo_interface net_stream_conn w5500_tcplist_accept(struct _w5500_socket *s
break;
case STATE_TCP_ESTABLISHED:
socket->read_open = true;
- /* fall-through */
+ [[fallthrough]];
case STATE_TCP_CLOSE_WAIT:
socket->write_open = true;
- return lo_box_w5500_tcp_as_net_stream_conn(socket);
+ return ERROR_NEW_VAL(net_stream_conn, LO_BOX(net_stream_conn, socket));
default:
goto restart;
}
}
}
-static int w5500_tcplist_close(struct _w5500_socket *socket) {
+static error w5500_tcplist_close(struct _w5500_socket *socket) {
log_debugln("tcp_listener.close()");
ASSERT_SELF(stream_listener, TCP);
socket->list_open = false;
w5500_tcp_maybe_free(chip, socket);
- return 0;
+ return ERROR_NULL;
}
/* tcp_conn methods ***********************************************************/
-static ssize_t w5500_tcp_writev(struct _w5500_socket *socket, const struct iovec *iov, int iovcnt) {
+static size_t_and_error w5500_tcp_writev(struct _w5500_socket *socket, const struct wr_iovec *iov, int iovcnt) {
assert(iov);
assert(iovcnt > 0);
size_t count = 0;
@@ -636,14 +654,14 @@ static ssize_t w5500_tcp_writev(struct _w5500_socket *socket, const struct iovec
while (done < count) {
if (!socket->write_open) {
log_debugln(" => soft closed");
- return -NET_ECLOSED;
+ return ERROR_AND(size_t, done, error_new(E_NET_ECLOSED));
}
cr_mutex_lock(&chip->mu);
uint8_t state = w5500ll_read_sock_reg(chip->spidev, socknum, state);
if (state != STATE_TCP_ESTABLISHED && state != STATE_TCP_CLOSE_WAIT) {
cr_mutex_unlock(&chip->mu);
log_debugln(" => hard closed");
- return -NET_ECLOSED;
+ return ERROR_AND(size_t, done, error_new(E_NET_ECLOSED));
}
uint16_t freesize = uint16be_unmarshal(w5500ll_read_sock_reg(chip->spidev, socknum, tx_free_size));
@@ -672,7 +690,7 @@ static ssize_t w5500_tcp_writev(struct _w5500_socket *socket, const struct iovec
break;
case SOCKINTR_SEND_TIMEOUT:
log_debugln(" => ACK timeout");
- return -NET_EACK_TIMEOUT;
+ return ERROR_AND(size_t, done, error_new(E_NET_EACK_TIMEOUT));
case SOCKINTR_SEND_OK|SOCKINTR_SEND_TIMEOUT:
assert_notreached("send both OK and timed out?");
default:
@@ -680,7 +698,7 @@ static ssize_t w5500_tcp_writev(struct _w5500_socket *socket, const struct iovec
}
}
log_debugln(" => send finished");
- return done;
+ return ERROR_AND(size_t, done, ERROR_NULL);
}
static void w5500_tcp_set_read_deadline(struct _w5500_socket *socket, uint64_t ns) {
@@ -694,7 +712,7 @@ static void w5500_tcp_alarm_handler(void *_arg) {
cr_sema_signal_from_intrhandler(&socket->read_sema);
}
-static ssize_t w5500_tcp_readv(struct _w5500_socket *socket, const struct iovec *iov, int iovcnt) {
+static size_t_or_error w5500_tcp_readv(struct _w5500_socket *socket, const struct rd_iovec *iov, int iovcnt) {
assert(iov);
assert(iovcnt > 0);
size_t count = 0;
@@ -717,12 +735,12 @@ static ssize_t w5500_tcp_readv(struct _w5500_socket *socket, const struct iovec
if (!socket->read_open) {
LO_CALL(bootclock, del_trigger, &trigger);
log_debugln(" => soft closed");
- return -NET_ECLOSED;
+ return ERROR_NEW_ERR(size_t, error_new(E_NET_ECLOSED));
}
if (socket->read_deadline_ns && socket->read_deadline_ns <= LO_CALL(bootclock, get_time_ns)) {
LO_CALL(bootclock, del_trigger, &trigger);
log_debugln(" => recv timeout");
- return -NET_ERECV_TIMEOUT;
+ return ERROR_NEW_ERR(size_t, error_new(E_NET_ERECV_TIMEOUT));
}
cr_mutex_lock(&chip->mu);
uint8_t state = w5500ll_read_sock_reg(chip->spidev, socknum, state);
@@ -735,7 +753,7 @@ static ssize_t w5500_tcp_readv(struct _w5500_socket *socket, const struct iovec
LO_CALL(bootclock, del_trigger, &trigger);
cr_mutex_unlock(&chip->mu);
log_debugln(" => hard closed");
- return -NET_ECLOSED;
+ return ERROR_NEW_ERR(size_t, error_new(E_NET_ECLOSED));
}
avail = uint16be_unmarshal(w5500ll_read_sock_reg(chip->spidev, socknum, rx_size));
@@ -746,7 +764,7 @@ static ssize_t w5500_tcp_readv(struct _w5500_socket *socket, const struct iovec
LO_CALL(bootclock, del_trigger, &trigger);
cr_mutex_unlock(&chip->mu);
log_debugln(" => EOF");
- return 0;
+ return ERROR_NEW_ERR(size_t, error_new(E_EOF));
}
cr_mutex_unlock(&chip->mu);
@@ -765,10 +783,10 @@ static ssize_t w5500_tcp_readv(struct _w5500_socket *socket, const struct iovec
/* Return. */
LO_CALL(bootclock, del_trigger, &trigger);
cr_mutex_unlock(&chip->mu);
- return avail;
+ return ERROR_NEW_VAL(size_t, avail);
}
-static int w5500_tcp_close_inner(struct _w5500_socket *socket, bool rd, bool wr) {
+static error w5500_tcp_close_inner(struct _w5500_socket *socket, bool rd, bool wr) {
log_debugln("tcp_conn.close(rd=", rd, ", wr=", wr, ")");
ASSERT_SELF(stream_conn, TCP);
@@ -796,17 +814,17 @@ static int w5500_tcp_close_inner(struct _w5500_socket *socket, bool rd, bool wr)
}
w5500_tcp_maybe_free(chip, socket);
- return 0;
+ return ERROR_NULL;
}
-static int w5500_tcp_close(struct _w5500_socket *socket) { return w5500_tcp_close_inner(socket, true, true); }
-static int w5500_tcp_close_read(struct _w5500_socket *socket) { return w5500_tcp_close_inner(socket, true, false); }
-static int w5500_tcp_close_write(struct _w5500_socket *socket) { return w5500_tcp_close_inner(socket, false, true); }
+static error w5500_tcp_close(struct _w5500_socket *socket) { return w5500_tcp_close_inner(socket, true, true); }
+static error w5500_tcp_close_read(struct _w5500_socket *socket) { return w5500_tcp_close_inner(socket, true, false); }
+static error w5500_tcp_close_write(struct _w5500_socket *socket) { return w5500_tcp_close_inner(socket, false, true); }
/* udp_conn methods ***********************************************************/
-static ssize_t w5500_udp_sendto(struct _w5500_socket *socket, void *buf, size_t count,
- struct net_ip4_addr node, uint16_t port) {
+static error w5500_udp_sendto(struct _w5500_socket *socket, void *buf, size_t count,
+ struct net_ip4_addr node, uint16_t port) {
log_debugln("udp_conn.sendto()");
ASSERT_SELF(packet_conn, UDP);
assert(buf);
@@ -815,7 +833,7 @@ static ssize_t w5500_udp_sendto(struct _w5500_socket *socket, void *buf, size_t
uint16_t bufsize = ((uint16_t)w5500ll_read_sock_reg(chip->spidev, socknum, tx_buf_size))*1024;
if (count > bufsize) {
log_debugln(" => msg too large");
- return -NET_EMSGSIZE;
+ return error_new(E_POSIX_EMSGSIZE);
}
for (;;) {
@@ -824,7 +842,7 @@ static ssize_t w5500_udp_sendto(struct _w5500_socket *socket, void *buf, size_t
if (state != STATE_UDP) {
cr_mutex_unlock(&chip->mu);
log_debugln(" => closed");
- return -NET_ECLOSED;
+ return error_new(E_NET_ECLOSED);
}
uint16_t freesize = uint16be_unmarshal(w5500ll_read_sock_reg(chip->spidev, socknum, tx_free_size));
@@ -842,8 +860,8 @@ static ssize_t w5500_udp_sendto(struct _w5500_socket *socket, void *buf, size_t
w5500ll_write_sock_reg(chip->spidev, socknum, remote_port, uint16be_marshal(port));
/* Queue data to be sent. */
uint16_t ptr = uint16be_unmarshal(w5500ll_read_sock_reg(chip->spidev, socknum, tx_write_pointer));
- w5500ll_writev(chip->spidev, ptr, CTL_BLOCK_SOCK(socknum, TX), &((struct iovec){
- .iov_base = buf,
+ w5500ll_writev(chip->spidev, ptr, CTL_BLOCK_SOCK(socknum, TX), &((struct wr_iovec){
+ .iov_write_from = buf,
.iov_len = count,
}), 1, 0, 0);
w5500ll_write_sock_reg(chip->spidev, socknum, tx_write_pointer, uint16be_marshal(ptr+count));
@@ -854,10 +872,10 @@ static ssize_t w5500_udp_sendto(struct _w5500_socket *socket, void *buf, size_t
switch (cr_chan_recv(&socket->write_ch)) {
case SOCKINTR_SEND_OK:
log_debugln(" => sent");
- return count;
+ return ERROR_NULL;
case SOCKINTR_SEND_TIMEOUT:
log_debugln(" => ARP timeout");
- return -NET_EARP_TIMEOUT;
+ return error_new(E_NET_EARP_TIMEOUT);
case SOCKINTR_SEND_OK|SOCKINTR_SEND_TIMEOUT:
assert_notreached("send both OK and timed out?");
default:
@@ -876,8 +894,8 @@ static void w5500_udp_alarm_handler(void *_arg) {
cr_sema_signal_from_intrhandler(&socket->read_sema);
}
-static ssize_t w5500_udp_recvfrom(struct _w5500_socket *socket, void *buf, size_t count,
- struct net_ip4_addr *ret_node, uint16_t *ret_port) {
+static size_t_or_error w5500_udp_recvfrom(struct _w5500_socket *socket, void *buf, size_t count,
+ struct net_ip4_addr *ret_node, uint16_t *ret_port) {
log_debugln("udp_conn.recvfrom()");
ASSERT_SELF(packet_conn, UDP);
assert(buf);
@@ -896,14 +914,14 @@ static ssize_t w5500_udp_recvfrom(struct _w5500_socket *socket, void *buf, size_
if (socket->read_deadline_ns && socket->read_deadline_ns <= LO_CALL(bootclock, get_time_ns)) {
LO_CALL(bootclock, del_trigger, &trigger);
log_debugln(" => recv timeout");
- return -NET_ERECV_TIMEOUT;
+ return ERROR_NEW_ERR(size_t, error_new(E_NET_ERECV_TIMEOUT));
}
cr_mutex_lock(&chip->mu);
uint8_t state = w5500ll_read_sock_reg(chip->spidev, socknum, state);
if (state != STATE_UDP) {
LO_CALL(bootclock, del_trigger, &trigger);
log_debugln(" => hard closed");
- return -NET_ECLOSED;
+ return ERROR_NEW_ERR(size_t, error_new(E_NET_ECLOSED));
}
avail = uint16be_unmarshal(w5500ll_read_sock_reg(chip->spidev, socknum, rx_size));
@@ -920,8 +938,8 @@ static ssize_t w5500_udp_recvfrom(struct _w5500_socket *socket, void *buf, size_
* can't find in the datasheet where it describes
* this; this is based off of socket.c:recvfrom(). */
uint8_t hdr[8];
- w5500ll_readv(chip->spidev, ptr, CTL_BLOCK_SOCK(socknum, RX), &((struct iovec){
- .iov_base = hdr,
+ w5500ll_readv(chip->spidev, ptr, CTL_BLOCK_SOCK(socknum, RX), &((struct rd_iovec){
+ .iov_read_to = hdr,
.iov_len = sizeof(hdr),
}), 1, 0);
if (ret_node) {
@@ -937,8 +955,8 @@ static ssize_t w5500_udp_recvfrom(struct _w5500_socket *socket, void *buf, size_
/* Now read the actual data. */
if (count > len)
count = len;
- w5500ll_readv(chip->spidev, ptr+8, CTL_BLOCK_SOCK(socknum, RX), &((struct iovec){
- .iov_base = buf,
+ w5500ll_readv(chip->spidev, ptr+8, CTL_BLOCK_SOCK(socknum, RX), &((struct rd_iovec){
+ .iov_read_to = buf,
.iov_len = len,
}), 1, 0);
/* Tell the chip that we read the data. */
@@ -947,14 +965,14 @@ static ssize_t w5500_udp_recvfrom(struct _w5500_socket *socket, void *buf, size_
/* Return. */
LO_CALL(bootclock, del_trigger, &trigger);
cr_mutex_unlock(&chip->mu);
- return len;
+ return ERROR_NEW_VAL(size_t, len);
}
-static int w5500_udp_close(struct _w5500_socket *socket) {
+static error w5500_udp_close(struct _w5500_socket *socket) {
log_debugln("udp_conn.close()");
ASSERT_SELF(packet_conn, UDP);
w5500_socket_close(socket);
w5500_free_socket(chip, socket);
- return 0;
+ return ERROR_NULL;
}
diff --git a/libhw_cr/w5500_ll.c b/libhw_cr/w5500_ll.c
new file mode 100644
index 0000000..ec40e5e
--- /dev/null
+++ b/libhw_cr/w5500_ll.c
@@ -0,0 +1,116 @@
+/* libhw_cr/w5500_ll.c - Low-level library for the WIZnet W5500 chip
+ *
+ * Based entirely on the W5500 datasheet (v1.1.0), not on reference code.
+ * https://docs.wiznet.io/img/products/w5500/W5500_ds_v110e.pdf
+ *
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <string.h> /* for memcmp() and mempy() */
+
+#include <libmisc/alloc.h>
+#include <libmisc/fmt.h>
+#include <libmisc/log.h>
+
+#include "w5500_ll.h"
+
+#if CONFIG_W5500_LL_DEBUG
+static void fmt_print_ctl_block(lo_interface fmt_dest w, uint8_t b) {
+ static char *strs[] = {
+ "RES",
+ "REG",
+ "TX",
+ "RX",
+ };
+ fmt_print(w, "CTL_BLOCK_SOCK(", (base10, (((b)>>5) & 0b111)), ", ", strs[((b)>>3)&0b11], ")");
+}
+#endif
+
+void _w5500ll_n_writev(const char *func,
+ lo_interface spi spidev, uint16_t addr, uint8_t block,
+ const struct wr_iovec *iov, int iovcnt,
+ size_t skip, size_t max)
+{
+ assert(!LO_IS_NULL(spidev));
+ assert((block & ~CTL_MASK_BLOCK) == 0);
+ assert(iov);
+ assert(iovcnt > 0);
+#if CONFIG_W5500_LL_DEBUG
+ log_n_debugln(W5500_LL,
+ func, "(): w5500ll_write(spidev",
+ ", addr=", (base16_u16_, addr),
+ ", block=", (ctl_block, block),
+ ", iov",
+ ", iovcnt=", iovcnt,
+ ")");
+#endif
+
+ uint8_t header[] = {
+ (uint8_t)((addr >> 8) & 0xFF),
+ (uint8_t)(addr & 0xFF),
+ (block & CTL_MASK_BLOCK) | CTL_W | CTL_OM_VDM,
+ };
+ int inner_cnt = 1+io_wr_slice_cnt(iov, iovcnt, skip, max);
+ [[gnu::cleanup(heap_cleanup)]] struct duplex_iovec *inner = heap_alloc(inner_cnt, struct duplex_iovec);
+ inner[0] = (struct duplex_iovec){
+ .iov_read_to = IOVEC_DISCARD,
+ .iov_write_from = header,
+ .iov_len = sizeof(header),
+ };
+ io_slice_wr_to_duplex(&inner[1], iov, iovcnt, skip, max);
+ LO_CALL(spidev, readwritev, inner, inner_cnt);
+}
+
+
+void _w5500ll_n_readv(const char *func,
+ lo_interface spi spidev, uint16_t addr, uint8_t block,
+ const struct rd_iovec *iov, int iovcnt,
+ size_t max)
+{
+ assert(!LO_IS_NULL(spidev));
+ assert((block & ~CTL_MASK_BLOCK) == 0);
+ assert(iov);
+ assert(iovcnt > 0);
+#if CONFIG_W5500_LL_DEBUG
+ log_n_debugln(W5500_LL,
+ func, "(): w5500ll_read(spidev",
+ ", addr=", (base16_u16_, addr),
+ ", block=", (ctl_block, block),
+ ", iov",
+ ", iovcnt=", iovcnt,
+ ")");
+#endif
+
+ uint8_t header[] = {
+ (uint8_t)((addr >> 8) & 0xFF),
+ (uint8_t)(addr & 0xFF),
+ (block & CTL_MASK_BLOCK) | CTL_R | CTL_OM_VDM,
+ };
+ int inner_cnt = 1+io_rd_slice_cnt(iov, iovcnt, 0, max);
+ [[gnu::cleanup(heap_cleanup)]] struct duplex_iovec *inner = heap_alloc(inner_cnt, struct duplex_iovec);
+ inner[0] = (struct duplex_iovec){
+ .iov_read_to = IOVEC_DISCARD,
+ .iov_write_from = header,
+ .iov_len = sizeof(header),
+ };
+ io_slice_rd_to_duplex(&inner[1], iov, iovcnt, 0, max);
+ LO_CALL(spidev, readwritev, inner, inner_cnt);
+}
+
+void _w5500ll_n_read_repeated(const char *func,
+ lo_interface spi spidev, uint16_t addr, uint8_t block,
+ void *buf, void *buf_scratch, size_t len)
+{
+ _w5500ll_n_readv(func, spidev, addr, block,
+ &((struct rd_iovec){.iov_read_to=buf, .iov_len=len}), 1,
+ 0);
+ for (;;) {
+ _w5500ll_n_readv(func, spidev, addr, block,
+ &((struct rd_iovec){.iov_read_to=buf_scratch, .iov_len=len}), 1,
+ 0);
+ if (memcmp(buf, buf_scratch, len) == 0)
+ break;
+ memcpy(buf, buf_scratch, len);
+ }
+}
diff --git a/libhw_cr/w5500_ll.h b/libhw_cr/w5500_ll.h
index aa41e7a..e375ebd 100644
--- a/libhw_cr/w5500_ll.h
+++ b/libhw_cr/w5500_ll.h
@@ -1,6 +1,6 @@
-/* libhw_cr/w5500_ll.h - Low-level header library for the WIZnet W5500 chip
+/* libhw_cr/w5500_ll.h - Low-level library for the WIZnet W5500 chip
*
- * Based entirely on the W5500 datasheet, v1.1.0.
+ * Based entirely on the W5500 datasheet (v1.1.0), not on reference code.
* https://docs.wiznet.io/img/products/w5500/W5500_ds_v110e.pdf
*
* Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
@@ -11,16 +11,14 @@
#define _LIBHW_CR_W5500_LL_H_
#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/assert.h> /* for static_assert() */
#include <libmisc/endian.h> /* for uint16be_t */
#include <libhw/generic/net.h> /* for struct net_eth_addr, struct net_ip4_addr */
#include <libhw/generic/spi.h> /* for lo_interface spi */
-/* Config *********************************************************************/
+/* Config. ***************************************************************************************/
#include "config.h"
@@ -28,7 +26,7 @@
#error config.h must define CONFIG_W5500_LL_DEBUG
#endif
-/* Low-level protocol built on SPI frames. ***********************************/
+/* Low-level protocol built on SPI frames. *******************************************************/
/* A u8 control byte has 3 parts: block-ID, R/W, and operating-mode. */
@@ -53,102 +51,81 @@
#define CTL_OM_FDM2 0b10 /* fixed-length data mode: 2 byte data length */
#define CTL_OM_FDM4 0b11 /* fixed-length data mode: 4 byte data length */
-#if CONFIG_W5500_LL_DEBUG
-static void fmt_print_ctl_block(lo_interface fmt_dest, uint8_t b) {
- static char *strs[] = {
- "RES",
- "REG",
- "TX",
- "RX",
- };
- fmt_print("CTL_BLOCK_SOCK(", (base10, (((b)>>5) & 0b111)), ", ", strs[((b)>>3)&0b11], ")");
-}
-#endif
+/* Even though SPI is a full-duplex protocol, the W5500's spiframe on
+ * top of it is only half-duplex. Lame. */
-/* Even though SPI is a full-duplex protocol, the W5500's spiframe on top of it is only half-duplex.
- * Lame. */
-
-static inline void
#if CONFIG_W5500_LL_DEBUG
-#define w5500ll_writev(...) _w5500ll_writev(__func__, __VA_ARGS__)
-_w5500ll_writev(const char *func,
+ #define w5500ll_writev(...) _w5500ll_n_writev (__func__, __VA_ARGS__)
+ #define w5500ll_readv(...) _w5500ll_n_readv (__func__, __VA_ARGS__)
#else
-w5500ll_writev(
-#endif
- lo_interface spi spidev, uint16_t addr, uint8_t block,
- const struct iovec *iov, int iovcnt,
- size_t skip, size_t max)
-{
- assert(!LO_IS_NULL(spidev));
- assert((block & ~CTL_MASK_BLOCK) == 0);
- assert(iov);
- assert(iovcnt > 0);
-#if CONFIG_W5500_LL_DEBUG
- log_n_debugln(W5500_LL,
- func, "(): w5500ll_write(spidev",
- ", addr=", (base16_u16_, addr),
- ", block=", (ctl_block, block),
- ", iov",
- ", iovcnt=", iovcnt,
- ")");
+ #define _w5500ll_n_writev(func, ...) w5500ll_writev (__VA_ARGS__)
+ #define _w5500ll_n_readv(func, ...) w5500ll_readv (__VA_ARGS__)
#endif
- uint8_t header[] = {
- (uint8_t)((addr >> 8) & 0xFF),
- (uint8_t)(addr & 0xFF),
- (block & CTL_MASK_BLOCK) | CTL_W | CTL_OM_VDM,
- };
- int inner_cnt = 1+io_slice_cnt(iov, iovcnt, skip, max);
- 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,
- .iov_len = sizeof(header),
- };
- io_slice_wr_to_duplex(&inner[1], iov, iovcnt, skip, max);
- LO_CALL(spidev, readwritev, inner, inner_cnt);
-}
-
-static inline void
+/* `skip` and `max` correspond to the <libhw/generic/io.h> `slice`
+ * functions' `byte_start` and `max_byte_cnt` arguments for working on
+ * just a subset of the iovec list. */
+
+void _w5500ll_n_writev(const char *func,
+ lo_interface spi spidev, uint16_t addr, uint8_t block,
+ const struct wr_iovec *iov, int iovcnt,
+ size_t skip, size_t max);
+void _w5500ll_n_readv(const char *func,
+ lo_interface spi spidev, uint16_t addr, uint8_t block,
+ const struct rd_iovec *iov, int iovcnt,
+ size_t max);
+
+/* Operate on registers. *************************************************************************/
+
+/*
+ * Given a `blocktyp` that is a struct describing the layout of
+ * registers in a block (e.g. `blocktyp = struct
+ * w5500_ll_block_common_reg`), read or write the `field` register
+ * (where `field` must be a field in that struct).
+ */
+
+#define w5500ll_write_reg(spidev, blockid, blocktyp, field, val) do { \
+ typeof((blocktyp){}.field) lval = val; \
+ w5500ll_writev(spidev, \
+ offsetof(blocktyp, field), blockid, \
+ &((struct wr_iovec){ \
+ .iov_write_from = &lval, \
+ .iov_len = sizeof(lval), \
+ }), 1, \
+ 0, 0); \
+ } while (0)
+
+/* The datasheet tells us that multi-byte reads are non-atomic and
+ * that "it is recommended that you read all 16-bits twice or more
+ * until getting the same value". */
#if CONFIG_W5500_LL_DEBUG
-#define w5500ll_readv(...) _w5500ll_read(__func__, __VA_ARGS__)
-_w5500ll_readv(const char *func,
+ #define _w5500ll_read_repeated(...) _w5500ll_n_read_repeated (__func__, __VA_ARGS__)
#else
-w5500ll_readv(
-#endif
- lo_interface spi spidev, uint16_t addr, uint8_t block,
- const struct iovec *iov, int iovcnt,
- size_t max)
-{
- assert(!LO_IS_NULL(spidev));
- assert((block & ~CTL_MASK_BLOCK) == 0);
- assert(iov);
- assert(iovcnt > 0);
-#if CONFIG_W5500_LL_DEBUG
- log_n_debugln(W5500_LL,
- func, "(): w5500ll_read(spidev",
- ", addr=", (base16_u16_, addr),
- ", block=", (ctl_block, block),
- ", iov",
- ", iovcnt=", iovcnt,
- ")");
+ #define _w5500ll_n_read_repeated(func, ...) _w5500ll_read_repeated (__VA_ARGS__)
#endif
+void _w5500ll_n_read_repeated(const char *func,
+ lo_interface spi spidev, uint16_t addr, uint8_t block,
+ void *buf, void *buf_scratch, size_t len);
+#define w5500ll_read_reg(spidev, blockid, blocktyp, field) ({ \
+ typeof((blocktyp){}.field) val; \
+ if (sizeof(val) == 1) { \
+ w5500ll_readv(spidev, \
+ offsetof(blocktyp, field), blockid, \
+ &((struct rd_iovec){ \
+ .iov_read_to = &val, \
+ .iov_len = sizeof(val), \
+ }), 1, \
+ 0); \
+ } else { \
+ typeof(val) val2; \
+ _w5500ll_read_repeated(spidev, \
+ offsetof(blocktyp, field), blockid, \
+ &val, &val2, sizeof(val)); \
+ } \
+ val; \
+ })
- uint8_t header[] = {
- (uint8_t)((addr >> 8) & 0xFF),
- (uint8_t)(addr & 0xFF),
- (block & CTL_MASK_BLOCK) | CTL_R | CTL_OM_VDM,
- };
- int inner_cnt = 1+io_slice_cnt(iov, iovcnt, 0, max);
- 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,
- .iov_len = sizeof(header),
- };
- io_slice_rd_to_duplex(&inner[1], iov, iovcnt, 0, max);
- LO_CALL(spidev, readwritev, inner, inner_cnt);
-}
+/* Register blocks. ******************************************************************************/
/* Common chip-wide registers. ***********************************************/
@@ -387,49 +364,4 @@ static_assert(sizeof(struct w5500ll_block_sock_reg) == 0x30);
struct w5500ll_block_sock_reg, \
field)
-/******************************************************************************/
-
-#define w5500ll_write_reg(spidev, blockid, blocktyp, field, val) do { \
- typeof((blocktyp){}.field) lval = val; \
- w5500ll_writev(spidev, \
- offsetof(blocktyp, field), \
- blockid, \
- &((struct iovec){ \
- &lval, \
- sizeof(lval), \
- }), \
- 1, 0, 0); \
- } while (0)
-
-/* The datasheet tells us that multi-byte reads are non-atomic and
- * that "it is recommended that you read all 16-bits twice or more
- * until getting the same value". */
-#define w5500ll_read_reg(spidev, blockid, blocktyp, field) ({ \
- typeof((blocktyp){}.field) val; \
- w5500ll_readv(spidev, \
- offsetof(blocktyp, field), \
- blockid, \
- &((struct iovec){ \
- .iov_base = &val, \
- .iov_len = sizeof(val), \
- }), \
- 1, 0); \
- if (sizeof(val) > 1) \
- for (;;) { \
- typeof(val) val2; \
- w5500ll_readv(spidev, \
- offsetof(blocktyp, field), \
- blockid, \
- &((struct iovec){ \
- .iov_base = &val2, \
- .iov_len = sizeof(val), \
- }), \
- 1, 0); \
- if (memcmp(&val2, &val, sizeof(val)) == 0) \
- break; \
- val = val2; \
- } \
- val; \
- })
-
#endif /* _LIBHW_CR_W5500_LL_H_ */
diff --git a/libhw_generic/CMakeLists.txt b/libhw_generic/CMakeLists.txt
index 602168b..6f5fa34 100644
--- a/libhw_generic/CMakeLists.txt
+++ b/libhw_generic/CMakeLists.txt
@@ -3,8 +3,14 @@
# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
# SPDX-License-Identifier: AGPL-3.0-or-later
+add_library(libhw_generic_headers INTERFACE)
+target_include_directories(libhw_generic_headers PUBLIC INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
+target_link_libraries(libhw_generic_headers INTERFACE
+ libmisc_headers
+)
+
add_library(libhw_generic INTERFACE)
-target_include_directories(libhw_generic PUBLIC INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
+target_link_libraries(libhw_generic INTERFACE libhw_generic_headers)
target_link_libraries(libhw_generic INTERFACE
libmisc
)
diff --git a/libhw_generic/alarmclock.c b/libhw_generic/alarmclock.c
index e3aaea3..3579829 100644
--- a/libhw_generic/alarmclock.c
+++ b/libhw_generic/alarmclock.c
@@ -7,3 +7,19 @@
#include <libhw/generic/alarmclock.h>
lo_interface alarmclock bootclock = {};
+
+void alarmclock_sleep_for_ns(lo_interface alarmclock clock, uint64_t delta_ns) {
+ alarmclock_sleep_until_ns(clock, LO_CALL(clock, get_time_ns) + delta_ns);
+}
+
+void alarmclock_sleep_for_us(lo_interface alarmclock clock, uint64_t delta_us) {
+ alarmclock_sleep_for_ns(clock, delta_us * (NS_PER_S/US_PER_S));
+}
+
+void alarmclock_sleep_for_ms(lo_interface alarmclock clock, uint64_t delta_ms) {
+ alarmclock_sleep_for_ns(clock, delta_ms * (NS_PER_S/MS_PER_S));
+}
+
+void alarmclock_sleep_for_s(lo_interface alarmclock clock, uint64_t delta_s) {
+ alarmclock_sleep_for_ns(clock, delta_s * NS_PER_S);
+}
diff --git a/libhw_generic/include/libhw/generic/alarmclock.h b/libhw_generic/include/libhw/generic/alarmclock.h
index 6ce2513..e7e66a1 100644
--- a/libhw_generic/include/libhw/generic/alarmclock.h
+++ b/libhw_generic/include/libhw/generic/alarmclock.h
@@ -7,7 +7,7 @@
#ifndef _LIBHW_GENERIC_ALARMCLOCK_H_
#define _LIBHW_GENERIC_ALARMCLOCK_H_
-#include <stdint.h> /* for uint{n}_t and UINT{n}_C */
+#include <stdint.h> /* for uint{n}_t and UINT{n}_C */
#include <libmisc/obj.h>
#include <libmisc/private.h>
@@ -44,13 +44,10 @@ struct alarmclock_trigger {
/** \
* Returns true on error. \
* \
- * Implementations may return an error if fire_at_ns is more \
- * than UINT32_MAX µs (72 minutes) in the future. \
- * \
* If fire_at_ns is in the past, then it will fire \
* immediately. \
*/ \
- LO_FUNC(bool, add_trigger, struct alarmclock_trigger *trigger, \
+ LO_FUNC(void, add_trigger, struct alarmclock_trigger *trigger, \
uint64_t fire_at_ns, \
void (*cb)(void *), \
void *cb_arg) \
@@ -62,21 +59,10 @@ LO_INTERFACE(alarmclock);
void alarmclock_sleep_until_ns(lo_interface alarmclock clock, uint64_t abstime_ns);
-static inline void alarmclock_sleep_for_ns(lo_interface alarmclock clock, uint64_t delta_ns) {
- alarmclock_sleep_until_ns(clock, LO_CALL(clock, get_time_ns) + delta_ns);
-}
-
-static inline void alarmclock_sleep_for_us(lo_interface alarmclock clock, uint64_t delta_us) {
- alarmclock_sleep_for_ns(clock, delta_us * (NS_PER_S/US_PER_S));
-}
-
-static inline void alarmclock_sleep_for_ms(lo_interface alarmclock clock, uint64_t delta_ms) {
- alarmclock_sleep_for_ns(clock, delta_ms * (NS_PER_S/MS_PER_S));
-}
-
-static inline void alarmclock_sleep_for_s(lo_interface alarmclock clock, uint64_t delta_s) {
- alarmclock_sleep_for_ns(clock, delta_s * NS_PER_S);
-}
+void alarmclock_sleep_for_ns(lo_interface alarmclock clock, uint64_t delta_ns);
+void alarmclock_sleep_for_us(lo_interface alarmclock clock, uint64_t delta_us);
+void alarmclock_sleep_for_ms(lo_interface alarmclock clock, uint64_t delta_ms);
+void alarmclock_sleep_for_s(lo_interface alarmclock clock, uint64_t delta_s);
/* Globals ********************************************************************/
diff --git a/libhw_generic/include/libhw/generic/io.h b/libhw_generic/include/libhw/generic/io.h
index 96680bb..edaf30c 100644
--- a/libhw_generic/include/libhw/generic/io.h
+++ b/libhw_generic/include/libhw/generic/io.h
@@ -7,22 +7,40 @@
#ifndef _LIBHW_GENERIC_IO_H_
#define _LIBHW_GENERIC_IO_H_
-#include <stddef.h> /* for size_t */
-#include <stdint.h> /* for uintptr_t */
-#include <sys/types.h> /* for ssize_t */
+#include <stddef.h> /* for size_t */
+#include <stdint.h> /* for uintptr_t, uint{n}_t, UINT{n}_MAX */
+#include <libmisc/error.h>
#include <libmisc/obj.h>
/* structs ********************************************************************/
-#if __unix__
-#include <sys/uio.h>
-#else
-struct iovec {
- void *iov_base;
+/* uoff_t ==========================================================*/
+
+typedef uint64_t uoff_t;
+#define UOFF_MAX UINT64_MAX
+DECLARE_ERROR_OR(uoff_t);
+DECLARE_ERROR_AND(uoff_t);
+
+/* rd_iovec ========================================================*/
+
+struct rd_iovec {
+ void *iov_read_to;
size_t iov_len;
};
-#endif
+DECLARE_ERROR_OR_(struct rd_iovec, rd_iovec);
+DECLARE_ERROR_AND_(struct rd_iovec, rd_iovec);
+
+/* wr_iovec ========================================================*/
+
+struct wr_iovec {
+ const void *iov_write_from;
+ size_t iov_len;
+};
+DECLARE_ERROR_OR_(struct wr_iovec, wr_iovec);
+DECLARE_ERROR_AND_(struct wr_iovec, wr_iovec);
+
+/* duplex_iovec ====================================================*/
#define IOVEC_DISCARD ((void*)(~((uintptr_t)0)))
@@ -32,44 +50,82 @@ struct duplex_iovec {
* iov_write_from. To skip a read or write, use the special
* value IOVEC_DISCARD.
*/
- void *iov_read_to;
- void *iov_write_from;
- size_t iov_len;
+ void *iov_read_to;
+ const void *iov_write_from;
+ size_t iov_len;
};
+DECLARE_ERROR_OR_(struct duplex_iovec, duplex_iovec);
+DECLARE_ERROR_AND_(struct duplex_iovec, duplex_iovec);
-/* utilities ******************************************************************/
+/* iovec utilities ************************************************************/
+
+/* If byte_max_cnt == 0, then there is no maximum. */
/* slice iovec lists */
-int io_slice_cnt ( const struct iovec *src, int src_cnt, size_t byte_start, size_t byte_max_cnt);
-void io_slice (struct iovec *dst, const struct iovec *src, int src_cnt, size_t byte_start, size_t byte_max_cnt);
+int io_rd_slice_cnt ( const struct rd_iovec *src, int src_cnt, size_t byte_start, size_t byte_max_cnt);
+void io_rd_slice (struct rd_iovec *dst, const struct rd_iovec *src, int src_cnt, size_t byte_start, size_t byte_max_cnt);
+int io_wr_slice_cnt ( const struct wr_iovec *src, int src_cnt, size_t byte_start, size_t byte_max_cnt);
+void io_wr_slice (struct wr_iovec *dst, const struct wr_iovec *src, int src_cnt, size_t byte_start, size_t byte_max_cnt);
int io_duplex_slice_cnt( const struct duplex_iovec *src, int src_cnt, size_t byte_start, size_t byte_max_cnt);
void io_duplex_slice (struct duplex_iovec *dst, const struct duplex_iovec *src, int src_cnt, size_t byte_start, size_t byte_max_cnt);
/* convert iovec lists */
-void io_rd_to_duplex(struct duplex_iovec *dst, const struct iovec *src, int iovcnt);
-void io_wr_to_duplex(struct duplex_iovec *dst, const struct iovec *src, int iovcnt);
+void io_rd_to_duplex(struct duplex_iovec *dst, const struct rd_iovec *src, int iovcnt);
+void io_wr_to_duplex(struct duplex_iovec *dst, const struct wr_iovec *src, int iovcnt);
/* slice and convert in one go */
-void io_slice_rd_to_duplex(struct duplex_iovec *dst, const struct iovec *src, int src_cnt, size_t byte_start, size_t byte_max_cnt);
-void io_slice_wr_to_duplex(struct duplex_iovec *dst, const struct iovec *src, int src_cnt, size_t byte_start, size_t byte_max_cnt);
+void io_slice_rd_to_duplex(struct duplex_iovec *dst, const struct rd_iovec *src, int src_cnt, size_t byte_start, size_t byte_max_cnt);
+void io_slice_wr_to_duplex(struct duplex_iovec *dst, const struct wr_iovec *src, int src_cnt, size_t byte_start, size_t byte_max_cnt);
/* basic interfaces ***********************************************************/
+/*
+ * Conventions:
+ *
+ * - Naming:
+ * + The "p"[osition] prefix means an explicit `uoff_t offset`,
+ * instead of using an internal cursor.
+ * + The "v"[ec] suffix means a sequence of iovecs, instead of a
+ * simple buf+len.
+ *
+ * - Errors:
+ * + Short *reads* are *not* errors (and so return size_t *or*
+ * error).
+ * + Short *writes* *are* errors (and so return size_t *and*
+ * (possibly-null) error).
+ */
+
+/* read ============================================================*/
+
/**
- * Return bytes-read on success, 0 on EOF, -errno on error; a short
- * read is *not* an error.
+ * Return bytes-read on success. A short read is *not* an error
+ * (unlike `write` methods).
*
* It is invalid to call readv when the sum length of iovecs is 0.
*/
#define io_reader_LO_IFACE \
- LO_FUNC(ssize_t, readv, const struct iovec *iov, int iovcnt)
+ LO_FUNC(size_t_or_error, readv, const struct rd_iovec *iov, int iovcnt)
LO_INTERFACE(io_reader);
#define io_readv(r, iov, iovcnt) LO_CALL(r, readv, iov, iovcnt)
-#define io_read(r, buf, count) LO_CALL(r, readv, &((struct iovec){.iov_base = buf, .iov_len = count}), 1)
+#define io_read(r, buf, count) LO_CALL(r, readv, &((struct rd_iovec){.iov_read_to = buf, .iov_len = count}), 1)
/**
- * Return `count` on success, -errno on error; a short write *is* an
- * error.
+ * Returns bytes-read on success. A short read is *not* an error
+ * (unlike `write` methods).
+ *
+ * It is invalid to call preadv when the sum length of iovecs is 0.
+ */
+#define io_preader_LO_IFACE \
+ LO_FUNC(size_t_or_error, preadv, const struct rd_iovec *iov, int iovcnt, uoff_t offset)
+LO_INTERFACE(io_preader);
+#define io_preadv(r, iov, iovcnt, off) LO_CALL(r, preadv, iov, iovcnt, off)
+#define io_pread(r, buf, count, off) LO_CALL(r, preadv, &((struct rd_iovec){.iov_read_to = buf, .iov_len = count}), 1, off)
+
+/* write ===========================================================*/
+
+/**
+ * Return bytes-written. A short write *is* an error (unlike `read`
+ * methods).
*
* Writes are *not* guaranteed to be atomic, so if you have concurrent
* writers then you should arrange for a mutex to protect the writer.
@@ -77,43 +133,88 @@ LO_INTERFACE(io_reader);
* It is invalid to call writev when the sum length of iovecs is 0.
*/
#define io_writer_LO_IFACE \
- LO_FUNC(ssize_t, writev, const struct iovec *iov, int iovcnt)
+ LO_FUNC(size_t_and_error, writev, const struct wr_iovec *iov, int iovcnt)
LO_INTERFACE(io_writer);
#define io_writev(w, iov, iovcnt) LO_CALL(w, writev, iov, iovcnt)
-#define io_write(w, buf, count) LO_CALL(w, writev, &((struct iovec){.iov_base = buf, .iov_len = count}), 1)
+#define io_write(w, buf, count) LO_CALL(w, writev, &((struct wr_iovec){.iov_write_from = buf, .iov_len = count}), 1)
/**
- * Return 0 on success, -errno on error.
+ * Returns bytes-written. A short write *is* an error (unlike `read`
+ * methods).
+ *
+ * Writes are *not* guaranteed to be atomic, so if you have concurrent
+ * writers then you should arrange for a mutex to protect the writer.
+ *
+ * It is invalid to call writev when the sum length of iovecs is 0.
*/
-#define io_closer_LO_IFACE \
- LO_FUNC(int, close)
-LO_INTERFACE(io_closer);
-#define io_close(c) LO_CALL(c, close)
+#define io_pwriter_LO_IFACE \
+ LO_FUNC(size_t_and_error, pwritev, const struct wr_iovec *iov, int iovcnt, uoff_t offset)
+LO_INTERFACE(io_pwriter);
+#define io_pwritev(r, iov, iovcnt, off) LO_CALL(r, pwritev, iov, iovcnt, off)
+#define io_pwrite(r, buf, count, off) LO_CALL(r, pwritev, &((struct wr_iovec){.iov_write_from = buf, .iov_len = count}), 1, off)
-/**
- * All methods return 0 on success, -errno on error.
- */
-#define io_bidi_closer_LO_IFACE \
- LO_NEST(io_closer) \
- LO_FUNC(int, close_read) \
- LO_FUNC(int, close_write)
-LO_INTERFACE(io_bidi_closer);
-#define io_close_read(c) LO_CALL(c, close_read)
-#define io_close_write(c) LO_CALL(c, close_write)
+/* readwrite =======================================================*/
/**
- * Return bytes-read and bytes-written on success, -errno on error; a
- * short read/write *is* an error.
+ * A short read/write *is* an error (like `write` methods and unlike
+ * `read` methods).
+ *
+ * Reads/writes are *not* guaranteed to be atomic, so if you have
+ * concurrent readers/writers then you should arrange for a mutex to
+ * protect the duplex_readwriter.
*
* It is invalid to call readwritev when the sum length of iovecs is 0.
*/
#define io_duplex_readwriter_LO_IFACE \
- LO_FUNC(void, readwritev, const struct duplex_iovec *iov, int iovcnt)
+ LO_FUNC(size_t_and_error, readwritev, const struct duplex_iovec *iov, int iovcnt)
LO_INTERFACE(io_duplex_readwriter);
-
#define io_readwritev(rw, iov, iovcnt) \
LO_CALL(rw, readwritev, iov, iovcnt)
+/* read then write =================================================*/
+
+/**
+ * LO_CALL(src, pread_to, dst, src_offset, count) is functionally:
+ *
+ * size_t_and_error copy(lo_interface io_writer dst, lo_interface io_preader src, uoff_t src_offset, size_t count) {
+ * buf = malloc(count);
+ * size_t_or_error read_r = io_pread(src, buf, count, src_offset);
+ * if (read_r.is_err)
+ * return ERROR_AND(size_t, 0, read_r.err);
+ * size_t_and_error write_r = io_write(dst, buf, read_r.size_t);
+ * free(buf);
+ * return write_r;
+ * }
+ *
+ * except that it does not need to allocate a buffer. That is: It
+ * allows the reader to dump its data directly to the writer. This
+ * allows us to save a copy when the reader already has an in-memory
+ * buffer containing the data.
+ *
+ * The above code defines when a short read/write is an error or not.
+ *
+ * It must call writev() exactly 0-or-1 times, and if it does call it,
+ * then it must be called with exactly 1 iovec.
+ */
+#define io_preader_to_LO_IFACE \
+ LO_FUNC(size_t_and_error, pread_to, lo_interface io_writer dst, uoff_t src_offset, size_t count)
+LO_INTERFACE(io_preader_to);
+
+/* close ===========================================================*/
+
+#define io_closer_LO_IFACE \
+ LO_FUNC(error, close)
+LO_INTERFACE(io_closer);
+#define io_close(c) LO_CALL(c, close)
+
+#define io_bidi_closer_LO_IFACE \
+ LO_NEST(io_closer) \
+ LO_FUNC(error, close_read) \
+ LO_FUNC(error, close_write)
+LO_INTERFACE(io_bidi_closer);
+#define io_close_read(c) LO_CALL(c, close_read)
+#define io_close_write(c) LO_CALL(c, close_write)
+
/* aggregate interfaces *******************************************************/
#define io_readwriter_LO_IFACE \
diff --git a/libhw_generic/include/libhw/generic/net.h b/libhw_generic/include/libhw/generic/net.h
index 573a01f..e2d626f 100644
--- a/libhw_generic/include/libhw/generic/net.h
+++ b/libhw_generic/include/libhw/generic/net.h
@@ -7,25 +7,11 @@
#ifndef _LIBHW_GENERIC_NET_H_
#define _LIBHW_GENERIC_NET_H_
-#include <inttypes.h> /* for PRI{u,x}{n} */
#include <stddef.h> /* for size_t */
#include <stdint.h> /* for uint{n}_t} */
-#include <sys/types.h> /* for ssize_t */
-#include <libmisc/fmt.h>
#include <libhw/generic/io.h>
-
-/* Errnos *********************************************************************/
-
-#define NET_EOTHER 1
-#define NET_EARP_TIMEOUT 2
-#define NET_EACK_TIMEOUT 3
-#define NET_ERECV_TIMEOUT 4
-#define NET_ETHREAD 5
-#define NET_ECLOSED 6
-#define NET_EMSGSIZE 7
-
-const char *net_strerror(int net_errno);
+#include <libmisc/fmt.h>
/* Address types **************************************************************/
@@ -45,22 +31,6 @@ void fmt_print_net_eth_addr(lo_interface fmt_dest, struct net_eth_addr);
/* Streams (e.g. TCP) *********************************************************/
-lo_interface net_stream_conn;
-
-#define net_stream_listener_LO_IFACE \
- /** \
- * It is invalid to accept() a new connection if an existing \
- * connection is still open. \
- */ \
- LO_FUNC(lo_interface net_stream_conn, accept) \
- \
- /** \
- * The net_stream_conn returned from accept() may still be \
- * valid after the listener is closed. \
- */ \
- LO_NEST(io_closer)
-LO_INTERFACE(net_stream_listener);
-
#define net_stream_conn_LO_IFACE \
LO_NEST(io_readwriter) \
LO_NEST(io_bidi_closer) \
@@ -79,10 +49,26 @@ LO_INTERFACE(net_stream_listener);
LO_FUNC(void, set_read_deadline, uint64_t ns_since_boot)
LO_INTERFACE(net_stream_conn);
+DECLARE_ERROR_OR_(lo_interface net_stream_conn, net_stream_conn);
+
+#define net_stream_listener_LO_IFACE \
+ /** \
+ * It is invalid to accept() a new connection if an existing \
+ * connection is still open. \
+ */ \
+ LO_FUNC(net_stream_conn_or_error, accept) \
+ \
+ /** \
+ * The net_stream_conn returned from accept() may still be \
+ * valid after the listener is closed. \
+ */ \
+ LO_NEST(io_closer)
+LO_INTERFACE(net_stream_listener);
+
/* Packets (e.g. UDP) *********************************************************/
#define net_packet_conn_LO_IFACE \
- LO_FUNC(ssize_t, sendto, \
+ LO_FUNC(error, sendto, \
void *buf, size_t len, \
struct net_ip4_addr node, uint16_t port) \
\
@@ -91,7 +77,7 @@ LO_INTERFACE(net_stream_conn);
* than the given `len` (as if the Linux MSG_TRUNC flag were \
* given). \
*/ \
- LO_FUNC(ssize_t, recvfrom, \
+ LO_FUNC(size_t_or_error, recvfrom, \
void *buf, size_t len, \
struct net_ip4_addr *ret_node, uint16_t *ret_port) \
\
@@ -126,8 +112,11 @@ struct net_iface_config {
LO_FUNC(void , ifdown ) \
\
LO_FUNC(lo_interface net_stream_listener, tcp_listen, uint16_t local_port) \
- LO_FUNC(lo_interface net_stream_conn , tcp_dial , struct net_ip4_addr remote_node, uint16_t remote_port) \
- LO_FUNC(lo_interface net_packet_conn , udp_conn , uint16_t local_port)
+ LO_FUNC(net_stream_conn_or_error , tcp_dial , struct net_ip4_addr remote_node, uint16_t remote_port) \
+ LO_FUNC(lo_interface net_packet_conn , udp_conn , uint16_t local_port) \
+ \
+ /** FIXME: arp_ping should probably have an explicit timeout or something. */ \
+ LO_FUNC(bool , arp_ping , struct net_ip4_addr)
LO_INTERFACE(net_iface);
#endif /* _LIBHW_GENERIC_NET_H_ */
diff --git a/libhw_generic/include/libhw/generic/spi.h b/libhw_generic/include/libhw/generic/spi.h
index 4bbf649..c0d9d91 100644
--- a/libhw_generic/include/libhw/generic/spi.h
+++ b/libhw_generic/include/libhw/generic/spi.h
@@ -12,10 +12,10 @@
#include <libhw/generic/io.h>
enum spi_mode {
- SPI_MODE_0 = 0, /* clk_polarity=0 (idle low), clk_phase=0 (sample on rise) */
- SPI_MODE_1 = 1, /* clk_polarity=0 (idle low), clk_phase=1 (sample on fall) */
- SPI_MODE_2 = 2, /* clk_polarity=1 (idle high), clk_phase=0 (sample on rise) */
- SPI_MODE_3 = 3, /* clk_polarity=1 (idle high), clk_phase=1 (sample on fall) */
+ SPI_MODE_0 = 0, /* clk_polarity=0 (idle low), clk_phase=0 (sample on transition-from-idle (rise)) ; shift on clock fall and CS fall */
+ SPI_MODE_1 = 1, /* clk_polarity=0 (idle low), clk_phase=1 (sample on transition-to-idle (fall)) ; shift on clock rise */
+ SPI_MODE_2 = 2, /* clk_polarity=1 (idle high), clk_phase=0 (sample on transition-from-idle (fall)) ; shift on clock rise and CS fall */
+ SPI_MODE_3 = 3, /* clk_polarity=1 (idle high), clk_phase=1 (sample on transition-to-idle (rise)) ; shift on clock fall */
};
/* This API assumes that an SPI frame is a multiple of 8-bits.
diff --git a/libhw_generic/io.c b/libhw_generic/io.c
index 4ebff10..a8c9da6 100644
--- a/libhw_generic/io.c
+++ b/libhw_generic/io.c
@@ -37,22 +37,27 @@
j++; \
}
-int io_slice_cnt(const struct iovec *src, int src_cnt, size_t byte_beg, size_t byte_max_cnt) {
- IOV_ITER();
- return j;
-}
+/* count */
+int io_rd_slice_cnt (const struct rd_iovec *src, int src_cnt, size_t byte_beg, size_t byte_max_cnt) { IOV_ITER(); return j; }
+int io_wr_slice_cnt (const struct wr_iovec *src, int src_cnt, size_t byte_beg, size_t byte_max_cnt) { IOV_ITER(); return j; }
+int io_duplex_slice_cnt(const struct duplex_iovec *src, int src_cnt, size_t byte_beg, size_t byte_max_cnt) { IOV_ITER(); return j; }
-int io_duplex_slice_cnt(const struct duplex_iovec *src, int src_cnt, size_t byte_beg, size_t byte_max_cnt) {
- IOV_ITER();
- return j;
+/* slice */
+void io_rd_slice(struct rd_iovec *dst, const struct rd_iovec *src, int src_cnt, size_t byte_beg, size_t byte_max_cnt) {
+ assert(src_cnt == 0 || dst);
+ IOV_ITER(
+ dst[j] = ((struct rd_iovec){
+ .iov_read_to = src[i].iov_read_to+off,
+ .iov_len = len,
+ });
+ );
}
-
-void io_slice(struct iovec *dst, const struct iovec *src, int src_cnt, size_t byte_beg, size_t byte_max_cnt) {
+void io_wr_slice(struct wr_iovec *dst, const struct wr_iovec *src, int src_cnt, size_t byte_beg, size_t byte_max_cnt) {
assert(src_cnt == 0 || dst);
IOV_ITER(
- dst[j] = ((struct iovec){
- .iov_base = src[i].iov_base+off,
- .iov_len = len,
+ dst[j] = ((struct wr_iovec){
+ .iov_write_from = src[i].iov_write_from+off,
+ .iov_len = len,
});
);
}
@@ -67,32 +72,32 @@ void io_slice_duplex(struct duplex_iovec *dst, const struct duplex_iovec *src, i
);
}
-void io_slice_rd_to_duplex(struct duplex_iovec *dst, const struct iovec *src, int src_cnt, size_t byte_beg, size_t byte_max_cnt) {
+/* slice+convert */
+void io_slice_rd_to_duplex(struct duplex_iovec *dst, const struct rd_iovec *src, int src_cnt, size_t byte_beg, size_t byte_max_cnt) {
assert(src_cnt == 0 || dst);
IOV_ITER(
dst[j] = ((struct duplex_iovec){
- .iov_read_to = src[i].iov_base+off,
+ .iov_read_to = src[i].iov_read_to+off,
.iov_write_from = IOVEC_DISCARD,
.iov_len = len,
});
);
}
-
-void io_slice_wr_to_duplex(struct duplex_iovec *dst, const struct iovec *src, int src_cnt, size_t byte_beg, size_t byte_max_cnt) {
+void io_slice_wr_to_duplex(struct duplex_iovec *dst, const struct wr_iovec *src, int src_cnt, size_t byte_beg, size_t byte_max_cnt) {
assert(src_cnt == 0 || dst);
IOV_ITER(
dst[j] = ((struct duplex_iovec){
.iov_read_to = IOVEC_DISCARD,
- .iov_write_from = src[i].iov_base+off,
+ .iov_write_from = src[i].iov_write_from+off,
.iov_len = len,
});
);
}
-void io_rd_to_duplex(struct duplex_iovec *dst, const struct iovec *src, int iovcnt) {
+/* convert */
+void io_rd_to_duplex(struct duplex_iovec *dst, const struct rd_iovec *src, int iovcnt) {
io_slice_rd_to_duplex(dst, src, iovcnt, 0, 0);
}
-
-void io_wr_to_duplex(struct duplex_iovec *dst, const struct iovec *src, int iovcnt) {
+void io_wr_to_duplex(struct duplex_iovec *dst, const struct wr_iovec *src, int iovcnt) {
io_slice_wr_to_duplex(dst, src, iovcnt, 0, 0);
}
diff --git a/libhw_generic/net.c b/libhw_generic/net.c
index d21626e..906e6e4 100644
--- a/libhw_generic/net.c
+++ b/libhw_generic/net.c
@@ -40,10 +40,10 @@ void fmt_print_net_ip4_addr(lo_interface fmt_dest w, struct net_ip4_addr addr) {
void fmt_print_net_eth_addr(lo_interface fmt_dest w, struct net_eth_addr addr) {
fmt_print(w,
- (base16_u8_, addr.octets[0]), ":",
- (base16_u8_, addr.octets[1]), ":",
- (base16_u8_, addr.octets[2]), ":",
- (base16_u8_, addr.octets[3]), ":",
- (base16_u8_, addr.octets[4]), ":",
- (base16_u8_, addr.octets[5]));
+ (rjust, 2, '0', (base16, addr.octets[0])), ":",
+ (rjust, 2, '0', (base16, addr.octets[1])), ":",
+ (rjust, 2, '0', (base16, addr.octets[2])), ":",
+ (rjust, 2, '0', (base16, addr.octets[3])), ":",
+ (rjust, 2, '0', (base16, addr.octets[4])), ":",
+ (rjust, 2, '0', (base16, addr.octets[5])));
}
diff --git a/libhw_generic/tests/test_io.c b/libhw_generic/tests/test_io.c
index 0d6df11..c6eeba0 100644
--- a/libhw_generic/tests/test_io.c
+++ b/libhw_generic/tests/test_io.c
@@ -12,9 +12,9 @@
int main() {
char data[] = "abcdefghijklmnopqrstuvwxyz";
- struct iovec src[] = {
- {.iov_base = &data[1], .iov_len=3}, /* "bcd" */
- {.iov_base = &data[20], .iov_len=4}, /* "uvwx" */
+ struct wr_iovec src[] = {
+ {.iov_write_from = &data[1], .iov_len=3}, /* "bcd" */
+ {.iov_write_from = &data[20], .iov_len=4}, /* "uvwx" */
};
const int src_cnt = sizeof(src)/sizeof(src[0]);
@@ -23,7 +23,7 @@ int main() {
#define TC(start, max, ...) do { \
char *exp[] = {__VA_ARGS__}; \
int exp_cnt = sizeof(exp)/sizeof(exp[0]); \
- int act_cnt = io_slice_cnt(src, src_cnt, start, max); \
+ int act_cnt = io_wr_slice_cnt(src, src_cnt, start, max); \
test_assert(act_cnt == exp_cnt); \
memset(dst, 0, sizeof(dst)); \
io_slice_wr_to_duplex(dst, src, src_cnt, start, max); \
diff --git a/libmisc/CMakeLists.txt b/libmisc/CMakeLists.txt
index 48407bd..7388a91 100644
--- a/libmisc/CMakeLists.txt
+++ b/libmisc/CMakeLists.txt
@@ -3,15 +3,28 @@
# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
# SPDX-License-Identifier: AGPL-3.0-or-later
+add_library(libmisc_headers INTERFACE)
+target_include_directories(libmisc_headers PUBLIC INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
+target_compile_options(libmisc_headers INTERFACE
+ -no-integrated-cpp
+ -wrapper "${CMAKE_CURRENT_SOURCE_DIR}/wrap-cc"
+)
+
add_library(libmisc INTERFACE)
-target_include_directories(libmisc PUBLIC INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
+target_link_libraries(libmisc INTERFACE libmisc_headers)
target_sources(libmisc INTERFACE
assert.c
+ endian.c
+ error.c
+ error_generated.c
fmt.c
+ hash.c
intercept.c
linkedlist.c
log.c
map.c
+ rand.c
+ utf8.c
)
add_lib_test(libmisc test_assert)
@@ -24,5 +37,6 @@ add_lib_test(libmisc test_macro)
add_lib_test(libmisc test_map)
add_lib_test(libmisc test_obj)
add_lib_test(libmisc test_obj_nest)
+add_lib_test(libmisc test_obj_autobox)
add_lib_test(libmisc test_private)
add_lib_test(libmisc test_rand)
diff --git a/libmisc/assert.c b/libmisc/assert.c
index cb3a270..dc7f250 100644
--- a/libmisc/assert.c
+++ b/libmisc/assert.c
@@ -11,13 +11,13 @@
#ifndef NDEBUG
void __assert_msg_fail(const char *expr,
- const char *file, unsigned int line, const char *func,
- const char *msg) {
+ const char *file, unsigned int line, const char *func,
+ const char *msg) {
static bool in_fail = false;
if (!in_fail) {
in_fail = true;
log_errorln(file, ":", line, ":", func, "(): ",
- "assertion ", (qstr, expr), " failed",
+ "assertion \"", (str, expr), "\" failed",
msg ? ": " : "", msg ?: "");
in_fail = false;
}
diff --git a/libmisc/endian.c b/libmisc/endian.c
new file mode 100644
index 0000000..2528f48
--- /dev/null
+++ b/libmisc/endian.c
@@ -0,0 +1,136 @@
+/* libmisc/endian.c - Endian-conversion helpers
+ *
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <libmisc/macro.h> /* for LM_FORCE_SEMICOLON */
+
+#include <libmisc/endian.h>
+
+#define endian_declare_wrappers(NBIT, ENDIAN) \
+ uint##NBIT##ENDIAN##_t uint##NBIT##ENDIAN##_marshal(uint##NBIT##_t in) { \
+ uint##NBIT##ENDIAN##_t out; \
+ uint##NBIT##ENDIAN##_encode(out.octets, in); \
+ return out; \
+ } \
+ uint##NBIT##_t uint##NBIT##ENDIAN##_unmarshal(uint##NBIT##ENDIAN##_t in) { \
+ return uint##NBIT##ENDIAN##_decode(in.octets); \
+ } \
+ LM_FORCE_SEMICOLON
+
+/* Big endian *****************************************************************/
+
+size_t uint16be_encode(uint8_t *out, uint16_t in) {
+ out[0] = (uint8_t)((in >> 8) & 0xFF);
+ out[1] = (uint8_t)((in >> 0) & 0xFF);
+ return 2;
+}
+
+uint16_t uint16be_decode(uint8_t *in) {
+ return (((uint16_t)(in[0])) << 8)
+ | (((uint16_t)(in[1])) << 0)
+ ;
+}
+
+size_t uint32be_encode(uint8_t *out, uint32_t in) {
+ out[0] = (uint8_t)((in >> 24) & 0xFF);
+ out[1] = (uint8_t)((in >> 16) & 0xFF);
+ out[2] = (uint8_t)((in >> 8) & 0xFF);
+ out[3] = (uint8_t)((in >> 0) & 0xFF);
+ return 4;
+}
+
+uint32_t uint32be_decode(uint8_t *in) {
+ return (((uint32_t)(in[0])) << 24)
+ | (((uint32_t)(in[1])) << 16)
+ | (((uint32_t)(in[2])) << 8)
+ | (((uint32_t)(in[3])) << 0)
+ ;
+}
+
+size_t uint64be_encode(uint8_t *out, uint64_t in) {
+ out[0] = (uint8_t)((in >> 56) & 0xFF);
+ out[1] = (uint8_t)((in >> 48) & 0xFF);
+ out[2] = (uint8_t)((in >> 40) & 0xFF);
+ out[3] = (uint8_t)((in >> 32) & 0xFF);
+ out[4] = (uint8_t)((in >> 24) & 0xFF);
+ out[5] = (uint8_t)((in >> 16) & 0xFF);
+ out[6] = (uint8_t)((in >> 8) & 0xFF);
+ out[7] = (uint8_t)((in >> 0) & 0xFF);
+ return 8;
+}
+
+uint64_t uint64be_decode(uint8_t *in) {
+ return (((uint64_t)(in[0])) << 56)
+ | (((uint64_t)(in[1])) << 48)
+ | (((uint64_t)(in[2])) << 40)
+ | (((uint64_t)(in[3])) << 32)
+ | (((uint64_t)(in[4])) << 24)
+ | (((uint64_t)(in[5])) << 16)
+ | (((uint64_t)(in[6])) << 8)
+ | (((uint64_t)(in[7])) << 0)
+ ;
+}
+
+endian_declare_wrappers(16, be);
+endian_declare_wrappers(32, be);
+endian_declare_wrappers(64, be);
+
+/* Little endian **************************************************************/
+
+size_t uint16le_encode(uint8_t *out, uint16_t in) {
+ out[0] = (uint8_t)((in >> 0) & 0xFF);
+ out[1] = (uint8_t)((in >> 8) & 0xFF);
+ return 2;
+}
+
+uint16_t uint16le_decode(uint8_t *in) {
+ return (((uint16_t)(in[0])) << 0)
+ | (((uint16_t)(in[1])) << 8)
+ ;
+}
+
+size_t uint32le_encode(uint8_t *out, uint32_t in) {
+ out[0] = (uint8_t)((in >> 0) & 0xFF);
+ out[1] = (uint8_t)((in >> 8) & 0xFF);
+ out[2] = (uint8_t)((in >> 16) & 0xFF);
+ out[3] = (uint8_t)((in >> 24) & 0xFF);
+ return 4;
+}
+
+uint32_t uint32le_decode(uint8_t *in) {
+ return (((uint32_t)(in[0])) << 0)
+ | (((uint32_t)(in[1])) << 8)
+ | (((uint32_t)(in[2])) << 16)
+ | (((uint32_t)(in[3])) << 24)
+ ;
+}
+
+size_t uint64le_encode(uint8_t *out, uint64_t in) {
+ out[0] = (uint8_t)((in >> 0) & 0xFF);
+ out[1] = (uint8_t)((in >> 8) & 0xFF);
+ out[2] = (uint8_t)((in >> 16) & 0xFF);
+ out[3] = (uint8_t)((in >> 24) & 0xFF);
+ out[4] = (uint8_t)((in >> 32) & 0xFF);
+ out[5] = (uint8_t)((in >> 40) & 0xFF);
+ out[6] = (uint8_t)((in >> 48) & 0xFF);
+ out[7] = (uint8_t)((in >> 56) & 0xFF);
+ return 8;
+}
+
+uint64_t uint64le_decode(uint8_t *in) {
+ return (((uint64_t)(in[0])) << 0)
+ | (((uint64_t)(in[1])) << 8)
+ | (((uint64_t)(in[2])) << 16)
+ | (((uint64_t)(in[3])) << 24)
+ | (((uint64_t)(in[4])) << 32)
+ | (((uint64_t)(in[5])) << 40)
+ | (((uint64_t)(in[6])) << 48)
+ | (((uint64_t)(in[7])) << 56)
+ ;
+}
+
+endian_declare_wrappers(16, le);
+endian_declare_wrappers(32, le);
+endian_declare_wrappers(64, le);
diff --git a/libmisc/error.c b/libmisc/error.c
new file mode 100644
index 0000000..345755c
--- /dev/null
+++ b/libmisc/error.c
@@ -0,0 +1,35 @@
+/* libmisc/error.c - Go-esque errors
+ *
+ * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <string.h> /* for strdup() */
+
+#include <libmisc/error.h>
+
+const char *error_msg(error err) {
+ return (err._msg && err._msg[0])
+ ? err._msg
+ : _errnum_str_msg(err.num);
+}
+
+error error_dup(error err) {
+ return (error){
+ .num = err.num,
+ ._msg = err._msg ? strdup(err._msg) : NULL,
+ };
+}
+
+void error_cleanup(error *errptr) {
+ if (!errptr)
+ return;
+ if (errptr->_msg)
+ free(errptr->_msg);
+ errptr->num = E_NOERROR;
+ errptr->_msg = NULL;
+}
+
+void fmt_print_error(lo_interface fmt_dest w, error err) {
+ fmt_print(w, (str, error_msg(err)), " (", _errnum_str_sym(err.num), ")");
+}
diff --git a/libmisc/error_generated.c b/libmisc/error_generated.c
new file mode 100644
index 0000000..e0afcab
--- /dev/null
+++ b/libmisc/error_generated.c
@@ -0,0 +1,186 @@
+/* libmisc/error_generated.c - Generated by libmisc/error_generated.c.gen. DO NOT EDIT! */
+
+#include <libmisc/error.h>
+
+const char *_errnum_str_sym(_errnum errnum) {
+ switch (errnum) {
+ case E_NOERROR: return "E_NOERROR";
+ case E_EOF: return "E_EOF";
+ case E_NET_EARP_TIMEOUT: return "E_NET_EARP_TIMEOUT";
+ case E_NET_EACK_TIMEOUT: return "E_NET_EACK_TIMEOUT";
+ case E_NET_ERECV_TIMEOUT: return "E_NET_ERECV_TIMEOUT";
+ case E_NET_ECLOSED: return "E_NET_ECLOSED";
+ case E_POSIX_E2BIG: return "E_POSIX_E2BIG";
+ case E_POSIX_EACCES: return "E_POSIX_EACCES";
+ case E_POSIX_EADDRINUSE: return "E_POSIX_EADDRINUSE";
+ case E_POSIX_EADDRNOTAVAIL: return "E_POSIX_EADDRNOTAVAIL";
+ case E_POSIX_EAFNOSUPPORT: return "E_POSIX_EAFNOSUPPORT";
+ case E_POSIX_EAGAIN: return "E_POSIX_EAGAIN";
+ case E_POSIX_EALREADY: return "E_POSIX_EALREADY";
+ case E_POSIX_EBADF: return "E_POSIX_EBADF";
+ case E_POSIX_EBADMSG: return "E_POSIX_EBADMSG";
+ case E_POSIX_EBUSY: return "E_POSIX_EBUSY";
+ case E_POSIX_ECANCELED: return "E_POSIX_ECANCELED";
+ case E_POSIX_ECHILD: return "E_POSIX_ECHILD";
+ case E_POSIX_ECONNABORTED: return "E_POSIX_ECONNABORTED";
+ case E_POSIX_ECONNREFUSED: return "E_POSIX_ECONNREFUSED";
+ case E_POSIX_ECONNRESET: return "E_POSIX_ECONNRESET";
+ case E_POSIX_EDEADLK: return "E_POSIX_EDEADLK";
+ case E_POSIX_EDESTADDRREQ: return "E_POSIX_EDESTADDRREQ";
+ case E_POSIX_EDOM: return "E_POSIX_EDOM";
+ case E_POSIX_EDQUOT: return "E_POSIX_EDQUOT";
+ case E_POSIX_EEXIST: return "E_POSIX_EEXIST";
+ case E_POSIX_EFAULT: return "E_POSIX_EFAULT";
+ case E_POSIX_EFBIG: return "E_POSIX_EFBIG";
+ case E_POSIX_EHOSTUNREACH: return "E_POSIX_EHOSTUNREACH";
+ case E_POSIX_EIDRM: return "E_POSIX_EIDRM";
+ case E_POSIX_EILSEQ: return "E_POSIX_EILSEQ";
+ case E_POSIX_EINPROGRESS: return "E_POSIX_EINPROGRESS";
+ case E_POSIX_EINTR: return "E_POSIX_EINTR";
+ case E_POSIX_EINVAL: return "E_POSIX_EINVAL";
+ case E_POSIX_EIO: return "E_POSIX_EIO";
+ case E_POSIX_EISCONN: return "E_POSIX_EISCONN";
+ case E_POSIX_EISDIR: return "E_POSIX_EISDIR";
+ case E_POSIX_ELOOP: return "E_POSIX_ELOOP";
+ case E_POSIX_EMFILE: return "E_POSIX_EMFILE";
+ case E_POSIX_EMLINK: return "E_POSIX_EMLINK";
+ case E_POSIX_EMSGSIZE: return "E_POSIX_EMSGSIZE";
+ case E_POSIX_EMULTIHOP: return "E_POSIX_EMULTIHOP";
+ case E_POSIX_ENAMETOOLONG: return "E_POSIX_ENAMETOOLONG";
+ case E_POSIX_ENETDOWN: return "E_POSIX_ENETDOWN";
+ case E_POSIX_ENETRESET: return "E_POSIX_ENETRESET";
+ case E_POSIX_ENETUNREACH: return "E_POSIX_ENETUNREACH";
+ case E_POSIX_ENFILE: return "E_POSIX_ENFILE";
+ case E_POSIX_ENOBUFS: return "E_POSIX_ENOBUFS";
+ case E_POSIX_ENODEV: return "E_POSIX_ENODEV";
+ case E_POSIX_ENOENT: return "E_POSIX_ENOENT";
+ case E_POSIX_ENOEXEC: return "E_POSIX_ENOEXEC";
+ case E_POSIX_ENOLCK: return "E_POSIX_ENOLCK";
+ case E_POSIX_ENOLINK: return "E_POSIX_ENOLINK";
+ case E_POSIX_ENOMEM: return "E_POSIX_ENOMEM";
+ case E_POSIX_ENOMSG: return "E_POSIX_ENOMSG";
+ case E_POSIX_ENOPROTOOPT: return "E_POSIX_ENOPROTOOPT";
+ case E_POSIX_ENOSPC: return "E_POSIX_ENOSPC";
+ case E_POSIX_ENOSYS: return "E_POSIX_ENOSYS";
+ case E_POSIX_ENOTCONN: return "E_POSIX_ENOTCONN";
+ case E_POSIX_ENOTDIR: return "E_POSIX_ENOTDIR";
+ case E_POSIX_ENOTEMPTY: return "E_POSIX_ENOTEMPTY";
+ case E_POSIX_ENOTRECOVERABLE: return "E_POSIX_ENOTRECOVERABLE";
+ case E_POSIX_ENOTSOCK: return "E_POSIX_ENOTSOCK";
+ case E_POSIX_ENOTSUP: return "E_POSIX_ENOTSUP";
+ case E_POSIX_ENOTTY: return "E_POSIX_ENOTTY";
+ case E_POSIX_ENXIO: return "E_POSIX_ENXIO";
+ case E_POSIX_EOPNOTSUPP: return "E_POSIX_EOPNOTSUPP";
+ case E_POSIX_EOVERFLOW: return "E_POSIX_EOVERFLOW";
+ case E_POSIX_EOWNERDEAD: return "E_POSIX_EOWNERDEAD";
+ case E_POSIX_EPERM: return "E_POSIX_EPERM";
+ case E_POSIX_EPIPE: return "E_POSIX_EPIPE";
+ case E_POSIX_EPROTO: return "E_POSIX_EPROTO";
+ case E_POSIX_EPROTONOSUPPORT: return "E_POSIX_EPROTONOSUPPORT";
+ case E_POSIX_EPROTOTYPE: return "E_POSIX_EPROTOTYPE";
+ case E_POSIX_ERANGE: return "E_POSIX_ERANGE";
+ case E_POSIX_EROFS: return "E_POSIX_EROFS";
+ case E_POSIX_ESOCKTNOSUPPORT: return "E_POSIX_ESOCKTNOSUPPORT";
+ case E_POSIX_ESPIPE: return "E_POSIX_ESPIPE";
+ case E_POSIX_ESRCH: return "E_POSIX_ESRCH";
+ case E_POSIX_ESTALE: return "E_POSIX_ESTALE";
+ case E_POSIX_ETIMEDOUT: return "E_POSIX_ETIMEDOUT";
+ case E_POSIX_ETXTBSY: return "E_POSIX_ETXTBSY";
+ case E_POSIX_EWOULDBLOCK: return "E_POSIX_EWOULDBLOCK";
+ case E_POSIX_EXDEV: return "E_POSIX_EXDEV";
+ case E_EUNKNOWN: return "E_EUNKNOWN";
+ default: return "E_<invalid>";
+ }
+}
+
+const char *_errnum_str_msg(_errnum errnum) {
+ switch (errnum) {
+ case E_NOERROR: return "no error";
+ case E_EOF: return "EOF";
+ case E_NET_EARP_TIMEOUT: return "ARP timeout";
+ case E_NET_EACK_TIMEOUT: return "TCP ACK timeout";
+ case E_NET_ERECV_TIMEOUT: return "receive timeout";
+ case E_NET_ECLOSED: return "already closed";
+ case E_POSIX_E2BIG: return "Argument list too long";
+ case E_POSIX_EACCES: return "Permission denied";
+ case E_POSIX_EADDRINUSE: return "Address in use";
+ case E_POSIX_EADDRNOTAVAIL: return "Address not available";
+ case E_POSIX_EAFNOSUPPORT: return "Address family not supported";
+ case E_POSIX_EAGAIN: return "Resource unavailable, try again";
+ case E_POSIX_EALREADY: return "Connection already in progress";
+ case E_POSIX_EBADF: return "Bad file descriptor";
+ case E_POSIX_EBADMSG: return "Bad message";
+ case E_POSIX_EBUSY: return "Device or resource busy";
+ case E_POSIX_ECANCELED: return "Operation canceled";
+ case E_POSIX_ECHILD: return "No child processes";
+ case E_POSIX_ECONNABORTED: return "Connection aborted";
+ case E_POSIX_ECONNREFUSED: return "Connection refused";
+ case E_POSIX_ECONNRESET: return "Connection reset";
+ case E_POSIX_EDEADLK: return "Resource deadlock would occur";
+ case E_POSIX_EDESTADDRREQ: return "Destination address required";
+ case E_POSIX_EDOM: return "Mathematics argument out of domain of function";
+ case E_POSIX_EDQUOT: return "Reserved";
+ case E_POSIX_EEXIST: return "File exists";
+ case E_POSIX_EFAULT: return "Bad address";
+ case E_POSIX_EFBIG: return "File too large";
+ case E_POSIX_EHOSTUNREACH: return "Host is unreachable";
+ case E_POSIX_EIDRM: return "Identifier removed";
+ case E_POSIX_EILSEQ: return "Illegal byte sequence";
+ case E_POSIX_EINPROGRESS: return "Operation in progress";
+ case E_POSIX_EINTR: return "Interrupted function";
+ case E_POSIX_EINVAL: return "Invalid argument";
+ case E_POSIX_EIO: return "I/O error";
+ case E_POSIX_EISCONN: return "Socket is connected";
+ case E_POSIX_EISDIR: return "Is a directory";
+ case E_POSIX_ELOOP: return "Too many levels of symbolic links";
+ case E_POSIX_EMFILE: return "File descriptor value too large";
+ case E_POSIX_EMLINK: return "Too many hard links";
+ case E_POSIX_EMSGSIZE: return "Message too large";
+ case E_POSIX_EMULTIHOP: return "Reserved";
+ case E_POSIX_ENAMETOOLONG: return "Filename too long";
+ case E_POSIX_ENETDOWN: return "Network is down";
+ case E_POSIX_ENETRESET: return "Connection aborted by network";
+ case E_POSIX_ENETUNREACH: return "Network unreachable";
+ case E_POSIX_ENFILE: return "Too many files open in system";
+ case E_POSIX_ENOBUFS: return "No buffer space available";
+ case E_POSIX_ENODEV: return "No such device";
+ case E_POSIX_ENOENT: return "No such file or directory";
+ case E_POSIX_ENOEXEC: return "Executable file format error";
+ case E_POSIX_ENOLCK: return "No locks available";
+ case E_POSIX_ENOLINK: return "Reserved";
+ case E_POSIX_ENOMEM: return "Not enough space";
+ case E_POSIX_ENOMSG: return "No message of the desired type";
+ case E_POSIX_ENOPROTOOPT: return "Protocol not available";
+ case E_POSIX_ENOSPC: return "No space left on device";
+ case E_POSIX_ENOSYS: return "Functionality not supported";
+ case E_POSIX_ENOTCONN: return "The socket is not connected";
+ case E_POSIX_ENOTDIR: return "Not a directory or a symbolic link to a directory";
+ case E_POSIX_ENOTEMPTY: return "Directory not empty";
+ case E_POSIX_ENOTRECOVERABLE: return "State not recoverable";
+ case E_POSIX_ENOTSOCK: return "Not a socket";
+ case E_POSIX_ENOTSUP: return "Not supported";
+ case E_POSIX_ENOTTY: return "Inappropriate I/O control operation";
+ case E_POSIX_ENXIO: return "No such device or address";
+ case E_POSIX_EOPNOTSUPP: return "Operation not supported on socket";
+ case E_POSIX_EOVERFLOW: return "Value too large to be stored in data type";
+ case E_POSIX_EOWNERDEAD: return "Previous owner died";
+ case E_POSIX_EPERM: return "Operation not permitted";
+ case E_POSIX_EPIPE: return "Broken pipe";
+ case E_POSIX_EPROTO: return "Protocol error";
+ case E_POSIX_EPROTONOSUPPORT: return "Protocol not supported";
+ case E_POSIX_EPROTOTYPE: return "Protocol wrong type for socket";
+ case E_POSIX_ERANGE: return "Result too large";
+ case E_POSIX_EROFS: return "Read-only file system";
+ case E_POSIX_ESOCKTNOSUPPORT: return "Socket type not supported";
+ case E_POSIX_ESPIPE: return "Invalid seek";
+ case E_POSIX_ESRCH: return "No such process";
+ case E_POSIX_ESTALE: return "Reserved";
+ case E_POSIX_ETIMEDOUT: return "Connection timed out";
+ case E_POSIX_ETXTBSY: return "Text file busy";
+ case E_POSIX_EWOULDBLOCK: return "Operation would block";
+ case E_POSIX_EXDEV: return "Improper hard link";
+ case E_EUNKNOWN:
+ default:
+ return "unknown error";
+ }
+}
diff --git a/libmisc/error_generated.c.gen b/libmisc/error_generated.c.gen
new file mode 100755
index 0000000..944d909
--- /dev/null
+++ b/libmisc/error_generated.c.gen
@@ -0,0 +1,35 @@
+#!/usr/bin/env bash
+# libmisc/error_generated.c.gen - Generate _errnum strings
+#
+# Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+error_h=$1
+outfile=$2
+
+{
+ echo "/* ${outfile} - Generated by $0. DO NOT EDIT! */"
+ echo
+ echo '#include <libmisc/error.h>'
+ echo
+ echo 'const char *_errnum_str_sym(_errnum errnum) {'
+ echo $'\tswitch (errnum) {'
+ sed -nE \
+ -e 's@^(#define)?\s+(E_[_A-Z0-9]+)[ ,][^/]*/\* ([^*(]+) (\*/|\().*@'$'\tcase \\2: return "\\2";''@p' \
+ -- "$error_h"
+ echo $'\tcase E_EUNKNOWN: return "E_EUNKNOWN";'
+ echo $'\tdefault: return "E_<invalid>";'
+ echo $'\t}'
+ echo '}'
+ echo
+ echo 'const char *_errnum_str_msg(_errnum errnum) {'
+ echo $'\tswitch (errnum) {'
+ sed -nE \
+ -e 's@^(#define)?\s+(E_[_A-Z0-9]+)[ ,][^/]*/\* ([^*(]+) (\*/|\().*@'$'\tcase \\2: return "\\3";''@p' \
+ -- "$error_h"
+ echo $'\tcase E_EUNKNOWN:'
+ echo $'\tdefault:'
+ echo $'\t\treturn "unknown error";'
+ echo $'\t}'
+ echo '}'
+} >"$outfile"
diff --git a/libmisc/fmt.c b/libmisc/fmt.c
index 33788b6..00b39d1 100644
--- a/libmisc/fmt.c
+++ b/libmisc/fmt.c
@@ -6,12 +6,39 @@
#include <string.h> /* for strnlen() */
+#include <libmisc/utf8.h>
+
#include <libmisc/fmt.h>
static const char *const hexdig = "0123456789ABCDEF";
/* small/trivial formatters ***************************************************/
+void fmt_print_mem(lo_interface fmt_dest w, const void *_str, size_t size) {
+ const uint8_t *str = _str;
+ while (size--)
+ fmt_print_byte(w, *(str++));
+}
+void fmt_print_str(lo_interface fmt_dest w, const char *str) {
+ while (*str)
+ fmt_print_byte(w, *(str++));
+}
+void fmt_print_strn(lo_interface fmt_dest w, const char *str, size_t size) {
+ while (size-- && *str)
+ fmt_print_byte(w, *(str++));
+}
+
+void fmt_print_hmem(lo_interface fmt_dest w, const void *_str, size_t size) {
+ const uint8_t *str = _str;
+ fmt_print_byte(w, '{');
+ for (size_t i = 0; i < size; i++) {
+ if (i)
+ fmt_print_byte(w, ',');
+ fmt_print_hbyte(w, str[i]);
+ }
+ fmt_print_byte(w, '}');
+}
+
void fmt_print_byte(lo_interface fmt_dest w, uint8_t b) {
LO_CALL(w, putb, b);
}
@@ -33,7 +60,7 @@ void fmt_print_base16_u64_(lo_interface fmt_dest w, uint64_t x) {
fmt_print(w, "0x", (rjust, 16, '0', (base16, x)));
}
-void fmt_print_ptr(lo_interface fmt_dest w, void *ptr) {
+void fmt_print_ptr(lo_interface fmt_dest w, volatile const void *ptr) {
LM_CAT3_(fmt_print_base16_u, __INTPTR_WIDTH__, _)(w, (uintptr_t)ptr);
}
@@ -44,9 +71,33 @@ void fmt_print_ptr(lo_interface fmt_dest w, void *ptr) {
*/
void fmt_print_qbyte(lo_interface fmt_dest w, uint8_t b) {
fmt_print_byte(w, '\'');
- if (' ' <= b && b <= '~') {
- if (b == '\'' || b == '\\')
- fmt_print_byte(w, '\\');
+ if (b == '\0' ||
+ b == '\b' ||
+ b == '\f' ||
+ b == '\n' ||
+ b == '\r' ||
+ b == '\t' ||
+ b == '\v' ||
+ b == '\\' ||
+ b == '\'' ||
+ b == '"' ||
+ b == '?') {
+ fmt_print_byte(w, '\\');
+ switch (b) {
+ case '\0': fmt_print_byte(w, '0'); break;
+ case '\a': fmt_print_byte(w, 'a'); break;
+ case '\b': fmt_print_byte(w, 'b'); break;
+ case '\f': fmt_print_byte(w, 'f'); break;
+ case '\n': fmt_print_byte(w, 'n'); break;
+ case '\r': fmt_print_byte(w, 'r'); break;
+ case '\t': fmt_print_byte(w, 't'); break;
+ case '\v': fmt_print_byte(w, 'v'); break;
+ case '\\': fmt_print_byte(w, '\\'); break;
+ case '\'': fmt_print_byte(w, '\''); break;
+ case '"': fmt_print_byte(w, '"'); break;
+ case '?': fmt_print_byte(w, '?'); break;
+ }
+ } else if (' ' <= b && b <= '~') {
fmt_print_byte(w, b);
} else {
fmt_print_byte(w, '\\');
@@ -67,19 +118,18 @@ void fmt_print_qmem(lo_interface fmt_dest w, const void *_str, size_t size) {
fmt_print_byte(w, '"');
for (size_t pos = 0; pos < size;) {
uint32_t ch;
- uint8_t chlen;
- if ((str[pos] & 0b10000000) == 0b00000000) { ch = str[pos] & 0b01111111; chlen = 1; }
- else if ((str[pos] & 0b11100000) == 0b11000000) { ch = str[pos] & 0b00011111; chlen = 2; }
- else if ((str[pos] & 0b11110000) == 0b11100000) { ch = str[pos] & 0b00001111; chlen = 3; }
- else if ((str[pos] & 0b11111000) == 0b11110000) { ch = str[pos] & 0b00000111; chlen = 4; }
- else goto invalid_utf8;
- if ((ch == 0 && chlen != 1) || pos + chlen > size) goto invalid_utf8;
- for (uint8_t i = 1; i < chlen; i++) {
- if ((str[pos+i] & 0b11000000) != 0b10000000) goto invalid_utf8;
- ch = (ch << 6) | (str[pos+i] & 0b00111111);
+ uint8_t chlen;
+ utf8_decode_codepoint(&str[pos], size-pos, &ch, &chlen);
+ if (!chlen) {
+ /* invalid UTF-8 */
+ /* \xAB */
+ fmt_print_byte(w, '\\');
+ fmt_print_byte(w, 'x');
+ fmt_print_byte(w, hexdig[(str[pos] >> 4) & 0xF]);
+ fmt_print_byte(w, hexdig[(str[pos] >> 0) & 0xF]);
+ pos++;
+ continue;
}
- if (ch > 0x10FFFF) goto invalid_utf8;
-
if (ch == '\0' ||
ch == '\b' ||
ch == '\f' ||
@@ -132,15 +182,6 @@ void fmt_print_qmem(lo_interface fmt_dest w, const void *_str, size_t size) {
fmt_print_byte(w, hexdig[(ch >> 0) & 0xF]);
}
pos += chlen;
- continue;
-
- invalid_utf8:
- /* \xAB */
- fmt_print_byte(w, '\\');
- fmt_print_byte(w, 'x');
- fmt_print_byte(w, hexdig[(str[pos] >> 4) & 0xF]);
- fmt_print_byte(w, hexdig[(str[pos] >> 0) & 0xF]);
- pos++;
}
fmt_print_byte(w, '"');
}
@@ -212,14 +253,14 @@ declare(16, 64);
/* fmt_buf ********************************************************************/
-LO_IMPLEMENTATION_C(fmt_dest, struct fmt_buf, fmt_buf, static);
+LO_IMPLEMENTATION_C(fmt_dest, struct fmt_buf, fmt_buf);
-static void fmt_buf_putb(struct fmt_buf *buf, uint8_t b) {
+void fmt_buf_putb(struct fmt_buf *buf, uint8_t b) {
if (buf->len < buf->cap)
((uint8_t *)(buf->dat))[buf->len] = b;
buf->len++;
}
-static size_t fmt_buf_tell(struct fmt_buf *buf) {
+size_t fmt_buf_tell(struct fmt_buf *buf) {
return buf->len;
}
diff --git a/libmisc/hash.c b/libmisc/hash.c
new file mode 100644
index 0000000..3814cec
--- /dev/null
+++ b/libmisc/hash.c
@@ -0,0 +1,24 @@
+/* libmisc/hash.c - General-purpose hash utilities
+ *
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <libmisc/hash.h>
+
+/* djb2 hash */
+void hash_init(hash_t *hash) {
+ *hash = 5381;
+}
+void hash_write(hash_t *hash, void *dat, size_t len) {
+ for (size_t i = 0; i < len; i++)
+ *hash = (*hash * 33) + (hash_t)(((unsigned char *)dat)[i]);
+}
+
+/* utilities */
+hash_t hash(void *dat, size_t len) {
+ hash_t h;
+ hash_init(&h);
+ hash_write(&h, dat, len);
+ return h;
+}
diff --git a/libmisc/include/libmisc/alloc.h b/libmisc/include/libmisc/alloc.h
index afddbce..d8bbc38 100644
--- a/libmisc/include/libmisc/alloc.h
+++ b/libmisc/include/libmisc/alloc.h
@@ -11,6 +11,8 @@
#include <stdlib.h> /* for calloc(), free() */
#include <string.h> /* for memset() */
+#include <libmisc/assert.h>
+
#define stack_alloc(N, TYP) ({ \
size_t _size; \
TYP *_ret = NULL; \
@@ -18,9 +20,22 @@
_ret = alloca(_size); \
memset(_ret, 0, _size); \
} \
+ assert(_ret); \
_ret; \
})
-#define heap_alloc(N, TYP) ((TYP *)calloc(N, sizeof(TYP)))
+#define heap_alloc(N, TYP) ({ \
+ TYP *_ret = calloc(N, sizeof(TYP)); \
+ assert(_ret); \
+ _ret; \
+})
+
+static inline void heap_cleanup(void *_ptrptr) {
+ void **ptrptr = _ptrptr;
+ if (!ptrptr)
+ return;
+ free(*ptrptr);
+ *ptrptr = NULL;
+}
#endif /* _LIBMISC_ALLOC_H_ */
diff --git a/libmisc/include/libmisc/assert.h b/libmisc/include/libmisc/assert.h
index ccdb288..f726046 100644
--- a/libmisc/include/libmisc/assert.h
+++ b/libmisc/include/libmisc/assert.h
@@ -7,12 +7,19 @@
#ifndef _LIBMISC_ASSERT_H_
#define _LIBMISC_ASSERT_H_
+#define __assert_no_type_limits(EXPR) \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Wtype-limits\"") \
+ EXPR \
+ _Pragma("GCC diagnostic pop")
+
+
#ifdef NDEBUG
# define __assert_msg(expr, expr_str, msg) ((void)0)
#else
# define __assert_msg(expr, expr_str, msg) \
do { \
- if (!(expr)) \
+ __assert_no_type_limits(if (!(expr))) \
__assert_msg_fail(expr_str, __FILE__, __LINE__, __func__, msg); \
} while (0)
[[noreturn]] void __assert_msg_fail(const char *expr,
@@ -23,7 +30,7 @@
#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(...) __assert_no_type_limits(_Static_assert(__VA_ARGS__);) _Static_assert(1, "force semicolon") /* C11 */
#define static_assert_as_expr(...) (sizeof(struct {static_assert(__VA_ARGS__);})) /* libmisc */
#endif /* _LIBMISC_ASSERT_H_ */
diff --git a/libmisc/include/libmisc/endian.h b/libmisc/include/libmisc/endian.h
index 75240fe..966c3bc 100644
--- a/libmisc/include/libmisc/endian.h
+++ b/libmisc/include/libmisc/endian.h
@@ -10,204 +10,25 @@
#include <stddef.h> /* for size_t */
#include <stdint.h> /* for uint{n}_t */
-#include <libmisc/assert.h>
-
-/* Big endian *****************************************************************/
-
-typedef struct {
- uint8_t octets[2];
-} uint16be_t;
-static_assert(sizeof(uint16be_t) == 2);
-
-static inline size_t uint16be_encode(uint8_t *out, uint16_t in) {
- out[0] = (uint8_t)((in >> 8) & 0xFF);
- out[1] = (uint8_t)((in >> 0) & 0xFF);
- return 2;
-}
-
-static inline uint16_t uint16be_decode(uint8_t *in) {
- return (((uint16_t)(in[0])) << 8)
- | (((uint16_t)(in[1])) << 0)
- ;
-}
-
-static inline uint16be_t uint16be_marshal(uint16_t in) {
- uint16be_t out;
- uint16be_encode(out.octets, in);
- return out;
-}
-
-static inline uint16_t uint16be_unmarshal(uint16be_t in) {
- return uint16be_decode(in.octets);
-}
-
-typedef struct {
- uint8_t octets[4];
-} uint32be_t;
-static_assert(sizeof(uint32be_t) == 4);
-
-static inline size_t uint32be_encode(uint8_t *out, uint32_t in) {
- out[0] = (uint8_t)((in >> 24) & 0xFF);
- out[1] = (uint8_t)((in >> 16) & 0xFF);
- out[2] = (uint8_t)((in >> 8) & 0xFF);
- out[3] = (uint8_t)((in >> 0) & 0xFF);
- return 4;
-}
-
-static inline uint32_t uint32be_decode(uint8_t *in) {
- return (((uint32_t)(in[0])) << 24)
- | (((uint32_t)(in[1])) << 16)
- | (((uint32_t)(in[2])) << 8)
- | (((uint32_t)(in[3])) << 0)
- ;
-}
-
-static inline uint32be_t uint32be_marshal(uint32_t in) {
- uint32be_t out;
- uint32be_encode(out.octets, in);
- return out;
-}
-
-static inline uint32_t uint32be_unmarshal(uint32be_t in) {
- return uint32be_decode(in.octets);
-}
-
-typedef struct {
- uint8_t octets[8];
-} uint64be_t;
-static_assert(sizeof(uint64be_t) == 8);
-
-static inline size_t uint64be_encode(uint8_t *out, uint64_t in) {
- out[0] = (uint8_t)((in >> 56) & 0xFF);
- out[1] = (uint8_t)((in >> 48) & 0xFF);
- out[2] = (uint8_t)((in >> 40) & 0xFF);
- out[3] = (uint8_t)((in >> 32) & 0xFF);
- out[4] = (uint8_t)((in >> 24) & 0xFF);
- out[5] = (uint8_t)((in >> 16) & 0xFF);
- out[6] = (uint8_t)((in >> 8) & 0xFF);
- out[7] = (uint8_t)((in >> 0) & 0xFF);
- return 8;
-}
-
-static inline uint64_t uint64be_decode(uint8_t *in) {
- return (((uint64_t)(in[0])) << 56)
- | (((uint64_t)(in[1])) << 48)
- | (((uint64_t)(in[2])) << 40)
- | (((uint64_t)(in[3])) << 32)
- | (((uint64_t)(in[4])) << 24)
- | (((uint64_t)(in[5])) << 16)
- | (((uint64_t)(in[6])) << 8)
- | (((uint64_t)(in[7])) << 0)
- ;
-}
-
-static inline uint64be_t uint64be_marshal(uint64_t in) {
- uint64be_t out;
- uint64be_encode(out.octets, in);
- return out;
-}
-
-static inline uint64_t uint64be_unmarshal(uint64be_t in) {
- return uint64be_decode(in.octets);
-}
-
-/* Little endian **************************************************************/
-
-typedef struct {
- uint8_t octets[2];
-} uint16le_t;
-static_assert(sizeof(uint16le_t) == 2);
-
-static inline size_t uint16le_encode(uint8_t *out, uint16_t in) {
- out[0] = (uint8_t)((in >> 0) & 0xFF);
- out[1] = (uint8_t)((in >> 8) & 0xFF);
- return 2;
-}
-
-static inline uint16_t uint16le_decode(uint8_t *in) {
- return (((uint16_t)(in[0])) << 0)
- | (((uint16_t)(in[1])) << 8)
- ;
-}
-
-static inline uint16le_t uint16le_marshal(uint16_t in) {
- uint16le_t out;
- uint16le_encode(out.octets, in);
- return out;
-}
-
-static inline uint16_t uint16le_unmarshal(uint16le_t in) {
- return uint16le_decode(in.octets);
-}
-
-typedef struct {
- uint8_t octets[4];
-} uint32le_t;
-static_assert(sizeof(uint32le_t) == 4);
-
-static inline size_t uint32le_encode(uint8_t *out, uint32_t in) {
- out[0] = (uint8_t)((in >> 0) & 0xFF);
- out[1] = (uint8_t)((in >> 8) & 0xFF);
- out[2] = (uint8_t)((in >> 16) & 0xFF);
- out[3] = (uint8_t)((in >> 24) & 0xFF);
- return 4;
-}
-
-static inline uint32_t uint32le_decode(uint8_t *in) {
- return (((uint32_t)(in[0])) << 0)
- | (((uint32_t)(in[1])) << 8)
- | (((uint32_t)(in[2])) << 16)
- | (((uint32_t)(in[3])) << 24)
- ;
-}
-
-static inline uint32le_t uint32le_marshal(uint32_t in) {
- uint32le_t out;
- uint32le_encode(out.octets, in);
- return out;
-}
-
-static inline uint32_t uint32le_unmarshal(uint32le_t in) {
- return uint32le_decode(in.octets);
-}
-
-typedef struct {
- uint8_t octets[8];
-} uint64le_t;
-static_assert(sizeof(uint64le_t) == 8);
-
-static inline size_t uint64le_encode(uint8_t *out, uint64_t in) {
- out[0] = (uint8_t)((in >> 0) & 0xFF);
- out[1] = (uint8_t)((in >> 8) & 0xFF);
- out[2] = (uint8_t)((in >> 16) & 0xFF);
- out[3] = (uint8_t)((in >> 24) & 0xFF);
- out[4] = (uint8_t)((in >> 32) & 0xFF);
- out[5] = (uint8_t)((in >> 40) & 0xFF);
- out[6] = (uint8_t)((in >> 48) & 0xFF);
- out[7] = (uint8_t)((in >> 56) & 0xFF);
- return 8;
-}
-
-static inline uint64_t uint64le_decode(uint8_t *in) {
- return (((uint64_t)(in[0])) << 0)
- | (((uint64_t)(in[1])) << 8)
- | (((uint64_t)(in[2])) << 16)
- | (((uint64_t)(in[3])) << 24)
- | (((uint64_t)(in[4])) << 32)
- | (((uint64_t)(in[5])) << 40)
- | (((uint64_t)(in[6])) << 48)
- | (((uint64_t)(in[7])) << 56)
- ;
-}
-
-static inline uint64le_t uint64le_marshal(uint64_t in) {
- uint64le_t out;
- uint64le_encode(out.octets, in);
- return out;
-}
-
-static inline uint64_t uint64le_unmarshal(uint64le_t in) {
- return uint64le_decode(in.octets);
-}
+#define _endian_declare_conv(NBIT, ENDIAN) \
+ /* byte array encode/decode */ \
+ size_t uint##NBIT##ENDIAN##_encode(uint8_t *out, uint##NBIT##_t in); \
+ uint##NBIT##_t uint##NBIT##ENDIAN##_decode(uint8_t *in); \
+ /* struct marshal/unmarshal */ \
+ typedef struct { \
+ uint8_t octets[NBIT/8]; \
+ } uint##NBIT##ENDIAN##_t; \
+ uint##NBIT##ENDIAN##_t uint##NBIT##ENDIAN##_marshal(uint##NBIT##_t in); \
+ uint##NBIT##_t uint##NBIT##ENDIAN##_unmarshal(uint##NBIT##ENDIAN##_t in)
+
+_endian_declare_conv(16, be);
+_endian_declare_conv(32, be);
+_endian_declare_conv(64, be);
+
+_endian_declare_conv(16, le);
+_endian_declare_conv(32, le);
+_endian_declare_conv(64, le);
+
+#undef _endian_declare_conv
#endif /* _LIBMISC_ENDIAN_H_ */
diff --git a/libmisc/include/libmisc/error.h b/libmisc/include/libmisc/error.h
new file mode 100644
index 0000000..8a64a9f
--- /dev/null
+++ b/libmisc/include/libmisc/error.h
@@ -0,0 +1,171 @@
+/* libmisc/error.h - Go-esque errors
+ *
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#ifndef _LIBMISC_ERROR_H_
+#define _LIBMISC_ERROR_H_
+
+#include <stddef.h> /* for size_t */
+#include <stdint.h> /* for uint{n}_t */
+
+#include <libmisc/assert.h>
+#include <libmisc/fmt.h>
+
+/* _errnum ********************************************************************/
+
+typedef enum {
+ /* Original to libmisc */
+ E_NOERROR = 0, /* no error */
+ E_EOF, /* EOF */
+ E_NET_EARP_TIMEOUT, /* ARP timeout */
+ E_NET_EACK_TIMEOUT, /* TCP ACK timeout */
+ E_NET_ERECV_TIMEOUT, /* receive timeout */
+ E_NET_ECLOSED, /* already closed */
+ /* At least C99 through C23 */
+ E_STDC_EDOM,
+ E_STDC_EILSEQ,
+ E_STDC_ERANGE,
+ /* POSIX-2024 */
+ E_POSIX_E2BIG, /* Argument list too long */
+ E_POSIX_EACCES, /* Permission denied */
+ E_POSIX_EADDRINUSE, /* Address in use */
+ E_POSIX_EADDRNOTAVAIL, /* Address not available */
+ E_POSIX_EAFNOSUPPORT, /* Address family not supported */
+ E_POSIX_EAGAIN, /* Resource unavailable, try again (may be the same value as [EWOULDBLOCK]) */
+ E_POSIX_EALREADY, /* Connection already in progress */
+ E_POSIX_EBADF, /* Bad file descriptor */
+ E_POSIX_EBADMSG, /* Bad message */
+ E_POSIX_EBUSY, /* Device or resource busy */
+ E_POSIX_ECANCELED, /* Operation canceled */
+ E_POSIX_ECHILD, /* No child processes */
+ E_POSIX_ECONNABORTED, /* Connection aborted */
+ E_POSIX_ECONNREFUSED, /* Connection refused */
+ E_POSIX_ECONNRESET, /* Connection reset */
+ E_POSIX_EDEADLK, /* Resource deadlock would occur */
+ E_POSIX_EDESTADDRREQ, /* Destination address required */
+#define E_POSIX_EDOM E_STDC_EDOM /* Mathematics argument out of domain of function */
+ E_POSIX_EDQUOT, /* Reserved */
+ E_POSIX_EEXIST, /* File exists */
+ E_POSIX_EFAULT, /* Bad address */
+ E_POSIX_EFBIG, /* File too large */
+ E_POSIX_EHOSTUNREACH, /* Host is unreachable */
+ E_POSIX_EIDRM, /* Identifier removed */
+#define E_POSIX_EILSEQ E_STDC_EILSEQ /* Illegal byte sequence */ /* (in the context of text encoding) */
+ E_POSIX_EINPROGRESS, /* Operation in progress */
+ E_POSIX_EINTR, /* Interrupted function */
+ E_POSIX_EINVAL, /* Invalid argument */
+ E_POSIX_EIO, /* I/O error */
+ E_POSIX_EISCONN, /* Socket is connected */
+ E_POSIX_EISDIR, /* Is a directory */
+ E_POSIX_ELOOP, /* Too many levels of symbolic links */
+ E_POSIX_EMFILE, /* File descriptor value too large */
+ E_POSIX_EMLINK, /* Too many hard links */
+ E_POSIX_EMSGSIZE, /* Message too large */
+ E_POSIX_EMULTIHOP, /* Reserved */
+ E_POSIX_ENAMETOOLONG, /* Filename too long */
+ E_POSIX_ENETDOWN, /* Network is down */
+ E_POSIX_ENETRESET, /* Connection aborted by network */
+ E_POSIX_ENETUNREACH, /* Network unreachable */
+ E_POSIX_ENFILE, /* Too many files open in system */
+ E_POSIX_ENOBUFS, /* No buffer space available */
+ E_POSIX_ENODEV, /* No such device */
+ E_POSIX_ENOENT, /* No such file or directory */
+ E_POSIX_ENOEXEC, /* Executable file format error */
+ E_POSIX_ENOLCK, /* No locks available */
+ E_POSIX_ENOLINK, /* Reserved */
+ E_POSIX_ENOMEM, /* Not enough space */
+ E_POSIX_ENOMSG, /* No message of the desired type */
+ E_POSIX_ENOPROTOOPT, /* Protocol not available */
+ E_POSIX_ENOSPC, /* No space left on device */
+ E_POSIX_ENOSYS, /* Functionality not supported */
+ E_POSIX_ENOTCONN, /* The socket is not connected */
+ E_POSIX_ENOTDIR, /* Not a directory or a symbolic link to a directory */
+ E_POSIX_ENOTEMPTY, /* Directory not empty */
+ E_POSIX_ENOTRECOVERABLE, /* State not recoverable */ /* Added in POSIX-2008 */
+ E_POSIX_ENOTSOCK, /* Not a socket */
+ E_POSIX_ENOTSUP, /* Not supported (may be the same value as [EOPNOTSUPP]) */
+ E_POSIX_ENOTTY, /* Inappropriate I/O control operation */
+ E_POSIX_ENXIO, /* No such device or address */
+ E_POSIX_EOPNOTSUPP, /* Operation not supported on socket (may be the same value as [ENOTSUP]) */
+ E_POSIX_EOVERFLOW, /* Value too large to be stored in data type */
+ E_POSIX_EOWNERDEAD, /* Previous owner died */ /* Added in POSIX-2008 */
+ E_POSIX_EPERM, /* Operation not permitted */
+ E_POSIX_EPIPE, /* Broken pipe */
+ E_POSIX_EPROTO, /* Protocol error */
+ E_POSIX_EPROTONOSUPPORT, /* Protocol not supported */
+ E_POSIX_EPROTOTYPE, /* Protocol wrong type for socket */
+#define E_POSIX_ERANGE E_STDC_ERANGE /* Result too large */
+ E_POSIX_EROFS, /* Read-only file system */
+ E_POSIX_ESOCKTNOSUPPORT, /* Socket type not supported */
+ E_POSIX_ESPIPE, /* Invalid seek */
+ E_POSIX_ESRCH, /* No such process */
+ E_POSIX_ESTALE, /* Reserved */
+ E_POSIX_ETIMEDOUT, /* Connection timed out */
+ E_POSIX_ETXTBSY, /* Text file busy */
+ E_POSIX_EWOULDBLOCK, /* Operation would block (may be the same value as [EAGAIN]) */
+ E_POSIX_EXDEV, /* Improper hard link */
+ /* End cap */
+ E_EUNKNOWN,
+} _errnum;
+
+const char *_errnum_str_sym(_errnum);
+const char *_errnum_str_msg(_errnum);
+
+/* error **********************************************************************/
+
+typedef struct {
+ _errnum num;
+ char *_msg;
+} error;
+
+#ifdef NDEBUG
+#define error_new(ERRNUM, ...) ((error){ \
+ .num = ERRNUM , \
+ __VA_OPT__(._msg = fmt_asprint(__VA_ARGS__),) \
+})
+#else
+#define error_new(ERRNUM, ...) ((error){ \
+ .num = ERRNUM, \
+ ._msg = fmt_asprint("" __VA_OPT__(,) __VA_ARGS__), \
+})
+#endif
+
+#define ERROR_NULL ((error){})
+#define ERROR_IS_NULL(err) ((err).num == 0 && (err)._msg == NULL)
+
+const char *error_msg(error err);
+error error_dup(error err);
+void error_cleanup(error *errptr);
+void fmt_print_error(lo_interface fmt_dest w, error err);
+
+/* or_error ******************************************************************/
+
+#define DECLARE_ERROR_OR_(TYP, NAM) typedef struct { union { TYP NAM; error err; }; bool is_err; } NAM##_or_error
+#define DECLARE_ERROR_OR(TYP) DECLARE_ERROR_OR_(TYP, TYP)
+#define ERROR_NEW_VAL(TYP, VAL) ((TYP##_or_error){ .TYP = (VAL), .is_err = false })
+#define ERROR_NEW_ERR(TYP, ERR) ((TYP##_or_error){ .err = (ERR), .is_err = true })
+
+/* and_error *****************************************************************/
+
+#define DECLARE_ERROR_AND_(TYP, NAM) typedef struct { TYP NAM; error err; } NAM##_and_error
+#define DECLARE_ERROR_AND(TYP) DECLARE_ERROR_AND_(TYP, TYP)
+#define ERROR_AND(TYP, VAL, ERR) ((TYP##_and_error){ .TYP = (VAL), .err = (ERR) })
+
+/* some pre-defined types ****************************************************/
+
+DECLARE_ERROR_OR(size_t);
+DECLARE_ERROR_OR(uint8_t);
+DECLARE_ERROR_OR(uint16_t);
+DECLARE_ERROR_OR(uint32_t);
+DECLARE_ERROR_OR(uint64_t);
+DECLARE_ERROR_OR_(bool, ok);
+
+DECLARE_ERROR_AND(size_t);
+DECLARE_ERROR_AND(uint8_t);
+DECLARE_ERROR_AND(uint16_t);
+DECLARE_ERROR_AND(uint32_t);
+DECLARE_ERROR_AND(uint64_t);
+
+#endif /* _LIBMISC_ERROR_H_ */
diff --git a/libmisc/include/libmisc/fmt.h b/libmisc/include/libmisc/fmt.h
index c29c085..0fb2eaf 100644
--- a/libmisc/include/libmisc/fmt.h
+++ b/libmisc/include/libmisc/fmt.h
@@ -9,6 +9,7 @@
#include <stddef.h> /* for size_t */
#include <stdint.h> /* for (u)int{n}_t */
+#include <stdlib.h> /* for realloc() */
#include <libmisc/macro.h>
#include <libmisc/obj.h>
@@ -24,21 +25,9 @@ LO_INTERFACE(fmt_dest);
/* Simple bytes. */
void fmt_print_byte(lo_interface fmt_dest w, uint8_t b);
-
-/* These are `static inline` so that the compiler can unroll the loops. */
-static inline void fmt_print_mem(lo_interface fmt_dest w, const void *_str, size_t size) {
- const uint8_t *str = _str;
- while (size--)
- fmt_print_byte(w, *(str++));
-}
-static inline void fmt_print_str(lo_interface fmt_dest w, const char *str) {
- while (*str)
- fmt_print_byte(w, *(str++));
-}
-static inline void fmt_print_strn(lo_interface fmt_dest w, const char *str, size_t size) {
- while (size-- && *str)
- fmt_print_byte(w, *(str++));
-}
+void fmt_print_mem(lo_interface fmt_dest w, const void *str, size_t size);
+void fmt_print_str(lo_interface fmt_dest w, const char *str);
+void fmt_print_strn(lo_interface fmt_dest w, const char *str, size_t size);
/* Quoted bytes. */
void fmt_print_qbyte(lo_interface fmt_dest w, uint8_t b);
@@ -46,6 +35,10 @@ void fmt_print_qmem(lo_interface fmt_dest w, const void *str, size_t size);
void fmt_print_qstr(lo_interface fmt_dest w, const char *str);
void fmt_print_qstrn(lo_interface fmt_dest w, const char *str, size_t size);
+/* Hex bytes. */
+#define fmt_print_hbyte fmt_print_base16_u8_
+void fmt_print_hmem(lo_interface fmt_dest w, const void *str, size_t size);
+
/* Integers. */
#define _fmt_declare_base(base) \
void _fmt_print_base##base##_u8(lo_interface fmt_dest w, uint8_t val); \
@@ -107,6 +100,11 @@ void fmt_print_bool(lo_interface fmt_dest w, bool b);
const char * : fmt_print_str , \
bool : fmt_print_bool )(w, val)
+/** Same as fmt_print(), but usable from inside of fmt_print(). */
+#define fmt_print2(w, ...) do { LM_FOREACH_PARAM2_(_fmt_param2, (w), __VA_ARGS__) } while (0)
+#define _fmt_param2(...) _LM_DEFER2(_fmt_param_indirect)()(__VA_ARGS__)
+#define _fmt_param_indirect() _fmt_param
+
/* print-to-memory ************************************************************/
struct fmt_buf {
@@ -124,16 +122,25 @@ LO_IMPLEMENTATION_H(fmt_dest, struct fmt_buf, fmt_buf);
_w.len; \
})
-/* justify ********************************************************************/
+#define fmt_asprint(...) ({ \
+ struct fmt_buf _w = {}; \
+ lo_interface fmt_dest w = lo_box_fmt_buf_as_fmt_dest(&_w); \
+ fmt_print(w, __VA_ARGS__); \
+ while (_w.cap <= _w.len) { \
+ _w.cap = _w.len + 1; \
+ _w.len = 0; \
+ _w.dat = realloc(_w.dat, _w.cap); \
+ fmt_print(w, __VA_ARGS__); \
+ } \
+ ((char *)_w.dat)[_w.len] = '\0'; \
+ _w.dat; \
+})
-/* *grubles about not being allowed to nest things* */
-#define _fmt_param_indirect() _fmt_param
-#define _fmt_print2(w, ...) do { LM_FOREACH_PARAM2_(_fmt_param2, (w), __VA_ARGS__) } while (0)
-#define _fmt_param2(...) _LM_DEFER2(_fmt_param_indirect)()(__VA_ARGS__)
+/* justify ********************************************************************/
#define fmt_print_ljust(w, width, fillchar, ...) do { \
size_t beg = LO_CALL(w, tell); \
- _fmt_print2(w, __VA_ARGS__); \
+ fmt_print2(w, __VA_ARGS__); \
while ((LO_CALL(w, tell) - beg) < width) \
fmt_print_byte(w, fillchar); \
} while (0)
@@ -141,16 +148,16 @@ LO_IMPLEMENTATION_H(fmt_dest, struct fmt_buf, fmt_buf);
#define fmt_print_rjust(w, width, fillchar, ...) do { \
struct fmt_buf _discard = {}; \
lo_interface fmt_dest discard = lo_box_fmt_buf_as_fmt_dest(&_discard); \
- _fmt_print2(discard, __VA_ARGS__); \
+ fmt_print2(discard, __VA_ARGS__); \
while (_discard.len++ < width) \
fmt_print_byte(w, fillchar); \
- _fmt_print2(w, __VA_ARGS__); \
+ fmt_print2(w, __VA_ARGS__); \
} while (0)
void fmt_print_base16_u8_(lo_interface fmt_dest w, uint8_t x);
void fmt_print_base16_u16_(lo_interface fmt_dest w, uint16_t x);
void fmt_print_base16_u32_(lo_interface fmt_dest w, uint32_t x);
void fmt_print_base16_u64_(lo_interface fmt_dest w, uint64_t x);
-void fmt_print_ptr(lo_interface fmt_dest w, void *ptr);
+void fmt_print_ptr(lo_interface fmt_dest w, volatile const void *ptr);
#endif /* _LIBMISC_FMT_H_ */
diff --git a/libmisc/include/libmisc/hash.h b/libmisc/include/libmisc/hash.h
index 91e6b10..029bd3b 100644
--- a/libmisc/include/libmisc/hash.h
+++ b/libmisc/include/libmisc/hash.h
@@ -1,31 +1,21 @@
/* libmisc/hash.h - General-purpose hash 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
*/
#ifndef _LIBMISC_HASH_H_
#define _LIBMISC_HASH_H_
-#include <stdint.h> /* for uint{n}_t */
#include <stddef.h> /* for size_t */
+#include <stdint.h> /* for uint{n}_t */
-/* djb2 hash */
-typedef uint32_t hash_t;
-static inline void hash_init(hash_t *hash) {
- *hash = 5381;
-}
-static inline void hash_write(hash_t *hash, void *dat, size_t len) {
- for (size_t i = 0; i < len; i++)
- *hash = (*hash * 33) + (hash_t)(((unsigned char *)dat)[i]);
-}
+/* base */
+typedef uint32_t hash_t; /* size subject to change */
+void hash_init(hash_t *hash);
+void hash_write(hash_t *hash, void *dat, size_t len);
/* utilities */
-static inline hash_t hash(void *dat, size_t len) {
- hash_t h;
- hash_init(&h);
- hash_write(&h, dat, len);
- return h;
-}
+hash_t hash(void *dat, size_t len);
#endif /* _LIBMISC_HASH_H_ */
diff --git a/libmisc/include/libmisc/log.h b/libmisc/include/libmisc/log.h
index e6dfb52..c40b642 100644
--- a/libmisc/include/libmisc/log.h
+++ b/libmisc/include/libmisc/log.h
@@ -9,9 +9,9 @@
#include <stdint.h> /* for uint8_t */
-#include <libmisc/macro.h>
-#include <libmisc/fmt.h>
#include <libmisc/_intercept.h>
+#include <libmisc/fmt.h>
+#include <libmisc/macro.h>
#ifdef NDEBUG
#define _LOG_NDEBUG 1
diff --git a/libmisc/include/libmisc/macro.h b/libmisc/include/libmisc/macro.h
index a2d4264..0f9fc3f 100644
--- a/libmisc/include/libmisc/macro.h
+++ b/libmisc/include/libmisc/macro.h
@@ -9,7 +9,9 @@
#include <libmisc/assert.h>
-#define LM_FORCE_SEMICOLON static_assert(1, "force semicolon")
+/* C: syntax ******************************************************************/
+
+#define LM_FORCE_SEMICOLON _Static_assert(1, "force semicolon")
#define LM_PARTIAL_SWITCH(VAL) \
_Pragma("GCC diagnostic push") \
@@ -17,14 +19,14 @@
switch (VAL) \
_Pragma("GCC diagnostic pop") \
-/* for function definitions */
+/* C: function definitions ****************************************************/
#define LM_UNUSED(argname)
#define LM_ALWAYS_INLINE [[gnu::always_inline]] inline
#define LM_NEVER_INLINE [[gnu::noinline]]
#define LM_FLATTEN [[gnu::flatten]]
-/* types */
+/* C: 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)))
@@ -38,7 +40,7 @@
: NULL; \
})
-/* numeric */
+/* C: numeric *****************************************************************/
#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` */
@@ -46,12 +48,12 @@
#define LM_NEXT_POWER_OF_2(x) ( (x) ? 1ULL<<((sizeof(unsigned long long)*8)-__builtin_clzll(x)) : 1) /** Return the lowest power of 2 that is > x */
#define LM_FLOORLOG2(x) ((sizeof(unsigned long long)*8)-__builtin_clzll(x)-1) /** Return floor(log_2(x) */
-/* strings */
+/* CPP: strings ***************************************************************/
#define LM_STR(x) #x
#define LM_STR_(x) LM_STR(x)
-/* token pasting */
+/* CPP: token pasting *********************************************************/
#define LM_CAT2(a, b) a ## b
#define LM_CAT3(a, b, c) a ## b ## c
@@ -59,7 +61,7 @@
#define LM_CAT2_(a, b) LM_CAT2(a, b)
#define LM_CAT3_(a, b, c) LM_CAT3(a, b, c)
-/* macro arguments */
+/* CPP: macro arguments *******************************************************/
#define LM_FIRST(a, ...) a
#define LM_SECOND(a, b, ...) b
@@ -70,7 +72,7 @@
#define LM_EAT(...)
#define LM_EXPAND(...) __VA_ARGS__
-/* conditionals */
+/* CPP: conditionals **********************************************************/
#define LM_T xxTxx
#define LM_F xxFxx
@@ -82,7 +84,7 @@
#define _LM_IF__xxTxx(...) __VA_ARGS__ LM_EAT
#define _LM_IF__xxFxx(...) LM_EXPAND
-/* tuples */
+/* CPP: tuples ****************************************************************/
#define LM_IS_TUPLE(x) LM_IS_SENTINEL(_LM_IS_TUPLE x)
#define _LM_IS_TUPLE(...) LM_SENTINEL()
@@ -112,7 +114,7 @@
#define LM_TUPLES_HEAD(tuples) LM_EXPAND(LM_FIRST LM_EAT() (_LM_TUPLES_COMMA tuples))
#define LM_TUPLES_TAIL(tuples) LM_EAT tuples
-/* iteration */
+/* CPP: iteration *************************************************************/
/* The desire to support a high number of iterations is in competition
* with the desire for short compile times. 16 is the lowest
@@ -168,4 +170,18 @@
/** The same as LM_FOREACH_TUPLE(), but callable from inside of LM_FOREACH_TUPLE(). */
#define LM_FOREACH_TUPLE2(...) _LM_DEFER2(_LM_FOREACH_TUPLE_indirect)()(__VA_ARGS__)
+/* CPP: wrap-cc extensions ****************************************************/
+
+#ifdef __LIBMISC_ENHANCED_CPP__
+/**
+ * `LM_DEFAPPEND(macro, val)` is like `#define macro val`, but can (1)
+ * be used from inside of a macro, and (2) appends to a value if it is
+ * already defined with LM_DEFAPPEND. There are lots of edge-cases,
+ * don't get cute.
+ */
+#define LM_DEFAPPEND(macro, ...) __xx__LM_DEFAPPEND__xx__(#macro, #__VA_ARGS__) LM_FORCE_SEMICOLON
+#define LM_DEFAPPEND_(macro, ...) _LM_DEFAPPEND_(#macro, __VA_ARGS__)
+#define _LM_DEFAPPEND_(macrostr, ...) __xx__LM_DEFAPPEND__xx__(macrostr, #__VA_ARGS__) LM_FORCE_SEMICOLON
+#endif
+
#endif /* _LIBMISC_MACRO_H_ */
diff --git a/libmisc/include/libmisc/map.h b/libmisc/include/libmisc/map.h
index 113bc0e..65a71bc 100644
--- a/libmisc/include/libmisc/map.h
+++ b/libmisc/include/libmisc/map.h
@@ -64,9 +64,9 @@ struct _map {
* 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; \
+#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);
@@ -75,10 +75,10 @@ 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); \
+#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);
@@ -88,8 +88,8 @@ bool _map_del(struct _map *m, void *kp);
*/
#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.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);
@@ -118,7 +118,7 @@ struct _map_iter {
* ...
* }
*
- * It is safe to mutate the map with map_store() and, map_del() while
+ * 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.
*/
diff --git a/libmisc/include/libmisc/obj.h b/libmisc/include/libmisc/obj.h
index 6645db7..c00e512 100644
--- a/libmisc/include/libmisc/obj.h
+++ b/libmisc/include/libmisc/obj.h
@@ -50,28 +50,52 @@
}; \
LM_FOREACH_TUPLE(_ARG_iface_name##_LO_IFACE, \
_LO_IFACE_PROTO, _ARG_iface_name) \
- extern int LM_CAT2_(_HIDDEN_BOGUS_, __COUNTER__)
+ LM_FORCE_SEMICOLON
-#define _LO_IFACE_VTABLE(_tuple_typ, ...) _LO_IFACE_VTABLE_##_tuple_typ(__VA_ARGS__)
-#define _LO_IFACE_VTABLE_lo_nest(_ARG_child_iface_name) const struct _lo_##_ARG_child_iface_name##_vtable *_lo_##_ARG_child_iface_name##_vtable; LM_FOREACH_TUPLE2(_ARG_child_iface_name##_LO_IFACE, _LO_IFACE_VTABLE2)
-#define _LO_IFACE_VTABLE_lo_func(_ARG_ret_type, _ARG_func_name, ...) _ARG_ret_type (*_ARG_func_name)(void * __VA_OPT__(,) __VA_ARGS__);
+#define _LO_IFACE_VTABLE(_tuple_typ, ...) _LO_IFACE_VTABLE_##_tuple_typ(__VA_ARGS__)
+#define _LO_IFACE_VTABLE_lo_nest(_ARG_child_iface_name) \
+ const struct _lo_##_ARG_child_iface_name##_vtable *_lo_##_ARG_child_iface_name##_vtable; \
+ LM_FOREACH_TUPLE2(_ARG_child_iface_name##_LO_IFACE, _LO_IFACE_VTABLE2)
+#define _LO_IFACE_VTABLE_lo_func(_ARG_ret_type, _ARG_func_name, ...) \
+ _ARG_ret_type (*_ARG_func_name)(void * __VA_OPT__(,) __VA_ARGS__);
#define _LO_IFACE_VTABLE_indirect() _LO_IFACE_VTABLE
#define _LO_IFACE_VTABLE2(...) _LM_DEFER2(_LO_IFACE_VTABLE_indirect)()(__VA_ARGS__)
-#define _LO_IFACE_PROTO(_ARG_iface_name, _tuple_typ, ...) _LO_IFACE_PROTO_##_tuple_typ(_ARG_iface_name, __VA_ARGS__)
-#define _LO_IFACE_PROTO_lo_nest(_ARG_iface_name, _ARG_child_iface_name) \
- LM_ALWAYS_INLINE static lo_interface _ARG_child_iface_name \
- box_##_ARG_iface_name##_as_##_ARG_child_iface_name(lo_interface _ARG_iface_name obj) { \
- return (lo_interface _ARG_child_iface_name){ \
- .self = obj.self, \
- .vtable = obj.vtable->_lo_##_ARG_child_iface_name##_vtable, \
- }; \
+#define _LO_IFACE_PROTO(_ARG_iface_name, _tuple_typ, ...) _LO_IFACE_PROTO_##_tuple_typ(_ARG_iface_name, __VA_ARGS__)
+#define _LO_IFACE_PROTO_lo_nest(_ARG_iface_name, _ARG_child_iface_name) \
+ LM_DEFAPPEND(_LO_REGISTRY_##_ARG_child_iface_name, \
+ (lo_interface _ARG_iface_name, _ARG_iface_name)); \
+ LM_ALWAYS_INLINE static lo_interface _ARG_child_iface_name \
+ lo_box_##_ARG_iface_name##_as_##_ARG_child_iface_name(lo_interface _ARG_iface_name obj) { \
+ return (lo_interface _ARG_child_iface_name){ \
+ .self = obj.self, \
+ .vtable = obj.vtable->_lo_##_ARG_child_iface_name##_vtable, \
+ }; \
}
#define _LO_IFACE_PROTO_lo_func(_ARG_iface_name, _ARG_ret_type, _ARG_func_name, ...) \
/* empty */
/**
+ * `LO_BOX(iface_name, obj)` boxes `obj` as a `lo_interface
+ * iface_name`; if `obj` is not already a `lo_interface iface_name`
+ * box, then it simply calls the appropriate
+ * lo_box_{XXX}_as_{iface_name}() function/macro.
+ */
+#define LO_BOX(_ARG_iface_name, obj) _Generic((obj), \
+ lo_interface _ARG_iface_name: obj \
+ LM_FOREACH_TUPLE(_LO_REGISTRY_##_ARG_iface_name, \
+ _LO_BOX, _ARG_iface_name, obj))
+#define LO_BOX2(_ARG_iface_name, obj) _Generic((obj), \
+ lo_interface _ARG_iface_name: obj \
+ LM_FOREACH_TUPLE2(_LO_REGISTRY_##_ARG_iface_name, \
+ _LO_BOX, _ARG_iface_name, obj))
+#define _LO_BOX(_ARG_iface_name, _ARG_obj, _ARG_typ, _ARG_typnam) \
+ , _ARG_typ: lo_box_##_ARG_typnam##_as_##_ARG_iface_name(_LO_coerce(_ARG_typ, _ARG_obj))
+#define _LO_coerce(typ, obj) \
+ _Generic((obj), typ: (obj), default: *((typ*)0))
+
+/**
* `LO_NULL(iface_name)` is the null/nil/zero value for `lo_interface {iface_name}`.
*/
#define LO_NULL(_ARG_iface_name) ((lo_interface _ARG_iface_name){})
@@ -95,56 +119,62 @@
(_ARG_obj).vtable->_ARG_meth((_ARG_obj).self __VA_OPT__(,) __VA_ARGS__)
/**
- * Use `LO_IMPLEMENTATION_H(iface_name, impl_type, impl_name)` in a .h
- * file to declare that `{impl_type}` implements the `{iface_name}`
- * interface with functions named `{impl_name}_{method_name}`.
+ * `LO_IMPLEMENTATION_{H,C,STATIC}` declare that `{impl_type}`
+ * implements the `{iface_name}` interface with functions named
+ * `{impl_name}_{method_name}`.
*
- * This will also define a `lo_box_{impl_name}_as_{iface_name}(obj)`
- * function.
+ * Either use _H and _C in the .h file and .c file respectively, or
+ * use _STATIC in just a .c file.
*
- * You must also call the LO_IMPLEMENTATION_C in a single .c file.
+ * These define:
+ * - The vtable symbol
+ * - The prototypes for the `{impl_name}_{method_name}` method
+ * functions.
+ * - A `lo_box_{impl_name}_as_{iface_name}(obj)` const-expr macro.
*/
-#define LO_IMPLEMENTATION_H(_ARG_iface_name, _ARG_impl_type, _ARG_impl_name) \
- /* Vtable. */ \
- extern const struct _lo_##_ARG_iface_name##_vtable \
- _lo_##_ARG_impl_name##_##_ARG_iface_name##_vtable; \
- /* Boxing. */ \
- LM_ALWAYS_INLINE static lo_interface _ARG_iface_name \
- lo_box_##_ARG_impl_name##_as_##_ARG_iface_name(_ARG_impl_type *self) { \
- return (lo_interface _ARG_iface_name){ \
- .self = self, \
- .vtable = &_lo_##_ARG_impl_name##_##_ARG_iface_name##_vtable, \
- }; \
- } \
+#define LO_IMPLEMENTATION_H( iface_name, impl_type, impl_name) _LO_IMPL_H(extern, iface_name, impl_type, impl_name)
+#define LO_IMPLEMENTATION_C( iface_name, impl_type, impl_name) _LO_IMPL_C(extern, iface_name, impl_type, impl_name)
+#define LO_IMPLEMENTATION_STATIC(iface_name, impl_type, impl_name) _LO_IMPL_H(static, iface_name, impl_type, impl_name); \
+ _LO_IMPL_C(static, iface_name, impl_type, impl_name)
+
+#define _LO_IMPL_H(_ARG_visibility, _ARG_iface_name, _ARG_impl_type, _ARG_impl_name) \
+ /* Vtable. */ \
+ _LO_h_vis_vtable_##_ARG_visibility const struct _lo_##_ARG_iface_name##_vtable \
+ _lo_##_ARG_impl_name##_##_ARG_iface_name##_vtable; \
+ /* Method prototypes. */ \
+ LM_FOREACH_TUPLE(_ARG_iface_name##_LO_IFACE, \
+ _LO_IMPL_PROTO, _LO_h_vis_fn_##_ARG_visibility, _ARG_impl_type, _ARG_impl_name) \
+ /* Boxing. */ \
+ LM_DEFAPPEND(_LO_REGISTRY_##_ARG_iface_name, \
+ (_ARG_impl_type *, _ARG_impl_name)); \
+ LM_DEFAPPEND(lo_box_##_ARG_impl_name##_as_##_ARG_iface_name(_ARG_self), ( \
+ (lo_interface _ARG_iface_name){ \
+ .self = (_ARG_self), \
+ .vtable = &_lo_##_ARG_impl_name##_##_ARG_iface_name##_vtable, \
+ } \
+ )); \
LM_FORCE_SEMICOLON
+#define _LO_h_vis_vtable_extern extern
+#define _LO_h_vis_vtable_static static
+#define _LO_h_vis_fn_extern
+#define _LO_h_vis_fn_static static
+
+#define _LO_IMPL_PROTO( _ARG_quals, _ARG_impl_type, _ARG_impl_name, _tuple_typ, ...) _LO_IMPL_PROTO_##_tuple_typ(_ARG_quals, _ARG_impl_type, _ARG_impl_name, __VA_ARGS__)
+#define _LO_IMPL_PROTO_lo_nest(_ARG_quals, _ARG_impl_type, _ARG_impl_name, _ARG_child_iface_name) /* empty */
+#define _LO_IMPL_PROTO_lo_func(_ARG_quals, _ARG_impl_type, _ARG_impl_name, _ARG_ret_type, _ARG_func_name, ...) _ARG_quals _ARG_ret_type _ARG_impl_name##_##_ARG_func_name(_ARG_impl_type * __VA_OPT__(,) __VA_ARGS__);
+
+#define _LO_IMPL_C(_ARG_visibility, _ARG_iface_name, _ARG_impl_type, _ARG_impl_name) \
+ /* Vtable. */ \
+ _LO_c_vis_vtable_##_ARG_visibility const struct _lo_##_ARG_iface_name##_vtable \
+ _lo_##_ARG_impl_name##_##_ARG_iface_name##_vtable = { \
+ LM_FOREACH_TUPLE(_ARG_iface_name##_LO_IFACE, \
+ _LO_IMPL_VTABLE, _ARG_impl_name) \
+ }; \
+ LM_FORCE_SEMICOLON
+#define _LO_c_vis_vtable_extern
+#define _LO_c_vis_vtable_static [[maybe_unused]] static
-/**
- * Use `LO_IMPLEMENTATION_C(iface_name, impl_type, impl_name[, static])` in a .c
- * file to declare that `{impl_type}` implements the `{iface_name}` interface
- * with functions named `{impl_name}_{method_name}`.
- *
- * You must also call the LO_IMPLEMENTATION_H in the corresponding .h file.
- *
- * If `iface_name` contains a nested interface, then the
- * implementation of the nested interfaces must be declared with
- * `LO_IMPLEMENTATION_C` first.
- */
-#define LO_IMPLEMENTATION_C(_ARG_iface_name, _ARG_impl_type, _ARG_impl_name, ...) \
- /* Method prototypes. */ \
- LM_FOREACH_TUPLE(_ARG_iface_name##_LO_IFACE, \
- _LO_IMPL_PROTO, _ARG_impl_type, _ARG_impl_name, __VA_ARGS__) \
- /* Vtable. */ \
- const struct _lo_##_ARG_iface_name##_vtable \
- _lo_##_ARG_impl_name##_##_ARG_iface_name##_vtable = { \
- LM_FOREACH_TUPLE(_ARG_iface_name##_LO_IFACE, \
- _LO_IMPL_VTABLE, _ARG_impl_name) \
- }
-
-#define _LO_IMPL_PROTO( _ARG_impl_type, _ARG_impl_name, _ARG_quals, _tuple_typ, ...) _LO_IMPL_PROTO_##_tuple_typ(_ARG_impl_type, _ARG_impl_name, _ARG_quals, __VA_ARGS__)
-#define _LO_IMPL_PROTO_lo_nest(_ARG_impl_type, _ARG_impl_name, _ARG_quals, _ARG_child_iface_name) /* empty */
-#define _LO_IMPL_PROTO_lo_func(_ARG_impl_type, _ARG_impl_name, _ARG_quals, _ARG_ret_type, _ARG_func_name, ...) _ARG_quals _ARG_ret_type _ARG_impl_name##_##_ARG_func_name(_ARG_impl_type * __VA_OPT__(,) __VA_ARGS__);
-
-#define _LO_IMPL_VTABLE(_ARG_impl_name, _tuple_typ, ...) _LO_IMPL_VTABLE_##_tuple_typ(_ARG_impl_name, __VA_ARGS__)
+#define _LO_IMPL_VTABLE( _ARG_impl_name, _tuple_typ, ...) _LO_IMPL_VTABLE_##_tuple_typ(_ARG_impl_name, __VA_ARGS__)
#define _LO_IMPL_VTABLE_lo_nest(_ARG_impl_name, _ARG_child_iface_name) ._lo_##_ARG_child_iface_name##_vtable = &_lo_##_ARG_impl_name##_##_ARG_child_iface_name##_vtable, LM_FOREACH_TUPLE2(_ARG_child_iface_name##_LO_IFACE, _LO_IMPL_VTABLE2, _ARG_impl_name)
#define _LO_IMPL_VTABLE_lo_func(_ARG_impl_name, _ARG_ret_type, _ARG_func_name, ...) ._ARG_func_name = (void*)_ARG_impl_name##_##_ARG_func_name,
diff --git a/libmisc/include/libmisc/rand.h b/libmisc/include/libmisc/rand.h
index 7ef238b..ca16f42 100644
--- a/libmisc/include/libmisc/rand.h
+++ b/libmisc/include/libmisc/rand.h
@@ -7,40 +7,12 @@
#ifndef _LIBMISC_RAND_H_
#define _LIBMISC_RAND_H_
-#include <stdint.h> /* for uint{n}_t, UINT{n}_C() */
-#include <stdlib.h> /* for random() */
-
-#include <libmisc/assert.h>
+#include <stdint.h> /* for uint{n}_t */
/**
* Return a psuedo-random number in the half-open interval [0,cnt).
* `cnt` must not be greater than 1<<63.
*/
-static inline uint64_t rand_uint63n(uint64_t cnt) {
- assert(cnt != 0 && ((cnt-1) & 0x8000000000000000) == 0);
- if (cnt <= UINT64_C(1)<<31) {
- uint32_t fair_cnt = ((UINT32_C(1)<<31) / cnt) * cnt;
- uint32_t rnd;
- do {
- rnd = random();
- } while (rnd >= fair_cnt);
- return rnd % cnt;
- } else if (cnt <= UINT64_C(1)<<62) {
- uint64_t fair_cnt = ((UINT64_C(1)<<62) / cnt) * cnt;
- uint64_t rnd;
- do {
- rnd = (((uint64_t)random()) << 31) | random();
- } while (rnd >= fair_cnt);
- return rnd % cnt;
- } else if (cnt <= UINT64_C(1)<<63) {
- uint64_t fair_cnt = ((UINT64_C(1)<<63) / cnt) * cnt;
- uint64_t rnd;
- do {
- rnd = (((uint64_t)random()) << 62) | (((uint64_t)random()) << 31) | random();
- } while (rnd >= fair_cnt);
- return rnd % cnt;
- }
- assert_notreached("cnt is out of bounds");
-}
+uint64_t rand_uint63n(uint64_t cnt);
#endif /* _LIBMISC_RAND_H_ */
diff --git a/libmisc/include/libmisc/utf8.h b/libmisc/include/libmisc/utf8.h
new file mode 100644
index 0000000..54fcc92
--- /dev/null
+++ b/libmisc/include/libmisc/utf8.h
@@ -0,0 +1,25 @@
+/* libmisc/utf8.h - UTF-8 routines
+ *
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#ifndef _LIBMISC_UTF8_H_
+#define _LIBMISC_UTF8_H_
+
+#include <stddef.h> /* for size_t */
+#include <stdint.h> /* for uint{n}_t */
+
+/**
+ * Decode the codepoint starting at `str` and consuming at most `len`
+ * bytes. Invalid UTF-8 is indicated with chlen=0. For valid UTF-8,
+ * chlen is always in the range [1, 4].
+ */
+void utf8_decode_codepoint(const uint8_t *str, size_t len, uint32_t *ret_ch, uint8_t *ret_chlen);
+
+bool _utf8_is_valid(const uint8_t *str, size_t len, bool forbid_nul);
+
+#define utf8_is_valid(str, len) _utf8_is_valid(str, len, false)
+#define utf8_is_valid_without_nul(str, len) _utf8_is_valid(str, len, true)
+
+#endif /* _LIBMISC_UTF8_H_ */
diff --git a/libmisc/intercept.c b/libmisc/intercept.c
index 30870bf..d0e3602 100644
--- a/libmisc/intercept.c
+++ b/libmisc/intercept.c
@@ -11,7 +11,7 @@
[[gnu::weak]]
void __lm_putchar(unsigned char c) {
- (void) putchar(c);
+ (void)putchar(c);
}
[[gnu::weak]]
diff --git a/libmisc/log.c b/libmisc/log.c
index da4c92e..96e9ca4 100644
--- a/libmisc/log.c
+++ b/libmisc/log.c
@@ -8,12 +8,11 @@
#include <libmisc/assert.h> /* for static_assert() */
-#include <libmisc/log.h>
#include <libmisc/_intercept.h>
+#include <libmisc/log.h>
struct log_stdout {};
-LO_IMPLEMENTATION_H(fmt_dest, struct log_stdout, log_stdout);
-LO_IMPLEMENTATION_C(fmt_dest, struct log_stdout, log_stdout, static);
+LO_IMPLEMENTATION_STATIC(fmt_dest, struct log_stdout, log_stdout);
static size_t log_bytes = 0;
diff --git a/libmisc/map.c b/libmisc/map.c
index cc34c16..d1b2a57 100644
--- a/libmisc/map.c
+++ b/libmisc/map.c
@@ -7,9 +7,9 @@
#include <stdlib.h>
#include <string.h>
-#include <libmisc/hash.h>
#include <libmisc/alloc.h>
#include <libmisc/assert.h>
+#include <libmisc/hash.h>
#include <libmisc/map.h>
#define FLAG_ITER (UINT8_C(1)<<0)
diff --git a/libmisc/rand.c b/libmisc/rand.c
new file mode 100644
index 0000000..d1643ee
--- /dev/null
+++ b/libmisc/rand.c
@@ -0,0 +1,38 @@
+/* libmisc/rand.c - Non-crytpographic random-number utilities
+ *
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <stdlib.h> /* for random() */
+
+#include <libmisc/assert.h>
+
+#include <libmisc/rand.h>
+
+uint64_t rand_uint63n(uint64_t cnt) {
+ assert(cnt != 0 && ((cnt-1) & 0x8000000000000000) == 0);
+ if (cnt <= UINT64_C(1)<<31) {
+ uint32_t fair_cnt = ((UINT32_C(1)<<31) / cnt) * cnt;
+ uint32_t rnd;
+ do {
+ rnd = random();
+ } while (rnd >= fair_cnt);
+ return rnd % cnt;
+ } else if (cnt <= UINT64_C(1)<<62) {
+ uint64_t fair_cnt = ((UINT64_C(1)<<62) / cnt) * cnt;
+ uint64_t rnd;
+ do {
+ rnd = (((uint64_t)random()) << 31) | random();
+ } while (rnd >= fair_cnt);
+ return rnd % cnt;
+ } else if (cnt <= UINT64_C(1)<<63) {
+ uint64_t fair_cnt = ((UINT64_C(1)<<63) / cnt) * cnt;
+ uint64_t rnd;
+ do {
+ rnd = (((uint64_t)random()) << 62) | (((uint64_t)random()) << 31) | random();
+ } while (rnd >= fair_cnt);
+ return rnd % cnt;
+ }
+ assert_notreached("cnt is out of bounds");
+}
diff --git a/libmisc/tests/test_assert.c b/libmisc/tests/test_assert.c
index cdbc567..84b4d36 100644
--- a/libmisc/tests/test_assert.c
+++ b/libmisc/tests/test_assert.c
@@ -5,7 +5,6 @@
*/
#include <setjmp.h>
-#include <stdarg.h> /* for va_list, va_start(), va_end() */
#include <stdlib.h>
#include <string.h>
@@ -79,6 +78,10 @@ static void global_log_clear(void) {
static_assert(sizeof(char) == 1);
int main() {
+ unsigned char x = 4;
+ static_assert(0 <= x);
+ static_assert(x < 256);
+
#ifndef NDEBUG
test_should_succeed(assert(true));
test_should_fail(assert(false), "error: ASSERT: "__FILE__":"LM_STR_(__LINE__)":main(): assertion \"false\" failed\n");
diff --git a/libmisc/tests/test_fmt.c b/libmisc/tests/test_fmt.c
index 6a6eb7c..64b3b8a 100644
--- a/libmisc/tests/test_fmt.c
+++ b/libmisc/tests/test_fmt.c
@@ -4,6 +4,7 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
+#include <stdlib.h> /* for free() */
#include <string.h> /* for strcmp(), memcmp(), memset() */
#include <libmisc/fmt.h>
@@ -62,6 +63,26 @@ int main() {
test_assert(strcmp(str, "\"hell\"") == 0);
memset(str, 0, sizeof(str));
+ do_print((qstr, "hello\xFFworld🚧"));
+ test_assert(strcmp(str, "\"hello\\xFFworld\\U0001F6A7\"") == 0);
+ memset(str, 0, sizeof(str));
+
+ do_print((qstr, "¡hello world!"));
+ test_assert(strcmp(str, "\"\\u00A1hello world!\"") == 0);
+ memset(str, 0, sizeof(str));
+
+ do_print((qmem, "🚧", 3)); /* truncated UTF-8 */
+ test_assert(strcmp(str, "\"\\xF0\\x9F\\x9A\"") == 0);
+ memset(str, 0, sizeof(str));
+
+ do_print((qmem, "\xF7\xBF\xBF\xBF", 4)); /* over unicode_max */
+ test_assert(strcmp(str, "\"\\xF7\\xBF\\xBF\\xBF\"") == 0);
+ memset(str, 0, sizeof(str));
+
+ do_print((qmem, "\xE0\xA0", 2)); /* non-optimal encoding (of ' ') */
+ test_assert(strcmp(str, "\"\\xE0\\xA0\"") == 0);
+ memset(str, 0, sizeof(str));
+
do_print((byte, 'h'), (byte, 'w'));
test_assert(strcmp(str, "hw") == 0);
memset(str, 0, sizeof(str));
@@ -70,6 +91,26 @@ int main() {
test_assert(strcmp(str, "'h''w'") == 0);
memset(str, 0, sizeof(str));
+ do_print((qbyte, 0));
+ test_assert(strcmp(str, "'\\0'") == 0);
+ memset(str, 0, sizeof(str));
+
+ do_print((qbyte, '\\'));
+ test_assert(strcmp(str, "'\\\\'") == 0);
+ memset(str, 0, sizeof(str));
+
+ do_print((qbyte, '\''));
+ test_assert(strcmp(str, "'\\''") == 0);
+ memset(str, 0, sizeof(str));
+
+ do_print((qbyte, '\n'));
+ test_assert(strcmp(str, "'\\n'") == 0);
+ memset(str, 0, sizeof(str));
+
+ do_print((qbyte, 0xff));
+ test_assert(strcmp(str, "'\\xFF'") == 0);
+ memset(str, 0, sizeof(str));
+
do_print("zero ", 0);
test_assert(strcmp(str, "zero 0") == 0);
memset(str, 0, sizeof(str));
@@ -166,5 +207,37 @@ int main() {
test_assert(strcmp(str, " 1x") == 0);
memset(str, 0, sizeof(str));
+ do_print((base16_u8_, 1));
+ test_assert(strcmp(str, "0x01") == 0);
+ memset(str, 0, sizeof(str));
+
+ do_print((base16_u16_, 1));
+ test_assert(strcmp(str, "0x0001") == 0);
+ memset(str, 0, sizeof(str));
+
+ do_print((base16_u32_, 1));
+ test_assert(strcmp(str, "0x00000001") == 0);
+ memset(str, 0, sizeof(str));
+
+ do_print((base16_u64_, 1));
+ test_assert(strcmp(str, "0x0000000000000001") == 0);
+ memset(str, 0, sizeof(str));
+
+ do_print((hbyte, 1));
+ test_assert(strcmp(str, "0x01") == 0);
+ memset(str, 0, sizeof(str));
+
+ do_print((hmem, "hello", 6));
+ test_assert(strcmp(str, "{0x68,0x65,0x6C,0x6C,0x6F,0x00}") == 0);
+ memset(str, 0, sizeof(str));
+
+ char *astr = fmt_asprint("");
+ test_assert(astr != NULL && astr[0] == '\0');
+ free(astr);
+
+ astr = fmt_asprint("hello ", (base2, 9), (qstr, " world!\n"));
+ test_assert(strcmp(astr, "hello 1001\" world!\\n\"") == 0);
+ free(astr);
+
return 0;
}
diff --git a/libmisc/tests/test_log.c b/libmisc/tests/test_log.c
index ee762e2..6e7cdfd 100644
--- a/libmisc/tests/test_log.c
+++ b/libmisc/tests/test_log.c
@@ -4,7 +4,6 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-#include <stdarg.h> /* for va_list */
#include <stdio.h> /* for vsnprintf() */
#include <stdlib.h> /* for realloc(), free() */
#include <string.h> /* for strlen(), strcmp() */
diff --git a/libmisc/tests/test_macro.c b/libmisc/tests/test_macro.c
index 5157820..6810005 100644
--- a/libmisc/tests/test_macro.c
+++ b/libmisc/tests/test_macro.c
@@ -178,5 +178,14 @@ int main() {
free(act_suffix);
}
+ printf("== LM_DEFAPPEND ===========================================\n");
+ LM_DEFAPPEND(mylist, a);
+ LM_DEFAPPEND(mylist,
+ b);
+ {
+ const char *str = LM_STR_(mylist);
+ test_assert(strcmp(str, "a b") == 0);
+ }
+
return 0;
}
diff --git a/libmisc/tests/test_obj.c b/libmisc/tests/test_obj.c
index 687ad4e..c3c6786 100644
--- a/libmisc/tests/test_obj.c
+++ b/libmisc/tests/test_obj.c
@@ -28,19 +28,19 @@ LO_IMPLEMENTATION_H(frobber, struct myclass, myclass);
/* `struct myclass` implementation ********************************************/
-LO_IMPLEMENTATION_C(frobber, struct myclass, myclass, static);
+LO_IMPLEMENTATION_C(frobber, struct myclass, myclass);
-static int myclass_frob(struct myclass *self) {
+int myclass_frob(struct myclass *self) {
test_assert(self);
return self->a;
}
-static int myclass_frob1(struct myclass *self, int arg) {
+int myclass_frob1(struct myclass *self, int arg) {
test_assert(self);
return arg;
}
-static void myclass_frob0(struct myclass *self) {
+void myclass_frob0(struct myclass *self) {
test_assert(self);
}
diff --git a/libmisc/tests/test_obj_autobox.c b/libmisc/tests/test_obj_autobox.c
new file mode 100644
index 0000000..394f716
--- /dev/null
+++ b/libmisc/tests/test_obj_autobox.c
@@ -0,0 +1,77 @@
+/* libmisc/tests/test_obj_autobox.c - Generated by `libmisc/tests/test_obj_nest.c libmisc/tests/test_obj_autobox.c`. DO NOT EDIT! */
+/* libmisc/tests/test_obj_nest.c - Tests for <libmisc/obj.h> nesting
+ *
+ * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <string.h> /* for memcpy() */
+
+#include <libmisc/obj.h>
+
+#include "test.h"
+
+/* interfaces *****************************************************************/
+
+#define reader_LO_IFACE \
+ LO_FUNC(size_t, read, void *, size_t)
+LO_INTERFACE(reader);
+
+#define writer_LO_IFACE \
+ LO_FUNC(size_t, write, void *, size_t)
+LO_INTERFACE(writer);
+
+#define read_writer_LO_IFACE \
+ LO_NEST(reader) \
+ LO_NEST(writer)
+LO_INTERFACE(read_writer);
+
+/* implementation *************************************************************/
+
+struct myclass {
+ size_t len;
+ char buf[512];
+};
+LO_IMPLEMENTATION_STATIC(reader, struct myclass, myclass);
+LO_IMPLEMENTATION_STATIC(writer, struct myclass, myclass);
+LO_IMPLEMENTATION_STATIC(read_writer, struct myclass, myclass);
+
+static size_t myclass_read(struct myclass *self, void *buf, size_t count) {
+ test_assert(self);
+ if (count > self->len)
+ count = self->len;
+ memcpy(buf, self->buf, count);
+ return count;
+}
+
+static size_t myclass_write(struct myclass *self, void *buf, size_t count) {
+ test_assert(self);
+ if (self->len)
+ return 0;
+ if (count > sizeof(self->buf))
+ count = sizeof(self->buf);
+ memcpy(self->buf, buf, count);
+ self->len = count;
+ return count;
+}
+
+/* main test body *************************************************************/
+
+int main() {
+ struct myclass _obj = {};
+ lo_interface read_writer obj = LO_BOX(read_writer, &_obj);
+ test_assert(LO_CALL(obj, write, "Hello", 6) == 6);
+ char buf[6] = {};
+ test_assert(LO_CALL(obj, read, buf, 3) == 3);
+ test_assert(memcmp(buf, "Hel\0\0\0", 6) == 0);
+
+ lo_interface reader rd = LO_BOX(reader, &_obj);
+ rd = LO_BOX(reader, obj);
+ (void) rd;
+
+ lo_interface writer wr = LO_BOX(writer, &_obj);
+ wr = LO_BOX(writer, obj);
+ (void) wr;
+
+ return 0;
+}
diff --git a/libmisc/tests/test_obj_autobox.c.gen b/libmisc/tests/test_obj_autobox.c.gen
new file mode 100755
index 0000000..3cfa3d4
--- /dev/null
+++ b/libmisc/tests/test_obj_autobox.c.gen
@@ -0,0 +1,17 @@
+#!/bin/sh
+# libmisc/tests/test_obj_autobox.c.gen - Generate tests for LO_BOX()
+#
+# Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+infile=$1
+outfile=$2
+
+grep --quiet lo_box_ -- "$infile"
+
+{
+ echo "/* ${outfile} - Generated by \`$*\`. DO NOT EDIT! */"
+ sed -E 's/lo_box_([a-z0-9_]+)_as_([a-z0-9_]+)\(/LO_BOX(\2, /g' <"$infile"
+} >"$outfile"
+
+! grep -H lo_box_ -- "$outfile"
diff --git a/libmisc/tests/test_obj_nest.c b/libmisc/tests/test_obj_nest.c
index d5e563e..b52cd7b 100644
--- a/libmisc/tests/test_obj_nest.c
+++ b/libmisc/tests/test_obj_nest.c
@@ -13,11 +13,11 @@
/* interfaces *****************************************************************/
#define reader_LO_IFACE \
- LO_FUNC(ssize_t, read, void *, size_t)
+ LO_FUNC(size_t, read, void *, size_t)
LO_INTERFACE(reader);
#define writer_LO_IFACE \
- LO_FUNC(ssize_t, write, void *, size_t)
+ LO_FUNC(size_t, write, void *, size_t)
LO_INTERFACE(writer);
#define read_writer_LO_IFACE \
@@ -25,23 +25,17 @@ LO_INTERFACE(writer);
LO_NEST(writer)
LO_INTERFACE(read_writer);
-/* implementation header ******************************************************/
+/* implementation *************************************************************/
struct myclass {
size_t len;
char buf[512];
};
-LO_IMPLEMENTATION_H(reader, struct myclass, myclass);
-LO_IMPLEMENTATION_H(writer, struct myclass, myclass);
-LO_IMPLEMENTATION_H(read_writer, struct myclass, myclass);
+LO_IMPLEMENTATION_STATIC(reader, struct myclass, myclass);
+LO_IMPLEMENTATION_STATIC(writer, struct myclass, myclass);
+LO_IMPLEMENTATION_STATIC(read_writer, struct myclass, myclass);
-/* implementation main ********************************************************/
-
-LO_IMPLEMENTATION_C(reader, struct myclass, myclass, static);
-LO_IMPLEMENTATION_C(writer, struct myclass, myclass, static);
-LO_IMPLEMENTATION_C(read_writer, struct myclass, myclass, static);
-
-static ssize_t myclass_read(struct myclass *self, void *buf, size_t count) {
+static size_t myclass_read(struct myclass *self, void *buf, size_t count) {
test_assert(self);
if (count > self->len)
count = self->len;
@@ -49,10 +43,10 @@ static ssize_t myclass_read(struct myclass *self, void *buf, size_t count) {
return count;
}
-static ssize_t myclass_write(struct myclass *self, void *buf, size_t count) {
+static size_t myclass_write(struct myclass *self, void *buf, size_t count) {
test_assert(self);
if (self->len)
- return -1;
+ return 0;
if (count > sizeof(self->buf))
count = sizeof(self->buf);
memcpy(self->buf, buf, count);
@@ -69,5 +63,14 @@ int main() {
char buf[6] = {};
test_assert(LO_CALL(obj, read, buf, 3) == 3);
test_assert(memcmp(buf, "Hel\0\0\0", 6) == 0);
+
+ lo_interface reader rd = lo_box_myclass_as_reader(&_obj);
+ rd = lo_box_read_writer_as_reader(obj);
+ (void) rd;
+
+ lo_interface writer wr = lo_box_myclass_as_writer(&_obj);
+ wr = lo_box_read_writer_as_writer(obj);
+ (void) wr;
+
return 0;
}
diff --git a/libmisc/tests/test_rand.c b/libmisc/tests/test_rand.c
index ecb1c49..1cfbd65 100644
--- a/libmisc/tests/test_rand.c
+++ b/libmisc/tests/test_rand.c
@@ -6,8 +6,8 @@
#include <setjmp.h>
-#include <libmisc/rand.h>
#include <libmisc/_intercept.h>
+#include <libmisc/rand.h>
#include "test.h"
diff --git a/libmisc/utf8.c b/libmisc/utf8.c
new file mode 100644
index 0000000..28357f0
--- /dev/null
+++ b/libmisc/utf8.c
@@ -0,0 +1,44 @@
+/* libmisc/utf8.c - UTF-8 routines
+ *
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <libmisc/utf8.h>
+
+void utf8_decode_codepoint(const uint8_t *str, size_t len, uint32_t *ret_ch, uint8_t *ret_chlen) {
+ uint32_t ch;
+ uint8_t chlen;
+ uint32_t chmin;
+ if ((str[0] & 0b10000000) == 0b00000000) { ch = str[0] & 0b01111111; chlen = 1; chmin = 0; } /* bits=7+(0*6)= 7 */
+ else if ((str[0] & 0b11100000) == 0b11000000) { ch = str[0] & 0b00011111; chlen = 2; chmin = UINT32_C(1)<< 7; } /* bits=5+(1*6)=11 */
+ else if ((str[0] & 0b11110000) == 0b11100000) { ch = str[0] & 0b00001111; chlen = 3; chmin = UINT32_C(1)<<11; } /* bits=4+(2*6)=16 */
+ else if ((str[0] & 0b11111000) == 0b11110000) { ch = str[0] & 0b00000111; chlen = 4; chmin = UINT32_C(1)<<16; } /* bits=3+(3*6)=21 */
+ else goto invalid;
+ if (chlen > len)
+ goto invalid;
+ for (uint8_t i = 1; i < chlen; i++) {
+ if ((str[i] & 0b11000000) != 0b10000000)
+ goto invalid;
+ ch = (ch << 6) | (str[i] & 0b00111111);
+ }
+ if (ch > 0x10FFFF || ch < chmin)
+ goto invalid;
+ *ret_ch = ch;
+ *ret_chlen = chlen;
+ return;
+ invalid:
+ *ret_chlen = 0;
+}
+
+bool _utf8_is_valid(const uint8_t *str, size_t len, bool forbid_nul) {
+ for (size_t pos = 0; pos < len;) {
+ uint32_t ch;
+ uint8_t chlen;
+ utf8_decode_codepoint(&str[pos], len-pos, &ch, &chlen);
+ if (chlen == 0 || (forbid_nul && ch == 0))
+ return false;
+ pos += chlen;
+ }
+ return true;
+}
diff --git a/libmisc/wrap-cc b/libmisc/wrap-cc
new file mode 100755
index 0000000..e7a0b91
--- /dev/null
+++ b/libmisc/wrap-cc
@@ -0,0 +1,186 @@
+#!/usr/bin/env python3
+# libmisc/wrap-cc - Wrapper around GCC to enhance the preprocessor
+#
+# Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+import os
+import subprocess
+import sys
+import typing
+
+
+def scan_tuple(
+ text: str, beg: int, on_part: typing.Callable[[str], None] | None = None
+) -> int:
+ assert text[beg] == "("
+ pos = beg + 1
+ arg_start = pos
+ parens = 1
+ instring = False
+ while parens:
+ c = text[pos]
+ if instring:
+ match c:
+ case "\\":
+ pos += 1
+ case '"':
+ instring = False
+ else:
+ match c:
+ case "(":
+ parens += 1
+ case ")":
+ parens -= 1
+ if on_part and parens == 0 and text[beg + 1 : pos].strip():
+ on_part(text[arg_start:pos])
+ case ",":
+ if on_part and parens == 1:
+ on_part(text[arg_start:pos])
+ arg_start = pos + 1
+ case '"':
+ instring = True
+ pos += 1
+ assert text[pos - 1] == ")"
+ return pos - 1
+
+
+def unquote(cstr: str) -> str:
+ assert len(cstr) >= 2 and cstr[0] == '"' and cstr[-1] == '"'
+ cstr = cstr[1:-1]
+ out = ""
+ while cstr:
+ if cstr[0] == "\\":
+ match cstr[1]:
+ case "n":
+ out += "\n"
+ cstr = cstr[2:]
+ case "\\":
+ out += "\\"
+ cstr = cstr[2:]
+ case '"':
+ out += '"'
+ cstr = cstr[2:]
+ else:
+ out += cstr[0]
+ cstr = cstr[1:]
+ return out
+
+
+def preprocess(all_args: list[str]) -> typing.NoReturn:
+ # argparse #################################################################
+ _args = all_args
+
+ def shift(n: int) -> list[str]:
+ nonlocal _args
+ ret = _args[:n]
+ _args = _args[n:]
+ return ret
+
+ arg0 = shift(1)[0]
+ common_flags: list[str] = []
+ output_flags: list[str] = []
+ positional: list[str] = []
+ while _args:
+ if len(_args[0]) > 2 and _args[0][0] == "-" and _args[0][1] in "IDU":
+ _args = [_args[0][:2], _args[0][2:], *_args[1:]]
+ match _args[0]:
+ # Mode
+ case "-E" | "-quiet":
+ common_flags += shift(1)
+ case "-lang-asm":
+ os.execvp(all_args[0], all_args)
+ # Search path
+ case "-I" | "-imultilib" | "-isystem":
+ common_flags += shift(2)
+ # Define/Undefine
+ case "-D" | "-U":
+ common_flags += shift(2)
+ # Optimization
+ case "-O0" | "-O1" | "-O2" | "-O3" | "-Os" | "-Ofast" | "-Og" | "-Oz":
+ common_flags += shift(1)
+ case "-g":
+ common_flags += shift(1)
+ # Output files
+ case "-MD" | "-MF" | "-MT" | "-dumpbase" | "-dumpbase-ext":
+ output_flags += shift(2)
+ case "-o":
+ output_flags += shift(2)
+ # Other
+ case _:
+ if _args[0].startswith("-"):
+ if _args[0].startswith("-std="):
+ common_flags += shift(1)
+ elif _args[0].startswith("-m"):
+ common_flags += shift(1)
+ elif _args[0].startswith("-f"):
+ common_flags += shift(1)
+ elif _args[0].startswith("-W"):
+ common_flags += shift(1)
+ else:
+ raise ValueError(f"unknown flag: {_args!r}")
+ else:
+ positional += shift(1)
+ if len(positional) != 1:
+ raise ValueError("expected 1 input file")
+ infile = positional[0]
+
+ # enhance ##################################################################
+
+ common_flags += ["-D", "__LIBMISC_ENHANCED_CPP__"]
+
+ text = subprocess.run(
+ [arg0, *common_flags, infile],
+ stdin=subprocess.DEVNULL,
+ stdout=subprocess.PIPE,
+ stderr=sys.stderr,
+ check=True,
+ text=True,
+ ).stdout
+
+ macros: dict[str, str] = {}
+
+ marker = "__xx__LM_DEFAPPEND__xx__"
+ pos = 0
+ while (marker_beg := text.find(marker, pos)) >= 0:
+ args: list[str] = []
+
+ def add_arg(arg: str) -> None:
+ nonlocal args
+ args.append(arg)
+
+ beg_paren = marker_beg + len(marker)
+ end_paren = scan_tuple(text, beg_paren, add_arg)
+
+ before = text[:marker_beg]
+ # old = text[marker_beg : end_paren + 1]
+ after = text[end_paren + 1 :]
+
+ assert len(args) == 2
+ k = unquote(args[0].strip())
+ v = unquote(args[1].strip())
+ if k not in macros:
+ macros[k] = v
+ else:
+ macros[k] += " " + v
+
+ text = before + after
+ pos = len(before)
+
+ common_flags += ["-D", marker + "=LM_EAT"]
+ for k, v in macros.items():
+ common_flags += ["-D", k + "=" + v]
+
+ # Run, for-real ############################################################
+ os.execvp(arg0, [arg0, *common_flags, *output_flags, infile])
+
+
+def main(all_args: list[str]) -> typing.NoReturn:
+ if len(all_args) >= 2 and all_args[0].endswith("cc1") and all_args[1] == "-E":
+ preprocess(all_args)
+ else:
+ os.execvp(all_args[0], all_args)
+
+
+if __name__ == "__main__":
+ main(sys.argv[1:])
diff --git a/libusb/usb_common.c b/libusb/usb_common.c
index 32aa53f..4fe7dd4 100644
--- a/libusb/usb_common.c
+++ b/libusb/usb_common.c
@@ -4,12 +4,12 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-#include <stdint.h> /* for uint{n}_t types */
-#include <stddef.h> /* for size_t */
-#include <string.h> /* memcpy() */
-#include <stdlib.h> /* for malloc(), realloc(), reallocarray() */
+#include <stddef.h> /* for size_t */
+#include <stdint.h> /* for uint{n}_t types */
+#include <stdlib.h> /* for malloc(), realloc(), reallocarray() */
+#include <string.h> /* memcpy() */
-#include <tusb.h> /* for various tusb_*_t types */
+#include <tusb.h> /* for various tusb_*_t types */
#include <libmisc/assert.h>
@@ -100,8 +100,7 @@ void usb_common_lateinit(void) {
tud_init(CONFIG_USB_COMMON_RHPORT);
}
-COROUTINE usb_common_cr(void *_arg) {
- (void) _arg;
+COROUTINE usb_common_cr(void *LM_UNUSED(_arg)) {
cr_begin();
for (;;) {
@@ -185,7 +184,7 @@ uint8_t const *tud_descriptor_device_cb(void) {
.bNumConfigurations = 0, /* Number of possible configurations */
};
desc.bNumConfigurations = globals.configc;
- return (uint8_t const *) &desc;
+ return (uint8_t const *)&desc;
}
/**
diff --git a/notes.md b/notes.md
deleted file mode 100644
index 84c2e72..0000000
--- a/notes.md
+++ /dev/null
@@ -1,193 +0,0 @@
-<!--
- notes.md - Misc notes
-
- Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
- SPDX-License-Identifier: AGPL-3.0-or-later
--->
-
-Which file to include:
-
-> The <stdint.h> header is a subset of the <inttypes.h> header
-
-|------------------------------------------|-----------------------------------|--------------------------------|
-| C INTS | | |
-| `{CHAR,SHRT,INT,LONG,LLONG}_{MIN,MAX}` | `<limits.h>` | |
-| `U{CHAR,SHRT,INT,LONG,LLONG}_MAX` | `<limits.h>` | |
-|------------------------------------------|-----------------------------------|--------------------------------|
-| C SIZED INTS | | |
-| `(u)int{n}_t` (and `_{MIN,MAX,C}`) | `<stdint.h>` | exact |
-| `(u)int_least{n}_t` (and `_{MIN,MAX,C}`) | `<stdint.h>` | type may be more than `n` bits |
-| `(u)int_fast{n}_t` (and `_{MIN,MAX,C}`) | `<stdint.h>` | type may be more than `n` bits |
-| `(u)intptr_t` (and `_{MIN,MAX,C}`) | `<stdint.h>` | |
-| `(u)intmax_t` (and `_{MIN,MAX,C}`) | `<stdint.h>` | |
-| `PRI*` | `<inttypes.h>` | |
-| `SCN*` | `<inttypes.h>` | |
-|------------------------------------------|-----------------------------------|--------------------------------|
-| C ADDRESS INTS | | |
-| `ptrdiff_t` | `<stddef.h>` | |
-| `PTRDIFF_{MIN,MAX}` | `<stdint.h>` | |
-| `size_t` | `<stddef.h>` (or `<sys/types.h>`) | |
-| `SIZE_MAX` | `<stdint.h>` | |
-|------------------------------------------|-----------------------------------|--------------------------------|
-| C WCHAR INTS | | |
-| `wchar_t` | `<stddef.h>` | |
-| `WCHAR_{MIN,MAX}` | `<stdint.h>` | |
-| `wint_t` | `<wchar.h>` | |
-| `WINT_{MIN,MAX}` | `<stdint.h>` | |
-|------------------------------------------|-----------------------------------|--------------------------------|
-| POSIX INTS | | |
-| `sig_atomic_t` | `<signal.h>` | |
-| `SIG_ATOMIC_{MIN,MAX}` | `<stdint.h>` | |
-| `mode_t` | `<sys/types.h>` | unsigned |
-| `dev_t` | `<sys/types.h>` | unsigned |
-| `nlink_t` | `<sys/types.h>` | unsigned |
-| `{u,g,}id_t` | `<sys/types.h>` | unsigned |
-| `blkcnt_t` | `<sys/types.h>` | signed |
-| `off_t` | `<sys/types.h>` | signed |
-| `fsblkcnt_t` | `<sys/types.h>` | unsigned |
-| `fsfilecnt_t` | `<sys/types.h>` | unsigned |
-| `ino_t` | `<sys/types.h>` | unsigned |
-| `blksize_t` | `<sys/types.h>` | signed |
-| `pid_t` | `<sys/types.h>` | signed |
-| `ssize_t` | `<sys/types.h>` | signed |
-| `SSIZE_MAX` | `<limits.h>` | not in newlib |
-| `suseconds_t` | `<sys/types.h>` | signed |
-| `clock_t` | `<sys/types.h>` | could be float |
-| `time_t` | `<sys/types.h>` | signed |
-
-
-Here's my reading of the lowest-bitrate possible for our HDMI sink:
-
-HDMI v1.4 (2009/06/05) § 6.2.1 "Format Support Requirements"
-
-> - An HDMI Source shall support at least one of the following video
-> format timings:
-> + 640x480p @ 59.94/60Hz
-> + 720x480p @ 59.94/60Hz
-> + 720x576p @ 50Hz
-> …
->
-> - An HDMI Sink that accepts 60Hz video formats shall support the
-> 640x480p @ 59.94/60Hz and 720x480p @ 59.94/60Hz video format
-> timings
->
-> - An HDMI Sink that accepts 50Hz video formats shall support the
-> 640x480p @ 59.94/60Hz and 720x576p @ 50Hz video format timings.
-
-These latter 2 requirements match what is in CEI-861-D §3.1 "General
-Video Format requirements" Table 1.
-
-I'm a little confused about the 50Hz systems requirement; if it
-needs to support 640x480@60Hz, does that mean that it's *also* a 60Hz
-system and must therefore also support 720x480@60Hz?
-
-Anyway, I need to support at least 640x480p@60Hz and 720x480@60Hz, and
-it would be nice to support 720x576p@50Hz. Note that PicoDVI supports
-these first two, but not the @50Hz one.
-
-| format | bitrate |
-|---------------|-----------------------|
-| 640x480p@60Hz | 18,432,000 pixels/sec |
-| 720x480p@60Hz | 20,736,000 pixels/sec |
-| 720x576p@50Hz | 20,736,000 pixels/sec |
-
-https://forums.parallax.com/discussion/download/128730/Hdmi-1.4-1000008562-6364143185282736974850538.pdf
-https://ia803002.us.archive.org/1/items/CEA-861-D/CEA-861-D.pdf
-
-The RP2040 has several clocks:
-
-Sources:
-
-- GPCLK0 (GPIO-based clock 0)
-- GPCLK1 (GPIO-based clock 1)
-- XOSC (External (Crystal) Oscillator)
- + System PLL
- + USB PLL
-- ROSC (Ring Oscillator)
-
-These can be muxed onto several clocks which each have dividers (and
-most of them enable/disable too):
-
-- clk_gpout0 (GPIO Muxing)
-- clk_gpout1 (GPIO Muxing)
-- clk_gpout2 (GPIO Muxing)
-- clk_gpout3 (GPIO Muxing)
-- clk_adc (ADC)
-- clk_usb (USB)
-- clk_RTC (RTC)
-- clk_peri (UART and SPI)
-- clk_sys (CPU, bus, RAM)
-- clk_ref (watchdog and timers)
-
-```
-SSP = ARM Primecell Synchronous Serial Port
- ^ ^ ^
-```
-
-- SPI (Serial Peripheral Interface - Motorola)
-- SSI (Synchronous Serial Interface - Texas Instruments)
-- Microwire (National Semiconductor)
-
-| `sclk` | `SSPCLKOUT` | `SSP_CLK_OUT` | SSP clock output |
-| `ss_n` | `SSPFSSOUT` | `SSP_FSS_OUT` | SSP frame/slave select output |
-| `tx` | `SSPTXD` | `SSP_TX_D` | SSP transmit data |
-| `rd` | `SSPRXD` | `SSP_RX_D` | SSP receive data |
-
-"The SPI uses `clk_peri` as its reference clock for SPI timing, and is
-referred to as `SSPCLK` in the following sections. `clk_sys` is used
-as the bus clock, and is referred to as `PCLK` in the following
-sections" wut does that mean
-
-8 16-bit values in both the TX buffer and the RX buffer
-
-| Ver. 1.0.0 | 2013-08-01 | https://www.alldatasheet.com/datasheet-pdf/view/554784/ETC2/W5500.html https://www.alldatasheet.com/pdfjsview/web/viewer.html?file=//www.alldatasheet.com/datasheet-pdf/view/554784/ETC2/W5500/+_44J97VwSw9bZYvAB+/datasheet.pdf |
-| Ver. 1.0.1 | 2013-09-13 | |
-| Ver. 1.0.2 | 2013-11-14 | https://cdn.sparkfun.com/datasheets/Dev/Arduino/Shields/W5500_datasheet_v1.0.2_1.pdf |
-| Ver. 1.0.3 | 2014-05-29 | |
-| Ver. 1.0.4 | 2014-06-13 | |
-| Ver. 1.0.5 | 2014-11-10 | |
-| Ver. 1.0.6 | 2014-12-30 | |
-| Ver. 1.0.7 | 2016-02-24 | |
-| Ver. 1.0.8 | 2017-05-19 | https://docs.wiznet.io/img/products/w5500/w5500_ds_v108e.pdf (on-page version and date are wrong) |
-| Ver. 1.0.9 | 2019-05-22 | https://docs.wiznet.io/img/products/w5500/w5500_ds_v109e.pdf |
-| Ver. 1.1.0 | 2022-12-17 | https://docs.wiznet.io/img/products/w5500/W5500_ds_v110e.pdf |
-
-https://github.com/Bodmer/TFT_eSPI/discussions/2432
-
-----
-
-The theoretical max rate of the the W5500 is just shy of 80 Mb/s = 10 MB/s
-
-IDK about HDMI compression yet, but naively uncompressed we're looking
-at wanting to shove ~60 MB/s (480 Mb/s).
-
-Compression is an optional feature introduced in HDMI 2.1 :(
-
-----
-
-PIO-based USB needs the system clock to be a multiple of 120mhz
-
-----
-
-https://electronics.stackexchange.com/questions/684221/usb-c-on-off-switch-design-that-is-pd-compatible-off-similar-to-cold-plugging
-
-----
-
-OpenBMC
-
-~$300 price range:
- - Motherboards with a BMC
- - Old proprietary IP-KVM
- - TinyPilot KVM
- - PiKVM
-~$60 price range:
- - DIY PiKVM
- - JetKVM
-~$30 price range
- - 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/