summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.editorconfig10
-rw-r--r--.gitignore4
-rw-r--r--.gitmodules3
-rw-r--r--3rd-party/COPYING.wiznet-dhcp.txt60
m---------3rd-party/pico-fmt0
m---------3rd-party/pico-sdk0
-rw-r--r--CMakeLists.txt48
-rw-r--r--GNUmakefile121
-rw-r--r--HACKING.md11
-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-bin15
-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.py288
-rw-r--r--build-aux/measurestack/app_main.py17
-rw-r--r--build-aux/measurestack/app_output.py46
-rw-r--r--build-aux/measurestack/app_plugins.py469
-rw-r--r--build-aux/measurestack/test_analyze.py55
-rw-r--r--build-aux/measurestack/testutil.py134
-rw-r--r--build-aux/measurestack/util.py18
-rwxr-xr-xbuild-aux/tent-graph180
-rwxr-xr-xbuild-aux/valgrind2
-rw-r--r--cmd/sbc_harness/CMakeLists.txt84
-rw-r--r--cmd/sbc_harness/fs_harness_flash_bin.c312
-rw-r--r--cmd/sbc_harness/fs_harness_uptime_txt.c156
-rw-r--r--cmd/sbc_harness/fs_harness_uptime_txt.h19
l---------cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/printf.mit.txt1
-rw-r--r--cmd/sbc_harness/static/Documentation/harness_uptime_txt.txt17
-rw-r--r--cmd/sbc_harness/tusb_log.c15
-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)49
-rw-r--r--flashimg/cpu_main/config/tusb_config.h (renamed from cmd/sbc_harness/config/tusb_config.h)49
-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.c167
-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)97
-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.txt1
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.c22
-rw-r--r--flashimg/cpu_main/usb_keyboard.c (renamed from cmd/sbc_harness/usb_keyboard.c)39
-rw-r--r--flashimg/cpu_main/usb_keyboard.h (renamed from cmd/sbc_harness/usb_keyboard.h)8
-rw-r--r--gdb-helpers/libcr.py142
-rw-r--r--lib9p/CMakeLists.txt45
-rw-r--r--lib9p/core.c200
-rwxr-xr-xlib9p/core.gen2
-rw-r--r--lib9p/core_gen/c.py73
-rw-r--r--lib9p/core_gen/c9util.py4
-rw-r--r--lib9p/core_gen/c_fmt_print.py (renamed from lib9p/core_gen/c_format.py)100
-rw-r--r--lib9p/core_gen/c_marshal.py56
-rw-r--r--lib9p/core_gen/c_unmarshal.py4
-rw-r--r--lib9p/core_gen/c_validate.py38
-rw-r--r--lib9p/core_gen/h.py30
-rw-r--r--lib9p/core_generated.c6848
-rw-r--r--lib9p/core_include/lib9p/_core_generated.h254
-rw-r--r--lib9p/core_include/lib9p/core.h105
-rw-r--r--lib9p/core_tables.c188
-rw-r--r--lib9p/core_tables.h19
-rw-r--r--lib9p/core_utf8.h34
-rw-r--r--lib9p/idl/0000-uninitialized.9p13
-rw-r--r--lib9p/idl/1992-9P0.9p.wip2
-rw-r--r--lib9p/idl/2002-9P2000.9p32
-rw-r--r--lib9p/idl/2005-9P2000.u.9p12
-rwxr-xr-xlib9p/idl/2010-9P2000.L.9p.gen2
-rw-r--r--lib9p/srv.c1350
-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.h261
-rw-r--r--lib9p/tests/client_config/config.h3
-rw-r--r--lib9p/tests/test_compile.c1675
-rwxr-xr-xlib9p/tests/test_compile.c.gen8
-rw-r--r--lib9p/tests/test_compile_config/config.h21
-rw-r--r--lib9p/tests/test_server/CMakeLists.txt6
-rw-r--r--lib9p/tests/test_server/config/config.h19
-rw-r--r--lib9p/tests/test_server/fs_flush.c128
-rw-r--r--lib9p/tests/test_server/fs_flush.h26
-rw-r--r--lib9p/tests/test_server/fs_shutdown.c82
-rw-r--r--lib9p/tests/test_server/fs_shutdown.h3
-rw-r--r--lib9p/tests/test_server/fs_slowread.c116
-rw-r--r--lib9p/tests/test_server/fs_slowread.h22
-rw-r--r--lib9p/tests/test_server/fs_whoami.c103
-rw-r--r--lib9p/tests/test_server/fs_whoami.h3
-rw-r--r--lib9p/tests/test_server/main.c77
-rw-r--r--lib9p/tests/testclient-hangup.c100
-rw-r--r--lib9p/tests/testclient-hangup.explog14
-rwxr-xr-xlib9p/tests/testclient-p9p9
-rw-r--r--lib9p/tests/testclient-p9p.explog38
-rw-r--r--lib9p/tests/testclient-sess.c82
-rw-r--r--lib9p/tests/testclient-sess.explog73
-rw-r--r--lib9p_util/include/util9p/static.h32
-rw-r--r--lib9p_util/static.c240
-rw-r--r--libcr/CMakeLists.txt5
-rw-r--r--libcr/coroutine.c103
-rw-r--r--libcr/include/libcr/coroutine.h44
-rw-r--r--libcr/tests/test_matrix.c6
-rw-r--r--libcr/tests/test_matrix/config.h2
-rw-r--r--libcr_ipc/CMakeLists.txt11
-rw-r--r--libcr_ipc/chan.c153
-rw-r--r--libcr_ipc/include/libcr_ipc/chan.h242
-rw-r--r--libcr_ipc/include/libcr_ipc/mutex.h10
-rw-r--r--libcr_ipc/include/libcr_ipc/rpc.h188
-rw-r--r--libcr_ipc/include/libcr_ipc/rwmutex.h14
-rw-r--r--libcr_ipc/include/libcr_ipc/sema.h12
-rw-r--r--libcr_ipc/mutex.c13
-rw-r--r--libcr_ipc/rpc.c37
-rw-r--r--libcr_ipc/rwmutex.c46
-rw-r--r--libcr_ipc/sema.c26
-rw-r--r--libcr_ipc/tests/config.h2
-rw-r--r--libcr_ipc/tests/test_chan.c104
-rw-r--r--libcr_ipc/tests/test_chan_compile.c13
-rw-r--r--libcr_ipc/tests/test_mutex.c6
-rw-r--r--libcr_ipc/tests/test_mutex_compile.c11
-rw-r--r--libcr_ipc/tests/test_rpc.c26
-rw-r--r--libcr_ipc/tests/test_rpc_compile.c13
-rw-r--r--libcr_ipc/tests/test_rwmutex.c2
-rw-r--r--libcr_ipc/tests/test_rwmutex_compile.c11
-rw-r--r--libcr_ipc/tests/test_select.c90
-rw-r--r--libcr_ipc/tests/test_sema.c18
-rw-r--r--libcr_ipc/tests/test_sema_compile.c11
-rw-r--r--libdhcp/CMakeLists.txt7
-rw-r--r--libdhcp/dhcp_client.c127
-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.h (renamed from libobj/tests/test.h)0
-rw-r--r--libdhcp/tests/test_client.c120
-rw-r--r--libfmt/CMakeLists.txt17
-rw-r--r--libfmt/include/libfmt/fmt.h23
-rw-r--r--libfmt/libmisc.c63
-rw-r--r--libfmt/libobj.c17
-rw-r--r--libfmt/quote.c159
-rw-r--r--libhw_cr/CMakeLists.txt1
-rw-r--r--libhw_cr/host_alarmclock.c43
-rw-r--r--libhw_cr/host_include/libhw/host_alarmclock.h5
-rw-r--r--libhw_cr/host_include/libhw/host_net.h9
-rw-r--r--libhw_cr/host_net.c340
-rw-r--r--libhw_cr/host_util.c128
-rw-r--r--libhw_cr/host_util.h41
-rw-r--r--libhw_cr/rp2040_dma.c24
-rw-r--r--libhw_cr/rp2040_dma.h11
-rw-r--r--libhw_cr/rp2040_gpioirq.c4
-rw-r--r--libhw_cr/rp2040_hwspi.c31
-rw-r--r--libhw_cr/rp2040_hwtimer.c29
-rw-r--r--libhw_cr/rp2040_include/libhw/rp2040_hwspi.h2
-rw-r--r--libhw_cr/rp2040_include/libhw/w5500.h13
-rw-r--r--libhw_cr/w5500.c264
-rw-r--r--libhw_cr/w5500_ll.c115
-rw-r--r--libhw_cr/w5500_ll.h201
-rw-r--r--libhw_generic/CMakeLists.txt9
-rw-r--r--libhw_generic/alarmclock.c18
-rw-r--r--libhw_generic/include/libhw/generic/alarmclock.h29
-rw-r--r--libhw_generic/include/libhw/generic/io.h199
-rw-r--r--libhw_generic/include/libhw/generic/net.h74
-rw-r--r--libhw_generic/io.c45
-rw-r--r--libhw_generic/net.c20
-rw-r--r--libhw_generic/tests/test_io.c8
-rw-r--r--libmisc/CMakeLists.txt21
-rw-r--r--libmisc/assert.c16
-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.c266
-rw-r--r--libmisc/hash.c24
-rw-r--r--libmisc/include/libmisc/_intercept.h17
-rw-r--r--libmisc/include/libmisc/alloc.h41
-rw-r--r--libmisc/include/libmisc/assert.h24
-rw-r--r--libmisc/include/libmisc/endian.h219
-rw-r--r--libmisc/include/libmisc/error.h171
-rw-r--r--libmisc/include/libmisc/fmt.h163
-rw-r--r--libmisc/include/libmisc/hash.h24
-rw-r--r--libmisc/include/libmisc/linkedlist.h112
-rw-r--r--libmisc/include/libmisc/log.h21
-rw-r--r--libmisc/include/libmisc/macro.h138
-rw-r--r--libmisc/include/libmisc/map.h95
-rw-r--r--libmisc/include/libmisc/obj.h184
-rw-r--r--libmisc/include/libmisc/private.h4
-rw-r--r--libmisc/include/libmisc/rand.h32
-rw-r--r--libmisc/include/libmisc/utf8.h25
-rw-r--r--libmisc/intercept.c20
-rw-r--r--libmisc/linkedlist.c14
-rw-r--r--libmisc/log.c19
-rw-r--r--libmisc/map.c74
-rw-r--r--libmisc/rand.c38
-rw-r--r--libmisc/tests/test_assert.c76
-rw-r--r--libmisc/tests/test_endian.c2
-rw-r--r--libmisc/tests/test_fmt.c243
-rw-r--r--libmisc/tests/test_log.c82
-rw-r--r--libmisc/tests/test_macro.c137
-rw-r--r--libmisc/tests/test_obj.c (renamed from libobj/tests/test_obj.c)12
-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.c (renamed from libobj/tests/test_nest.c)41
-rw-r--r--libmisc/tests/test_rand.c7
-rw-r--r--libmisc/utf8.c44
-rwxr-xr-xlibmisc/wrap-cc186
-rw-r--r--libobj/CMakeLists.txt14
-rw-r--r--libobj/include/libobj/obj.h156
-rw-r--r--libusb/usb_common.c23
-rw-r--r--notes.md193
219 files changed, 13966 insertions, 9899 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/.gitmodules b/.gitmodules
index 17dec29..8a4c874 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -6,6 +6,3 @@
[submodule "3rd-party/pico-sdk"]
path = 3rd-party/pico-sdk
url = https://github.com/LukeShu/pico-sdk
-[submodule "3rd-party/pico-fmt"]
- path = 3rd-party/pico-fmt
- url = https://github.com/LukeShu/pico-fmt
diff --git a/3rd-party/COPYING.wiznet-dhcp.txt b/3rd-party/COPYING.wiznet-dhcp.txt
new file mode 100644
index 0000000..363bc9c
--- /dev/null
+++ b/3rd-party/COPYING.wiznet-dhcp.txt
@@ -0,0 +1,60 @@
+-----------------------------------------------------------------------------
+https://github.com/Wiznet/ioLibrary_Driver/blob/b981401e7f3d07015619adf44c13998e13e777f9/Internet/DHCP/dhcp.c
+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
diff --git a/3rd-party/pico-fmt b/3rd-party/pico-fmt
deleted file mode 160000
-Subproject beaecdcba7fdf0d584d245a9d0ad6be6bdc94a1
diff --git a/3rd-party/pico-sdk b/3rd-party/pico-sdk
-Subproject c8a16c00453e4db4b771d7f1281391057c7477d
+Subproject bbad146d79b42081d85b76e44f136ff8d42f1a1
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9fa048f..2d40b05 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -14,8 +14,6 @@ include("${PICO_SDK_PATH}/external/pico_sdk_import.cmake")
project(sbc_harness)
-add_subdirectory(3rd-party/pico-fmt/pico_fmt)
-add_subdirectory(3rd-party/pico-fmt/pico_printf)
pico_sdk_init()
if ((PICO_PLATFORM STREQUAL "host") AND (NOT PICO_NO_GC_SECTIONS))
@@ -24,13 +22,18 @@ if ((PICO_PLATFORM STREQUAL "host") AND (NOT PICO_NO_GC_SECTIONS))
add_link_options("LINKER:--gc-sections")
endif()
+# Use modern C...
+set(CMAKE_C_STANDARD 23)
+# ... but with some misfeatures disabled.
+add_compile_options(-Werror=vla)
+
+# Have the compiler help detect mistakes.
add_compile_options(-Wall -Wextra -Wswitch-enum -Werror)
string(TOUPPER "${CMAKE_BUILD_TYPE}" _upper_cmake_build_type)
string(REPLACE " " ";" _build_type_flags "${CMAKE_C_FLAGS_${_upper_cmake_build_type}}")
if ("-DNDEBUG" IN_LIST _build_type_flags)
add_compile_options(-Wno-unused-variable -Wno-unused-parameter -Wno-unused-but-set-variable)
- target_compile_definitions(pico_printf INTERFACE PICO_PRINTF_ALWAYS_INCLUDED=1)
endif()
function(_suppress_tinyusb_warnings)
@@ -41,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)
@@ -117,9 +125,36 @@ function(add_lib_test arg_libname arg_testname)
endif()
endfunction()
+function(_apply_matrix_helper _m_depth _m_assignments)
+ list(LENGTH _m_arg_matrix _m_dimensions)
+ math(EXPR _m_dimensions ${_m_dimensions}/2)
+ if("${_m_depth}" EQUAL "${_m_dimensions}")
+ cmake_language(CALL "${_m_arg_action}" "${_m_n}" "${_m_assignments}")
+ math(EXPR _m_n "${_m_n}+1")
+ set(_m_n "${_m_n}" PARENT_SCOPE)
+ else()
+ math(EXPR _m_ik "${_m_depth}*2")
+ list(GET _m_arg_matrix "${_m_ik}" _m_tmp_key)
+
+ math(EXPR _m_iv "${_m_ik}+1")
+ list(GET _m_arg_matrix "${_m_iv}" _m_tmp_vals)
+ string(REGEX REPLACE "^\\[(.*)\\]$" "\\1" _m_tmp_vals "${_m_tmp_vals}")
+
+ foreach(_m_tmp_val IN LISTS _m_tmp_vals)
+ math(EXPR _m_tmp_depth "${_m_depth}+1")
+ set(_m_tmp_assignments "${_m_assignments}")
+ list(APPEND _m_tmp_assignments "${_m_tmp_key}=${_m_tmp_val}")
+ _apply_matrix_helper("${_m_tmp_depth}" "${_m_tmp_assignments}")
+ set(_m_n "${_m_n}" PARENT_SCOPE)
+ endforeach()
+ endif()
+endfunction()
+function(apply_matrix _m_arg_action _m_arg_matrix)
+ set(_m_n 0)
+ _apply_matrix_helper(0 "")
+endfunction()
+
add_subdirectory(libmisc)
-add_subdirectory(libobj)
-add_subdirectory(libfmt)
add_subdirectory(libcr)
add_subdirectory(libcr_ipc)
add_subdirectory(libhw_generic)
@@ -129,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 8636973..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
$^ $@
@@ -55,18 +67,30 @@ libusb/include/libusb/tusb_helpers.h 3rd-party/MS-LCID.pdf 3rd-party/MS-LCID.txt
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,$(generate/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:
@@ -75,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` ##########################################################
@@ -106,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 9e19c26..04835f1 100644
--- a/HACKING.md
+++ b/HACKING.md
@@ -7,11 +7,10 @@
# Source Layout
-Our own "flavor" of C: GNU C plus `-fplan9-extensions`, making use of:
+Our own "flavor" of C: GNU C, plus making use of:
- - `libobj/`: For Go-like object-oriented programming
- - `libmisc/`: Low-level C programming utilities; sort of an augmented
- "libc"
+ - `libmisc/`: Low-level C programming utilities (including Go-like
+ object-oriented programming); sort of an augmented "libc"
Our own tiny cooperative-multitasking OS:
@@ -28,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
@@ -154,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 91f1612..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)
)
}
@@ -114,6 +114,7 @@ lint_func_blocklist() {
local blocklist=(
gpio_default_irq_handler
+ {,__wrap,weak_raw_,stdio_,_}{,v}{,sn}printf
)
while read -r func; do
@@ -131,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 a93874f..f151642 100644
--- a/build-aux/measurestack/analyze.py
+++ b/build-aux/measurestack/analyze.py
@@ -3,24 +3,103 @@
# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
# SPDX-License-Identifier: AGPL-3.0-or-later
+import random
import re
import sys
import typing
from . import vcg
+# Whether to print "//dbg-cache:" on cache writes
+dbg_cache = False
+# Whether to print the graph in a /* comment */ before processing it
+dbg_dumpgraph = False
+# Whether to print "//dbg-nstatic:" lines that trace nstatic() execution
+dbg_nstatic = False
+# Whether to disable nstatic() caching (but does NOT disable any cache-related debug logging)
+dbg_nocache = False
+# Whether to sort things for consistently-ordered execution, or shuffle things to detect bugs
+dbg_sort: typing.Literal["unsorted", "sorted", "shuffled"] = "unsorted"
+
# pylint: disable=unused-variable
__all__ = [
"BaseName",
"QName",
"UsageKind",
"Node",
+ "maybe_sorted",
"AnalyzeResultVal",
"AnalyzeResultGroup",
"AnalyzeResult",
"analyze",
]
+
+def dumps(x: typing.Any, depth: int = 0, compact: bool = False) -> str:
+ match x:
+ case int() | str() | None:
+ return repr(x)
+ case dict():
+ if len(x) == 0:
+ return "{}"
+ ret = "{"
+ if not compact:
+ ret += "\n"
+ for k, v in x.items():
+ if not compact:
+ ret += "\t" * (depth + 1)
+ ret += dumps(k, depth + 1, True)
+ ret += ":"
+ if not compact:
+ ret += " "
+ ret += dumps(v, depth + 1, compact)
+ ret += ","
+ if not compact:
+ ret += "\n"
+ if not compact:
+ ret += "\t" * depth
+ ret += "}"
+ return ret
+ case list():
+ if len(x) == 0:
+ return "[]"
+ ret = "["
+ if not compact:
+ ret += "\n"
+ for v in x:
+ if not compact:
+ ret += "\t" * (depth + 1)
+ ret += dumps(v, depth + 1, compact)
+ ret += ","
+ if not compact:
+ ret += "\n"
+ if not compact:
+ ret += "\t" * depth
+ ret += "]"
+ return ret
+ case set():
+ if len(x) == 0:
+ return "set()"
+ ret = "{"
+ if not compact:
+ ret += "\n"
+ for v in x:
+ if not compact:
+ ret += "\t" * (depth + 1)
+ ret += dumps(v, depth + 1, compact)
+ ret += ","
+ if not compact:
+ ret += "\n"
+ if not compact:
+ ret += "\t" * depth
+ ret += "}"
+ return ret
+ case _:
+ if hasattr(x, "__dict__"):
+ return f"{x.__class__.__name__}(*{dumps(x.__dict__, depth, compact)})"
+ return f"TODO({x.__class__.__name__})"
+
+
# types ########################################################################
@@ -152,32 +231,44 @@ class AnalyzeResult(typing.NamedTuple):
class SkipModel(typing.NamedTuple):
"""Running the skipmodel calls `.fn(chain, ...)` with the chain
- consisting of the last `.nchain` items (if .nchain is an int), or
- the chain starting with the *last* occurance of `.nchain` (if
- .nchain is a collection). If the chain is not that long or does
- not contain a member of the collection, then .fn is not called and
- the call is *not* skipped.
+ consisting of the last few items of the input chain.
+
+ If `.nchain` is an int:
+
+ - the chain is the last `.nchain` items or the input chain. If
+ the input chain is not that long, then `.fn` is not called and
+ the call is *not* skipped.
+ If `.nchain` is a collection:
+
+ - the chain starts with the *last* occurance of `.nchain` in the
+ input chain. If the input chain does not contain a member of
+ the collection, then .fn is called with an empty chain.
"""
nchain: int | typing.Collection[BaseName]
- fn: typing.Callable[[typing.Sequence[QName], QName], bool]
-
- def __call__(self, chain: typing.Sequence[QName], call: QName) -> tuple[bool, int]:
- if isinstance(self.nchain, int):
- if len(chain) >= self.nchain:
- _chain = chain[-self.nchain :]
- return self.fn(_chain, call), len(_chain)
- else:
- for i in reversed(range(len(chain))):
- if chain[i].base() in self.nchain:
- _chain = chain[i - 1 :]
- return self.fn(_chain, call), len(_chain)
- return False, 0
+ fn: typing.Callable[[typing.Sequence[QName], Node, QName], bool]
+
+ def __call__(
+ self, chain: typing.Sequence[QName], node: Node, call: QName
+ ) -> tuple[bool, int]:
+ match self.nchain:
+ case int():
+ if len(chain) >= self.nchain:
+ _chain = chain[-self.nchain :]
+ return self.fn(_chain, node, call), len(_chain) + 1
+ return False, 0
+ case _:
+ for i in reversed(range(len(chain))):
+ if chain[i].base() in self.nchain:
+ _chain = chain[i:]
+ return self.fn(_chain, node, call), len(_chain) + 1
+ return self.fn([], node, call), 1
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]: ...
@@ -186,7 +277,7 @@ class Application(typing.Protocol):
# code #########################################################################
-re_node_label = re.compile(
+re_node_normal_label = re.compile(
r"(?P<funcname>[^\n]+)\n"
+ r"(?P<location>[^\n]+:[0-9]+:[0-9]+)\n"
+ r"(?P<nstatic>[0-9]+) bytes \((?P<usage_kind>static|dynamic|dynamic,bounded)\)\n"
@@ -194,6 +285,10 @@ re_node_label = re.compile(
+ r"(?:\n.*)*",
flags=re.MULTILINE,
)
+re_node_alias_label = re.compile(
+ r"(?P<funcname>[^\n]+)\n" + r"(?P<location>[^\n]+:[0-9]+:[0-9]+)",
+ flags=re.MULTILINE,
+)
class _Graph:
@@ -235,6 +330,39 @@ class _Graph:
return self._resolve_cache[funcname]
+if typing.TYPE_CHECKING:
+ from _typeshed import SupportsRichComparisonT as _T_sortable
+
+_T = typing.TypeVar("_T")
+
+
+@typing.overload
+def maybe_sorted(
+ unsorted: typing.Iterable["_T_sortable"], /, *, key: None = None
+) -> typing.Iterable["_T_sortable"]: ...
+@typing.overload
+def maybe_sorted(
+ unsorted: typing.Iterable[_T], /, *, key: typing.Callable[[_T], "_T_sortable"]
+) -> typing.Iterable[_T]: ...
+
+
+def maybe_sorted(
+ unsorted: typing.Iterable[_T],
+ /,
+ *,
+ key: typing.Callable[[_T], "_T_sortable"] | None = None,
+) -> typing.Iterable[_T]:
+ match dbg_sort:
+ case "unsorted":
+ return unsorted
+ case "sorted":
+ return sorted(unsorted, key=key) # type: ignore
+ case "shuffled":
+ ret = [*unsorted]
+ random.shuffle(ret)
+ return ret
+
+
def _make_graph(
ci_fnames: typing.Collection[str],
app: Application,
@@ -253,20 +381,44 @@ def _make_graph(
case "title":
node.funcname = QName(v)
case "label":
- if elem.attrs.get("shape", "") != "ellipse":
- m = re_node_label.fullmatch(v)
- if not m:
- raise ValueError(f"unexpected label value {v!r}")
- node.location = m.group("location")
- node.usage_kind = typing.cast(
- UsageKind, m.group("usage_kind")
- )
- node.nstatic = int(m.group("nstatic"))
- node.ndynamic = int(m.group("ndynamic"))
+ shape: str | None = elem.attrs.get("shape", None)
+ match shape:
+ case "ellipse": # external
+ pass
+ case "triangle": # alias (since GCC 15)
+ m = re_node_alias_label.fullmatch(v)
+ if not m:
+ raise ValueError(
+ f"unexpected label value {v!r}"
+ )
+ node.location = m.group("location")
+ node.usage_kind = "static"
+ node.nstatic = 0
+ node.ndynamic = 0
+ case None: # normal
+ m = re_node_normal_label.fullmatch(v)
+ if not m:
+ raise ValueError(
+ f"unexpected label value {v!r}"
+ )
+ node.location = m.group("location")
+ node.usage_kind = typing.cast(
+ UsageKind, m.group("usage_kind")
+ )
+ node.nstatic = int(m.group("nstatic"))
+ node.ndynamic = int(m.group("ndynamic"))
+ case _:
+ raise ValueError(
+ f"unexpected shape value {shape!r}"
+ )
case "shape":
- if v != "ellipse":
- raise ValueError(f"unexpected shape value {v!r}")
- skip = True
+ match v:
+ case "ellipse": # external
+ skip = True
+ case "triangle": # alias (since GCC 15)
+ pass
+ case _:
+ raise ValueError(f"unexpected shape value {v!r}")
case _:
raise ValueError(f"unknown edge key {k!r}")
if not skip:
@@ -297,7 +449,10 @@ def _make_graph(
raise ValueError(f"unknown caller: {caller}")
if callee == QName("__indirect_call"):
callees, missing_ok = app.indirect_callees(elem)
- for callee in callees:
+ 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
else:
@@ -305,16 +460,22 @@ def _make_graph(
case _:
raise ValueError(f"unknown elem type {elem.typ!r}")
- for ci_fname in ci_fnames:
+ for ci_fname in maybe_sorted(ci_fnames):
with open(ci_fname, "r", encoding="utf-8") as fh:
for elem in vcg.parse_vcg(fh):
handle_elem(elem)
- for node in app.extra_nodes():
+ def sort_key(node: Node) -> QName:
+ return node.funcname
+
+ for node in maybe_sorted(app.extra_nodes(), key=sort_key):
if node.funcname in 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 = {}
@@ -332,33 +493,33 @@ def analyze(
cfg_max_call_depth: int,
) -> AnalyzeResult:
graphdata = _make_graph(ci_fnames, app)
+ if dbg_dumpgraph:
+ print(f"/* {dumps(graphdata)} */")
missing: set[QName] = set()
dynamic: set[QName] = set()
included_funcs: set[QName] = set()
- dbg = False
-
track_inclusion: bool = True
skipmodels = app.skipmodels()
for name, model in skipmodels.items():
- if isinstance(model.nchain, int):
- assert model.nchain > 1
- else:
+ if not isinstance(model.nchain, int):
assert len(model.nchain) > 0
_nstatic_cache: dict[QName, int] = {}
def _nstatic(chain: list[QName], funcname: QName) -> tuple[int, int]:
- nonlocal dbg
nonlocal track_inclusion
assert funcname in graphdata.graph
+ def putdbg(msg: str) -> None:
+ print(f"//dbg-nstatic: {'- '*len(chain)}{msg}")
+
node = graphdata.graph[funcname]
- if dbg:
- print(f"//dbg: {'- '*len(chain)}{funcname}\t{node.nstatic}")
+ if dbg_nstatic:
+ putdbg(f"{funcname}\t{node.nstatic}")
if node.usage_kind == "dynamic" or node.ndynamic > 0:
dynamic.add(funcname)
if track_inclusion:
@@ -378,37 +539,52 @@ def analyze(
call_qname = graphdata.resolve_funcname(call_orig_qname)
if not call_qname:
if skipmodel:
- skip, _ = skipmodel(chain, call_orig_qname)
+ skip, _ = skipmodel(chain[:-1], node, call_orig_qname)
if skip:
- if dbg:
- print(
- f"//dbg: {'- '*len(chain)}{call_orig_qname}\tskip missing"
- )
+ if dbg_nstatic:
+ putdbg(f"{call_orig_qname}\tskip missing")
continue
if not call_missing_ok:
missing.add(call_orig_qname)
- if dbg:
- print(f"//dbg: {'- '*len(chain)}{call_orig_qname}\tmissing")
+ if dbg_nstatic:
+ putdbg(f"{call_orig_qname}\tmissing")
continue
# 2. Skip
if skipmodel:
- skip, skip_nchain = skipmodel(chain, call_qname)
+ skip, skip_nchain = skipmodel(chain[:-1], node, call_qname)
max_call_nchain = max(max_call_nchain, skip_nchain)
if skip:
- if dbg:
- print(f"//dbg: {'- '*len(chain)}{call_qname}\tskip")
+ if dbg_nstatic:
+ putdbg(f"{call_qname}\tskip")
continue
# 3. Call
- if skip_nchain == 0 and call_qname in _nstatic_cache:
- max_call_nstatic = max(max_call_nstatic, _nstatic_cache[call_qname])
+ if (
+ (not dbg_nocache)
+ and skip_nchain == 0
+ and call_qname in _nstatic_cache
+ ):
+ call_nstatic = _nstatic_cache[call_qname]
+ if dbg_nstatic:
+ putdbg(f"{call_qname}\ttotal={call_nstatic} (cache-read)")
+ max_call_nstatic = max(max_call_nstatic, call_nstatic)
else:
call_nstatic, call_nchain = _nstatic(chain, call_qname)
max_call_nstatic = max(max_call_nstatic, call_nstatic)
max_call_nchain = max(max_call_nchain, call_nchain)
if skip_nchain == 0 and call_nchain == 0:
- _nstatic_cache[call_qname] = call_nstatic
+ if dbg_nstatic:
+ putdbg(f"{call_qname}\ttotal={call_nstatic} (cache-write)")
+ if call_qname not in _nstatic_cache:
+ if dbg_cache:
+ print(f"//dbg-cache: {call_qname} = {call_nstatic}")
+ _nstatic_cache[call_qname] = call_nstatic
+ else:
+ assert dbg_nocache
+ assert _nstatic_cache[call_qname] == call_nstatic
+ elif dbg_nstatic:
+ putdbg(f"{call_qname}\ttotal={call_nstatic} (do-not-cache)")
chain.pop()
return node.nstatic + max_call_nstatic, max(0, max_call_nchain - 1)
diff --git a/build-aux/measurestack/app_main.py b/build-aux/measurestack/app_main.py
index 7573146..884aeee 100644
--- a/build-aux/measurestack/app_main.py
+++ b/build-aux/measurestack/app_main.py
@@ -27,8 +27,8 @@ def main(
# sbc-harness ####################################################
- libobj_plugin = app_plugins.LibObjPlugin(arg_c_fnames)
- lib9p_plugin = app_plugins.Lib9PPlugin(arg_base_dir, arg_c_fnames, libobj_plugin)
+ libmisc_plugin = app_plugins.LibMiscPlugin(arg_c_fnames)
+ lib9p_plugin = app_plugins.Lib9PPlugin(arg_base_dir, arg_c_fnames)
def sbc_is_thread(name: QName) -> int:
if str(name).endswith("_cr") and name.base() != BaseName("lib9p_srv_read_cr"):
@@ -47,13 +47,11 @@ def main(
plugins += [
app_plugins.CmdPlugin(),
- libobj_plugin,
- app_plugins.PicoFmtPlugin(arg_pico_platform),
- app_plugins.LibHWPlugin(arg_pico_platform, libobj_plugin),
+ libmisc_plugin,
+ app_plugins.LibHWPlugin(arg_pico_platform, libmisc_plugin),
app_plugins.LibCRPlugin(),
app_plugins.LibCRIPCPlugin(),
lib9p_plugin,
- app_plugins.LibMiscPlugin(),
]
# pico-sdk #######################################################
@@ -69,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,12 +88,10 @@ def main(
def misc_filter(name: QName) -> tuple[int, bool]:
if name in [
QName("__assert_msg_fail"),
- QName("__lm_printf"),
- QName("__lm_light_printf"),
- QName("fmt_vfctprintf"),
- QName("fmt_vsnprintf"),
]:
return 1, False
+ if str(name.base()).endswith("_putb"):
+ return 1, False
return 0, False
extra_includes: list[BaseName] = []
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 bbb0eae..a921407 100644
--- a/build-aux/measurestack/app_plugins.py
+++ b/build-aux/measurestack/app_plugins.py
@@ -14,13 +14,11 @@ from .util import synthetic_node
# pylint: disable=unused-variable
__all__ = [
"CmdPlugin",
- "LibObjPlugin",
"LibHWPlugin",
"LibCRPlugin",
"LibCRIPCPlugin",
"Lib9PPlugin",
"LibMiscPlugin",
- "PicoFmtPlugin",
"PicoSDKPlugin",
"TinyUSBDevicePlugin",
"NewlibPlugin",
@@ -41,32 +39,54 @@ 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]:
return {}
-re_comment = re.compile(r"/\*.*?\*/")
-re_ws = re.compile(r"\s+")
-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*[,)].*"
-)
-re_call_objcall = re.compile(r"LO_CALL\((?P<obj>[^,]+), (?P<meth>[^,)]+)[,)].*")
-
+class LibMiscPlugin:
+ re_comment = re.compile(r"/\*.*?\*/")
+ re_ws = re.compile(r"\s+")
+ 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_(?P<vis>H|C|STATIC)\s*\("
+ r"\s*(?P<iface>[^, ]+)\s*,"
+ r"\s*(?P<impl_typ>[^,]+)\s*,"
+ r"\s*(?P<impl_name>[^, ]+)\s*\)"
+ )
+ re_lo_call = re.compile(r".*\bLO_CALL\((?P<obj>[^,]+), (?P<meth>[^,)]+)[,)].*")
-class LibObjPlugin:
objcalls: dict[str, set[QName]] # method_name => {method_impls}
def __init__(self, arg_c_fnames: typing.Collection[str]) -> None:
@@ -74,16 +94,16 @@ class LibObjPlugin:
for fname in arg_c_fnames:
with open(fname, "r", encoding="utf-8") as fh:
while line := fh.readline():
- if m := re_lo_iface.match(line):
+ if m := self.re_lo_iface.match(line):
iface_name = m.group("name")
if iface_name not in ifaces:
ifaces[iface_name] = set()
while line.endswith("\\\n"):
line += fh.readline()
line = line.replace("\\\n", " ")
- line = re_comment.sub(" ", line)
- line = re_ws.sub(" ", line)
- for m2 in re_lo_func.finditer(line):
+ line = self.re_comment.sub(" ", line)
+ line = self.re_ws.sub(" ", line)
+ for m2 in self.re_lo_func.finditer(line):
ifaces[iface_name].add(m2.group("name"))
implementations: dict[str, set[str]] = {} # iface_name => {impl_names}
@@ -93,7 +113,7 @@ class LibObjPlugin:
with open(fname, "r", encoding="utf-8") as fh:
for line in fh:
line = line.strip()
- if m := re_lo_implementation.match(line):
+ if m := self.re_lo_implementation.match(line):
implementations[m.group("iface")].add(m.group("impl_name"))
objcalls: dict[str, set[QName]] = {} # method_name => {method_impls}
@@ -117,15 +137,25 @@ class LibObjPlugin:
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 := 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
@@ -137,11 +167,11 @@ class LibObjPlugin:
class LibHWPlugin:
pico_platform: str
- libobj: LibObjPlugin
+ libmisc: LibMiscPlugin
- def __init__(self, arg_pico_platform: str, libobj: LibObjPlugin) -> None:
+ def __init__(self, arg_pico_platform: str, libmisc: LibMiscPlugin) -> None:
self.pico_platform = arg_pico_platform
- self.libobj = libobj
+ self.libmisc = libmisc
def is_intrhandler(self, name: QName) -> bool:
return name.base() in [
@@ -161,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:
@@ -175,11 +208,14 @@ class LibHWPlugin:
"io_readwritev",
]:
if f"{fn}(" in line:
- return self.libobj.indirect_callees(loc, f"LO_CALL(x, {fn[3:]})")
- if "io_read(" in line:
- return self.libobj.indirect_callees(loc, "LO_CALL(x, readv)")
- if "io_writev(" in line:
- return self.libobj.indirect_callees(loc, "LO_CALL(x, writev)")
+ return self.libmisc.indirect_callees(loc, f"LO_CALL(x, {fn[3:]})")
+ 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"),
@@ -219,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:
@@ -241,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:
@@ -257,37 +299,18 @@ class LibCRIPCPlugin:
return {}
-re_tmessage_handler = re.compile(
- r"^\s*\[LIB9P_TYP_T[^]]+\]\s*=\s*\(tmessage_handler\)\s*(?P<handler>\S+),\s*$"
-)
-re_lib9p_msg_entry = re.compile(r"^\s*_MSG_(?:[A-Z]+)\((?P<typ>\S+)\),$")
-re_lib9p_caller = re.compile(
- r"^lib9p_(?P<grp>[TR])msg_(?P<meth>validate|unmarshal|marshal)$"
-)
-re_lib9p_callee = re.compile(
- r"^(?P<meth>validate|unmarshal|marshal)_(?P<msg>(?P<grp>[TR]).*)$"
-)
-
-
class Lib9PPlugin:
- tmessage_handlers: set[QName] | None
+ re_lib9p_msg_entry = re.compile(r"^\s*_MSG\((?P<typ>\S+)\),$")
+
lib9p_msgs: set[str]
_CONFIG_9P_MAX_CONNS: int | None
_CONFIG_9P_MAX_REQS: int | None
- formatters: typing.Collection[BaseName]
def __init__(
self,
arg_base_dir: str,
arg_c_fnames: typing.Collection[str],
- libobj_plugin: LibObjPlugin,
) -> None:
- self.formatters = {
- x.base()
- for x in libobj_plugin.objcalls["format"]
- if str(x.base()).startswith("lib9p_")
- }
-
# Find filenames #######################################################
def _is_config_h(fname: str) -> bool:
@@ -305,7 +328,7 @@ class Lib9PPlugin:
)
lib9p_generated_c_fname = util.get_zero_or_one(
- lambda fname: fname.endswith("lib9p/_core_generated.c"), arg_c_fnames
+ lambda fname: fname.endswith("lib9p/core_generated.c"), arg_c_fnames
)
# Read config ##########################################################
@@ -322,27 +345,17 @@ 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 #########################################################
- tmessage_handlers: set[QName] | None = None
- if lib9p_srv_c_fname:
- tmessage_handlers = set()
- with open(lib9p_srv_c_fname, "r", encoding="utf-8") as fh:
- for line in fh:
- line = line.rstrip()
- if m := re_tmessage_handler.fullmatch(line):
- tmessage_handlers.add(QName(m.group("handler")))
- self.tmessage_handlers = tmessage_handlers
-
lib9p_msgs: set[str] = set()
if lib9p_generated_c_fname:
with open(lib9p_generated_c_fname, "r", encoding="utf-8") as fh:
for line in fh:
line = line.rstrip()
- if m := re_lib9p_msg_entry.fullmatch(line):
+ if m := self.re_lib9p_msg_entry.fullmatch(line):
typ = m.group("typ")
lib9p_msgs.add(typ)
self.lib9p_msgs = lib9p_msgs
@@ -368,195 +381,53 @@ class Lib9PPlugin:
def extra_nodes(self) -> typing.Collection[Node]:
return []
- def indirect_callees(
- self, loc: str, line: str
- ) -> tuple[typing.Collection[QName], bool] | None:
- if "/3rd-party/" in loc:
- return None
- if (
- self.tmessage_handlers
- and "/srv.c:" in loc
- and "tmessage_handlers[typ](" in line
- ):
- # Functions for disabled protocol extensions will be missing.
- return self.tmessage_handlers, True
- if self.lib9p_msgs and "/9p.c:" in loc:
- for meth in ["validate", "unmarshal", "marshal"]:
- if line.startswith(f"tentry.{meth}("):
- # Functions for disabled protocol extensions will be missing.
- return [QName(f"{meth}_{msg}") for msg in self.lib9p_msgs], True
- return None
-
- def skipmodels(self) -> dict[BaseName, analyze.SkipModel]:
- ret: dict[BaseName, analyze.SkipModel] = {
- BaseName("_lib9p_validate"): analyze.SkipModel(
- 2,
- self._skipmodel__lib9p_validate_unmarshal_marshal,
- ),
- BaseName("_lib9p_unmarshal"): analyze.SkipModel(
- 2,
- self._skipmodel__lib9p_validate_unmarshal_marshal,
- ),
- BaseName("_lib9p_marshal"): analyze.SkipModel(
- 2,
- self._skipmodel__lib9p_validate_unmarshal_marshal,
- ),
- BaseName("_vfctprintf"): analyze.SkipModel(
- self.formatters, self._skipmodel__vfctprintf
- ),
- }
- return ret
-
- def _skipmodel__lib9p_validate_unmarshal_marshal(
- self, chain: typing.Sequence[QName], call: QName
- ) -> bool:
- m_caller = re_lib9p_caller.fullmatch(str(chain[-2].base()))
- assert m_caller
-
- m_callee = re_lib9p_callee.fullmatch(str(call.base()))
- if not m_callee:
- return False
- return m_caller.group("grp") != m_callee.group("grp")
-
- def _skipmodel__vfctprintf(
- self, chain: typing.Sequence[QName], call: QName
- ) -> bool:
- if call.base() == BaseName("libfmt_conv_formatter"):
- return any(c.base() in self.formatters for c in chain)
- return False
-
-
-class LibMiscPlugin:
- def is_intrhandler(self, name: QName) -> bool:
- return False
-
- def init_array(self) -> typing.Collection[QName]:
- return []
-
- def extra_includes(self) -> typing.Collection[BaseName]:
- return []
-
- def extra_nodes(self) -> typing.Collection[Node]:
- return []
-
- def indirect_callees(
- self, loc: str, line: str
- ) -> tuple[typing.Collection[QName], bool] | None:
- return None
-
- def skipmodels(self) -> dict[BaseName, analyze.SkipModel]:
- return {
- BaseName("__assert_msg_fail"): analyze.SkipModel(
- {BaseName("__assert_msg_fail")}, self._skipmodel___assert_msg_fail
- ),
- }
-
- def _skipmodel___assert_msg_fail(
- self, chain: typing.Sequence[QName], call: QName
- ) -> bool:
- if call.base() in [BaseName("__lm_printf"), BaseName("__lm_light_printf")]:
- return any(
- c.base() == BaseName("__assert_msg_fail") for c in reversed(chain[:-1])
- )
- return False
-
-
-class PicoFmtPlugin:
- known_fct: dict[BaseName, BaseName]
-
- def __init__(self, arg_pico_platform: str) -> None:
- self.known_fct = {
- # pico_fmt
- BaseName("fmt_vsnprintf"): BaseName("_out_buffer"),
- }
- match arg_pico_platform:
- case "rp2040":
- self.known_fct.update(
- {
- # pico_stdio
- BaseName("__wrap_vprintf"): BaseName("stdio_buffered_printer"),
- BaseName("stdio_vprintf"): BaseName("stdio_buffered_printer"),
- # libfmt
- BaseName("__lm_light_printf"): BaseName("libfmt_light_fct"),
- }
- )
- case "host":
- self.known_fct.update(
- {
- # libfmt
- BaseName("__lm_printf"): BaseName("libfmt_libc_fct"),
- BaseName("__lm_light_printf"): BaseName("libfmt_libc_fct"),
- }
- )
-
- def is_intrhandler(self, name: QName) -> bool:
- return False
-
- def init_array(self) -> typing.Collection[QName]:
- return []
-
- def extra_includes(self) -> typing.Collection[BaseName]:
- return []
+ def mutate_node(self, node: Node) -> None:
+ pass
- def extra_nodes(self) -> typing.Collection[Node]:
- return []
+ re_table_call = re.compile(
+ r"\s*_lib9p_(?P<meth>validate|unmarshal|marshal)\(.*(?P<grp>[RT])msg.*\);\s*"
+ )
+ re_print_call = re.compile(r".*lib9p_table_msg.*\.print\(.*")
def indirect_callees(
self, loc: str, line: str
) -> tuple[typing.Collection[QName], bool] | None:
- if "/3rd-party/pico-fmt/" not in loc:
+ if "/3rd-party/" in loc:
return None
- if "/printf.c:" in loc:
- m = util.re_call_other.fullmatch(line)
- call: str | None = m.group("func") if m else None
- if "->fct" in line:
- return [x.as_qname() for x in self.known_fct.values()], False
- if "specifier_table" in line:
+ if self.lib9p_msgs and "lib9p/core.c:" in loc:
+ if m := self.re_table_call.fullmatch(line):
+ meth = m.group("meth")
+ grp = m.group("grp")
+ # Functions for disabled protocol extensions will be missing.
return [
- # pico-fmt
- QName("conv_sint"),
- QName("conv_uint"),
- # QName("conv_double"),
- QName("conv_char"),
- QName("conv_str"),
- QName("conv_ptr"),
- QName("conv_pct"),
- # libfmt
- QName("libfmt_conv_formatter"),
- QName("libfmt_conv_quote"),
- ], False
+ QName(f"{meth}_{msg}")
+ for msg in self.lib9p_msgs
+ if msg.startswith(grp)
+ ], True
+ if self.re_print_call.fullmatch(line):
+ # Functions for disabled protocol extensions will be missing.
+ return [QName(f"fmt_print_{msg}") for msg in self.lib9p_msgs], True
+ if "lib9p/srv.c:" in loc:
+ if "srv->msglog(" in line:
+ # Actual ROMs shouldn't set this, and so will be missing on rp2040 builds.
+ return [QName("log_msg")], True
return None
def skipmodels(self) -> dict[BaseName, analyze.SkipModel]:
- ret: dict[BaseName, analyze.SkipModel] = {
- BaseName("fmt_state_putchar"): analyze.SkipModel(
- self.known_fct.keys(), self._skipmodel_fmt_state_putchar
- ),
- }
- return ret
-
- def _skipmodel_fmt_state_putchar(
- self, chain: typing.Sequence[QName], call: QName
- ) -> bool:
- if call.base() in self.known_fct.values():
- fct: BaseName | None = None
- for pcall in reversed(chain):
- if pcall.base() in self.known_fct:
- fct = self.known_fct[pcall.base()]
- return call.base() != fct
- return True
- return False
+ return {}
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
@@ -590,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"),
@@ -626,6 +499,8 @@ class PicoSDKPlugin:
return [QName("rom_func_lookup(ROM_FUNC_FLASH_RANGE_ERASE)")], False
case "flash_flush_cache_func":
return [QName("rom_func_lookup(ROM_FUNC_FLASH_FLUSH_CACHE)")], False
+ case "flash_range_program_func":
+ return [QName("rom_func_lookup(ROM_FUNC_FLASH_RANGE_PROGRAM)")], False
case "rom_table_lookup":
return [QName("rom_hword_as_ptr(BOOTROM_TABLE_LOOKUP_OFFSET)")], False
if "/flash.c:" in loc and "boot2_copyout" in line:
@@ -646,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
@@ -660,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"})]
@@ -680,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"}),
@@ -738,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)"}
@@ -754,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"}),
@@ -774,29 +656,46 @@ 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
+ return ret
-re_tud_class = re.compile(
- r"^\s*#\s*define\s+(?P<k>CFG_TUD_(?:\S{3}|AUDIO|VIDEO|MIDI|VENDOR|USBTMC|DFU_RUNTIME|ECM_RNDIS))\s+(?P<v>\S+).*"
-)
-re_tud_entry = re.compile(r"^\s+\.(?P<meth>\S+)\s*=\s*(?P<impl>[a-zA-Z0-9_]+)(?:,.*)?")
-re_tud_if1 = re.compile(r"^\s*#\s*if (\S+)\s*")
-re_tud_if2 = re.compile(r"^\s*#\s*if (\S+)\s*\|\|\s*(\S+)\s*")
-re_tud_endif = re.compile(r"^\s*#\s*endif\s*")
+ 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(
+ r"^\s*#\s*define\s+(?P<k>CFG_TUD_(?:\S{3}|AUDIO|VIDEO|MIDI|VENDOR|USBTMC|DFU_RUNTIME|ECM_RNDIS))\s+(?P<v>\S+).*"
+ )
+ re_tud_entry = re.compile(
+ r"^\s+\.(?P<meth>\S+)\s*=\s*(?P<impl>[a-zA-Z0-9_]+)(?:,.*)?"
+ )
+ re_tud_if1 = re.compile(r"^\s*#\s*if (\S+)\s*")
+ re_tud_if2 = re.compile(r"^\s*#\s*if (\S+)\s*\|\|\s*(\S+)\s*")
+ re_tud_endif = re.compile(r"^\s*#\s*endif\s*")
+
tud_drivers: dict[str, set[QName]] # method_name => {method_impls}
def __init__(self, arg_c_fnames: typing.Collection[str]) -> None:
@@ -818,7 +717,7 @@ class TinyUSBDevicePlugin:
in_table = False
for line in fh:
line = line.rstrip()
- if m := re_tud_class.fullmatch(line):
+ if m := self.re_tud_class.fullmatch(line):
k = m.group("k")
v = m.group("v")
tusb_config[k] = bool(int(v))
@@ -830,13 +729,13 @@ class TinyUSBDevicePlugin:
for line in fh:
line = line.rstrip()
if in_table:
- if m := re_tud_if1.fullmatch(line):
+ if m := self.re_tud_if1.fullmatch(line):
enabled = tusb_config[m.group(1)]
- elif m := re_tud_if2.fullmatch(line):
+ elif m := self.re_tud_if2.fullmatch(line):
enabled = tusb_config[m.group(1)] or tusb_config[m.group(2)]
- elif re_tud_endif.fullmatch(line):
+ elif self.re_tud_endif.fullmatch(line):
enabled = True
- if m := re_tud_entry.fullmatch(line):
+ if m := self.re_tud_entry.fullmatch(line):
meth = m.group("meth")
impl = m.group("impl")
if meth == "name" or not enabled:
@@ -863,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:
@@ -879,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
@@ -904,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"}),
@@ -918,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),
@@ -948,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:
@@ -962,10 +887,7 @@ class LibGCCPlugin:
return False
def init_array(self) -> typing.Collection[QName]:
- return [
- QName("libfmt_install_formatter"),
- QName("libfmt_install_quote"),
- ]
+ return []
def extra_includes(self) -> typing.Collection[BaseName]:
return []
@@ -981,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/test_analyze.py b/build-aux/measurestack/test_analyze.py
index ff1732d..df205e8 100644
--- a/build-aux/measurestack/test_analyze.py
+++ b/build-aux/measurestack/test_analyze.py
@@ -5,17 +5,20 @@
# pylint: disable=unused-variable
+import re
+import typing
+
import pytest
-from .analyze import BaseName, QName
+from . import analyze, testutil, util
def test_name_base() -> None:
- assert QName("foo.c:bar.1").base() == BaseName("bar")
+ assert analyze.QName("foo.c:bar.1").base() == analyze.BaseName("bar")
def test_name_pretty() -> None:
- name = QName("foo.c:bar.1")
+ name = analyze.QName("foo.c:bar.1")
assert f"{name}" == "QName('foo.c:bar.1')"
assert f"{name.base()}" == "BaseName('bar')"
assert f"{[name]}" == "[QName('foo.c:bar.1')]"
@@ -23,7 +26,7 @@ def test_name_pretty() -> None:
def test_name_eq() -> None:
- name = QName("foo.c:bar.1")
+ name = analyze.QName("foo.c:bar.1")
with pytest.raises(AssertionError) as e:
if name == "foo":
pass
@@ -32,3 +35,47 @@ def test_name_eq() -> None:
if name.base() == "foo":
pass
assert "comparing BaseName with str" in str(e)
+
+
+def test_max_call_depth() -> None:
+ graph: typing.Sequence[tuple[str, typing.Collection[str]]] = [
+ ("a", {"b"}), # 1
+ ("b", {"c"}), # 2
+ ("c", {"d"}), # 3
+ ("d", {"e"}), # 4
+ ("e", {}), # 5
+ ]
+
+ testcases: dict[int, bool] = {
+ 1: True,
+ 2: True,
+ 3: True,
+ 4: True,
+ 5: False,
+ 6: False,
+ 7: False,
+ }
+
+ def test_filter(name: analyze.QName) -> tuple[int, bool]:
+ if str(name.base()) in ["a"]:
+ return 1, True
+ return 0, False
+
+ def doit(depth: int, graph_plugin: util.Plugin) -> None:
+ analyze.analyze(
+ ci_fnames=[],
+ app_func_filters={"Main": test_filter},
+ app=util.PluginApplication(testutil.nop_location_xform, [graph_plugin]),
+ cfg_max_call_depth=depth,
+ )
+
+ pat = re.compile("^max call depth exceeded: ")
+
+ for depth, should_fail in testcases.items():
+ graph_plugin = testutil.GraphProviderPlugin(depth, graph)
+
+ if should_fail:
+ with pytest.raises(ValueError, match=pat):
+ doit(depth, graph_plugin)
+ else:
+ doit(depth, graph_plugin)
diff --git a/build-aux/measurestack/testutil.py b/build-aux/measurestack/testutil.py
new file mode 100644
index 0000000..3c32134
--- /dev/null
+++ b/build-aux/measurestack/testutil.py
@@ -0,0 +1,134 @@
+# build-aux/measurestack/testutil.py - Utilities for writing tests
+#
+# Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+import typing
+
+from . import analyze, util
+
+# pylint: disable=unused-variable
+__all__ = [
+ "aprime_gen",
+ "aprime_decompose",
+ "NopPlugin",
+ "GraphProviderPlugin",
+ "nop_location_xform",
+]
+
+
+def aprime_gen(l: int, n: int) -> typing.Sequence[int]:
+ """Return an `l`-length sequence of nonnegative
+ integers such that any `n`-length-or-shorter combination of
+ members with repeats allowed can be uniquely identified by its
+ sum.
+
+ (If that were "product" instead of "sum", the obvious solution
+ would be the first `l` primes.)
+
+ """
+ seq = [1]
+ while len(seq) < l:
+ x = seq[-1] * n + 1
+ seq.append(x)
+ return seq
+
+
+def aprime_decompose(
+ aprimes: typing.Sequence[int], tot: int
+) -> tuple[typing.Collection[int], typing.Collection[int]]:
+ ret_idx = []
+ ret_val = []
+ while tot:
+ idx = max(i for i in range(len(aprimes)) if aprimes[i] <= tot)
+ val = aprimes[idx]
+ ret_idx.append(idx)
+ ret_val.append(val)
+ tot -= val
+ return ret_idx, ret_val
+
+
+class NopPlugin:
+ def is_intrhandler(self, name: analyze.QName) -> bool:
+ return False
+
+ def init_array(self) -> typing.Collection[analyze.QName]:
+ return []
+
+ def extra_includes(self) -> typing.Collection[analyze.BaseName]:
+ return []
+
+ def indirect_callees(
+ self, loc: str, line: str
+ ) -> tuple[typing.Collection[analyze.QName], bool] | None:
+ return None
+
+ def skipmodels(self) -> dict[analyze.BaseName, analyze.SkipModel]:
+ return {}
+
+ 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]
+
+ def __init__(
+ self,
+ max_call_depth: int,
+ graph: typing.Sequence[tuple[str, typing.Collection[str]]],
+ ) -> None:
+ seq = aprime_gen(len(graph), max_call_depth)
+ nodes: list[analyze.Node] = []
+ for i, (name, calls) in enumerate(graph):
+ nodes.append(util.synthetic_node(name, seq[i], calls))
+ assert (
+ len(graph)
+ == len(nodes)
+ == len(set(n.nstatic for n in nodes))
+ == len(set(str(n.funcname.base()) for n in nodes))
+ )
+ self._nodes = nodes
+
+ def extra_nodes(self) -> typing.Collection[analyze.Node]:
+ return self._nodes
+
+ def decode_nstatic(self, tot: int) -> typing.Collection[str]:
+ idxs, _ = aprime_decompose([n.nstatic for n in self._nodes], tot)
+ return [str(self._nodes[i].funcname.base()) for i in idxs]
+
+ def encode_nstatic(self, calls: typing.Collection[str]) -> int:
+ tot = 0
+ d: dict[str, int] = {}
+ for node in self._nodes:
+ d[str(node.funcname.base())] = node.nstatic
+ print(d)
+ for call in calls:
+ tot += d[call]
+ return tot
+
+ def sorted_calls(self, calls: typing.Collection[str]) -> typing.Sequence[str]:
+ d: dict[str, int] = {}
+ for node in self._nodes:
+ d[str(node.funcname.base())] = node.nstatic
+
+ def k(call: str) -> int:
+ return d[call]
+
+ return sorted(calls, key=k)
+
+ def assert_nstatic(self, act_tot: int, exp_calls: typing.Collection[str]) -> None:
+ exp_tot = self.encode_nstatic(exp_calls)
+ if act_tot != exp_tot:
+ act_str = f"{act_tot}: {self.sorted_calls(self.decode_nstatic(act_tot))}"
+ exp_str = f"{exp_tot}: {self.sorted_calls(exp_calls)}"
+ assert (
+ False
+ ), f"act:{act_tot} != exp:{exp_tot}\n\t-exp = {exp_str}\n\t+act = {act_str}"
+
+
+def nop_location_xform(loc: str) -> str:
+ return loc
diff --git a/build-aux/measurestack/util.py b/build-aux/measurestack/util.py
index 47b2617..c94ce07 100644
--- a/build-aux/measurestack/util.py
+++ b/build-aux/measurestack/util.py
@@ -7,7 +7,7 @@ import re
import typing
from . import analyze, vcg
-from .analyze import BaseName, Node, QName
+from .analyze import BaseName, Node, QName, maybe_sorted
# pylint: disable=unused-variable
__all__ = [
@@ -32,7 +32,7 @@ def synthetic_node(
n.nstatic = nstatic
n.ndynamic = 0
- n.calls = dict((QName(c), False) for c in calls)
+ n.calls = dict((QName(c), False) for c in maybe_sorted(calls))
return n
@@ -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 6e722d7..0000000
--- a/cmd/sbc_harness/CMakeLists.txt
+++ /dev/null
@@ -1,84 +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
- libfmt
- libusb
- libdhcp
- libhw_cr
- lib9p_srv
- lib9p_util
-)
-pico_minimize_runtime(sbc_harness_objs
- INCLUDE PRINTF PRINTF_MINIMAL PRINTF_LONG_LONG PRINTF_PTRDIFF_T
-)
-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/pico-sdk.bsd3.txt
- static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/printf.mit.txt
- static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/tinyusb.mit.txt
- static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/newlib.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 bc3d061..0000000
--- a/cmd/sbc_harness/fs_harness_flash_bin.c
+++ /dev/null
@@ -1,312 +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);
-
- infof("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);
- }
-
- infof("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);
-
- infof("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);
- }
- debugf("... 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);
-
- infof("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);
- }
- debugf("... 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;
-
- infof("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);
- }
- debugf("... 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_stat flash_file_stat(struct flash_file *self, struct lib9p_srv_ctx *ctx) {
- assert(self);
- assert(ctx);
-
- return (struct lib9p_stat){
- .kern_type = 0,
- .kern_dev = 0,
- .file_qid = flash_file_qid(self),
- .file_mode = LIB9P_DM_EXCL|0666,
- .file_atime = UTIL9P_ATIME,
- .file_mtime = UTIL9P_MTIME,
- .file_size = DATA_SIZE,
- .file_name = lib9p_str(self->name),
- .file_owner_uid = lib9p_str("root"),
- .file_owner_gid = lib9p_str("root"),
- .file_last_modified_uid = lib9p_str("root"),
- .file_extension = lib9p_str(NULL),
- .file_owner_n_uid = 0,
- .file_owner_n_gid = 0,
- .file_last_modified_n_uid = 0,
- };
-}
-static void flash_file_wstat(struct flash_file *self, struct lib9p_srv_ctx *ctx,
- struct lib9p_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 1425bf9..0000000
--- a/cmd/sbc_harness/fs_harness_uptime_txt.c
+++ /dev/null
@@ -1,156 +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 <stdio.h> /* for snprintf() */
-#include <stdlib.h> /* for malloc(), free() */
-
-#include <libhw/generic/alarmclock.h>
-#include <util9p/static.h>
-
-#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_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_stat){
- .kern_type = 0,
- .kern_dev = 0,
- .file_qid = uptime_file_qid(self),
- .file_mode = 0444,
- .file_atime = UTIL9P_ATIME,
- .file_mtime = UTIL9P_MTIME,
- .file_size = size,
- .file_name = lib9p_str(self->name),
- .file_owner_uid = lib9p_str("root"),
- .file_owner_gid = lib9p_str("root"),
- .file_last_modified_uid = lib9p_str("root"),
- .file_extension = lib9p_str(NULL),
- .file_owner_n_uid = 0,
- .file_owner_n_gid = 0,
- .file_last_modified_n_uid = 0,
- };
-}
-static void uptime_file_wstat(struct uptime_file *self, struct lib9p_srv_ctx *ctx,
- struct lib9p_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 = malloc(sizeof(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 = snprintf(self->buf, sizeof(self->buf), "%"PRIu64"ns\n", now);
- }
-
- 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/YOUR_RIGHTS_AND_OBLIGATIONS/printf.mit.txt b/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/printf.mit.txt
deleted file mode 120000
index 5a6e342..0000000
--- a/cmd/sbc_harness/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/printf.mit.txt
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../3rd-party/pico-sdk/src/rp2_common/pico_printf/LICENSE \ No newline at end of file
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/cmd/sbc_harness/tusb_log.c b/cmd/sbc_harness/tusb_log.c
deleted file mode 100644
index 4c6b7df..0000000
--- a/cmd/sbc_harness/tusb_log.c
+++ /dev/null
@@ -1,15 +0,0 @@
-/* sbc_harness/tusb_log.c - Logger for tusb_config.h
- *
- * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-#define LOG_NAME TINY_USB
-#include <libmisc/log.h>
-
-void _libmisc_tu_mess_failed(const char *expr,
- const char *file, unsigned int line, const char *func) {
- errorf("%s:%u:%s(): assertion \"%s\" failed",
- file, line, func,
- expr);
-}
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 5367dbe..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,7 +37,15 @@
/* 9P *************************************************************************/
-#define CONFIG_9P_MAX_ERR_SIZE 128 /* 128 is what Plan 9 4e uses */
+#define CONFIG_9P_ENABLE_9P2000 1 /* bool */
+#define CONFIG_9P_ENABLE_9P2000_u 1 /* bool */
+#define CONFIG_9P_ENABLE_9P2000_e 0 /* bool */
+#define CONFIG_9P_ENABLE_9P2000_L 0 /* bool */
+#define CONFIG_9P_ENABLE_9P2000_p9p 0 /* bool */
+
+/* 9P_SRV *********************************************************************/
+
+#define CONFIG_9P_SRV_DEBUG 1 /* bool */
/**
* This max-msg-size is sized so that a Twrite message can return
@@ -57,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)
@@ -64,12 +73,6 @@
*/
#define CONFIG_9P_SRV_MAX_HOSTMSG_SIZE CONFIG_9P_SRV_MAX_MSG_SIZE+16
-#define CONFIG_9P_ENABLE_9P2000 1 /* bool */
-#define CONFIG_9P_ENABLE_9P2000_u 1 /* bool */
-#define CONFIG_9P_ENABLE_9P2000_e 0 /* bool */
-#define CONFIG_9P_ENABLE_9P2000_L 0 /* bool */
-#define CONFIG_9P_ENABLE_9P2000_p9p 0 /* bool */
-
/* DHCP ***********************************************************************/
#define CONFIG_DHCP_CAN_RECV_UNICAST_IP_WITHOUT_IP 0 /* bool */
@@ -90,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 */
@@ -104,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 0a6d3e4..18be9b5 100644
--- a/cmd/sbc_harness/config/tusb_config.h
+++ b/flashimg/cpu_main/config/tusb_config.h
@@ -1,6 +1,6 @@
-/* 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 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*
* SPDX-License-Identifier: MIT
@@ -31,40 +31,31 @@
#ifndef _TUSB_CONFIG_H_
#define _TUSB_CONFIG_H_
+#include <stdint.h> /* for uint{n}_t */
+
#ifdef __cplusplus
extern "C" {
#endif
//--------------------------------------------------------------------
-// Override the default definition of TU_ASSERT() to use our logging
+// Override the default TU_MESS_FAILED() and tu_print_*() to use our logging
//--------------------------------------------------------------------
-// "magically" select between the 1-arg and 2-args variants, inject a
-// stringified version of `_cond`.
-//
-// Note: Use GNU-C `, ##__VA_ARGS__`, not standard C `__VA_OPT__(,)
-// __VA_ARGS__`; because __VA_OPT__ doesn't handle present-but-empty
-// arguments the way that we need.
-#define TU_ASSERT(_cond, ...) \
- _GET_3RD_ARG(_cond, ##__VA_ARGS__, \
- _LIBMISC_TU_ASSERT_2ARGS, _LIBMISC_TU_ASSERT_1ARGS, _dummy) \
- (_cond, #_cond, ##__VA_ARGS__)
-
-#define _LIBMISC_TU_ASSERT_1ARGS(_cond, _cond_str) \
- _LIBMISC_TU_ASSERT_2ARGS(_cond, _cond_str, false)
-
-#define _LIBMISC_TU_ASSERT_2ARGS(_cond, _cond_str, _ret) \
- do { \
- if ( !(_cond) ) { \
- _libmisc_tu_mess_failed(_cond_str, \
- __FILE__, __LINE__, __func__); \
- TU_BREAKPOINT(); \
- return _ret; \
- } \
- } while(0)
-
-void _libmisc_tu_mess_failed(const char *expr,
- const char *file, unsigned int line, const char *func);
+#define TU_MESS_FAILED(_cond_str) _libmisc_tu_mess_failed(_cond_str, __FILE__, __LINE__, __func__)
+#define tu_print_str _libmisc_tu_print_str
+#define tu_print_byte _libmisc_tu_print_byte
+#define tu_print_base10 _libmisc_tu_print_base10
+#define tu_print_base16 _libmisc_tu_print_base16
+#define tu_print_base16_u8 _libmisc_tu_print_base16_u8
+#define tu_print_base16_u16 _libmisc_tu_print_base16_u16
+
+void _libmisc_tu_mess_failed(const char *expr, const char *file, unsigned int line, const char *func);
+void _libmisc_tu_print_str(const char *);
+void _libmisc_tu_print_byte(uint8_t);
+void _libmisc_tu_print_base10(unsigned long);
+void _libmisc_tu_print_base16(unsigned long);
+void _libmisc_tu_print_base16_u8(uint8_t);
+void _libmisc_tu_print_base16_u16(uint16_t);
//--------------------------------------------------------------------
// Configuration: common
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..0a2797f
--- /dev/null
+++ b/flashimg/cpu_main/fs_harness_uptime_txt.c
@@ -0,0 +1,167 @@
+/* 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);
+
+ uint64_t now = LO_CALL(bootclock, get_time_ns);
+ uint64_t size = 0;
+ while (now) {
+ size++;
+ now /= 10;
+ }
+ if (!size)
+ size++;
+ size += 3;
+
+ *out = ((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),
+ });
+ 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 5630e83..9dd2588 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,9 +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 */
@@ -30,10 +31,10 @@
#include <libmisc/log.h>
/* local headers */
-#include "usb_keyboard.h"
-#include "static.h"
#include "fs_harness_flash_bin.h"
#include "fs_harness_uptime_txt.h"
+#include "static.h"
+#include "usb_keyboard.h"
/* configuration **************************************************************/
@@ -61,7 +62,7 @@ enum { PATH_BASE = __COUNTER__ };
__VA_OPT__(,) __VA_ARGS__ \
}))
-struct lib9p_srv_file root =
+static struct lib9p_srv_file root =
STATIC_DIR("",
STATIC_DIR("Documentation",
STATIC_FILE("YOUR_RIGHTS_AND_OBLIGATIONS.md",
@@ -71,18 +72,18 @@ struct lib9p_srv_file root =
STATIC_FILE("agpl-3.0.txt",
.data_start = _binary_static_Documentation_YOUR_RIGHTS_AND_OBLIGATIONS_agpl_3_0_txt_start,
.data_end = _binary_static_Documentation_YOUR_RIGHTS_AND_OBLIGATIONS_agpl_3_0_txt_end),
+ STATIC_FILE("dhcp.bsd3-mit.txt",
+ .data_start = _binary_static_Documentation_YOUR_RIGHTS_AND_OBLIGATIONS_dhcp_bsd3_mit_txt_start,
+ .data_end = _binary_static_Documentation_YOUR_RIGHTS_AND_OBLIGATIONS_dhcp_bsd3_mit_txt_end),
+ STATIC_FILE("newlib.txt",
+ .data_start = _binary_static_Documentation_YOUR_RIGHTS_AND_OBLIGATIONS_newlib_txt_start,
+ .data_end = _binary_static_Documentation_YOUR_RIGHTS_AND_OBLIGATIONS_newlib_txt_end),
STATIC_FILE("pico-sdk.bsd3.txt",
.data_start = _binary_static_Documentation_YOUR_RIGHTS_AND_OBLIGATIONS_pico_sdk_bsd3_txt_start,
.data_end = _binary_static_Documentation_YOUR_RIGHTS_AND_OBLIGATIONS_pico_sdk_bsd3_txt_end),
- STATIC_FILE("printf.mit.txt",
- .data_start = _binary_static_Documentation_YOUR_RIGHTS_AND_OBLIGATIONS_printf_mit_txt_start,
- .data_end = _binary_static_Documentation_YOUR_RIGHTS_AND_OBLIGATIONS_printf_mit_txt_end),
STATIC_FILE("tinyusb.mit.txt",
.data_start = _binary_static_Documentation_YOUR_RIGHTS_AND_OBLIGATIONS_tinyusb_mit_txt_start,
.data_end = _binary_static_Documentation_YOUR_RIGHTS_AND_OBLIGATIONS_tinyusb_mit_txt_end),
- STATIC_FILE("newlib.txt",
- .data_start = _binary_static_Documentation_YOUR_RIGHTS_AND_OBLIGATIONS_newlib_txt_start,
- .data_end = _binary_static_Documentation_YOUR_RIGHTS_AND_OBLIGATIONS_newlib_txt_end),
),
STATIC_FILE("harness_rom_bin.txt",
.data_start = _binary_static_Documentation_harness_rom_bin_txt_start,
@@ -114,8 +115,8 @@ 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 ***********************************************************************/
@@ -129,7 +130,7 @@ static COROUTINE hello_world_cr(void *_chan) {
for (size_t i = 0;; i = (i+1) % strlen(msg)) {
int result = usb_keyboard_rpc_send_req(chan, (uint32_t)msg[i]);
if (result < 1) {
- errorf("error sending rune U+%d", (uint32_t)msg[i]);
+ log_errorln("error sending rune U+", msg[i]);
break;
}
}
@@ -149,7 +150,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 +158,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);
@@ -173,7 +174,7 @@ static COROUTINE write9p_cr(void *) {
cr_end();
}
-const char *const hexdig = "0123456789ABCDEF";
+static const char *const hexdig = "0123456789ABCDEF";
static_assert(_CONFIG_9P_MAX_REQS <= 16);
COROUTINE init_cr(void *) {
@@ -204,7 +205,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){{
@@ -221,33 +222,71 @@ COROUTINE init_cr(void *) {
usb_keyboard_init();
usb_common_lateinit();
- globals.keyboard_chan = (usb_keyboard_rpc_t){0};
+ globals.keyboard_chan = (usb_keyboard_rpc_t){};
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: ")); */
- infof("===================================================================");
- coroutine_add("init", init_cr, NULL);
+ log_infoln("===================================================================");
+ 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/flashimg/cpu_main/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/dhcp.bsd3-mit.txt b/flashimg/cpu_main/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/dhcp.bsd3-mit.txt
new file mode 120000
index 0000000..0277bc8
--- /dev/null
+++ b/flashimg/cpu_main/static/Documentation/YOUR_RIGHTS_AND_OBLIGATIONS/dhcp.bsd3-mit.txt
@@ -0,0 +1 @@
+../../../../../3rd-party/COPYING.wiznet-dhcp.txt \ No newline at end of file
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/flashimg/cpu_main/tusb_log.c b/flashimg/cpu_main/tusb_log.c
new file mode 100644
index 0000000..aacec87
--- /dev/null
+++ b/flashimg/cpu_main/tusb_log.c
@@ -0,0 +1,22 @@
+/* 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
+ */
+
+#define LOG_NAME TINY_USB
+#include <libmisc/log.h>
+
+#include "tusb_config.h"
+
+void _libmisc_tu_mess_failed(const char *expr,
+ const char *file, unsigned int line, const char *func) {
+ log_errorln(file, ":", line, ":", func, "(): assertion ", (qstr, expr), " failed");
+}
+
+void _libmisc_tu_print_str(const char *x) { fmt_print_str(_log_dest, x); }
+void _libmisc_tu_print_byte(uint8_t x) { fmt_print_byte(_log_dest, x); }
+void _libmisc_tu_print_base10(unsigned long x) { fmt_print_base10(_log_dest, x); }
+void _libmisc_tu_print_base16(unsigned long x) { fmt_print(_log_dest, "0x", (base16, x)); }
+void _libmisc_tu_print_base16_u8(uint8_t x) { fmt_print_base16_u8_(_log_dest, x); }
+void _libmisc_tu_print_base16_u16(uint16_t x) { fmt_print_base16_u16_(_log_dest, x); }
diff --git a/cmd/sbc_harness/usb_keyboard.c b/flashimg/cpu_main/usb_keyboard.c
index f3cb42d..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;
@@ -49,13 +49,13 @@ COROUTINE usb_keyboard_cr(void *_chan) {
uint8_t report_id = 0;
uint8_t modifier = 0;
- uint8_t keycodes[6] = {0};
+ uint8_t keycodes[6] = {};
for (;;) {
while (!tud_hid_n_ready(kbd_ifc))
cr_yield();
- if (usb_keyboard_rpc_can_recv_req(chan)) {
- usb_keyboard_rpc_req_t req = usb_keyboard_rpc_recv_req(chan);
+ if (cr_rpc_can_recv_req(chan)) {
+ usb_keyboard_rpc_req_t req = cr_rpc_recv_req(chan);
uint32_t rune = req.req;
modifier = ascii2keycode[rune][0] ? KEYBOARD_MODIFIER_LEFTSHIFT : 0;
@@ -69,7 +69,7 @@ COROUTINE usb_keyboard_cr(void *_chan) {
keycodes[0] = 0;
tud_hid_n_keyboard_report(kbd_ifc, report_id, modifier, keycodes);
- usb_keyboard_rpc_send_resp(req, 1);
+ cr_rpc_send_resp(req, 1);
} else {
modifier = 0;
keycodes[0] = 0;
@@ -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/gdb-helpers/libcr.py b/gdb-helpers/libcr.py
index fcfd86e..6f95a81 100644
--- a/gdb-helpers/libcr.py
+++ b/gdb-helpers/libcr.py
@@ -89,6 +89,7 @@ def gdb_longjmp(buf: gdb_JmpBuf) -> None:
class CrGlobals:
+ main: "CrMain"
coroutines: list["CrCoroutine"]
_breakpoint: "CrBreakpoint"
_known_threads: set[gdb.InferiorThread]
@@ -98,6 +99,7 @@ class CrGlobals:
gdb.parse_and_eval("sizeof(coroutine_table)/sizeof(coroutine_table[0])")
)
+ self.main = CrMain(self)
self.coroutines = [CrCoroutine(self, i + 1) for i in range(num)]
self._breakpoint = CrBreakpoint()
@@ -126,35 +128,37 @@ class CrGlobals:
# Ignore thread creation events.
self._known_threads = cur_threads
return
- if self.coroutine_running:
- if not self.coroutine_running.is_selected():
- if gdb_bug_32428:
- print("Must return to running coroutine before continuing.")
- print("Hit ^C twice then run:")
- print(f" cr select {self.coroutine_running.id}")
- while True:
- time.sleep(1)
- assert self.coroutine_running.cont_env
- gdb_longjmp(self.coroutine_running.cont_env)
+ if not self.coroutine_running.is_selected():
+ if gdb_bug_32428:
+ print("Must return to running coroutine before continuing.")
+ print("Hit ^C twice then run:")
+ print(f" cr select {self.coroutine_running.cid}")
+ while True:
+ time.sleep(1)
+ assert self.coroutine_running.cont_env
+ gdb_longjmp(self.coroutine_running.cont_env)
+ self.main.cont_env = None
for cr in self.coroutines:
cr.cont_env = None
def is_valid_cid(self, cid: int) -> bool:
- return 0 < cid <= len(self.coroutines)
+ return (0 < cid <= len(self.coroutines)) and (
+ self.coroutines[cid - 1].state != self.CR_NONE
+ )
@property
- def coroutine_running(self) -> "CrCoroutine | None":
+ def coroutine_running(self) -> "CrMain | CrCoroutine":
cid = int(gdb.parse_and_eval("coroutine_running"))
if not self.is_valid_cid(cid):
- return None
+ return self.main
return self.coroutines[cid - 1]
@property
- def coroutine_selected(self) -> "CrCoroutine | None":
+ def coroutine_selected(self) -> "CrMain | CrCoroutine":
for cr in self.coroutines:
if cr.is_selected():
return cr
- return None
+ return self.main
@property
def CR_NONE(self) -> gdb.Value:
@@ -164,6 +168,35 @@ class CrGlobals:
def CR_RUNNING(self) -> gdb.Value:
return gdb.parse_and_eval("CR_RUNNING")
+ def select(self, cr: "CrMain | CrCoroutine", level: int = -1) -> None:
+ self.coroutine_selected.cont_env = gdb_setjmp()
+
+ if cr.cont_env:
+ gdb_longjmp(cr.cont_env)
+ else:
+ env: gdb_JmpBuf
+ if cr == self.coroutine_running:
+ assert False # cr.cont_env should have been set
+ match cr:
+ case CrMain():
+ env = self.readjmp("&coroutine_main_env")
+ case CrCoroutine():
+ if cr.state == self.CR_RUNNING:
+ env = self.readjmp("&coroutine_add_env")
+ else:
+ env = self.readjmp(f"&coroutine_table[{cr.cid-1}].env")
+ gdb_longjmp(env)
+ cr_select_top_frame()
+
+ @contextlib.contextmanager
+ def with_selected(self, cr: "CrMain | CrCoroutine") -> typing.Iterator[None]:
+ saved_env = gdb_setjmp()
+ self.select(cr)
+ try:
+ yield
+ finally:
+ gdb_longjmp(saved_env)
+
class CrBreakpointUnwinder(gdb.unwinder.Unwinder):
"""Used to temporarily disable unwinding so that
@@ -245,6 +278,22 @@ def cr_select_top_frame() -> None:
break
+class CrMain:
+ cr_globals: CrGlobals
+ cont_env: gdb_JmpBuf | None
+
+ def __init__(self, cr_globals: CrGlobals) -> None:
+ self.cr_globals = cr_globals
+ self.cont_env = None
+
+ @property
+ def cid(self) -> int:
+ return 0
+
+ def is_selected(self) -> bool:
+ return not any(cr.is_selected() for cr in self.cr_globals.coroutines)
+
+
class CrCoroutine:
cr_globals: CrGlobals
cid: int
@@ -256,10 +305,6 @@ class CrCoroutine:
self.cont_env = None
@property
- def id(self) -> int:
- return self.cid
-
- @property
def state(self) -> gdb.Value:
return gdb.parse_and_eval(f"coroutine_table[{self.cid-1}].state")
@@ -272,36 +317,10 @@ class CrCoroutine:
def is_selected(self) -> bool:
sp = int(gdb.parse_and_eval("$sp"))
- lo = int(gdb.parse_and_eval(f"coroutine_table[{self.id-1}].stack"))
- hi = lo + int(gdb.parse_and_eval(f"coroutine_table[{self.id-1}].stack_size"))
+ lo = int(gdb.parse_and_eval(f"coroutine_table[{self.cid-1}].stack"))
+ hi = lo + int(gdb.parse_and_eval(f"coroutine_table[{self.cid-1}].stack_size"))
return lo <= sp < hi
- def select(self, level: int = -1) -> None:
- if self.cr_globals.coroutine_selected:
- self.cr_globals.coroutine_selected.cont_env = gdb_setjmp()
-
- if self.cont_env:
- gdb_longjmp(self.cont_env)
- else:
- env: gdb_JmpBuf
- if self == self.cr_globals.coroutine_running:
- assert False # self.cont_env should have been set
- elif self.state == self.cr_globals.CR_RUNNING:
- env = self.cr_globals.readjmp("&coroutine_add_env")
- else:
- env = self.cr_globals.readjmp(f"&coroutine_table[{self.id-1}].env")
- gdb_longjmp(env)
- cr_select_top_frame()
-
- @contextlib.contextmanager
- def with_selected(self) -> typing.Iterator[None]:
- saved_env = gdb_setjmp()
- self.select()
- try:
- yield
- finally:
- gdb_longjmp(saved_env)
-
# User-facing commands #########################################################
@@ -342,8 +361,11 @@ class CrListCommand(gdb.Command):
rows: list[tuple[str, str, str, str, str]] = [
("", "Id", "Name", "State", "Frame")
]
- for cr in self.cr_globals.coroutines:
- if cr.state == self.cr_globals.CR_NONE:
+ for cid in range(len(self.cr_globals.coroutines) + 1):
+ cr: CrMain | CrCoroutine = (
+ self.cr_globals.coroutines[cid - 1] if cid else self.cr_globals.main
+ )
+ if isinstance(cr, CrCoroutine) and cr.state == self.cr_globals.CR_NONE:
continue
rows += [
(
@@ -353,9 +375,9 @@ class CrListCommand(gdb.Command):
"G" if cr.is_selected() else " ",
]
),
- str(cr.id),
- repr(cr.name),
- str(cr.state),
+ str(cr.cid),
+ repr(cr.name) if isinstance(cr, CrCoroutine) else "-",
+ str(cr.state) if isinstance(cr, CrCoroutine) else "-",
self._pretty_frame(cr, from_tty),
)
]
@@ -382,9 +404,9 @@ class CrListCommand(gdb.Command):
l = l[:maxline]
print(l)
- def _pretty_frame(self, cr: CrCoroutine, from_tty: bool) -> str:
+ def _pretty_frame(self, cr: CrMain | CrCoroutine, from_tty: bool) -> str:
try:
- with cr.with_selected():
+ with self.cr_globals.with_selected(cr):
saved_level = gdb.selected_frame().level()
cr_select_top_frame()
full = gdb.execute("frame", from_tty=from_tty, to_string=True)
@@ -411,16 +433,15 @@ class CrSelectCommand(gdb.Command):
if len(argv) != 1:
raise gdb.GdbError("Usage: cr select COROUTINE")
cr = self._find(argv[0])
- cr.select()
+ self.cr_globals.select(cr)
gdb.execute("frame")
- def _find(self, name: str) -> CrCoroutine:
+ def _find(self, name: str) -> CrMain | CrCoroutine:
if name.isnumeric():
cid = int(name)
- if (
- self.cr_globals.is_valid_cid(cid)
- and self.cr_globals.coroutines[cid - 1].state != self.cr_globals.CR_NONE
- ):
+ if cid == 0:
+ return self.cr_globals.main
+ if self.cr_globals.is_valid_cid(cid):
return self.cr_globals.coroutines[cid - 1]
crs: list[CrCoroutine] = []
for cr in self.cr_globals.coroutines:
@@ -445,6 +466,7 @@ def cr_initialize() -> None:
if _cr_globals:
old = _cr_globals
new = CrGlobals()
+ new.main.cont_env = old.main.cont_env
for i in range(min(len(old.coroutines), len(new.coroutines))):
new.coroutines[i].cont_env = old.coroutines[i].cont_env
old.delete()
diff --git a/lib9p/CMakeLists.txt b/lib9p/CMakeLists.txt
index 543d01a..9ef8465 100644
--- a/lib9p/CMakeLists.txt
+++ b/lib9p/CMakeLists.txt
@@ -3,23 +3,36 @@
# 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
- core_tables.c
)
target_link_libraries(lib9p_core INTERFACE
- libfmt
libhw_generic
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
@@ -50,6 +63,26 @@ if (ENABLE_TESTS)
add_lib9p_executable("testclient-sess")
add_lib9p_test("./testclient-sess")
- add_lib_test(lib9p_core test_compile)
- target_include_directories(test_compile PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_compile_config)
+ add_lib9p_executable("testclient-hangup")
+ add_lib9p_test("./testclient-hangup")
+
+ set(cfg_matrix
+ "CONFIG_9P_ENABLE_9P2000;[0;1]"
+ "CONFIG_9P_ENABLE_9P2000_u;[0;1]"
+ "CONFIG_9P_ENABLE_9P2000_e;[0;1]"
+ "CONFIG_9P_ENABLE_9P2000_L;[0;1]"
+ "CONFIG_9P_ENABLE_9P2000_p9p;[0;1]"
+ )
+ function(add_compile_test n defs)
+ 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}")
+ endfunction()
+ apply_matrix(add_compile_test "${cfg_matrix}")
endif()
diff --git a/lib9p/core.c b/lib9p/core.c
index a07461d..ae2d3ca 100644
--- a/lib9p/core.c
+++ b/lib9p/core.c
@@ -4,27 +4,29 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-#include <inttypes.h> /* for PRIu{n} */
-#include <stdarg.h> /* for va_* */
-#include <string.h> /* for strncpy() */
+#include <string.h> /* for strlen(), strnlen(), strncpy(), memcmp(), memset() */
-#include <libfmt/fmt.h> /* for fmt_vsnprintf() */
+#include <libmisc/assert.h> /* for assert() */
+#include <libmisc/endian.h> /* for uint32le_decode() */
+#include <libmisc/log.h> /* for const_byte_str() */
#include <lib9p/core.h>
+#include "core_tables.h"
+
/* strings ********************************************************************/
-struct lib9p_s lib9p_str(char *s) {
+struct lib9p_s lib9p_str(const char *s) {
if (!s)
- return (struct lib9p_s){0};
+ return (struct lib9p_s){};
return (struct lib9p_s){
.len = strlen(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){0};
+ return (struct lib9p_s){};
return (struct lib9p_s){
.len = strnlen(s, maxlen),
.utf8 = s,
@@ -43,53 +45,163 @@ bool lib9p_str_eq(struct lib9p_s a, struct lib9p_s b) {
(a.len == 0 || memcmp(a.utf8, b.utf8, a.len) == 0);
}
-/* ctx ************************************************************************/
+/* bounds checks **************************************************************/
-void lib9p_ctx_clear_error(struct lib9p_ctx *ctx) {
- assert(ctx);
-#if CONFIG_9P_ENABLE_9P2000_u
- ctx->err_num = 0;
-#endif
- ctx->err_msg[0] = '\0';
+static inline void assert_ver(enum lib9p_version ver) {
+ assert(0 <= ver && ver < LIB9P_VER_NUM);
+}
+
+static inline void assert_typ(enum lib9p_msg_type typ) {
+ assert(0 <= typ && typ < 0xFF);
}
-bool lib9p_ctx_has_error(struct lib9p_ctx *ctx) {
+/* simple lookups *************************************************************/
+
+const char *lib9p_version_str(enum lib9p_version ver) {
+ assert_ver(ver);
+ return _lib9p_table_ver[ver].name;
+}
+
+uint32_t lib9p_version_min_Rerror_size(enum lib9p_version ver) {
+ assert_ver(ver);
+ return _lib9p_table_ver[ver].min_Rerror_size;
+}
+
+uint32_t lib9p_version_min_Rread_size(enum lib9p_version ver) {
+ assert_ver(ver);
+ return _lib9p_table_ver[ver].min_Rread_size;
+}
+
+const char *lib9p_msgtype_str(enum lib9p_version ver, enum lib9p_msg_type typ) {
+ assert_ver(ver);
+ assert_typ(typ);
+ return _lib9p_table_msg[ver][typ].name ?: const_byte_str(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);
- return ctx->err_msg[0];
+ 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);
}
-int lib9p_error(struct lib9p_ctx *ctx, lib9p_errno_t linux_errno, char const *msg) {
- if (lib9p_ctx_has_error(ctx))
- return -1;
- strncpy(ctx->err_msg, msg, sizeof(ctx->err_msg));
- ctx->err_msg[sizeof(ctx->err_msg)-1] = '\0';
+#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)
-#if CONFIG_9P_ENABLE_9P2000_u
- ctx->err_num = linux_errno;
-#else
- (void)(linux_errno);
-#endif
+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);
+}
- return -1;
+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);
}
-int lib9p_errorf(struct lib9p_ctx *ctx, lib9p_errno_t linux_errno, char const *fmt, ...) {
- int n;
- va_list args;
+#define _lib9p_unmarshal(TABLE) do { \
+ assert_ver(ctx->version); \
+ enum lib9p_msg_type typ = net_bytes[4]; \
+ *ret_typ = typ; \
+ struct _lib9p_recv_tentry tentry = TABLE[ctx->version][typ/2]; \
+ assert(tentry.unmarshal); \
+ \
+ tentry.unmarshal(ctx, net_bytes, ret_body); \
+} while (0)
- if (lib9p_ctx_has_error(ctx))
- return -1;
- va_start(args, fmt);
- n = fmt_vsnprintf(ctx->err_msg, sizeof(ctx->err_msg), fmt, args);
- va_end(args);
- if ((size_t)(n+1) < sizeof(ctx->err_msg))
- memset(&ctx->err_msg[n+1], 0, sizeof(ctx->err_msg)-(n+1));
+void lib9p_Tmsg_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes,
+ enum lib9p_msg_type *ret_typ, void *ret_body) {
+ _lib9p_unmarshal(_lib9p_table_Tmsg_recv);
+}
-#if CONFIG_9P_ENABLE_9P2000_u
- ctx->err_num = linux_errno;
-#else
- (void)(linux_errno);
-#endif
+void lib9p_Rmsg_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes,
+ enum lib9p_msg_type *ret_typ, void *ret_body) {
+ _lib9p_unmarshal(_lib9p_table_Rmsg_recv);
+}
+
+#define _lib9p_marshal(LOW_TYP_BIT, TABLE) do { \
+ assert_ver(ctx->version); \
+ assert(typ % 2 == LOW_TYP_BIT); \
+ assert_typ(typ); \
+ \
+ memset(ret, 0, sizeof(*ret)); \
+ \
+ struct _marshal_ret _ret = { \
+ .net_iov_cnt = 1, \
+ .net_iov = ret->iov, \
+ .net_copied_size = 0, \
+ .net_copied = ret->copied, \
+ }; \
+ struct _lib9p_send_tentry tentry = TABLE[ctx->version][typ/2]; \
+ assert(tentry.marshal); \
+ \
+ 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_err; \
+} while (0)
+
+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);
+}
+
+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);
+}
- return -1;
+/* `struct lib9p_stat` helpers ************************************************/
+
+#if _LIB9P_ENABLE_stat
+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) {
+ 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 = host_size.size_t;
+ return ERROR_NULL;
+}
+
+void lib9p_stat_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes,
+ struct lib9p_stat *ret) {
+ _lib9p_stat_unmarshal(ctx, net_bytes, ret);
+}
+
+uint32_t lib9p_stat_marshal(struct lib9p_ctx *ctx, uint32_t max_net_size, struct lib9p_stat *obj,
+ uint8_t *ret_bytes) {
+ struct lib9p_ctx _ctx = *ctx;
+ _ctx.max_msg_size = max_net_size;
+
+ struct wr_iovec iov = {};
+ struct _marshal_ret ret = {
+ .net_iov_cnt = 1,
+ .net_iov = &iov,
+ .net_copied_size = 0,
+ .net_copied = ret_bytes,
+ };
+ if (_lib9p_stat_marshal(&_ctx, obj, &ret))
+ return 0;
+ return ret.net_iov[0].iov_len;
}
+#endif
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 b2e856d..ab34387 100644
--- a/lib9p/core_gen/c.py
+++ b/lib9p/core_gen/c.py
@@ -7,7 +7,7 @@ import sys
import idl
-from . import c9util, c_format, c_marshal, c_unmarshal, c_validate, cutil
+from . import c9util, c_fmt_print, c_marshal, c_unmarshal, c_validate, cutil
# This strives to be "general-purpose" in that it just acts on the
# *.9p inputs; but (unfortunately?) there are a few special-cases in
@@ -23,28 +23,17 @@ def gen_c(versions: set[str], typs: list[idl.UserType]) -> str:
ret = f"""/* Generated by `{' '.join(sys.argv)}`. DO NOT EDIT! */
-#include <stdbool.h>
-#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"
"""
- # libobj vtables ###########################################################
- ret += """
-/* libobj vtables *************************************************************/
-"""
- for typ in typs:
- ret += cutil.ifdef_push(1, c9util.ver_ifdef(typ.in_versions))
- ret += f"LO_IMPLEMENTATION_C(fmt_formatter, {c9util.typename(typ)}, {c9util.basename(typ)}, static);\n"
- ret += cutil.ifdef_pop(0)
-
# utilities ################################################################
ret += """
/* utilities ******************************************************************/
@@ -79,7 +68,9 @@ def gen_c(versions: set[str], typs: list[idl.UserType]) -> str:
if not isinstance(typ, idl.Bitfield):
continue
ret += "\n"
- ret += cutil.ifdef_push(1, c9util.ver_ifdef(typ.in_versions))
+ ret += cutil.ifdef_push( # SPECIAL (initialization)
+ 1, c9util.ver_ifdef(typ.in_versions - {"uninitialized"})
+ )
ret += f"static const {c9util.typename(typ)} {typ.typname}_masks[{c9util.ver_enum('NUM')}] = {{\n"
verwidth = max(len(ver) for ver in versions)
for ver in sorted(versions):
@@ -110,8 +101,8 @@ def gen_c(versions: set[str], typs: list[idl.UserType]) -> str:
# marshal_* ################################################################
ret += c_marshal.gen_c_marshal(versions, typs)
- # *_format #################################################################
- ret += c_format.gen_c_format(versions, typs)
+ # fmt_print_* ##############################################################
+ ret += c_fmt_print.gen_c_fmt_print(versions, typs)
# tables.h #################################################################
ret += """
@@ -121,21 +112,15 @@ def gen_c(versions: set[str], typs: list[idl.UserType]) -> str:
ret += "\n"
ret += f"const struct {c9util.ident('_ver_tentry')} {c9util.ident('_table_ver')}[{c9util.ver_enum('NUM')}] = {{\n"
rerror = next(typ for typ in typs if typ.typname == "Rerror")
- for ver in ["unknown", *sorted(versions)]:
- # XXX: There are good arguments that min_msg_size should be
- # something larger than rerror.min_size().
- # srv.c:respond_error() assumes that min_msg_size is
- # rerror.min_size(); if you do change min_msg_size to
- # something larger, then be sure to update respond_error().
- if ver == "unknown":
- min_msg_size = rerror.min_size("9P2000") # SPECIAL (initialization)
- else:
- ret += cutil.ifdef_push(1, c9util.ver_ifdef({ver}))
- min_msg_size = rerror.min_size(ver)
- if ver == "9P2000.L": # SPECIAL (9P2000.L)
- rlerror = next(typ for typ in typs if typ.typname == "Rlerror")
- min_msg_size = rlerror.min_size(ver)
- ret += f'\t[{c9util.ver_enum(ver)}] = {{.name="{ver}", .min_msg_size={min_msg_size}}},\n'
+ rlerror = next(typ for typ in typs if typ.typname == "Rlerror")
+ rread = next(typ for typ in typs if typ.typname == "Rread")
+ for ver in sorted(versions):
+ ret += cutil.ifdef_push(1, c9util.ver_ifdef({ver}))
+ min_rerror_size = rerror.min_size(ver)
+ if ver == "9P2000.L": # SPECIAL (9P2000.L)
+ min_rerror_size = rlerror.min_size(ver)
+ min_rread_size = rread.min_size(ver)
+ ret += f'\t[{c9util.ver_enum(ver)}] = {{.name="{ver}", .min_Rerror_size={min_rerror_size}, .min_Rread_size={min_rread_size}}},\n'
ret += cutil.ifdef_pop(0)
ret += "};\n"
@@ -143,19 +128,14 @@ def gen_c(versions: set[str], typs: list[idl.UserType]) -> str:
cstruct: str, cname: str, each: str, _range: tuple[int, int, int]
) -> str:
ret = f"const struct {c9util.ident(cstruct)} {c9util.ident(cname)}[{c9util.ver_enum('NUM')}][{hex(len(range(*_range)))}] = {{\n"
- for ver in ["unknown", *sorted(versions)]:
- if ver != "unknown":
- ret += cutil.ifdef_push(1, c9util.ver_ifdef({ver}))
+ for ver in sorted(versions):
+ ret += cutil.ifdef_push(1, c9util.ver_ifdef({ver}))
ret += f"\t[{c9util.ver_enum(ver)}] = {{\n"
for n in range(*_range):
xmsg: idl.Message | None = id2typ.get(n, None)
if xmsg:
- if ver == "unknown": # SPECIAL (initialization)
- if xmsg.typname not in ["Tversion", "Rversion", "Rerror"]:
- xmsg = None
- else:
- if ver not in xmsg.in_versions:
- xmsg = None
+ if ver not in xmsg.in_versions:
+ xmsg = None
if xmsg:
ret += f"\t\t{each}({xmsg.typname}),\n"
ret += "\t},\n"
@@ -166,8 +146,8 @@ def gen_c(versions: set[str], typs: list[idl.UserType]) -> str:
ret += "\n"
ret += cutil.macro(
f"#define _MSG(typ) [{c9util.Ident('TYP_')}##typ] = {{\n"
- f"\t\t.name = #typ,\n"
- f"\t\t.box_as_fmt_formatter = (_box_as_fmt_formatter_fn_t)lo_box_{c9util.ident('msg_')}##typ##_as_fmt_formatter,\n"
+ f"\t\t.name = #typ,\n"
+ f"\t\t.print = (_print_fn_t)fmt_print_##typ,\n"
f"\t}}\n"
)
ret += msg_table("_msg_tentry", "_table_msg", "_MSG", (0, 0x100, 1))
@@ -194,7 +174,8 @@ def gen_c(versions: set[str], typs: list[idl.UserType]) -> str:
ret += msg_table("_send_tentry", "_table_Rmsg_send", "_MSG_SEND", (1, 0x100, 2))
ret += f"""
-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) {{
+{cutil.ifdef_push(1, c9util.ver_ifdef(next(typ for typ in typs if typ.typname == 'stat').in_versions)).rstrip()}
+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) {{
@@ -203,7 +184,7 @@ LM_FLATTEN void {c9util.ident('_stat_unmarshal')}(struct lib9p_ctx *ctx, uint8_t
LM_FLATTEN bool {c9util.ident('_stat_marshal')}(struct lib9p_ctx *ctx, struct {c9util.ident('stat')} *val, struct _marshal_ret *ret) {{
\treturn marshal_stat(ctx, val, ret);
}}
-"""
+{cutil.ifdef_pop(0)}"""
############################################################################
return ret
diff --git a/lib9p/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_format.py b/lib9p/core_gen/c_fmt_print.py
index f9eee90..7a0a9d3 100644
--- a/lib9p/core_gen/c_format.py
+++ b/lib9p/core_gen/c_fmt_print.py
@@ -1,4 +1,4 @@
-# lib9p/core_gen/c_format.py - Generate C pretty-print functions
+# lib9p/core_gen/c_fmt_print.py - Generate C pretty-print functions
#
# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
# SPDX-License-Identifier: AGPL-3.0-or-later
@@ -6,14 +6,14 @@
import idl
-from . import c9util, cutil
+from . import c9util, cutil, idlutil
# This strives to be "general-purpose" in that it just acts on the
# *.9p inputs; but (unfortunately?) there are a few special-cases in
# this script, marked with "SPECIAL".
# pylint: disable=unused-variable
-__all__ = ["gen_c_format"]
+__all__ = ["gen_c_fmt_print"]
def bf_numname(typ: idl.Bitfield, num: idl.BitNum, base: str) -> str:
@@ -21,46 +21,34 @@ def bf_numname(typ: idl.Bitfield, num: idl.BitNum, base: str) -> str:
return c9util.Ident(c9util.add_prefix(prefix, base))
-def ext_printf(line: str) -> str:
- assert line.startswith("\t")
- assert line.endswith("\n")
- # It sucks that %v trips -Wformat and -Wformat-extra-args
- # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47781
- ret = "#pragma GCC diagnostic push\n"
- ret += '#pragma GCC diagnostic ignored "-Wformat"\n'
- ret += '#pragma GCC diagnostic ignored "-Wformat-extra-args"\n'
- ret += line
- ret += "#pragma GCC diagnostic pop\n"
- return ret
-
-
-def gen_c_format(versions: set[str], typs: list[idl.UserType]) -> str:
+def gen_c_fmt_print(versions: set[str], typs: list[idl.UserType]) -> str:
ret = """
-/* *_format *******************************************************************/
+/* fmt_print_* ****************************************************************/
"""
- for typ in typs:
+ for typ in idlutil.topo_sorted(typs):
ret += "\n"
ret += cutil.ifdef_push(1, c9util.ver_ifdef(typ.in_versions))
- ret += f"static void {c9util.basename(typ)}_format({c9util.typename(typ)} *self, struct fmt_state *state) {{\n"
+ storage = "" if typ.typname == "stat" else "static " # SPECIAL (stat is public)
+ ret += f"[[maybe_unused]] {storage}void fmt_print_{typ.typname}(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, {c9util.typename(typ)} *self) {{\n"
match typ:
case idl.Number():
if typ.vals:
ret += "\tswitch (*self) {\n"
for name in typ.vals:
ret += f"\tcase {c9util.Ident(c9util.add_prefix(f'{typ.typname}_'.upper(), name))}:\n"
- ret += f'\t\tfmt_state_puts(state, "{name}");\n'
+ ret += f'\t\tfmt_print_str(w, "{name}");\n'
ret += "\t\tbreak;\n"
ret += "\tdefault:\n"
- ret += f'\t\tfmt_state_printf(state, "%"PRIu{typ.static_size*8}, *self);\n'
+ ret += "\t\tfmt_print_base10(w, *self);\n"
ret += "\t}\n"
else:
- ret += f'\t\tfmt_state_printf(state, "%"PRIu{typ.static_size*8}, *self);\n'
+ ret += "\t\tfmt_print_base10(w, *self);\n"
case idl.Bitfield():
val = "*self"
if typ.typname == "dm": # SPECIAL (pretty file permissions)
val = f"(*self & ~(({c9util.typename(typ)})0777))"
ret += "\tbool empty = true;\n"
- ret += "\tfmt_state_putchar(state, '(');\n"
+ ret += "\tfmt_print_byte(w, '(');\n"
nums: set[str] = set()
for bit in reversed(typ.bits):
@@ -72,8 +60,8 @@ def gen_c_format(versions: set[str], typs: list[idl.UserType]) -> str:
bitname = bit.bitname
ret += f"\tif ({val} & (UINT{typ.static_size*8}_C(1)<<{bit.num})) {{\n"
ret += "\t\tif (!empty)\n"
- ret += "\t\t\tfmt_state_putchar(state, '|');\n"
- ret += f'\t\tfmt_state_puts(state, "{bitname}");\n'
+ ret += "\t\t\tfmt_print_byte(w, '|');\n"
+ ret += f'\t\tfmt_print_str(w, "{bitname}");\n'
ret += "\t\tempty = false;\n"
ret += "\t}\n"
case idl.BitNum():
@@ -86,34 +74,32 @@ def gen_c_format(versions: set[str], typs: list[idl.UserType]) -> str:
f"{bit.cat.numname}_".upper(), name
)
ret += "\t\tif (!empty)\n"
- ret += "\t\t\tfmt_state_putchar(state, '|');\n"
- ret += f'\t\tfmt_state_puts(state, "{bitname}");\n'
+ ret += "\t\t\tfmt_print_byte(w, '|');\n"
+ ret += f'\t\tfmt_print_str(w, "{bitname}");\n'
ret += "\t\tempty = false;\n"
ret += "\t\tbreak;\n"
ret += "\tdefault:\n"
ret += "\t\tif (!empty)\n"
- ret += "\t\t\tfmt_state_putchar(state, '|');\n"
- ret += f'\t\tfmt_state_printf(state, "%"PRIu{typ.static_size*8}, {val} & {bf_numname(typ, bit.cat, 'MASK')});\n'
+ ret += "\t\t\tfmt_print_byte(w, '|');\n"
+ ret += f"\t\tfmt_print_base10(w, {val} & {bf_numname(typ, bit.cat, 'MASK')});\n"
ret += "\t\tempty = false;\n"
ret += "\t}\n"
nums.add(bit.cat.numname)
if typ.typname == "dm": # SPECIAL (pretty file permissions)
ret += "\tif (!empty)\n"
- ret += "\t\tfmt_state_putchar(state, '|');\n"
- ret += f'\tfmt_state_printf(state, "%#04"PRIo{typ.static_size*8}, *self & 0777);\n'
+ ret += "\t\tfmt_print_byte(w, '|');\n"
+ ret += "\tfmt_print(w, (rjust, 4, '0', (base8, *self & 0777)));\n"
else:
ret += "\tif (empty)\n"
- ret += "\t\tfmt_state_putchar(state, '0');\n"
- ret += "\tfmt_state_putchar(state, ')');\n"
- case idl.Struct(typname="s"): # SPECIAL(string)
- ret += ext_printf(
- '\tfmt_state_printf(state, "%.*q", self->len, self->utf8);\n'
- )
+ ret += "\t\tfmt_print_byte(w, '0');\n"
+ ret += "\tfmt_print_byte(w, ')');\n"
+ case idl.Struct(typname="s"): # SPECIAL (string)
+ ret += "\tfmt_print_qmem(w, self->utf8, self->len);\n"
case idl.Struct(): # and idl.Message():
if isinstance(typ, idl.Message):
- ret += f'\tfmt_state_puts(state, "{typ.typname} {{");\n'
+ ret += f'\tfmt_print_str(w, "{typ.typname} {{");\n'
else:
- ret += "\tfmt_state_putchar(state, '{');\n"
+ ret += "\tfmt_print_byte(w, '{');\n"
for member in typ.members:
if member.val:
continue
@@ -126,36 +112,34 @@ def gen_c_format(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 += ext_printf(
- f'\t\tfmt_state_printf(state, " {member.membname}=%.*q%s",\n'
- f"\t\t\t(int)({cnt_str} < 50 ? {cnt_str} : 50),\n"
- f"\t\t\t(char *)self->{member.membname},\n"
- f'\t\t\t{cnt_str} < 50 ? "" : "...");\n'
- )
+ ret += 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"
+ ret += '\t\t\tfmt_print_str(w, "...");\n'
ret += "\t} else {\n"
- ret += f'\t\tfmt_state_puts(state, " {member.membname}=<bytedata>");\n'
+ ret += f'\t\tfmt_print_str(w, " {member.membname}=<bytedata>");\n'
ret += "\t}\n"
continue
- ret += f'\tfmt_state_puts(state, " {member.membname}=[");\n'
+ ret += f'\tfmt_print_str(w, " {member.membname}=[");\n'
ret += f"\tfor ({cnt_typ} i = 0; i < {cnt_str}; i++) {{\n"
ret += "\t\tif (i)\n"
- ret += "\t\t\tfmt_state_putchar(state, ',');\n"
- ret += "\t\tfmt_state_putchar(state, ' ');\n"
+ ret += "\t\t\tfmt_print_byte(w, ',');\n"
+ ret += "\t\tfmt_print_byte(w, ' ');\n"
if isinstance(member.typ, idl.Primitive):
- ret += f'\t\tfmt_state_printf(state, "%"PRIu{member.typ.static_size*8}, self->{member.membname}[i]);\n'
+ ret += f"\t\tfmt_print_base10(w, self->{member.membname}[i]);\n"
else:
- ret += f"\t\t{c9util.basename(member.typ)}_format(&self->{member.membname}[i], state);\n"
+ ret += f"\t\tfmt_print_{member.typ.typname}(w, ctx, &self->{member.membname}[i]);\n"
ret += "\t}\n"
- ret += '\tfmt_state_puts(state, " ]");\n'
+ ret += '\tfmt_print_str(w, " ]");\n'
else:
- ret += f'\tfmt_state_puts(state, " {member.membname}=");\n'
+ ret += f'\tfmt_print_str(w, " {member.membname}=");\n'
if isinstance(member.typ, idl.Primitive):
- ret += f'\tfmt_state_printf(state, "%"PRIu{member.typ.static_size*8}, self->{member.membname});\n'
+ ret += f"\tfmt_print_base10(w, self->{member.membname});\n"
else:
- ret += f"\t{c9util.basename(member.typ)}_format(&self->{member.membname}, state);\n"
+ ret += f"\tfmt_print_{member.typ.typname}(w, ctx, &self->{member.membname});\n"
ret += cutil.ifdef_pop(1)
- ret += '\tfmt_state_puts(state, " }");\n'
+ ret += '\tfmt_print_str(w, " }");\n'
ret += "}\n"
ret += cutil.ifdef_pop(0)
diff --git a/lib9p/core_gen/c_marshal.py b/lib9p/core_gen/c_marshal.py
index 620bdea..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,27 +365,30 @@ 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)
+ szbits = 32
if max_size > cutil.UINT32_MAX: # SPECIAL (9P2000.e)
- ret += get_offset_expr(typ, go_to_end).gen_c(
- "uint64_t", "needed_size", "val->", 1, 0
- )
+ szbits = 64
+ ret += get_offset_expr(typ, go_to_end).gen_c(
+ f"uint{szbits}_t", "needed_size", "val->", 1, 0
+ )
+ if szbits > 32: # SPECIAL (9P2000.e)
ret += "\tif (needed_size > (uint64_t)(ctx->max_msg_size)) {\n"
else:
- ret += get_offset_expr(typ, go_to_end).gen_c(
- "uint32_t", "needed_size", "val->", 1, 0
- )
ret += "\tif (needed_size > ctx->max_msg_size) {\n"
- if isinstance(typ, idl.Message): # SPECIAL (disable for stat)
- ret += f'\t\tlib9p_errorf(ctx, {c9util.IDENT("ERRNO_L_ERANGE")}, "%s message too large to marshal into %s limit (limit=%"PRIu32")",\n'
- ret += f'\t\t\t"{typ.typname}",\n'
- ret += f'\t\t\tctx->version ? "negotiated" : "{'client' if typ.msgid % 2 == 0 else 'server'}",\n'
- ret += "\t\t\tctx->max_msg_size);\n"
- ret += "\t\treturn true;\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}\n"
# Pass 2 - write data
@@ -397,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_unmarshal.py b/lib9p/core_gen/c_unmarshal.py
index 1afbe1d..206a85b 100644
--- a/lib9p/core_gen/c_unmarshal.py
+++ b/lib9p/core_gen/c_unmarshal.py
@@ -123,9 +123,9 @@ def gen_c_unmarshal(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 void unmarshal_{typ.typname}([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {{\n"
+ ret += f"static void unmarshal_{typ.typname}([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {{\n"
ret += f"\t{c9util.typename(typ)} *out = out_buf;\n"
- ret += "\t[[gnu::unused]] void *extra = &out[1];\n"
+ ret += "\t[[maybe_unused]] void *extra = &out[1];\n"
ret += "\tuint32_t net_offset = 0;\n"
indent_stack = [IndentLevel(ifdef=True)]
diff --git a/lib9p/core_gen/c_validate.py b/lib9p/core_gen/c_validate.py
index 3073ed0..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_errorf(ctx, {c9util.IDENT("ERRNO_L_EBADMSG")}, "message is too short for content (%"PRIu32" > %"PRIu32") @ %d", net_offset, net_size, __LINE__);\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"
@@ -190,11 +190,10 @@ def gen_c_validate(versions: set[str], typs: list[idl.UserType]) -> str:
for tok in child.val.tokens
):
nbits = 32
- act = f"(uint{nbits}_t)GET_U{nbits}LE({lookup_sym(f'&{child.membname}')})"
- exp = f"(uint{nbits}_t)({c9util.idl_expr(child.val, lookup_sym)})"
+ 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_errorf(ctx, {c9util.IDENT("ERRNO_L_EBADMSG")}, "{path} value is wrong: actual: %"PRIu{nbits}" != correct:%"PRIu{nbits},\n'
- ret += f"{'\t'*(indent_lvl()+2)}{act}, {exp});\n"
+ 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
@@ -205,19 +204,18 @@ def gen_c_validate(versions: set[str], typs: list[idl.UserType]) -> str:
for tok in child.max.tokens
):
nbits = 32
- act = f"(uint{nbits}_t)GET_U{nbits}LE({lookup_sym(f'&{child.membname}')})"
- exp = f"(uint{nbits}_t)({c9util.idl_expr(child.max, lookup_sym)})"
+ 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_errorf(ctx, {c9util.IDENT("ERRNO_L_EBADMSG")}, "{path} value is too large: %"PRIu{nbits}" > %"PRIu{nbits},\n'
- ret += f"{'\t'*(indent_lvl()+2)}{act}, {exp});\n"
+ 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_errorf(ctx, {c9util.IDENT("ERRNO_L_EBADMSG")}, "unknown bits in {child.typ.typname} bitfield: %#0{nbytes*2}"PRIx{nbits},\n'
- ret += f"{'\t'*(indent_lvl()+2)}{act} & ~{child.typ.typname}_masks[ctx->version]);\n"
+ 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,
@@ -273,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)]
@@ -293,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 3defcb8..eba1492 100644
--- a/lib9p/core_gen/h.py
+++ b/lib9p/core_gen/h.py
@@ -162,21 +162,13 @@ 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
-
-#include <stdint.h> /* for uint{{n}}_t types */
-
-#include <libfmt/fmt.h> /* for fmt_formatter */
-#include <libhw/generic/io.h> /* for struct iovec */
"""
-
id2typ: dict[int, idl.Message] = {}
for msg in [msg for msg in typs if isinstance(msg, idl.Message)]:
id2typ[msg.msgid] = msg
ret += """
/* config *********************************************************************/
-
-#include "config.h"
"""
for ver in sorted(versions):
ret += "\n"
@@ -192,14 +184,21 @@ def gen_h(versions: set[str], typs: list[idl.UserType]) -> str:
ret += "\t#endif\n"
ret += "#endif\n"
+ # SPECIAL (convenience)
+ ret += "\n"
+ ret += f"#define _LIB9P_ENABLE_stat {c9util.ver_ifdef(next(typ for typ in typs if typ.typname == 'stat').in_versions)}\n"
+
ret += f"""
/* enum version ***************************************************************/
enum {c9util.ident('version')} {{
"""
- fullversions = ["unknown = 0", *sorted(versions)]
- verwidth = max(len(v) for v in fullversions)
- for ver in fullversions:
+ xversions = [ # SPECIAL (initialization)
+ "uninitialized = 0",
+ *sorted(v for v in versions if v != "uninitialized"),
+ ]
+ verwidth = max(len(v) for v in xversions)
+ for ver in xversions:
if ver in versions:
ret += cutil.ifdef_push(1, c9util.ver_ifdef({ver}))
ret += f"\t{c9util.ver_enum(ver)},"
@@ -207,7 +206,6 @@ enum {c9util.ident('version')} {{
ret += cutil.ifdef_pop(0)
ret += f"\t{c9util.ver_enum('NUM')},\n"
ret += "};\n"
- ret += f"LO_IMPLEMENTATION_H(fmt_formatter, enum {c9util.ident('version')}, {c9util.ident('version')});\n"
ret += """
/* enum msg_type **************************************************************/
@@ -223,7 +221,6 @@ enum {c9util.ident('version')} {{
ret += f"\t{c9util.Ident(f'TYP_{msg.typname:<{namewidth}}')} = {msg.msgid},\n"
ret += cutil.ifdef_pop(0)
ret += "};\n"
- ret += f"LO_IMPLEMENTATION_H(fmt_formatter, enum {c9util.ident('msg_type')}, {c9util.ident('msg_type')});\n"
ret += """
/* payload types **************************************************************/
@@ -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"
@@ -364,7 +361,6 @@ enum {c9util.ident('version')} {{
def gen_number(typ: idl.Number) -> str:
ret = f"typedef {c9util.typename(typ.prim)} {c9util.typename(typ)};\n"
- ret += f"LO_IMPLEMENTATION_H(fmt_formatter, {c9util.typename(typ)}, {c9util.basename(typ)});\n"
def lookup_sym(sym: str) -> str:
assert False
@@ -383,7 +379,6 @@ def gen_number(typ: idl.Number) -> str:
def gen_bitfield(typ: idl.Bitfield) -> str:
ret = f"typedef {c9util.typename(typ.prim)} {c9util.typename(typ)};\n"
- ret += f"LO_IMPLEMENTATION_H(fmt_formatter, {c9util.typename(typ)}, {c9util.basename(typ)});\n"
def lookup_sym(sym: str) -> str:
assert False
@@ -531,5 +526,4 @@ def gen_struct(typ: idl.Struct) -> str: # and idl.Message
ret += f"\t{c9util.typename(member.typ, member):<{typewidth}} {'*' if member.cnt else ' '}{member.membname};\n"
ret += cutil.ifdef_pop(1)
ret += "};\n"
- ret += f"LO_IMPLEMENTATION_H(fmt_formatter, {c9util.typename(typ)}, {c9util.basename(typ)});\n"
return ret
diff --git a/lib9p/core_generated.c b/lib9p/core_generated.c
index 1789bdc..5acc551 100644
--- a/lib9p/core_generated.c
+++ b/lib9p/core_generated.c
@@ -1,141 +1,15 @@
-/* Generated by `lib9p/core.gen lib9p/idl/2002-9P2000.9p lib9p/idl/2003-9P2000.p9p.9p lib9p/idl/2005-9P2000.u.9p lib9p/idl/2010-9P2000.L.9p lib9p/idl/2012-9P2000.e.9p`. DO NOT EDIT! */
+/* Generated by `lib9p/core.gen lib9p/idl/0000-uninitialized.9p lib9p/idl/2002-9P2000.9p lib9p/idl/2003-9P2000.p9p.9p lib9p/idl/2005-9P2000.u.9p lib9p/idl/2010-9P2000.L.9p lib9p/idl/2012-9P2000.e.9p`. DO NOT EDIT! */
-#include <stdbool.h>
-#include <stddef.h> /* for size_t */
-#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"
-
-/* libobj vtables *************************************************************/
-#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
-LO_IMPLEMENTATION_C(fmt_formatter, lib9p_tag_t, lib9p_tag, static);
-LO_IMPLEMENTATION_C(fmt_formatter, lib9p_fid_t, lib9p_fid, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_s, lib9p_s, static);
-#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
-#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
-LO_IMPLEMENTATION_C(fmt_formatter, lib9p_dm_t, lib9p_dm, static);
-#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
-#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
-LO_IMPLEMENTATION_C(fmt_formatter, lib9p_qt_t, lib9p_qt, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_qid, lib9p_qid, static);
-#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
-#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_stat, lib9p_stat, static);
-LO_IMPLEMENTATION_C(fmt_formatter, lib9p_o_t, lib9p_o, static);
-#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
-#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tversion, lib9p_msg_Tversion, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rversion, lib9p_msg_Rversion, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tauth, lib9p_msg_Tauth, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rauth, lib9p_msg_Rauth, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tattach, lib9p_msg_Tattach, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rattach, lib9p_msg_Rattach, static);
-#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
-#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rerror, lib9p_msg_Rerror, static);
-#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
-#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tflush, lib9p_msg_Tflush, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rflush, lib9p_msg_Rflush, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Twalk, lib9p_msg_Twalk, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rwalk, lib9p_msg_Rwalk, static);
-#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
-#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Topen, lib9p_msg_Topen, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Ropen, lib9p_msg_Ropen, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tcreate, lib9p_msg_Tcreate, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rcreate, lib9p_msg_Rcreate, static);
-#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
-#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tread, lib9p_msg_Tread, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rread, lib9p_msg_Rread, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Twrite, lib9p_msg_Twrite, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rwrite, lib9p_msg_Rwrite, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tclunk, lib9p_msg_Tclunk, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rclunk, lib9p_msg_Rclunk, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tremove, lib9p_msg_Tremove, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rremove, lib9p_msg_Rremove, static);
-#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
-#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tstat, lib9p_msg_Tstat, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rstat, lib9p_msg_Rstat, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Twstat, lib9p_msg_Twstat, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rwstat, lib9p_msg_Rwstat, static);
-#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
-#if CONFIG_9P_ENABLE_9P2000_p9p
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Topenfd, lib9p_msg_Topenfd, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Ropenfd, lib9p_msg_Ropenfd, static);
-#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
-#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u
-LO_IMPLEMENTATION_C(fmt_formatter, lib9p_nuid_t, lib9p_nuid, static);
-LO_IMPLEMENTATION_C(fmt_formatter, lib9p_errno_t, lib9p_errno, static);
-#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
-#if CONFIG_9P_ENABLE_9P2000_L
-LO_IMPLEMENTATION_C(fmt_formatter, lib9p_super_magic_t, lib9p_super_magic, static);
-LO_IMPLEMENTATION_C(fmt_formatter, lib9p_lo_t, lib9p_lo, static);
-LO_IMPLEMENTATION_C(fmt_formatter, lib9p_dt_t, lib9p_dt, static);
-LO_IMPLEMENTATION_C(fmt_formatter, lib9p_mode_t, lib9p_mode, static);
-LO_IMPLEMENTATION_C(fmt_formatter, lib9p_b4_t, lib9p_b4, static);
-LO_IMPLEMENTATION_C(fmt_formatter, lib9p_getattr_t, lib9p_getattr, static);
-LO_IMPLEMENTATION_C(fmt_formatter, lib9p_setattr_t, lib9p_setattr, static);
-LO_IMPLEMENTATION_C(fmt_formatter, lib9p_lock_type_t, lib9p_lock_type, static);
-LO_IMPLEMENTATION_C(fmt_formatter, lib9p_lock_flags_t, lib9p_lock_flags, static);
-LO_IMPLEMENTATION_C(fmt_formatter, lib9p_lock_status_t, lib9p_lock_status, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rlerror, lib9p_msg_Rlerror, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tstatfs, lib9p_msg_Tstatfs, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rstatfs, lib9p_msg_Rstatfs, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tlopen, lib9p_msg_Tlopen, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rlopen, lib9p_msg_Rlopen, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tlcreate, lib9p_msg_Tlcreate, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rlcreate, lib9p_msg_Rlcreate, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tsymlink, lib9p_msg_Tsymlink, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rsymlink, lib9p_msg_Rsymlink, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tmknod, lib9p_msg_Tmknod, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rmknod, lib9p_msg_Rmknod, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Trename, lib9p_msg_Trename, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rrename, lib9p_msg_Rrename, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Treadlink, lib9p_msg_Treadlink, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rreadlink, lib9p_msg_Rreadlink, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tgetattr, lib9p_msg_Tgetattr, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rgetattr, lib9p_msg_Rgetattr, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tsetattr, lib9p_msg_Tsetattr, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rsetattr, lib9p_msg_Rsetattr, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Txattrwalk, lib9p_msg_Txattrwalk, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rxattrwalk, lib9p_msg_Rxattrwalk, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Txattrcreate, lib9p_msg_Txattrcreate, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rxattrcreate, lib9p_msg_Rxattrcreate, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Treaddir, lib9p_msg_Treaddir, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rreaddir, lib9p_msg_Rreaddir, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tfsync, lib9p_msg_Tfsync, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rfsync, lib9p_msg_Rfsync, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tlock, lib9p_msg_Tlock, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rlock, lib9p_msg_Rlock, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tgetlock, lib9p_msg_Tgetlock, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rgetlock, lib9p_msg_Rgetlock, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tlink, lib9p_msg_Tlink, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rlink, lib9p_msg_Rlink, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tmkdir, lib9p_msg_Tmkdir, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rmkdir, lib9p_msg_Rmkdir, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Trenameat, lib9p_msg_Trenameat, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rrenameat, lib9p_msg_Rrenameat, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tunlinkat, lib9p_msg_Tunlinkat, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Runlinkat, lib9p_msg_Runlinkat, static);
-#endif /* CONFIG_9P_ENABLE_9P2000_L */
-#if CONFIG_9P_ENABLE_9P2000_e
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tsession, lib9p_msg_Tsession, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rsession, lib9p_msg_Rsession, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tsread, lib9p_msg_Tsread, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rsread, lib9p_msg_Rsread, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tswrite, lib9p_msg_Tswrite, static);
-LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rswrite, lib9p_msg_Rswrite, static);
-#endif /* CONFIG_9P_ENABLE_9P2000_e */
/* utilities ******************************************************************/
#if CONFIG_9P_ENABLE_9P2000
@@ -163,6 +37,11 @@ LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rswrite, lib9p_msg_Rswrite,
#else
#define _is_ver_9P2000_u(v) false
#endif
+#if CONFIG_9P_ENABLE_uninitialized
+ #define _is_ver_uninitialized(v) (v == LIB9P_VER_uninitialized)
+#else
+ #define _is_ver_uninitialized(v) false
+#endif
/**
* is_ver(ctx, ver) is essentially `(ctx->version == LIB9P_VER_##ver)`, but
@@ -177,168 +56,192 @@ LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rswrite, lib9p_msg_Rswrite,
#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
static const lib9p_dm_t dm_masks[LIB9P_VER_NUM] = {
#if CONFIG_9P_ENABLE_9P2000
- [LIB9P_VER_9P2000] = 0b11111100000000000000000111111111,
+ [LIB9P_VER_9P2000] = 0b11111100000000000000000111111111,
#endif /* CONFIG_9P_ENABLE_9P2000 */
#if CONFIG_9P_ENABLE_9P2000_L
- [LIB9P_VER_9P2000_L] = 0b00000000000000000000000000000000,
+ [LIB9P_VER_9P2000_L] = 0b00000000000000000000000000000000,
#endif /* CONFIG_9P_ENABLE_9P2000_L */
#if CONFIG_9P_ENABLE_9P2000_e
- [LIB9P_VER_9P2000_e] = 0b11111100000000000000000111111111,
+ [LIB9P_VER_9P2000_e] = 0b11111100000000000000000111111111,
#endif /* CONFIG_9P_ENABLE_9P2000_e */
#if CONFIG_9P_ENABLE_9P2000_p9p
- [LIB9P_VER_9P2000_p9p] = 0b11111100000000000000000111111111,
+ [LIB9P_VER_9P2000_p9p] = 0b11111100000000000000000111111111,
#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
#if CONFIG_9P_ENABLE_9P2000_u
- [LIB9P_VER_9P2000_u] = 0b11111100101111000000000111111111,
+ [LIB9P_VER_9P2000_u] = 0b11111100101111000000000111111111,
#endif /* CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_uninitialized
+ [LIB9P_VER_uninitialized] = 0b11111100000000000000000111111111,
+#endif /* CONFIG_9P_ENABLE_uninitialized */
};
#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 const lib9p_qt_t qt_masks[LIB9P_VER_NUM] = {
#if CONFIG_9P_ENABLE_9P2000
- [LIB9P_VER_9P2000] = 0b11111100,
+ [LIB9P_VER_9P2000] = 0b11111100,
#endif /* CONFIG_9P_ENABLE_9P2000 */
#if CONFIG_9P_ENABLE_9P2000_L
- [LIB9P_VER_9P2000_L] = 0b11111100,
+ [LIB9P_VER_9P2000_L] = 0b11111100,
#endif /* CONFIG_9P_ENABLE_9P2000_L */
#if CONFIG_9P_ENABLE_9P2000_e
- [LIB9P_VER_9P2000_e] = 0b11111100,
+ [LIB9P_VER_9P2000_e] = 0b11111100,
#endif /* CONFIG_9P_ENABLE_9P2000_e */
#if CONFIG_9P_ENABLE_9P2000_p9p
- [LIB9P_VER_9P2000_p9p] = 0b11111100,
+ [LIB9P_VER_9P2000_p9p] = 0b11111100,
#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
#if CONFIG_9P_ENABLE_9P2000_u
- [LIB9P_VER_9P2000_u] = 0b11111110,
+ [LIB9P_VER_9P2000_u] = 0b11111110,
#endif /* CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_uninitialized
+ [LIB9P_VER_uninitialized] = 0b11111100,
+#endif /* CONFIG_9P_ENABLE_uninitialized */
};
#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 const lib9p_o_t o_masks[LIB9P_VER_NUM] = {
#if CONFIG_9P_ENABLE_9P2000
- [LIB9P_VER_9P2000] = 0b01010011,
+ [LIB9P_VER_9P2000] = 0b01010011,
#endif /* CONFIG_9P_ENABLE_9P2000 */
#if CONFIG_9P_ENABLE_9P2000_L
- [LIB9P_VER_9P2000_L] = 0b00000000,
+ [LIB9P_VER_9P2000_L] = 0b00000000,
#endif /* CONFIG_9P_ENABLE_9P2000_L */
#if CONFIG_9P_ENABLE_9P2000_e
- [LIB9P_VER_9P2000_e] = 0b01010011,
+ [LIB9P_VER_9P2000_e] = 0b01010011,
#endif /* CONFIG_9P_ENABLE_9P2000_e */
#if CONFIG_9P_ENABLE_9P2000_p9p
- [LIB9P_VER_9P2000_p9p] = 0b01010011,
+ [LIB9P_VER_9P2000_p9p] = 0b01010011,
#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
#if CONFIG_9P_ENABLE_9P2000_u
- [LIB9P_VER_9P2000_u] = 0b01010011,
+ [LIB9P_VER_9P2000_u] = 0b01010011,
#endif /* CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_uninitialized
+ [LIB9P_VER_uninitialized] = 0b00000000,
+#endif /* CONFIG_9P_ENABLE_uninitialized */
};
#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
#if CONFIG_9P_ENABLE_9P2000_L
static const lib9p_lo_t lo_masks[LIB9P_VER_NUM] = {
#if CONFIG_9P_ENABLE_9P2000
- [LIB9P_VER_9P2000] = 0b00000000000000000000000000000000,
+ [LIB9P_VER_9P2000] = 0b00000000000000000000000000000000,
#endif /* CONFIG_9P_ENABLE_9P2000 */
- [LIB9P_VER_9P2000_L] = 0b00000000000111111111111111000011,
+ [LIB9P_VER_9P2000_L] = 0b00000000000111111111111111000011,
#if CONFIG_9P_ENABLE_9P2000_e
- [LIB9P_VER_9P2000_e] = 0b00000000000000000000000000000000,
+ [LIB9P_VER_9P2000_e] = 0b00000000000000000000000000000000,
#endif /* CONFIG_9P_ENABLE_9P2000_e */
#if CONFIG_9P_ENABLE_9P2000_p9p
- [LIB9P_VER_9P2000_p9p] = 0b00000000000000000000000000000000,
+ [LIB9P_VER_9P2000_p9p] = 0b00000000000000000000000000000000,
#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
#if CONFIG_9P_ENABLE_9P2000_u
- [LIB9P_VER_9P2000_u] = 0b00000000000000000000000000000000,
+ [LIB9P_VER_9P2000_u] = 0b00000000000000000000000000000000,
#endif /* CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_uninitialized
+ [LIB9P_VER_uninitialized] = 0b00000000000000000000000000000000,
+#endif /* CONFIG_9P_ENABLE_uninitialized */
};
static const lib9p_mode_t mode_masks[LIB9P_VER_NUM] = {
#if CONFIG_9P_ENABLE_9P2000
- [LIB9P_VER_9P2000] = 0b00000000000000000000000000000000,
+ [LIB9P_VER_9P2000] = 0b00000000000000000000000000000000,
#endif /* CONFIG_9P_ENABLE_9P2000 */
- [LIB9P_VER_9P2000_L] = 0b00000000000000001111111111111111,
+ [LIB9P_VER_9P2000_L] = 0b00000000000000001111111111111111,
#if CONFIG_9P_ENABLE_9P2000_e
- [LIB9P_VER_9P2000_e] = 0b00000000000000000000000000000000,
+ [LIB9P_VER_9P2000_e] = 0b00000000000000000000000000000000,
#endif /* CONFIG_9P_ENABLE_9P2000_e */
#if CONFIG_9P_ENABLE_9P2000_p9p
- [LIB9P_VER_9P2000_p9p] = 0b00000000000000000000000000000000,
+ [LIB9P_VER_9P2000_p9p] = 0b00000000000000000000000000000000,
#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
#if CONFIG_9P_ENABLE_9P2000_u
- [LIB9P_VER_9P2000_u] = 0b00000000000000000000000000000000,
+ [LIB9P_VER_9P2000_u] = 0b00000000000000000000000000000000,
#endif /* CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_uninitialized
+ [LIB9P_VER_uninitialized] = 0b00000000000000000000000000000000,
+#endif /* CONFIG_9P_ENABLE_uninitialized */
};
static const lib9p_getattr_t getattr_masks[LIB9P_VER_NUM] = {
#if CONFIG_9P_ENABLE_9P2000
- [LIB9P_VER_9P2000] = 0b0000000000000000000000000000000000000000000000000000000000000000,
+ [LIB9P_VER_9P2000] = 0b0000000000000000000000000000000000000000000000000000000000000000,
#endif /* CONFIG_9P_ENABLE_9P2000 */
- [LIB9P_VER_9P2000_L] = 0b0000000000000000000000000000000000000000000000000011111111111111,
+ [LIB9P_VER_9P2000_L] = 0b0000000000000000000000000000000000000000000000000011111111111111,
#if CONFIG_9P_ENABLE_9P2000_e
- [LIB9P_VER_9P2000_e] = 0b0000000000000000000000000000000000000000000000000000000000000000,
+ [LIB9P_VER_9P2000_e] = 0b0000000000000000000000000000000000000000000000000000000000000000,
#endif /* CONFIG_9P_ENABLE_9P2000_e */
#if CONFIG_9P_ENABLE_9P2000_p9p
- [LIB9P_VER_9P2000_p9p] = 0b0000000000000000000000000000000000000000000000000000000000000000,
+ [LIB9P_VER_9P2000_p9p] = 0b0000000000000000000000000000000000000000000000000000000000000000,
#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
#if CONFIG_9P_ENABLE_9P2000_u
- [LIB9P_VER_9P2000_u] = 0b0000000000000000000000000000000000000000000000000000000000000000,
+ [LIB9P_VER_9P2000_u] = 0b0000000000000000000000000000000000000000000000000000000000000000,
#endif /* CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_uninitialized
+ [LIB9P_VER_uninitialized] = 0b0000000000000000000000000000000000000000000000000000000000000000,
+#endif /* CONFIG_9P_ENABLE_uninitialized */
};
static const lib9p_setattr_t setattr_masks[LIB9P_VER_NUM] = {
#if CONFIG_9P_ENABLE_9P2000
- [LIB9P_VER_9P2000] = 0b00000000000000000000000000000000,
+ [LIB9P_VER_9P2000] = 0b00000000000000000000000000000000,
#endif /* CONFIG_9P_ENABLE_9P2000 */
- [LIB9P_VER_9P2000_L] = 0b00000000000000000000000111111111,
+ [LIB9P_VER_9P2000_L] = 0b00000000000000000000000111111111,
#if CONFIG_9P_ENABLE_9P2000_e
- [LIB9P_VER_9P2000_e] = 0b00000000000000000000000000000000,
+ [LIB9P_VER_9P2000_e] = 0b00000000000000000000000000000000,
#endif /* CONFIG_9P_ENABLE_9P2000_e */
#if CONFIG_9P_ENABLE_9P2000_p9p
- [LIB9P_VER_9P2000_p9p] = 0b00000000000000000000000000000000,
+ [LIB9P_VER_9P2000_p9p] = 0b00000000000000000000000000000000,
#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
#if CONFIG_9P_ENABLE_9P2000_u
- [LIB9P_VER_9P2000_u] = 0b00000000000000000000000000000000,
+ [LIB9P_VER_9P2000_u] = 0b00000000000000000000000000000000,
#endif /* CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_uninitialized
+ [LIB9P_VER_uninitialized] = 0b00000000000000000000000000000000,
+#endif /* CONFIG_9P_ENABLE_uninitialized */
};
static const lib9p_lock_flags_t lock_flags_masks[LIB9P_VER_NUM] = {
#if CONFIG_9P_ENABLE_9P2000
- [LIB9P_VER_9P2000] = 0b00000000000000000000000000000000,
+ [LIB9P_VER_9P2000] = 0b00000000000000000000000000000000,
#endif /* CONFIG_9P_ENABLE_9P2000 */
- [LIB9P_VER_9P2000_L] = 0b00000000000000000000000000000011,
+ [LIB9P_VER_9P2000_L] = 0b00000000000000000000000000000011,
#if CONFIG_9P_ENABLE_9P2000_e
- [LIB9P_VER_9P2000_e] = 0b00000000000000000000000000000000,
+ [LIB9P_VER_9P2000_e] = 0b00000000000000000000000000000000,
#endif /* CONFIG_9P_ENABLE_9P2000_e */
#if CONFIG_9P_ENABLE_9P2000_p9p
- [LIB9P_VER_9P2000_p9p] = 0b00000000000000000000000000000000,
+ [LIB9P_VER_9P2000_p9p] = 0b00000000000000000000000000000000,
#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
#if CONFIG_9P_ENABLE_9P2000_u
- [LIB9P_VER_9P2000_u] = 0b00000000000000000000000000000000,
+ [LIB9P_VER_9P2000_u] = 0b00000000000000000000000000000000,
#endif /* CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_uninitialized
+ [LIB9P_VER_uninitialized] = 0b00000000000000000000000000000000,
+#endif /* CONFIG_9P_ENABLE_uninitialized */
};
#endif /* CONFIG_9P_ENABLE_9P2000_L */
/* validate_* *****************************************************************/
-#define VALIDATE_NET_BYTES(n) \
- if (__builtin_add_overflow(net_offset, n, &net_offset)) \
- /* If needed-net-size overflowed uint32_t, then \
- * there's no way that actual-net-size will live up to \
- * that. */ \
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "message is too short for content"); \
- if (net_offset > net_size) \
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "message is too short for content (%"PRIu32" > %"PRIu32") @ %d", net_offset, net_size, __LINE__);
-#define VALIDATE_NET_UTF8(n) \
- { \
- size_t len = n; \
- VALIDATE_NET_BYTES(len); \
- if (!is_valid_utf8_without_nul(&net_bytes[net_offset-len], len)) \
- return lib9p_error(ctx, LIB9P_ERRNO_L_EBADMSG, "message contains invalid UTF-8"); \
- }
-#define RESERVE_HOST_BYTES(n) \
- if (__builtin_add_overflow(host_size, n, &host_size)) \
- /* If needed-host-size overflowed ssize_t, then there's \
- * no way that actual-net-size will live up to \
- * that. */ \
- return lib9p_error(ctx, 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])
@@ -349,17 +252,17 @@ 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);
- uint32_t offsetof_stat_size = net_offset + 0;
- uint32_t offsetof_kern_type = net_offset + 2;
- uint32_t offsetof_file_qid_type = net_offset + 8;
+ 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_file_qid_type) & ~qt_masks[ctx->version])
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8,
- GET_U8LE(offsetof_file_qid_type) & ~qt_masks[ctx->version]);
- uint32_t offsetof_file_mode = net_offset + 0;
+ if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version])
+ return 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());
VALIDATE_NET_BYTES(2);
@@ -376,56 +279,53 @@ static ssize_t validate_stat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *
}
#endif /* CONFIG_9P_ENABLE_9P2000_u */
uint32_t offsetof_end = net_offset + 0;
- if ((uint32_t)GET_U32LE(offsetof_stat_size) != (uint32_t)(offsetof_end - offsetof_kern_type))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "stat->stat_size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_stat_size), (uint32_t)(offsetof_end - offsetof_kern_type));
- if (GET_U32LE(offsetof_file_mode) & ~dm_masks[ctx->version])
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in dm bitfield: %#08"PRIx32,
- GET_U32LE(offsetof_file_mode) & ~dm_masks[ctx->version]);
+ if (GET_U32LE(offsetof__stat_size) != 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 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
-static ssize_t validate_Tversion(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+#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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tversion->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(100))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tversion->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(100));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rversion->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(101))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rversion->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(101));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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);
}
-static ssize_t validate_Tauth(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+#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 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);
@@ -438,38 +338,34 @@ static ssize_t validate_Tauth(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t
}
#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
uint32_t offsetof_end = net_offset + 0;
- if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tauth->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(102))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tauth->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(102));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8,
- 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rauth->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(103))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rauth->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(103));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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);
@@ -482,40 +378,36 @@ static ssize_t validate_Tattach(struct lib9p_ctx *ctx, uint32_t net_size, uint8_
}
#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
uint32_t offsetof_end = net_offset + 0;
- if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tattach->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(104))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tattach->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(104));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8,
- 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rattach->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(105))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rattach->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(105));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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
-static ssize_t validate_Rerror(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+#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 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);
@@ -526,52 +418,46 @@ static ssize_t validate_Rerror(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t
}
#endif /* CONFIG_9P_ENABLE_9P2000_u */
uint32_t offsetof_end = net_offset + 0;
- if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rerror->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(107))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rerror->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(107));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 */
+#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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tflush->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(108))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tflush->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(108));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rflush->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(109))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rflush->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(109));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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;
@@ -582,21 +468,18 @@ static ssize_t validate_Twalk(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t
VALIDATE_NET_UTF8(LAST_U16LE());
}
uint32_t offsetof_end = net_offset + 0;
- if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Twalk->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(110))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Twalk->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(110));
- if ((uint16_t)GET_U16LE(offsetof_nwname) > (uint16_t)(16))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Twalk->nwname value is too large: %"PRIu16" > %"PRIu16,
- (uint16_t)GET_U16LE(offsetof_nwname), (uint16_t)(16));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 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;
@@ -606,68 +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_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8,
- 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rwalk->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(111))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rwalk->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(111));
- if ((uint16_t)GET_U16LE(offsetof_nwqid) > (uint16_t)(16))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rwalk->nwqid value is too large: %"PRIu16" > %"PRIu16,
- (uint16_t)GET_U16LE(offsetof_nwqid), (uint16_t)(16));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Topen->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(112))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Topen->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(112));
+ if (GET_U32LE(offsetof_size) != 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 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_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in o bitfield: %#02"PRIx8,
- GET_U8LE(offsetof_mode) & ~o_masks[ctx->version]);
- return (ssize_t)host_size;
+ 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_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8,
- 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Ropen->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(113))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Ropen->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(113));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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);
@@ -676,92 +552,81 @@ static ssize_t validate_Tcreate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_
uint32_t offsetof_mode = net_offset + 4;
uint32_t offsetof_end = net_offset + 5;
VALIDATE_NET_BYTES(5);
- if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tcreate->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(114))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tcreate->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(114));
+ if (GET_U32LE(offsetof_size) != 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 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_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in dm bitfield: %#08"PRIx32,
- 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_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in o bitfield: %#02"PRIx8,
- GET_U8LE(offsetof_mode) & ~o_masks[ctx->version]);
- return (ssize_t)host_size;
+ 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_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8,
- 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rcreate->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(115))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rcreate->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(115));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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;
uint32_t offsetof_count = net_offset + 19;
uint32_t offsetof_end = net_offset + 23;
VALIDATE_NET_BYTES(23);
- if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tread->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(116))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tread->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(116));
- if ((uint64_t)GET_U64LE(offsetof_offset) > (uint64_t)(INT64_MAX))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tread->offset value is too large: %"PRIu64" > %"PRIu64,
- (uint64_t)GET_U64LE(offsetof_offset), (uint64_t)(INT64_MAX));
- if ((uint32_t)GET_U32LE(offsetof_count) > (uint32_t)(INT32_MAX))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tread->count value is too large: %"PRIu32" > %"PRIu32,
- (uint32_t)GET_U32LE(offsetof_count), (uint32_t)(INT32_MAX));
- return (ssize_t)host_size;
-}
-
-static ssize_t validate_Rread(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);
+ if (GET_U32LE(offsetof_size) != 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 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 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 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 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;
+ 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;
VALIDATE_NET_BYTES(11);
VALIDATE_NET_BYTES(LAST_U32LE());
uint32_t offsetof_end = net_offset + 0;
- if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rread->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(117))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rread->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(117));
- if ((uint32_t)GET_U32LE(offsetof_count) > (uint32_t)(INT32_MAX))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rread->count value is too large: %"PRIu32" > %"PRIu32,
- (uint32_t)GET_U32LE(offsetof_count), (uint32_t)(INT32_MAX));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 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;
@@ -769,138 +634,121 @@ static ssize_t validate_Twrite(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t
VALIDATE_NET_BYTES(23);
VALIDATE_NET_BYTES(LAST_U32LE());
uint32_t offsetof_end = net_offset + 0;
- if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Twrite->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(118))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Twrite->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(118));
- if ((uint64_t)GET_U64LE(offsetof_offset) > (uint64_t)(INT64_MAX))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Twrite->offset value is too large: %"PRIu64" > %"PRIu64,
- (uint64_t)GET_U64LE(offsetof_offset), (uint64_t)(INT64_MAX));
- if ((uint32_t)GET_U32LE(offsetof_count) > (uint32_t)(INT32_MAX))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Twrite->count value is too large: %"PRIu32" > %"PRIu32,
- (uint32_t)GET_U32LE(offsetof_count), (uint32_t)(INT32_MAX));
- return (ssize_t)host_size;
-}
-
-static ssize_t validate_Rwrite(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);
+ if (GET_U32LE(offsetof_size) != 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 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 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 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 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;
+ 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rwrite->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(119))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rwrite->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(119));
- if ((uint32_t)GET_U32LE(offsetof_count) > (uint32_t)(INT32_MAX))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rwrite->count value is too large: %"PRIu32" > %"PRIu32,
- (uint32_t)GET_U32LE(offsetof_count), (uint32_t)(INT32_MAX));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tclunk->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(120))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tclunk->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(120));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rclunk->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(121))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rclunk->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(121));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tremove->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(122))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tremove->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(122));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rremove->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(123))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rremove->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(123));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tstat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(124))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tstat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(124));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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;
uint32_t offsetof_stat = net_offset + 9;
- uint32_t offsetof_stat_stat_size = net_offset + 9;
- uint32_t offsetof_stat_kern_type = net_offset + 11;
- uint32_t offsetof_stat_file_qid_type = net_offset + 17;
+ uint32_t offsetof_stat__stat_size = net_offset + 9;
+ uint32_t offsetof_stat_fstype = net_offset + 11;
+ uint32_t offsetof_stat_qid_type = net_offset + 17;
VALIDATE_NET_BYTES(30);
- if (GET_U8LE(offsetof_stat_file_qid_type) & ~qt_masks[ctx->version])
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8,
- GET_U8LE(offsetof_stat_file_qid_type) & ~qt_masks[ctx->version]);
- uint32_t offsetof_stat_file_mode = net_offset + 0;
+ if (GET_U8LE(offsetof_stat_qid_type) & ~qt_masks[ctx->version])
+ return 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());
VALIDATE_NET_BYTES(2);
@@ -917,40 +765,36 @@ static ssize_t validate_Rstat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t
}
#endif /* CONFIG_9P_ENABLE_9P2000_u */
uint32_t offsetof_stat_end = net_offset + 0;
- if ((uint32_t)GET_U32LE(offsetof_stat_stat_size) != (uint32_t)(offsetof_stat_end - offsetof_stat_kern_type))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rstat->stat.stat_size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_stat_stat_size), (uint32_t)(offsetof_stat_end - offsetof_stat_kern_type));
- if (GET_U32LE(offsetof_stat_file_mode) & ~dm_masks[ctx->version])
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in dm bitfield: %#08"PRIx32,
- GET_U32LE(offsetof_stat_file_mode) & ~dm_masks[ctx->version]);
+ if (GET_U32LE(offsetof_stat__stat_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rstat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(125))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rstat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(125));
- if ((uint32_t)GET_U32LE(offsetof_nstat) != (uint32_t)(offsetof_end - offsetof_stat))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rstat->nstat value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_nstat), (uint32_t)(offsetof_end - offsetof_stat));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 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;
uint32_t offsetof_stat = net_offset + 13;
- uint32_t offsetof_stat_stat_size = net_offset + 13;
- uint32_t offsetof_stat_kern_type = net_offset + 15;
- uint32_t offsetof_stat_file_qid_type = net_offset + 21;
+ uint32_t offsetof_stat__stat_size = net_offset + 13;
+ uint32_t offsetof_stat_fstype = net_offset + 15;
+ uint32_t offsetof_stat_qid_type = net_offset + 21;
VALIDATE_NET_BYTES(34);
- if (GET_U8LE(offsetof_stat_file_qid_type) & ~qt_masks[ctx->version])
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8,
- GET_U8LE(offsetof_stat_file_qid_type) & ~qt_masks[ctx->version]);
- uint32_t offsetof_stat_file_mode = net_offset + 0;
+ if (GET_U8LE(offsetof_stat_qid_type) & ~qt_masks[ctx->version])
+ return 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());
VALIDATE_NET_BYTES(2);
@@ -967,178 +811,158 @@ static ssize_t validate_Twstat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t
}
#endif /* CONFIG_9P_ENABLE_9P2000_u */
uint32_t offsetof_stat_end = net_offset + 0;
- if ((uint32_t)GET_U32LE(offsetof_stat_stat_size) != (uint32_t)(offsetof_stat_end - offsetof_stat_kern_type))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Twstat->stat.stat_size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_stat_stat_size), (uint32_t)(offsetof_stat_end - offsetof_stat_kern_type));
- if (GET_U32LE(offsetof_stat_file_mode) & ~dm_masks[ctx->version])
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in dm bitfield: %#08"PRIx32,
- GET_U32LE(offsetof_stat_file_mode) & ~dm_masks[ctx->version]);
+ if (GET_U32LE(offsetof_stat__stat_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Twstat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(126))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Twstat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(126));
- if ((uint32_t)GET_U32LE(offsetof_nstat) != (uint32_t)(offsetof_end - offsetof_stat))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Twstat->nstat value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_nstat), (uint32_t)(offsetof_end - offsetof_stat));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rwstat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(127))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rwstat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(127));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Topenfd->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(98))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Topenfd->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(98));
+ if (GET_U32LE(offsetof_size) != 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 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_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in o bitfield: %#02"PRIx8,
- GET_U8LE(offsetof_mode) & ~o_masks[ctx->version]);
- return (ssize_t)host_size;
+ 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_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8,
- 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Ropenfd->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(99))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Ropenfd->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(99));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rlerror->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(7))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rlerror->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(7));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tstatfs->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(8))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tstatfs->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(8));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rstatfs->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(9))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rstatfs->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(9));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tlopen->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(12))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tlopen->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(12));
+ if (GET_U32LE(offsetof_size) != 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 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_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in lo bitfield: %#08"PRIx32,
- GET_U32LE(offsetof_flags) & ~lo_masks[ctx->version]);
- return (ssize_t)host_size;
+ 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_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8,
- 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rlopen->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(13))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rlopen->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(13));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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);
@@ -1147,45 +971,41 @@ static ssize_t validate_Tlcreate(struct lib9p_ctx *ctx, uint32_t net_size, uint8
uint32_t offsetof_mode = net_offset + 4;
uint32_t offsetof_end = net_offset + 12;
VALIDATE_NET_BYTES(12);
- if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tlcreate->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(14))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tlcreate->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(14));
+ if (GET_U32LE(offsetof_size) != 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 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_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in lo bitfield: %#08"PRIx32,
- 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_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in mode bitfield: %#08"PRIx32,
- GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]);
- return (ssize_t)host_size;
+ 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_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8,
- 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rlcreate->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(15))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rlcreate->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(15));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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);
@@ -1194,38 +1014,34 @@ static ssize_t validate_Tsymlink(struct lib9p_ctx *ctx, uint32_t net_size, uint8
VALIDATE_NET_UTF8(LAST_U16LE());
uint32_t offsetof_end = net_offset + 4;
VALIDATE_NET_BYTES(4);
- if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tsymlink->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(16))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tsymlink->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(16));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8,
- 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rsymlink->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(17))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rsymlink->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(17));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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);
@@ -1233,432 +1049,384 @@ static ssize_t validate_Tmknod(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t
uint32_t offsetof_mode = net_offset + 0;
uint32_t offsetof_end = net_offset + 16;
VALIDATE_NET_BYTES(16);
- if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tmknod->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(18))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tmknod->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(18));
+ if (GET_U32LE(offsetof_size) != 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 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_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in mode bitfield: %#08"PRIx32,
- GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]);
- return (ssize_t)host_size;
+ 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_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8,
- 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rmknod->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(19))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rmknod->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(19));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Trename->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(20))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Trename->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(20));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rrename->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(21))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rrename->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(21));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Treadlink->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(22))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Treadlink->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(22));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rreadlink->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(23))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rreadlink->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(23));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tgetattr->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(24))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tgetattr->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(24));
+ if (GET_U32LE(offsetof_size) != 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 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_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in getattr bitfield: %#016"PRIx64,
- GET_U64LE(offsetof_request_mask) & ~getattr_masks[ctx->version]);
- return (ssize_t)host_size;
+ 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_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8,
- 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rgetattr->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(25))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rgetattr->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(25));
+ if (GET_U32LE(offsetof_size) != 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 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_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in getattr bitfield: %#016"PRIx64,
- 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_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in mode bitfield: %#08"PRIx32,
- GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]);
- return (ssize_t)host_size;
+ 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;
uint32_t offsetof_mode = net_offset + 15;
uint32_t offsetof_end = net_offset + 67;
VALIDATE_NET_BYTES(67);
- if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tsetattr->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(26))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tsetattr->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(26));
+ if (GET_U32LE(offsetof_size) != 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 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_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in setattr bitfield: %#08"PRIx32,
- 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_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in mode bitfield: %#08"PRIx32,
- GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]);
- return (ssize_t)host_size;
+ 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rsetattr->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(27))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rsetattr->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(27));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Txattrwalk->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(30))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Txattrwalk->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(30));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rxattrwalk->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(31))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rxattrwalk->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(31));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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);
VALIDATE_NET_UTF8(LAST_U16LE());
uint32_t offsetof_end = net_offset + 12;
VALIDATE_NET_BYTES(12);
- if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Txattrcreate->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(32))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Txattrcreate->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(32));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rxattrcreate->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(33))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rxattrcreate->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(33));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Treaddir->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(40))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Treaddir->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(40));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rreaddir->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(41))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rreaddir->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(41));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tfsync->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(50))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tfsync->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(50));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rfsync->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(51))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rfsync->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(51));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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;
VALIDATE_NET_BYTES(38);
VALIDATE_NET_UTF8(LAST_U16LE());
uint32_t offsetof_end = net_offset + 0;
- if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tlock->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(52))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tlock->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(52));
+ if (GET_U32LE(offsetof_size) != 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 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_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in lock_flags bitfield: %#08"PRIx32,
- GET_U32LE(offsetof_flags) & ~lock_flags_masks[ctx->version]);
- return (ssize_t)host_size;
+ 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rlock->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(53))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rlock->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(53));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tgetlock->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(54))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tgetlock->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(54));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rgetlock->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(55))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rgetlock->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(55));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tlink->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(70))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tlink->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(70));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rlink->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(71))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rlink->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(71));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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);
@@ -1666,41 +1434,37 @@ static ssize_t validate_Tmkdir(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t
uint32_t offsetof_mode = net_offset + 0;
uint32_t offsetof_end = net_offset + 8;
VALIDATE_NET_BYTES(8);
- if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tmkdir->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(72))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tmkdir->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(72));
+ if (GET_U32LE(offsetof_size) != 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 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_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in mode bitfield: %#08"PRIx32,
- GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]);
- return (ssize_t)host_size;
+ 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_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8,
- 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rmkdir->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(73))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rmkdir->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(73));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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);
@@ -1708,102 +1472,90 @@ static ssize_t validate_Trenameat(struct lib9p_ctx *ctx, uint32_t net_size, uint
VALIDATE_NET_BYTES(6);
VALIDATE_NET_UTF8(LAST_U16LE());
uint32_t offsetof_end = net_offset + 0;
- if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Trenameat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(74))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Trenameat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(74));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rrenameat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(75))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rrenameat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(75));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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);
VALIDATE_NET_UTF8(LAST_U16LE());
uint32_t offsetof_end = net_offset + 4;
VALIDATE_NET_BYTES(4);
- if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tunlinkat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(76))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tunlinkat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(76));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Runlinkat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(77))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Runlinkat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(77));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tsession->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(150))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tsession->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(150));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rsession->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(151))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rsession->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(151));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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);
@@ -1813,35 +1565,31 @@ static ssize_t validate_Tsread(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t
VALIDATE_NET_UTF8(LAST_U16LE());
}
uint32_t offsetof_end = net_offset + 0;
- if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tsread->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(152))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tsread->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(152));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rsread->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(153))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rsread->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(153));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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);
@@ -1853,29 +1601,25 @@ static ssize_t validate_Tswrite(struct lib9p_ctx *ctx, uint32_t net_size, uint8_
VALIDATE_NET_BYTES(4);
VALIDATE_NET_BYTES(LAST_U32LE());
uint32_t offsetof_end = net_offset + 0;
- if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tswrite->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(154))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Tswrite->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(154));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rswrite->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
- (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
- if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(155))
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EBADMSG, "Rswrite->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
- (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(155));
- return (ssize_t)host_size;
+ if (GET_U32LE(offsetof_size) != 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 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 */
@@ -1898,44 +1642,44 @@ static ssize_t validate_Rswrite(struct lib9p_ctx *ctx, uint32_t net_size, uint8_
net_offset += 8;
#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
-static void unmarshal_stat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_stat([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_stat *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 2;
- UNMARSHAL_U16LE(ctx, out->kern_type);
- UNMARSHAL_U32LE(ctx, out->kern_dev);
- UNMARSHAL_U8LE(ctx, out->file_qid.type);
- UNMARSHAL_U32LE(ctx, out->file_qid.vers);
- UNMARSHAL_U64LE(ctx, out->file_qid.path);
- UNMARSHAL_U32LE(ctx, out->file_mode);
- UNMARSHAL_U32LE(ctx, out->file_atime);
- UNMARSHAL_U32LE(ctx, out->file_mtime);
- UNMARSHAL_U64LE(ctx, out->file_size);
- UNMARSHAL_U16LE(ctx, out->file_name.len);
- UNMARSHAL_BYTES(ctx, out->file_name.utf8, out->file_name.len);
- UNMARSHAL_U16LE(ctx, out->file_owner_uid.len);
- UNMARSHAL_BYTES(ctx, out->file_owner_uid.utf8, out->file_owner_uid.len);
- UNMARSHAL_U16LE(ctx, out->file_owner_gid.len);
- UNMARSHAL_BYTES(ctx, out->file_owner_gid.utf8, out->file_owner_gid.len);
- UNMARSHAL_U16LE(ctx, out->file_last_modified_uid.len);
- UNMARSHAL_BYTES(ctx, out->file_last_modified_uid.utf8, out->file_last_modified_uid.len);
+ UNMARSHAL_U16LE(ctx, out->fstype);
+ UNMARSHAL_U32LE(ctx, out->fsdev);
+ UNMARSHAL_U8LE(ctx, out->qid.type);
+ UNMARSHAL_U32LE(ctx, out->qid.vers);
+ UNMARSHAL_U64LE(ctx, out->qid.path);
+ UNMARSHAL_U32LE(ctx, out->mode);
+ UNMARSHAL_U32LE(ctx, out->atime);
+ UNMARSHAL_U32LE(ctx, out->mtime);
+ UNMARSHAL_U64LE(ctx, out->length);
+ UNMARSHAL_U16LE(ctx, out->name.len);
+ UNMARSHAL_BYTES(ctx, out->name.utf8, out->name.len);
+ UNMARSHAL_U16LE(ctx, out->owner_uname.len);
+ UNMARSHAL_BYTES(ctx, out->owner_uname.utf8, out->owner_uname.len);
+ UNMARSHAL_U16LE(ctx, out->owner_gname.len);
+ UNMARSHAL_BYTES(ctx, out->owner_gname.utf8, out->owner_gname.len);
+ UNMARSHAL_U16LE(ctx, out->last_modifier_uname.len);
+ UNMARSHAL_BYTES(ctx, out->last_modifier_uname.utf8, out->last_modifier_uname.len);
#if CONFIG_9P_ENABLE_9P2000_u
if (is_ver(ctx, 9P2000_u)) {
- UNMARSHAL_U16LE(ctx, out->file_extension.len);
- UNMARSHAL_BYTES(ctx, out->file_extension.utf8, out->file_extension.len);
- UNMARSHAL_U32LE(ctx, out->file_owner_n_uid);
- UNMARSHAL_U32LE(ctx, out->file_owner_n_gid);
- UNMARSHAL_U32LE(ctx, out->file_last_modified_n_uid);
+ UNMARSHAL_U16LE(ctx, out->extension.len);
+ UNMARSHAL_BYTES(ctx, out->extension.utf8, out->extension.len);
+ UNMARSHAL_U32LE(ctx, out->owner_unum);
+ UNMARSHAL_U32LE(ctx, out->owner_gnum);
+ UNMARSHAL_U32LE(ctx, out->last_modifier_unum);
}
#endif /* CONFIG_9P_ENABLE_9P2000_u */
}
#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
-#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
-static void unmarshal_Tversion([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+#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 void unmarshal_Tversion([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Tversion *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -1945,9 +1689,9 @@ static void unmarshal_Tversion([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *n
UNMARSHAL_BYTES(ctx, out->version.utf8, out->version.len);
}
-static void unmarshal_Rversion([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rversion([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rversion *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -1957,9 +1701,11 @@ static void unmarshal_Rversion([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *n
UNMARSHAL_BYTES(ctx, out->version.utf8, out->version.len);
}
-static void unmarshal_Tauth([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+#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 void unmarshal_Tauth([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Tauth *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -1971,14 +1717,14 @@ static void unmarshal_Tauth([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_
UNMARSHAL_BYTES(ctx, out->aname.utf8, out->aname.len);
#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u
if (( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) )) {
- UNMARSHAL_U32LE(ctx, out->n_uid);
+ UNMARSHAL_U32LE(ctx, out->unum);
}
#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
}
-static void unmarshal_Rauth([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rauth([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rauth *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -1988,9 +1734,9 @@ static void unmarshal_Rauth([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_
UNMARSHAL_U64LE(ctx, out->aqid.path);
}
-static void unmarshal_Tattach([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Tattach([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Tattach *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2003,14 +1749,14 @@ static void unmarshal_Tattach([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *ne
UNMARSHAL_BYTES(ctx, out->aname.utf8, out->aname.len);
#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u
if (( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) )) {
- UNMARSHAL_U32LE(ctx, out->n_uid);
+ UNMARSHAL_U32LE(ctx, out->unum);
}
#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
}
-static void unmarshal_Rattach([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rattach([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rattach *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2021,10 +1767,10 @@ static void unmarshal_Rattach([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *ne
}
#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 void unmarshal_Rerror([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+#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 void unmarshal_Rerror([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rerror *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2038,11 +1784,11 @@ static void unmarshal_Rerror([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net
#endif /* CONFIG_9P_ENABLE_9P2000_u */
}
-#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#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 void unmarshal_Tflush([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Tflush([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Tflush *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2050,18 +1796,18 @@ static void unmarshal_Tflush([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net
UNMARSHAL_U16LE(ctx, out->oldtag);
}
-static void unmarshal_Rflush([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rflush([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rflush *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
UNMARSHAL_U16LE(ctx, out->tag);
}
-static void unmarshal_Twalk([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Twalk([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Twalk *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2077,9 +1823,9 @@ static void unmarshal_Twalk([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_
}
}
-static void unmarshal_Rwalk([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rwalk([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rwalk *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2096,9 +1842,9 @@ static void unmarshal_Rwalk([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_
#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 void unmarshal_Topen([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Topen([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Topen *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2107,9 +1853,9 @@ static void unmarshal_Topen([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_
UNMARSHAL_U8LE(ctx, out->mode);
}
-static void unmarshal_Ropen([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Ropen([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Ropen *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2120,9 +1866,9 @@ static void unmarshal_Ropen([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_
UNMARSHAL_U32LE(ctx, out->iounit);
}
-static void unmarshal_Tcreate([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Tcreate([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Tcreate *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2134,9 +1880,9 @@ static void unmarshal_Tcreate([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *ne
UNMARSHAL_U8LE(ctx, out->mode);
}
-static void unmarshal_Rcreate([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rcreate([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rcreate *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2149,9 +1895,9 @@ static void unmarshal_Rcreate([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *ne
#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 void unmarshal_Tread([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Tread([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Tread *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2161,9 +1907,9 @@ static void unmarshal_Tread([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_
UNMARSHAL_U32LE(ctx, out->count);
}
-static void unmarshal_Rread([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rread([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rread *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2172,9 +1918,9 @@ static void unmarshal_Rread([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_
UNMARSHAL_BYTES(ctx, out->data, out->count);
}
-static void unmarshal_Twrite([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Twrite([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Twrite *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2185,9 +1931,9 @@ static void unmarshal_Twrite([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net
UNMARSHAL_BYTES(ctx, out->data, out->count);
}
-static void unmarshal_Rwrite([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rwrite([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rwrite *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2195,9 +1941,9 @@ static void unmarshal_Rwrite([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net
UNMARSHAL_U32LE(ctx, out->count);
}
-static void unmarshal_Tclunk([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Tclunk([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Tclunk *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2205,18 +1951,18 @@ static void unmarshal_Tclunk([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net
UNMARSHAL_U32LE(ctx, out->fid);
}
-static void unmarshal_Rclunk([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rclunk([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rclunk *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
UNMARSHAL_U16LE(ctx, out->tag);
}
-static void unmarshal_Tremove([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Tremove([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Tremove *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2224,9 +1970,9 @@ static void unmarshal_Tremove([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *ne
UNMARSHAL_U32LE(ctx, out->fid);
}
-static void unmarshal_Rremove([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rremove([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rremove *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2235,9 +1981,9 @@ static void unmarshal_Rremove([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *ne
#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 void unmarshal_Tstat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Tstat([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Tstat *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2245,46 +1991,46 @@ static void unmarshal_Tstat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_
UNMARSHAL_U32LE(ctx, out->fid);
}
-static void unmarshal_Rstat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rstat([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rstat *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
UNMARSHAL_U16LE(ctx, out->tag);
net_offset += 2;
net_offset += 2;
- UNMARSHAL_U16LE(ctx, out->stat.kern_type);
- UNMARSHAL_U32LE(ctx, out->stat.kern_dev);
- UNMARSHAL_U8LE(ctx, out->stat.file_qid.type);
- UNMARSHAL_U32LE(ctx, out->stat.file_qid.vers);
- UNMARSHAL_U64LE(ctx, out->stat.file_qid.path);
- UNMARSHAL_U32LE(ctx, out->stat.file_mode);
- UNMARSHAL_U32LE(ctx, out->stat.file_atime);
- UNMARSHAL_U32LE(ctx, out->stat.file_mtime);
- UNMARSHAL_U64LE(ctx, out->stat.file_size);
- UNMARSHAL_U16LE(ctx, out->stat.file_name.len);
- UNMARSHAL_BYTES(ctx, out->stat.file_name.utf8, out->stat.file_name.len);
- UNMARSHAL_U16LE(ctx, out->stat.file_owner_uid.len);
- UNMARSHAL_BYTES(ctx, out->stat.file_owner_uid.utf8, out->stat.file_owner_uid.len);
- UNMARSHAL_U16LE(ctx, out->stat.file_owner_gid.len);
- UNMARSHAL_BYTES(ctx, out->stat.file_owner_gid.utf8, out->stat.file_owner_gid.len);
- UNMARSHAL_U16LE(ctx, out->stat.file_last_modified_uid.len);
- UNMARSHAL_BYTES(ctx, out->stat.file_last_modified_uid.utf8, out->stat.file_last_modified_uid.len);
+ UNMARSHAL_U16LE(ctx, out->stat.fstype);
+ UNMARSHAL_U32LE(ctx, out->stat.fsdev);
+ UNMARSHAL_U8LE(ctx, out->stat.qid.type);
+ UNMARSHAL_U32LE(ctx, out->stat.qid.vers);
+ UNMARSHAL_U64LE(ctx, out->stat.qid.path);
+ UNMARSHAL_U32LE(ctx, out->stat.mode);
+ UNMARSHAL_U32LE(ctx, out->stat.atime);
+ UNMARSHAL_U32LE(ctx, out->stat.mtime);
+ UNMARSHAL_U64LE(ctx, out->stat.length);
+ UNMARSHAL_U16LE(ctx, out->stat.name.len);
+ UNMARSHAL_BYTES(ctx, out->stat.name.utf8, out->stat.name.len);
+ UNMARSHAL_U16LE(ctx, out->stat.owner_uname.len);
+ UNMARSHAL_BYTES(ctx, out->stat.owner_uname.utf8, out->stat.owner_uname.len);
+ UNMARSHAL_U16LE(ctx, out->stat.owner_gname.len);
+ UNMARSHAL_BYTES(ctx, out->stat.owner_gname.utf8, out->stat.owner_gname.len);
+ UNMARSHAL_U16LE(ctx, out->stat.last_modifier_uname.len);
+ UNMARSHAL_BYTES(ctx, out->stat.last_modifier_uname.utf8, out->stat.last_modifier_uname.len);
#if CONFIG_9P_ENABLE_9P2000_u
if (is_ver(ctx, 9P2000_u)) {
- UNMARSHAL_U16LE(ctx, out->stat.file_extension.len);
- UNMARSHAL_BYTES(ctx, out->stat.file_extension.utf8, out->stat.file_extension.len);
- UNMARSHAL_U32LE(ctx, out->stat.file_owner_n_uid);
- UNMARSHAL_U32LE(ctx, out->stat.file_owner_n_gid);
- UNMARSHAL_U32LE(ctx, out->stat.file_last_modified_n_uid);
+ UNMARSHAL_U16LE(ctx, out->stat.extension.len);
+ UNMARSHAL_BYTES(ctx, out->stat.extension.utf8, out->stat.extension.len);
+ UNMARSHAL_U32LE(ctx, out->stat.owner_unum);
+ UNMARSHAL_U32LE(ctx, out->stat.owner_gnum);
+ UNMARSHAL_U32LE(ctx, out->stat.last_modifier_unum);
}
#endif /* CONFIG_9P_ENABLE_9P2000_u */
}
-static void unmarshal_Twstat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Twstat([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Twstat *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2292,37 +2038,37 @@ static void unmarshal_Twstat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net
UNMARSHAL_U32LE(ctx, out->fid);
net_offset += 2;
net_offset += 2;
- UNMARSHAL_U16LE(ctx, out->stat.kern_type);
- UNMARSHAL_U32LE(ctx, out->stat.kern_dev);
- UNMARSHAL_U8LE(ctx, out->stat.file_qid.type);
- UNMARSHAL_U32LE(ctx, out->stat.file_qid.vers);
- UNMARSHAL_U64LE(ctx, out->stat.file_qid.path);
- UNMARSHAL_U32LE(ctx, out->stat.file_mode);
- UNMARSHAL_U32LE(ctx, out->stat.file_atime);
- UNMARSHAL_U32LE(ctx, out->stat.file_mtime);
- UNMARSHAL_U64LE(ctx, out->stat.file_size);
- UNMARSHAL_U16LE(ctx, out->stat.file_name.len);
- UNMARSHAL_BYTES(ctx, out->stat.file_name.utf8, out->stat.file_name.len);
- UNMARSHAL_U16LE(ctx, out->stat.file_owner_uid.len);
- UNMARSHAL_BYTES(ctx, out->stat.file_owner_uid.utf8, out->stat.file_owner_uid.len);
- UNMARSHAL_U16LE(ctx, out->stat.file_owner_gid.len);
- UNMARSHAL_BYTES(ctx, out->stat.file_owner_gid.utf8, out->stat.file_owner_gid.len);
- UNMARSHAL_U16LE(ctx, out->stat.file_last_modified_uid.len);
- UNMARSHAL_BYTES(ctx, out->stat.file_last_modified_uid.utf8, out->stat.file_last_modified_uid.len);
+ UNMARSHAL_U16LE(ctx, out->stat.fstype);
+ UNMARSHAL_U32LE(ctx, out->stat.fsdev);
+ UNMARSHAL_U8LE(ctx, out->stat.qid.type);
+ UNMARSHAL_U32LE(ctx, out->stat.qid.vers);
+ UNMARSHAL_U64LE(ctx, out->stat.qid.path);
+ UNMARSHAL_U32LE(ctx, out->stat.mode);
+ UNMARSHAL_U32LE(ctx, out->stat.atime);
+ UNMARSHAL_U32LE(ctx, out->stat.mtime);
+ UNMARSHAL_U64LE(ctx, out->stat.length);
+ UNMARSHAL_U16LE(ctx, out->stat.name.len);
+ UNMARSHAL_BYTES(ctx, out->stat.name.utf8, out->stat.name.len);
+ UNMARSHAL_U16LE(ctx, out->stat.owner_uname.len);
+ UNMARSHAL_BYTES(ctx, out->stat.owner_uname.utf8, out->stat.owner_uname.len);
+ UNMARSHAL_U16LE(ctx, out->stat.owner_gname.len);
+ UNMARSHAL_BYTES(ctx, out->stat.owner_gname.utf8, out->stat.owner_gname.len);
+ UNMARSHAL_U16LE(ctx, out->stat.last_modifier_uname.len);
+ UNMARSHAL_BYTES(ctx, out->stat.last_modifier_uname.utf8, out->stat.last_modifier_uname.len);
#if CONFIG_9P_ENABLE_9P2000_u
if (is_ver(ctx, 9P2000_u)) {
- UNMARSHAL_U16LE(ctx, out->stat.file_extension.len);
- UNMARSHAL_BYTES(ctx, out->stat.file_extension.utf8, out->stat.file_extension.len);
- UNMARSHAL_U32LE(ctx, out->stat.file_owner_n_uid);
- UNMARSHAL_U32LE(ctx, out->stat.file_owner_n_gid);
- UNMARSHAL_U32LE(ctx, out->stat.file_last_modified_n_uid);
+ UNMARSHAL_U16LE(ctx, out->stat.extension.len);
+ UNMARSHAL_BYTES(ctx, out->stat.extension.utf8, out->stat.extension.len);
+ UNMARSHAL_U32LE(ctx, out->stat.owner_unum);
+ UNMARSHAL_U32LE(ctx, out->stat.owner_gnum);
+ UNMARSHAL_U32LE(ctx, out->stat.last_modifier_unum);
}
#endif /* CONFIG_9P_ENABLE_9P2000_u */
}
-static void unmarshal_Rwstat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rwstat([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rwstat *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2331,9 +2077,9 @@ static void unmarshal_Rwstat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net
#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 void unmarshal_Topenfd([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Topenfd([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Topenfd *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2342,9 +2088,9 @@ static void unmarshal_Topenfd([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *ne
UNMARSHAL_U8LE(ctx, out->mode);
}
-static void unmarshal_Ropenfd([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Ropenfd([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Ropenfd *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2358,9 +2104,9 @@ static void unmarshal_Ropenfd([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *ne
#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
#if CONFIG_9P_ENABLE_9P2000_L
-static void unmarshal_Rlerror([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rlerror([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rlerror *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2368,9 +2114,9 @@ static void unmarshal_Rlerror([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *ne
UNMARSHAL_U32LE(ctx, out->errnum);
}
-static void unmarshal_Tstatfs([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Tstatfs([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Tstatfs *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2378,9 +2124,9 @@ static void unmarshal_Tstatfs([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *ne
UNMARSHAL_U32LE(ctx, out->fid);
}
-static void unmarshal_Rstatfs([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rstatfs([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rstatfs *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2396,9 +2142,9 @@ static void unmarshal_Rstatfs([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *ne
UNMARSHAL_U32LE(ctx, out->namelen);
}
-static void unmarshal_Tlopen([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Tlopen([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Tlopen *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2407,9 +2153,9 @@ static void unmarshal_Tlopen([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net
UNMARSHAL_U32LE(ctx, out->flags);
}
-static void unmarshal_Rlopen([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rlopen([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rlopen *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2420,9 +2166,9 @@ static void unmarshal_Rlopen([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net
UNMARSHAL_U32LE(ctx, out->iounit);
}
-static void unmarshal_Tlcreate([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Tlcreate([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Tlcreate *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2435,9 +2181,9 @@ static void unmarshal_Tlcreate([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *n
UNMARSHAL_U32LE(ctx, out->gid);
}
-static void unmarshal_Rlcreate([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rlcreate([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rlcreate *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2448,9 +2194,9 @@ static void unmarshal_Rlcreate([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *n
UNMARSHAL_U32LE(ctx, out->iounit);
}
-static void unmarshal_Tsymlink([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Tsymlink([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Tsymlink *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2463,9 +2209,9 @@ static void unmarshal_Tsymlink([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *n
UNMARSHAL_U32LE(ctx, out->gid);
}
-static void unmarshal_Rsymlink([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rsymlink([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rsymlink *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2475,9 +2221,9 @@ static void unmarshal_Rsymlink([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *n
UNMARSHAL_U64LE(ctx, out->qid.path);
}
-static void unmarshal_Tmknod([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Tmknod([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Tmknod *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2491,9 +2237,9 @@ static void unmarshal_Tmknod([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net
UNMARSHAL_U32LE(ctx, out->gid);
}
-static void unmarshal_Rmknod([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rmknod([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rmknod *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2503,9 +2249,9 @@ static void unmarshal_Rmknod([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net
UNMARSHAL_U64LE(ctx, out->qid.path);
}
-static void unmarshal_Trename([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Trename([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Trename *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2516,18 +2262,18 @@ static void unmarshal_Trename([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *ne
UNMARSHAL_BYTES(ctx, out->name.utf8, out->name.len);
}
-static void unmarshal_Rrename([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rrename([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rrename *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
UNMARSHAL_U16LE(ctx, out->tag);
}
-static void unmarshal_Treadlink([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Treadlink([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Treadlink *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2535,9 +2281,9 @@ static void unmarshal_Treadlink([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *
UNMARSHAL_U32LE(ctx, out->fid);
}
-static void unmarshal_Rreadlink([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rreadlink([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rreadlink *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2546,9 +2292,9 @@ static void unmarshal_Rreadlink([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *
UNMARSHAL_BYTES(ctx, out->target.utf8, out->target.len);
}
-static void unmarshal_Tgetattr([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Tgetattr([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Tgetattr *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2557,9 +2303,9 @@ static void unmarshal_Tgetattr([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *n
UNMARSHAL_U64LE(ctx, out->request_mask);
}
-static void unmarshal_Rgetattr([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rgetattr([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rgetattr *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2588,9 +2334,9 @@ static void unmarshal_Rgetattr([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *n
UNMARSHAL_U64LE(ctx, out->data_version);
}
-static void unmarshal_Tsetattr([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Tsetattr([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Tsetattr *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2607,18 +2353,18 @@ static void unmarshal_Tsetattr([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *n
UNMARSHAL_U64LE(ctx, out->mtime_nsec);
}
-static void unmarshal_Rsetattr([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rsetattr([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rsetattr *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
UNMARSHAL_U16LE(ctx, out->tag);
}
-static void unmarshal_Txattrwalk([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Txattrwalk([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Txattrwalk *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2629,9 +2375,9 @@ static void unmarshal_Txattrwalk([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t
UNMARSHAL_BYTES(ctx, out->name.utf8, out->name.len);
}
-static void unmarshal_Rxattrwalk([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rxattrwalk([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rxattrwalk *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2639,9 +2385,9 @@ static void unmarshal_Rxattrwalk([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t
UNMARSHAL_U64LE(ctx, out->attr_size);
}
-static void unmarshal_Txattrcreate([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Txattrcreate([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Txattrcreate *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2653,18 +2399,18 @@ static void unmarshal_Txattrcreate([[gnu::unused]] struct lib9p_ctx *ctx, uint8_
UNMARSHAL_U32LE(ctx, out->flags);
}
-static void unmarshal_Rxattrcreate([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rxattrcreate([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rxattrcreate *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
UNMARSHAL_U16LE(ctx, out->tag);
}
-static void unmarshal_Treaddir([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Treaddir([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Treaddir *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2674,9 +2420,9 @@ static void unmarshal_Treaddir([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *n
UNMARSHAL_U32LE(ctx, out->count);
}
-static void unmarshal_Rreaddir([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rreaddir([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rreaddir *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2685,9 +2431,9 @@ static void unmarshal_Rreaddir([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *n
UNMARSHAL_BYTES(ctx, out->data, out->count);
}
-static void unmarshal_Tfsync([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Tfsync([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Tfsync *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2696,18 +2442,18 @@ static void unmarshal_Tfsync([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net
UNMARSHAL_U32LE(ctx, out->datasync);
}
-static void unmarshal_Rfsync([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rfsync([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rfsync *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
UNMARSHAL_U16LE(ctx, out->tag);
}
-static void unmarshal_Tlock([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Tlock([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Tlock *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2722,9 +2468,9 @@ static void unmarshal_Tlock([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_
UNMARSHAL_BYTES(ctx, out->client_id.utf8, out->client_id.len);
}
-static void unmarshal_Rlock([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rlock([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rlock *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2732,9 +2478,9 @@ static void unmarshal_Rlock([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_
UNMARSHAL_U8LE(ctx, out->status);
}
-static void unmarshal_Tgetlock([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Tgetlock([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Tgetlock *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2748,9 +2494,9 @@ static void unmarshal_Tgetlock([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *n
UNMARSHAL_BYTES(ctx, out->client_id.utf8, out->client_id.len);
}
-static void unmarshal_Rgetlock([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rgetlock([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rgetlock *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2763,9 +2509,9 @@ static void unmarshal_Rgetlock([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *n
UNMARSHAL_BYTES(ctx, out->client_id.utf8, out->client_id.len);
}
-static void unmarshal_Tlink([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Tlink([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Tlink *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2776,18 +2522,18 @@ static void unmarshal_Tlink([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_
UNMARSHAL_BYTES(ctx, out->name.utf8, out->name.len);
}
-static void unmarshal_Rlink([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rlink([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rlink *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
UNMARSHAL_U16LE(ctx, out->tag);
}
-static void unmarshal_Tmkdir([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Tmkdir([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Tmkdir *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2799,9 +2545,9 @@ static void unmarshal_Tmkdir([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net
UNMARSHAL_U32LE(ctx, out->gid);
}
-static void unmarshal_Rmkdir([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rmkdir([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rmkdir *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2811,9 +2557,9 @@ static void unmarshal_Rmkdir([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net
UNMARSHAL_U64LE(ctx, out->qid.path);
}
-static void unmarshal_Trenameat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Trenameat([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Trenameat *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2826,18 +2572,18 @@ static void unmarshal_Trenameat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *
UNMARSHAL_BYTES(ctx, out->newname.utf8, out->newname.len);
}
-static void unmarshal_Rrenameat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rrenameat([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rrenameat *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
UNMARSHAL_U16LE(ctx, out->tag);
}
-static void unmarshal_Tunlinkat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Tunlinkat([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Tunlinkat *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2848,9 +2594,9 @@ static void unmarshal_Tunlinkat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *
UNMARSHAL_U32LE(ctx, out->flags);
}
-static void unmarshal_Runlinkat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Runlinkat([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Runlinkat *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2859,9 +2605,9 @@ static void unmarshal_Runlinkat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *
#endif /* CONFIG_9P_ENABLE_9P2000_L */
#if CONFIG_9P_ENABLE_9P2000_e
-static void unmarshal_Tsession([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Tsession([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Tsession *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2869,18 +2615,18 @@ static void unmarshal_Tsession([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *n
UNMARSHAL_U64LE(ctx, out->key);
}
-static void unmarshal_Rsession([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rsession([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rsession *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
UNMARSHAL_U16LE(ctx, out->tag);
}
-static void unmarshal_Tsread([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Tsread([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Tsread *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2895,9 +2641,9 @@ static void unmarshal_Tsread([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net
}
}
-static void unmarshal_Rsread([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rsread([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rsread *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2906,9 +2652,9 @@ static void unmarshal_Rsread([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net
UNMARSHAL_BYTES(ctx, out->data, out->count);
}
-static void unmarshal_Tswrite([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Tswrite([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Tswrite *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2925,9 +2671,9 @@ static void unmarshal_Tswrite([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *ne
UNMARSHAL_BYTES(ctx, out->data, out->count);
}
-static void unmarshal_Rswrite([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+static void unmarshal_Rswrite([[maybe_unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
struct lib9p_msg_Rswrite *out = out_buf;
- [[gnu::unused]] void *extra = &out[1];
+ [[maybe_unused]] void *extra = &out[1];
uint32_t net_offset = 0;
net_offset += 4;
net_offset += 1;
@@ -2938,96 +2684,94 @@ static void unmarshal_Rswrite([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *ne
/* 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
static bool marshal_stat(struct lib9p_ctx *ctx, struct lib9p_stat *val, struct _marshal_ret *ret) {
- uint32_t needed_size = 49 + val->file_name.len + val->file_owner_uid.len + val->file_owner_gid.len + val->file_last_modified_uid.len;
+ uint32_t needed_size = 49 + val->name.len + val->owner_uname.len + val->owner_gname.len + val->last_modifier_uname.len;
#if CONFIG_9P_ENABLE_9P2000_u
if is_ver(ctx, 9P2000_u) {
- needed_size += 14 + val->file_extension.len;
+ needed_size += 14 + val->extension.len;
}
#endif /* CONFIG_9P_ENABLE_9P2000_u */
if (needed_size > ctx->max_msg_size) {
return true;
}
uint32_t offsetof_end = needed_size;
- uint32_t offsetof_kern_type = 2;
- MARSHAL_U16LE(ctx, offsetof_end - offsetof_kern_type);
- MARSHAL_U16LE(ctx, val->kern_type);
- MARSHAL_U32LE(ctx, val->kern_dev);
- MARSHAL_U8LE(ctx, val->file_qid.type & qt_masks[ctx->version]);
- MARSHAL_U32LE(ctx, val->file_qid.vers);
- MARSHAL_U64LE(ctx, val->file_qid.path);
- MARSHAL_U32LE(ctx, val->file_mode & dm_masks[ctx->version]);
- MARSHAL_U32LE(ctx, val->file_atime);
- MARSHAL_U32LE(ctx, val->file_mtime);
- MARSHAL_U64LE(ctx, val->file_size);
- MARSHAL_U16LE(ctx, val->file_name.len);
- MARSHAL_BYTES(ctx, val->file_name.utf8, val->file_name.len);
- MARSHAL_U16LE(ctx, val->file_owner_uid.len);
- MARSHAL_BYTES(ctx, val->file_owner_uid.utf8, val->file_owner_uid.len);
- MARSHAL_U16LE(ctx, val->file_owner_gid.len);
- MARSHAL_BYTES(ctx, val->file_owner_gid.utf8, val->file_owner_gid.len);
- MARSHAL_U16LE(ctx, val->file_last_modified_uid.len);
- MARSHAL_BYTES(ctx, val->file_last_modified_uid.utf8, val->file_last_modified_uid.len);
+ uint32_t offsetof_fstype = 2;
+ MARSHAL_U16LE(ctx, offsetof_end - offsetof_fstype);
+ MARSHAL_U16LE(ctx, val->fstype);
+ MARSHAL_U32LE(ctx, val->fsdev);
+ MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->qid.vers);
+ MARSHAL_U64LE(ctx, val->qid.path);
+ MARSHAL_U32LE(ctx, val->mode & dm_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->atime);
+ MARSHAL_U32LE(ctx, val->mtime);
+ MARSHAL_U64LE(ctx, val->length);
+ MARSHAL_U16LE(ctx, val->name.len);
+ MARSHAL_BYTES(ctx, val->name.utf8, val->name.len);
+ MARSHAL_U16LE(ctx, val->owner_uname.len);
+ MARSHAL_BYTES(ctx, val->owner_uname.utf8, val->owner_uname.len);
+ MARSHAL_U16LE(ctx, val->owner_gname.len);
+ MARSHAL_BYTES(ctx, val->owner_gname.utf8, val->owner_gname.len);
+ MARSHAL_U16LE(ctx, val->last_modifier_uname.len);
+ MARSHAL_BYTES(ctx, val->last_modifier_uname.utf8, val->last_modifier_uname.len);
#if CONFIG_9P_ENABLE_9P2000_u
if (is_ver(ctx, 9P2000_u)) {
- MARSHAL_U16LE(ctx, val->file_extension.len);
- MARSHAL_BYTES(ctx, val->file_extension.utf8, val->file_extension.len);
- MARSHAL_U32LE(ctx, val->file_owner_n_uid);
- MARSHAL_U32LE(ctx, val->file_owner_n_gid);
- MARSHAL_U32LE(ctx, val->file_last_modified_n_uid);
+ MARSHAL_U16LE(ctx, val->extension.len);
+ MARSHAL_BYTES(ctx, val->extension.utf8, val->extension.len);
+ MARSHAL_U32LE(ctx, val->owner_unum);
+ MARSHAL_U32LE(ctx, val->owner_gnum);
+ MARSHAL_U32LE(ctx, val->last_modifier_unum);
}
#endif /* CONFIG_9P_ENABLE_9P2000_u */
return false;
}
#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
-#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
-static bool marshal_Tversion(struct lib9p_ctx *ctx, struct lib9p_msg_Tversion *val, struct _marshal_ret *ret) {
+#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 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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Tversion",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Tversion message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3037,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rversion",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rversion message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3057,10 +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;
}
-static bool marshal_Tauth(struct lib9p_ctx *ctx, struct lib9p_msg_Tauth *val, struct _marshal_ret *ret) {
+#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 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) ) {
@@ -3068,11 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Tauth",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Tauth message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3086,20 +2828,18 @@ static bool marshal_Tauth(struct lib9p_ctx *ctx, struct lib9p_msg_Tauth *val, st
MARSHAL_BYTES_ZEROCOPY(ctx, val->aname.utf8, val->aname.len);
#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u
if (( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) )) {
- MARSHAL_U32LE(ctx, val->n_uid);
+ MARSHAL_U32LE(ctx, val->unum);
}
#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
- return false;
+ 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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rauth",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rauth message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3109,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) ) {
@@ -3120,11 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Tattach",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Tattach message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3139,20 +2877,18 @@ static bool marshal_Tattach(struct lib9p_ctx *ctx, struct lib9p_msg_Tattach *val
MARSHAL_BYTES_ZEROCOPY(ctx, val->aname.utf8, val->aname.len);
#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u
if (( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) )) {
- MARSHAL_U32LE(ctx, val->n_uid);
+ MARSHAL_U32LE(ctx, val->unum);
}
#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
- return false;
+ 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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rattach",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rattach message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3162,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
-static bool marshal_Rerror(struct lib9p_ctx *ctx, struct lib9p_msg_Rerror *val, struct _marshal_ret *ret) {
+#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 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) {
@@ -3175,11 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rerror",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rerror message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3193,19 +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 */
+#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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Tflush",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Tflush message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3213,37 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rflush",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rflush message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Twalk",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Twalk message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3257,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rwalk",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rwalk message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3280,19 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Topen",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Topen message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3301,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Ropen",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Ropen message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3322,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Tcreate",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Tcreate message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3344,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rcreate",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rcreate message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3365,19 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Tread",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Tread message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3387,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rread",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rread message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3406,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Twrite",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Twrite message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3427,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rwrite",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rwrite message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3445,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Tclunk",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Tclunk message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3463,34 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rclunk",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rclunk message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Tremove",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Tremove message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3498,36 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rremove",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rremove message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Tstat",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Tstat message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3535,22 +3235,20 @@ 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) {
- uint32_t needed_size = 58 + val->stat.file_name.len + val->stat.file_owner_uid.len + val->stat.file_owner_gid.len + val->stat.file_last_modified_uid.len;
+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) {
- needed_size += 14 + val->stat.file_extension.len;
+ needed_size += 14 + val->stat.extension.len;
}
#endif /* CONFIG_9P_ENABLE_9P2000_u */
if (needed_size > ctx->max_msg_size) {
- lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rstat",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rstat message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3559,56 +3257,54 @@ static bool marshal_Rstat(struct lib9p_ctx *ctx, struct lib9p_msg_Rstat *val, st
MARSHAL_U8LE(ctx, 125);
MARSHAL_U16LE(ctx, val->tag);
MARSHAL_U16LE(ctx, offsetof_end - offsetof_stat);
- uint32_t offsetof_stat_end = 49 + val->stat.file_name.len + val->stat.file_owner_uid.len + val->stat.file_owner_gid.len + val->stat.file_last_modified_uid.len;
+ uint32_t offsetof_stat_end = 49 + val->stat.name.len + val->stat.owner_uname.len + val->stat.owner_gname.len + val->stat.last_modifier_uname.len;
#if CONFIG_9P_ENABLE_9P2000_u
if is_ver(ctx, 9P2000_u) {
- offsetof_stat_end += 14 + val->stat.file_extension.len;
+ offsetof_stat_end += 14 + val->stat.extension.len;
}
#endif /* CONFIG_9P_ENABLE_9P2000_u */
- uint32_t offsetof_stat_kern_type = 2;
- MARSHAL_U16LE(ctx, offsetof_stat_end - offsetof_stat_kern_type);
- MARSHAL_U16LE(ctx, val->stat.kern_type);
- MARSHAL_U32LE(ctx, val->stat.kern_dev);
- MARSHAL_U8LE(ctx, val->stat.file_qid.type & qt_masks[ctx->version]);
- MARSHAL_U32LE(ctx, val->stat.file_qid.vers);
- MARSHAL_U64LE(ctx, val->stat.file_qid.path);
- MARSHAL_U32LE(ctx, val->stat.file_mode & dm_masks[ctx->version]);
- MARSHAL_U32LE(ctx, val->stat.file_atime);
- MARSHAL_U32LE(ctx, val->stat.file_mtime);
- MARSHAL_U64LE(ctx, val->stat.file_size);
- MARSHAL_U16LE(ctx, val->stat.file_name.len);
- MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_name.utf8, val->stat.file_name.len);
- MARSHAL_U16LE(ctx, val->stat.file_owner_uid.len);
- MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_owner_uid.utf8, val->stat.file_owner_uid.len);
- MARSHAL_U16LE(ctx, val->stat.file_owner_gid.len);
- MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_owner_gid.utf8, val->stat.file_owner_gid.len);
- MARSHAL_U16LE(ctx, val->stat.file_last_modified_uid.len);
- MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_last_modified_uid.utf8, val->stat.file_last_modified_uid.len);
+ uint32_t offsetof_stat_fstype = 2;
+ MARSHAL_U16LE(ctx, offsetof_stat_end - offsetof_stat_fstype);
+ MARSHAL_U16LE(ctx, val->stat.fstype);
+ MARSHAL_U32LE(ctx, val->stat.fsdev);
+ MARSHAL_U8LE(ctx, val->stat.qid.type & qt_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->stat.qid.vers);
+ MARSHAL_U64LE(ctx, val->stat.qid.path);
+ MARSHAL_U32LE(ctx, val->stat.mode & dm_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->stat.atime);
+ MARSHAL_U32LE(ctx, val->stat.mtime);
+ MARSHAL_U64LE(ctx, val->stat.length);
+ MARSHAL_U16LE(ctx, val->stat.name.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.name.utf8, val->stat.name.len);
+ MARSHAL_U16LE(ctx, val->stat.owner_uname.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.owner_uname.utf8, val->stat.owner_uname.len);
+ MARSHAL_U16LE(ctx, val->stat.owner_gname.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.owner_gname.utf8, val->stat.owner_gname.len);
+ MARSHAL_U16LE(ctx, val->stat.last_modifier_uname.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.last_modifier_uname.utf8, val->stat.last_modifier_uname.len);
#if CONFIG_9P_ENABLE_9P2000_u
if (is_ver(ctx, 9P2000_u)) {
- MARSHAL_U16LE(ctx, val->stat.file_extension.len);
- MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_extension.utf8, val->stat.file_extension.len);
- MARSHAL_U32LE(ctx, val->stat.file_owner_n_uid);
- MARSHAL_U32LE(ctx, val->stat.file_owner_n_gid);
- MARSHAL_U32LE(ctx, val->stat.file_last_modified_n_uid);
+ MARSHAL_U16LE(ctx, val->stat.extension.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.extension.utf8, val->stat.extension.len);
+ MARSHAL_U32LE(ctx, val->stat.owner_unum);
+ MARSHAL_U32LE(ctx, val->stat.owner_gnum);
+ MARSHAL_U32LE(ctx, val->stat.last_modifier_unum);
}
#endif /* CONFIG_9P_ENABLE_9P2000_u */
- return false;
+ return ERROR_NULL;
}
-static bool marshal_Twstat(struct lib9p_ctx *ctx, struct lib9p_msg_Twstat *val, struct _marshal_ret *ret) {
- uint32_t needed_size = 62 + val->stat.file_name.len + val->stat.file_owner_uid.len + val->stat.file_owner_gid.len + val->stat.file_last_modified_uid.len;
+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) {
- needed_size += 14 + val->stat.file_extension.len;
+ needed_size += 14 + val->stat.extension.len;
}
#endif /* CONFIG_9P_ENABLE_9P2000_u */
if (needed_size > ctx->max_msg_size) {
- lib9p_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Twstat",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Twstat message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3618,70 +3314,66 @@ static bool marshal_Twstat(struct lib9p_ctx *ctx, struct lib9p_msg_Twstat *val,
MARSHAL_U16LE(ctx, val->tag);
MARSHAL_U32LE(ctx, val->fid);
MARSHAL_U16LE(ctx, offsetof_end - offsetof_stat);
- uint32_t offsetof_stat_end = 49 + val->stat.file_name.len + val->stat.file_owner_uid.len + val->stat.file_owner_gid.len + val->stat.file_last_modified_uid.len;
+ uint32_t offsetof_stat_end = 49 + val->stat.name.len + val->stat.owner_uname.len + val->stat.owner_gname.len + val->stat.last_modifier_uname.len;
#if CONFIG_9P_ENABLE_9P2000_u
if is_ver(ctx, 9P2000_u) {
- offsetof_stat_end += 14 + val->stat.file_extension.len;
+ offsetof_stat_end += 14 + val->stat.extension.len;
}
#endif /* CONFIG_9P_ENABLE_9P2000_u */
- uint32_t offsetof_stat_kern_type = 2;
- MARSHAL_U16LE(ctx, offsetof_stat_end - offsetof_stat_kern_type);
- MARSHAL_U16LE(ctx, val->stat.kern_type);
- MARSHAL_U32LE(ctx, val->stat.kern_dev);
- MARSHAL_U8LE(ctx, val->stat.file_qid.type & qt_masks[ctx->version]);
- MARSHAL_U32LE(ctx, val->stat.file_qid.vers);
- MARSHAL_U64LE(ctx, val->stat.file_qid.path);
- MARSHAL_U32LE(ctx, val->stat.file_mode & dm_masks[ctx->version]);
- MARSHAL_U32LE(ctx, val->stat.file_atime);
- MARSHAL_U32LE(ctx, val->stat.file_mtime);
- MARSHAL_U64LE(ctx, val->stat.file_size);
- MARSHAL_U16LE(ctx, val->stat.file_name.len);
- MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_name.utf8, val->stat.file_name.len);
- MARSHAL_U16LE(ctx, val->stat.file_owner_uid.len);
- MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_owner_uid.utf8, val->stat.file_owner_uid.len);
- MARSHAL_U16LE(ctx, val->stat.file_owner_gid.len);
- MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_owner_gid.utf8, val->stat.file_owner_gid.len);
- MARSHAL_U16LE(ctx, val->stat.file_last_modified_uid.len);
- MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_last_modified_uid.utf8, val->stat.file_last_modified_uid.len);
+ uint32_t offsetof_stat_fstype = 2;
+ MARSHAL_U16LE(ctx, offsetof_stat_end - offsetof_stat_fstype);
+ MARSHAL_U16LE(ctx, val->stat.fstype);
+ MARSHAL_U32LE(ctx, val->stat.fsdev);
+ MARSHAL_U8LE(ctx, val->stat.qid.type & qt_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->stat.qid.vers);
+ MARSHAL_U64LE(ctx, val->stat.qid.path);
+ MARSHAL_U32LE(ctx, val->stat.mode & dm_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->stat.atime);
+ MARSHAL_U32LE(ctx, val->stat.mtime);
+ MARSHAL_U64LE(ctx, val->stat.length);
+ MARSHAL_U16LE(ctx, val->stat.name.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.name.utf8, val->stat.name.len);
+ MARSHAL_U16LE(ctx, val->stat.owner_uname.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.owner_uname.utf8, val->stat.owner_uname.len);
+ MARSHAL_U16LE(ctx, val->stat.owner_gname.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.owner_gname.utf8, val->stat.owner_gname.len);
+ MARSHAL_U16LE(ctx, val->stat.last_modifier_uname.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.last_modifier_uname.utf8, val->stat.last_modifier_uname.len);
#if CONFIG_9P_ENABLE_9P2000_u
if (is_ver(ctx, 9P2000_u)) {
- MARSHAL_U16LE(ctx, val->stat.file_extension.len);
- MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_extension.utf8, val->stat.file_extension.len);
- MARSHAL_U32LE(ctx, val->stat.file_owner_n_uid);
- MARSHAL_U32LE(ctx, val->stat.file_owner_n_gid);
- MARSHAL_U32LE(ctx, val->stat.file_last_modified_n_uid);
+ MARSHAL_U16LE(ctx, val->stat.extension.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.extension.utf8, val->stat.extension.len);
+ MARSHAL_U32LE(ctx, val->stat.owner_unum);
+ MARSHAL_U32LE(ctx, val->stat.owner_gnum);
+ MARSHAL_U32LE(ctx, val->stat.last_modifier_unum);
}
#endif /* CONFIG_9P_ENABLE_9P2000_u */
- return false;
+ 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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rwstat",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rwstat message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Topenfd",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Topenfd message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3690,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Ropenfd",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Ropenfd message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3712,19 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rlerror",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rlerror message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3732,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Tstatfs",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Tstatfs message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3750,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rstatfs",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rstatfs message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3776,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Tlopen",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Tlopen message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3795,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rlopen",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rlopen message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3816,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Tlcreate",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Tlcreate message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3839,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rlcreate",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rlcreate message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3860,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Tsymlink",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Tsymlink message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3883,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rsymlink",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rsymlink message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3903,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Tmknod",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Tmknod message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3927,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rmknod",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rmknod message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3947,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Trename",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Trename message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -3968,34 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rrename",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rrename message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Treadlink",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Treadlink message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4003,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rreadlink",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rreadlink message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4022,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Tgetattr",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Tgetattr message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4041,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rgetattr",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rgetattr message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4080,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Tsetattr",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Tsetattr message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4107,34 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rsetattr",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rsetattr message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Txattrwalk",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Txattrwalk message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4145,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rxattrwalk",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rxattrwalk message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4163,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Txattrcreate",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Txattrcreate message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4185,34 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rxattrcreate",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rxattrcreate message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Treaddir",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Treaddir message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4222,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rreaddir",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rreaddir message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = (uint32_t)needed_size;
uint32_t offsetof_size = 0;
@@ -4241,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Tfsync",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Tfsync message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4260,34 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rfsync",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rfsync message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Tlock",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Tlock message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4302,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rlock",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rlock message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4320,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Tgetlock",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Tgetlock message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4344,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rgetlock",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rgetlock message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4367,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Tlink",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Tlink message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4388,34 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rlink",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rlink message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Tmkdir",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Tmkdir message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4427,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rmkdir",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rmkdir message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4447,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Trenameat",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Trenameat message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4470,34 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rrenameat",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rrenameat message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Tunlinkat",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Tunlinkat message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4508,36 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Runlinkat",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Runlinkat message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Tsession",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Tsession message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4545,37 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rsession",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rsession message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Tsread",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Tsread message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = (uint32_t)needed_size;
uint32_t offsetof_size = 0;
@@ -4588,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rsread",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rsread message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = (uint32_t)needed_size;
uint32_t offsetof_size = 0;
@@ -4607,20 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Tswrite",
- ctx->version ? "negotiated" : "client",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Tswrite message too large to marshal into ",
+ ctx->version ? "negotiated" : "client", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = (uint32_t)needed_size;
uint32_t offsetof_size = 0;
@@ -4635,17 +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_errorf(ctx, LIB9P_ERRNO_L_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
- "Rswrite",
- ctx->version ? "negotiated" : "server",
- ctx->max_msg_size);
- return true;
+ return error_new(E_POSIX_ERANGE, "Rswrite message too large to marshal into ",
+ ctx->version ? "negotiated" : "server", " limit",
+ " (", needed_size, " > ", ctx->max_msg_size, ")");
}
uint32_t offsetof_end = needed_size;
uint32_t offsetof_size = 0;
@@ -4653,3192 +4253,3185 @@ 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 */
-/* *_format *******************************************************************/
+/* fmt_print_* ****************************************************************/
-#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
-static void lib9p_tag_format(lib9p_tag_t *self, struct fmt_state *state) {
+#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
+[[maybe_unused]] static void fmt_print_tag(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, lib9p_tag_t *self) {
switch (*self) {
case LIB9P_TAG_NOTAG:
- fmt_state_puts(state, "NOTAG");
+ fmt_print_str(w, "NOTAG");
break;
default:
- fmt_state_printf(state, "%"PRIu16, *self);
+ fmt_print_base10(w, *self);
}
}
-static void lib9p_fid_format(lib9p_fid_t *self, struct fmt_state *state) {
+[[maybe_unused]] static void fmt_print_fid(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, lib9p_fid_t *self) {
switch (*self) {
case LIB9P_FID_NOFID:
- fmt_state_puts(state, "NOFID");
+ fmt_print_str(w, "NOFID");
break;
default:
- fmt_state_printf(state, "%"PRIu32, *self);
+ fmt_print_base10(w, *self);
}
}
-static void lib9p_s_format(struct lib9p_s *self, struct fmt_state *state) {
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wformat"
-#pragma GCC diagnostic ignored "-Wformat-extra-args"
- fmt_state_printf(state, "%.*q", self->len, self->utf8);
-#pragma GCC diagnostic pop
-}
-
-#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
-#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
-static void lib9p_dm_format(lib9p_dm_t *self, struct fmt_state *state) {
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_uninitialized */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_uninitialized
+[[maybe_unused]] static void fmt_print_dm(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, lib9p_dm_t *self) {
bool empty = true;
- fmt_state_putchar(state, '(');
+ fmt_print_byte(w, '(');
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<31)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "DIR");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "DIR");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<30)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "APPEND");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "APPEND");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<29)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "EXCL");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "EXCL");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<28)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "_PLAN9_MOUNT");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "_PLAN9_MOUNT");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<27)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "AUTH");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "AUTH");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<26)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "TMP");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "TMP");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<25)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<25");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<25");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<24)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<24");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<24");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<23)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "DEVICE");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "DEVICE");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<22)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<22");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<22");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<21)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "PIPE");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "PIPE");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<20)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "SOCKET");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "SOCKET");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<19)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "SETUID");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "SETUID");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<18)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "SETGID");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "SETGID");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<17)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<17");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<17");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<16)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<16");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<16");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<15)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<15");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<15");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<14)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<14");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<14");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<13)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<13");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<13");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<12)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<12");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<12");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<11)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<11");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<11");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<10)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<10");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<10");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<9)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<9");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<9");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<8)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "OWNER_R");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "OWNER_R");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<7)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "OWNER_W");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "OWNER_W");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<6)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "OWNER_X");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "OWNER_X");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<5)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "GROUP_R");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "GROUP_R");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<4)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "GROUP_W");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "GROUP_W");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<3)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "GROUP_X");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "GROUP_X");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<2)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "OTHER_R");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "OTHER_R");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<1)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "OTHER_W");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "OTHER_W");
empty = false;
}
if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<0)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "OTHER_X");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "OTHER_X");
empty = false;
}
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_printf(state, "%#04"PRIo32, *self & 0777);
- fmt_state_putchar(state, ')');
+ fmt_print_byte(w, '|');
+ fmt_print(w, (rjust, 4, '0', (base8, *self & 0777)));
+ fmt_print_byte(w, ')');
}
-#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 void lib9p_qt_format(lib9p_qt_t *self, struct fmt_state *state) {
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || 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 || CONFIG_9P_ENABLE_uninitialized
+[[maybe_unused]] static void fmt_print_qt(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, lib9p_qt_t *self) {
bool empty = true;
- fmt_state_putchar(state, '(');
+ fmt_print_byte(w, '(');
if (*self & (UINT8_C(1)<<7)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "DIR");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "DIR");
empty = false;
}
if (*self & (UINT8_C(1)<<6)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "APPEND");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "APPEND");
empty = false;
}
if (*self & (UINT8_C(1)<<5)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "EXCL");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "EXCL");
empty = false;
}
if (*self & (UINT8_C(1)<<4)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "_PLAN9_MOUNT");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "_PLAN9_MOUNT");
empty = false;
}
if (*self & (UINT8_C(1)<<3)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "AUTH");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "AUTH");
empty = false;
}
if (*self & (UINT8_C(1)<<2)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "TMP");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "TMP");
empty = false;
}
if (*self & (UINT8_C(1)<<1)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "SYMLINK");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "SYMLINK");
empty = false;
}
if (*self & (UINT8_C(1)<<0)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<0");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<0");
empty = false;
}
if (empty)
- fmt_state_putchar(state, '0');
- fmt_state_putchar(state, ')');
-}
-
-static void lib9p_qid_format(struct lib9p_qid *self, struct fmt_state *state) {
- fmt_state_putchar(state, '{');
- fmt_state_puts(state, " type=");
- lib9p_qt_format(&self->type, state);
- fmt_state_puts(state, " vers=");
- fmt_state_printf(state, "%"PRIu32, self->vers);
- fmt_state_puts(state, " path=");
- fmt_state_printf(state, "%"PRIu64, self->path);
- fmt_state_puts(state, " }");
+ fmt_print_byte(w, '0');
+ fmt_print_byte(w, ')');
}
-#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_uninitialized */
#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
-static void lib9p_stat_format(struct lib9p_stat *self, struct fmt_state *state) {
- fmt_state_putchar(state, '{');
- fmt_state_puts(state, " kern_type=");
- fmt_state_printf(state, "%"PRIu16, self->kern_type);
- fmt_state_puts(state, " kern_dev=");
- fmt_state_printf(state, "%"PRIu32, self->kern_dev);
- fmt_state_puts(state, " file_qid=");
- lib9p_qid_format(&self->file_qid, state);
- fmt_state_puts(state, " file_mode=");
- lib9p_dm_format(&self->file_mode, state);
- fmt_state_puts(state, " file_atime=");
- fmt_state_printf(state, "%"PRIu32, self->file_atime);
- fmt_state_puts(state, " file_mtime=");
- fmt_state_printf(state, "%"PRIu32, self->file_mtime);
- fmt_state_puts(state, " file_size=");
- fmt_state_printf(state, "%"PRIu64, self->file_size);
- fmt_state_puts(state, " file_name=");
- lib9p_s_format(&self->file_name, state);
- fmt_state_puts(state, " file_owner_uid=");
- lib9p_s_format(&self->file_owner_uid, state);
- fmt_state_puts(state, " file_owner_gid=");
- lib9p_s_format(&self->file_owner_gid, state);
- fmt_state_puts(state, " file_last_modified_uid=");
- lib9p_s_format(&self->file_last_modified_uid, state);
-#if CONFIG_9P_ENABLE_9P2000_u
- fmt_state_puts(state, " file_extension=");
- lib9p_s_format(&self->file_extension, state);
- fmt_state_puts(state, " file_owner_n_uid=");
- lib9p_nuid_format(&self->file_owner_n_uid, state);
- fmt_state_puts(state, " file_owner_n_gid=");
- lib9p_nuid_format(&self->file_owner_n_gid, state);
- fmt_state_puts(state, " file_last_modified_n_uid=");
- lib9p_nuid_format(&self->file_last_modified_n_uid, state);
-#endif /* CONFIG_9P_ENABLE_9P2000_u */
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_o_format(lib9p_o_t *self, struct fmt_state *state) {
+[[maybe_unused]] static void fmt_print_o(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, lib9p_o_t *self) {
bool empty = true;
- fmt_state_putchar(state, '(');
+ fmt_print_byte(w, '(');
if (*self & (UINT8_C(1)<<7)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<7");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<7");
empty = false;
}
if (*self & (UINT8_C(1)<<6)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "RCLOSE");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "RCLOSE");
empty = false;
}
if (*self & (UINT8_C(1)<<5)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "CEXEC");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "CEXEC");
empty = false;
}
if (*self & (UINT8_C(1)<<4)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "TRUNC");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "TRUNC");
empty = false;
}
if (*self & (UINT8_C(1)<<3)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<3");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<3");
empty = false;
}
if (*self & (UINT8_C(1)<<2)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<2");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<2");
empty = false;
}
switch (*self & LIB9P_O_MODE_MASK) {
case LIB9P_O_MODE_READ:
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "MODE_READ");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "MODE_READ");
empty = false;
break;
case LIB9P_O_MODE_WRITE:
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "MODE_WRITE");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "MODE_WRITE");
empty = false;
break;
case LIB9P_O_MODE_RDWR:
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "MODE_RDWR");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "MODE_RDWR");
empty = false;
break;
case LIB9P_O_MODE_EXEC:
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "MODE_EXEC");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "MODE_EXEC");
empty = false;
break;
default:
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_printf(state, "%"PRIu8, *self & LIB9P_O_MODE_MASK);
+ fmt_print_byte(w, '|');
+ fmt_print_base10(w, *self & LIB9P_O_MODE_MASK);
empty = false;
}
if (empty)
- fmt_state_putchar(state, '0');
- fmt_state_putchar(state, ')');
-}
-
-#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
-#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
-static void lib9p_msg_Tversion_format(struct lib9p_msg_Tversion *self, struct fmt_state *state) {
- fmt_state_puts(state, "Tversion {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " max_msg_size=");
- fmt_state_printf(state, "%"PRIu32, self->max_msg_size);
- fmt_state_puts(state, " version=");
- lib9p_s_format(&self->version, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rversion_format(struct lib9p_msg_Rversion *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rversion {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " max_msg_size=");
- fmt_state_printf(state, "%"PRIu32, self->max_msg_size);
- fmt_state_puts(state, " version=");
- lib9p_s_format(&self->version, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Tauth_format(struct lib9p_msg_Tauth *self, struct fmt_state *state) {
- fmt_state_puts(state, "Tauth {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " afid=");
- lib9p_fid_format(&self->afid, state);
- fmt_state_puts(state, " uname=");
- lib9p_s_format(&self->uname, state);
- fmt_state_puts(state, " aname=");
- lib9p_s_format(&self->aname, state);
-#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u
- fmt_state_puts(state, " n_uid=");
- lib9p_nuid_format(&self->n_uid, state);
-#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rauth_format(struct lib9p_msg_Rauth *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rauth {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " aqid=");
- lib9p_qid_format(&self->aqid, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Tattach_format(struct lib9p_msg_Tattach *self, struct fmt_state *state) {
- fmt_state_puts(state, "Tattach {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " fid=");
- lib9p_fid_format(&self->fid, state);
- fmt_state_puts(state, " afid=");
- lib9p_fid_format(&self->afid, state);
- fmt_state_puts(state, " uname=");
- lib9p_s_format(&self->uname, state);
- fmt_state_puts(state, " aname=");
- lib9p_s_format(&self->aname, state);
-#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u
- fmt_state_puts(state, " n_uid=");
- lib9p_nuid_format(&self->n_uid, state);
-#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rattach_format(struct lib9p_msg_Rattach *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rattach {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " qid=");
- lib9p_qid_format(&self->qid, state);
- fmt_state_puts(state, " }");
-}
-
-#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
-#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
-static void lib9p_msg_Rerror_format(struct lib9p_msg_Rerror *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rerror {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " errstr=");
- lib9p_s_format(&self->errstr, state);
-#if CONFIG_9P_ENABLE_9P2000_u
- fmt_state_puts(state, " errnum=");
- lib9p_errno_format(&self->errnum, state);
-#endif /* CONFIG_9P_ENABLE_9P2000_u */
- fmt_state_puts(state, " }");
-}
-
-#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
-#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
-static void lib9p_msg_Tflush_format(struct lib9p_msg_Tflush *self, struct fmt_state *state) {
- fmt_state_puts(state, "Tflush {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " oldtag=");
- fmt_state_printf(state, "%"PRIu16, self->oldtag);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rflush_format(struct lib9p_msg_Rflush *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rflush {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Twalk_format(struct lib9p_msg_Twalk *self, struct fmt_state *state) {
- fmt_state_puts(state, "Twalk {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " fid=");
- lib9p_fid_format(&self->fid, state);
- fmt_state_puts(state, " newfid=");
- lib9p_fid_format(&self->newfid, state);
- fmt_state_puts(state, " nwname=");
- fmt_state_printf(state, "%"PRIu16, self->nwname);
- fmt_state_puts(state, " wname=[");
- for (uint16_t i = 0; i < self->nwname; i++) {
- if (i)
- fmt_state_putchar(state, ',');
- fmt_state_putchar(state, ' ');
- lib9p_s_format(&self->wname[i], state);
- }
- fmt_state_puts(state, " ]");
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rwalk_format(struct lib9p_msg_Rwalk *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rwalk {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " nwqid=");
- fmt_state_printf(state, "%"PRIu16, self->nwqid);
- fmt_state_puts(state, " wqid=[");
- for (uint16_t i = 0; i < self->nwqid; i++) {
- if (i)
- fmt_state_putchar(state, ',');
- fmt_state_putchar(state, ' ');
- lib9p_qid_format(&self->wqid[i], state);
- }
- fmt_state_puts(state, " ]");
- fmt_state_puts(state, " }");
-}
-
-#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
-#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
-static void lib9p_msg_Topen_format(struct lib9p_msg_Topen *self, struct fmt_state *state) {
- fmt_state_puts(state, "Topen {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " fid=");
- lib9p_fid_format(&self->fid, state);
- fmt_state_puts(state, " mode=");
- lib9p_o_format(&self->mode, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Ropen_format(struct lib9p_msg_Ropen *self, struct fmt_state *state) {
- fmt_state_puts(state, "Ropen {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " qid=");
- lib9p_qid_format(&self->qid, state);
- fmt_state_puts(state, " iounit=");
- fmt_state_printf(state, "%"PRIu32, self->iounit);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Tcreate_format(struct lib9p_msg_Tcreate *self, struct fmt_state *state) {
- fmt_state_puts(state, "Tcreate {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " fid=");
- lib9p_fid_format(&self->fid, state);
- fmt_state_puts(state, " name=");
- lib9p_s_format(&self->name, state);
- fmt_state_puts(state, " perm=");
- lib9p_dm_format(&self->perm, state);
- fmt_state_puts(state, " mode=");
- lib9p_o_format(&self->mode, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rcreate_format(struct lib9p_msg_Rcreate *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rcreate {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " qid=");
- lib9p_qid_format(&self->qid, state);
- fmt_state_puts(state, " iounit=");
- fmt_state_printf(state, "%"PRIu32, self->iounit);
- fmt_state_puts(state, " }");
-}
-
-#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
-#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
-static void lib9p_msg_Tread_format(struct lib9p_msg_Tread *self, struct fmt_state *state) {
- fmt_state_puts(state, "Tread {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " fid=");
- lib9p_fid_format(&self->fid, state);
- fmt_state_puts(state, " offset=");
- fmt_state_printf(state, "%"PRIu64, self->offset);
- fmt_state_puts(state, " count=");
- fmt_state_printf(state, "%"PRIu32, self->count);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rread_format(struct lib9p_msg_Rread *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rread {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " count=");
- fmt_state_printf(state, "%"PRIu32, self->count);
- if (is_valid_utf8_without_nul((uint8_t *)self->data, (size_t)self->count)) {
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wformat"
-#pragma GCC diagnostic ignored "-Wformat-extra-args"
- fmt_state_printf(state, " data=%.*q%s",
- (int)(self->count < 50 ? self->count : 50),
- (char *)self->data,
- self->count < 50 ? "" : "...");
-#pragma GCC diagnostic pop
- } else {
- fmt_state_puts(state, " data=<bytedata>");
- }
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Twrite_format(struct lib9p_msg_Twrite *self, struct fmt_state *state) {
- fmt_state_puts(state, "Twrite {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " fid=");
- lib9p_fid_format(&self->fid, state);
- fmt_state_puts(state, " offset=");
- fmt_state_printf(state, "%"PRIu64, self->offset);
- fmt_state_puts(state, " count=");
- fmt_state_printf(state, "%"PRIu32, self->count);
- if (is_valid_utf8_without_nul((uint8_t *)self->data, (size_t)self->count)) {
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wformat"
-#pragma GCC diagnostic ignored "-Wformat-extra-args"
- fmt_state_printf(state, " data=%.*q%s",
- (int)(self->count < 50 ? self->count : 50),
- (char *)self->data,
- self->count < 50 ? "" : "...");
-#pragma GCC diagnostic pop
- } else {
- fmt_state_puts(state, " data=<bytedata>");
- }
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rwrite_format(struct lib9p_msg_Rwrite *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rwrite {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " count=");
- fmt_state_printf(state, "%"PRIu32, self->count);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Tclunk_format(struct lib9p_msg_Tclunk *self, struct fmt_state *state) {
- fmt_state_puts(state, "Tclunk {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " fid=");
- lib9p_fid_format(&self->fid, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rclunk_format(struct lib9p_msg_Rclunk *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rclunk {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Tremove_format(struct lib9p_msg_Tremove *self, struct fmt_state *state) {
- fmt_state_puts(state, "Tremove {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " fid=");
- lib9p_fid_format(&self->fid, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rremove_format(struct lib9p_msg_Rremove *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rremove {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " }");
-}
-
-#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
-#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
-static void lib9p_msg_Tstat_format(struct lib9p_msg_Tstat *self, struct fmt_state *state) {
- fmt_state_puts(state, "Tstat {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " fid=");
- lib9p_fid_format(&self->fid, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rstat_format(struct lib9p_msg_Rstat *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rstat {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " stat=");
- lib9p_stat_format(&self->stat, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Twstat_format(struct lib9p_msg_Twstat *self, struct fmt_state *state) {
- fmt_state_puts(state, "Twstat {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " fid=");
- lib9p_fid_format(&self->fid, state);
- fmt_state_puts(state, " stat=");
- lib9p_stat_format(&self->stat, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rwstat_format(struct lib9p_msg_Rwstat *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rwstat {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " }");
+ fmt_print_byte(w, '0');
+ fmt_print_byte(w, ')');
}
#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 void lib9p_msg_Topenfd_format(struct lib9p_msg_Topenfd *self, struct fmt_state *state) {
- fmt_state_puts(state, "Topenfd {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " fid=");
- lib9p_fid_format(&self->fid, state);
- fmt_state_puts(state, " mode=");
- lib9p_o_format(&self->mode, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Ropenfd_format(struct lib9p_msg_Ropenfd *self, struct fmt_state *state) {
- fmt_state_puts(state, "Ropenfd {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " qid=");
- lib9p_qid_format(&self->qid, state);
- fmt_state_puts(state, " iounit=");
- fmt_state_printf(state, "%"PRIu32, self->iounit);
- fmt_state_puts(state, " unixfd=");
- fmt_state_printf(state, "%"PRIu32, self->unixfd);
- fmt_state_puts(state, " }");
-}
-
-#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u
-static void lib9p_nuid_format(lib9p_nuid_t *self, struct fmt_state *state) {
+[[maybe_unused]] static void fmt_print_nuid(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, lib9p_nuid_t *self) {
switch (*self) {
case LIB9P_NUID_NONUID:
- fmt_state_puts(state, "NONUID");
+ fmt_print_str(w, "NONUID");
break;
default:
- fmt_state_printf(state, "%"PRIu32, *self);
+ fmt_print_base10(w, *self);
}
}
-static void lib9p_errno_format(lib9p_errno_t *self, struct fmt_state *state) {
+[[maybe_unused]] static void fmt_print_errno(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, lib9p_errno_t *self) {
switch (*self) {
case LIB9P_ERRNO_NOERROR:
- fmt_state_puts(state, "NOERROR");
+ fmt_print_str(w, "NOERROR");
break;
case LIB9P_ERRNO_L_EPERM:
- fmt_state_puts(state, "L_EPERM");
+ fmt_print_str(w, "L_EPERM");
break;
case LIB9P_ERRNO_L_ENOENT:
- fmt_state_puts(state, "L_ENOENT");
+ fmt_print_str(w, "L_ENOENT");
break;
case LIB9P_ERRNO_L_ESRCH:
- fmt_state_puts(state, "L_ESRCH");
+ fmt_print_str(w, "L_ESRCH");
break;
case LIB9P_ERRNO_L_EINTR:
- fmt_state_puts(state, "L_EINTR");
+ fmt_print_str(w, "L_EINTR");
break;
case LIB9P_ERRNO_L_EIO:
- fmt_state_puts(state, "L_EIO");
+ fmt_print_str(w, "L_EIO");
break;
case LIB9P_ERRNO_L_ENXIO:
- fmt_state_puts(state, "L_ENXIO");
+ fmt_print_str(w, "L_ENXIO");
break;
case LIB9P_ERRNO_L_E2BIG:
- fmt_state_puts(state, "L_E2BIG");
+ fmt_print_str(w, "L_E2BIG");
break;
case LIB9P_ERRNO_L_ENOEXEC:
- fmt_state_puts(state, "L_ENOEXEC");
+ fmt_print_str(w, "L_ENOEXEC");
break;
case LIB9P_ERRNO_L_EBADF:
- fmt_state_puts(state, "L_EBADF");
+ fmt_print_str(w, "L_EBADF");
break;
case LIB9P_ERRNO_L_ECHILD:
- fmt_state_puts(state, "L_ECHILD");
+ fmt_print_str(w, "L_ECHILD");
break;
case LIB9P_ERRNO_L_EAGAIN:
- fmt_state_puts(state, "L_EAGAIN");
+ fmt_print_str(w, "L_EAGAIN");
break;
case LIB9P_ERRNO_L_ENOMEM:
- fmt_state_puts(state, "L_ENOMEM");
+ fmt_print_str(w, "L_ENOMEM");
break;
case LIB9P_ERRNO_L_EACCES:
- fmt_state_puts(state, "L_EACCES");
+ fmt_print_str(w, "L_EACCES");
break;
case LIB9P_ERRNO_L_EFAULT:
- fmt_state_puts(state, "L_EFAULT");
+ fmt_print_str(w, "L_EFAULT");
break;
case LIB9P_ERRNO_L_ENOTBLK:
- fmt_state_puts(state, "L_ENOTBLK");
+ fmt_print_str(w, "L_ENOTBLK");
break;
case LIB9P_ERRNO_L_EBUSY:
- fmt_state_puts(state, "L_EBUSY");
+ fmt_print_str(w, "L_EBUSY");
break;
case LIB9P_ERRNO_L_EEXIST:
- fmt_state_puts(state, "L_EEXIST");
+ fmt_print_str(w, "L_EEXIST");
break;
case LIB9P_ERRNO_L_EXDEV:
- fmt_state_puts(state, "L_EXDEV");
+ fmt_print_str(w, "L_EXDEV");
break;
case LIB9P_ERRNO_L_ENODEV:
- fmt_state_puts(state, "L_ENODEV");
+ fmt_print_str(w, "L_ENODEV");
break;
case LIB9P_ERRNO_L_ENOTDIR:
- fmt_state_puts(state, "L_ENOTDIR");
+ fmt_print_str(w, "L_ENOTDIR");
break;
case LIB9P_ERRNO_L_EISDIR:
- fmt_state_puts(state, "L_EISDIR");
+ fmt_print_str(w, "L_EISDIR");
break;
case LIB9P_ERRNO_L_EINVAL:
- fmt_state_puts(state, "L_EINVAL");
+ fmt_print_str(w, "L_EINVAL");
break;
case LIB9P_ERRNO_L_ENFILE:
- fmt_state_puts(state, "L_ENFILE");
+ fmt_print_str(w, "L_ENFILE");
break;
case LIB9P_ERRNO_L_EMFILE:
- fmt_state_puts(state, "L_EMFILE");
+ fmt_print_str(w, "L_EMFILE");
break;
case LIB9P_ERRNO_L_ENOTTY:
- fmt_state_puts(state, "L_ENOTTY");
+ fmt_print_str(w, "L_ENOTTY");
break;
case LIB9P_ERRNO_L_ETXTBSY:
- fmt_state_puts(state, "L_ETXTBSY");
+ fmt_print_str(w, "L_ETXTBSY");
break;
case LIB9P_ERRNO_L_EFBIG:
- fmt_state_puts(state, "L_EFBIG");
+ fmt_print_str(w, "L_EFBIG");
break;
case LIB9P_ERRNO_L_ENOSPC:
- fmt_state_puts(state, "L_ENOSPC");
+ fmt_print_str(w, "L_ENOSPC");
break;
case LIB9P_ERRNO_L_ESPIPE:
- fmt_state_puts(state, "L_ESPIPE");
+ fmt_print_str(w, "L_ESPIPE");
break;
case LIB9P_ERRNO_L_EROFS:
- fmt_state_puts(state, "L_EROFS");
+ fmt_print_str(w, "L_EROFS");
break;
case LIB9P_ERRNO_L_EMLINK:
- fmt_state_puts(state, "L_EMLINK");
+ fmt_print_str(w, "L_EMLINK");
break;
case LIB9P_ERRNO_L_EPIPE:
- fmt_state_puts(state, "L_EPIPE");
+ fmt_print_str(w, "L_EPIPE");
break;
case LIB9P_ERRNO_L_EDOM:
- fmt_state_puts(state, "L_EDOM");
+ fmt_print_str(w, "L_EDOM");
break;
case LIB9P_ERRNO_L_ERANGE:
- fmt_state_puts(state, "L_ERANGE");
+ fmt_print_str(w, "L_ERANGE");
break;
case LIB9P_ERRNO_L_EDEADLK:
- fmt_state_puts(state, "L_EDEADLK");
+ fmt_print_str(w, "L_EDEADLK");
break;
case LIB9P_ERRNO_L_ENAMETOOLONG:
- fmt_state_puts(state, "L_ENAMETOOLONG");
+ fmt_print_str(w, "L_ENAMETOOLONG");
break;
case LIB9P_ERRNO_L_ENOLCK:
- fmt_state_puts(state, "L_ENOLCK");
+ fmt_print_str(w, "L_ENOLCK");
break;
case LIB9P_ERRNO_L_ENOSYS:
- fmt_state_puts(state, "L_ENOSYS");
+ fmt_print_str(w, "L_ENOSYS");
break;
case LIB9P_ERRNO_L_ENOTEMPTY:
- fmt_state_puts(state, "L_ENOTEMPTY");
+ fmt_print_str(w, "L_ENOTEMPTY");
break;
case LIB9P_ERRNO_L_ELOOP:
- fmt_state_puts(state, "L_ELOOP");
+ fmt_print_str(w, "L_ELOOP");
break;
case LIB9P_ERRNO_L_ENOMSG:
- fmt_state_puts(state, "L_ENOMSG");
+ fmt_print_str(w, "L_ENOMSG");
break;
case LIB9P_ERRNO_L_EIDRM:
- fmt_state_puts(state, "L_EIDRM");
+ fmt_print_str(w, "L_EIDRM");
break;
case LIB9P_ERRNO_L_ECHRNG:
- fmt_state_puts(state, "L_ECHRNG");
+ fmt_print_str(w, "L_ECHRNG");
break;
case LIB9P_ERRNO_L_EL2NSYNC:
- fmt_state_puts(state, "L_EL2NSYNC");
+ fmt_print_str(w, "L_EL2NSYNC");
break;
case LIB9P_ERRNO_L_EL3HLT:
- fmt_state_puts(state, "L_EL3HLT");
+ fmt_print_str(w, "L_EL3HLT");
break;
case LIB9P_ERRNO_L_EL3RST:
- fmt_state_puts(state, "L_EL3RST");
+ fmt_print_str(w, "L_EL3RST");
break;
case LIB9P_ERRNO_L_ELNRNG:
- fmt_state_puts(state, "L_ELNRNG");
+ fmt_print_str(w, "L_ELNRNG");
break;
case LIB9P_ERRNO_L_EUNATCH:
- fmt_state_puts(state, "L_EUNATCH");
+ fmt_print_str(w, "L_EUNATCH");
break;
case LIB9P_ERRNO_L_ENOCSI:
- fmt_state_puts(state, "L_ENOCSI");
+ fmt_print_str(w, "L_ENOCSI");
break;
case LIB9P_ERRNO_L_EL2HLT:
- fmt_state_puts(state, "L_EL2HLT");
+ fmt_print_str(w, "L_EL2HLT");
break;
case LIB9P_ERRNO_L_EBADE:
- fmt_state_puts(state, "L_EBADE");
+ fmt_print_str(w, "L_EBADE");
break;
case LIB9P_ERRNO_L_EBADR:
- fmt_state_puts(state, "L_EBADR");
+ fmt_print_str(w, "L_EBADR");
break;
case LIB9P_ERRNO_L_EXFULL:
- fmt_state_puts(state, "L_EXFULL");
+ fmt_print_str(w, "L_EXFULL");
break;
case LIB9P_ERRNO_L_ENOANO:
- fmt_state_puts(state, "L_ENOANO");
+ fmt_print_str(w, "L_ENOANO");
break;
case LIB9P_ERRNO_L_EBADRQC:
- fmt_state_puts(state, "L_EBADRQC");
+ fmt_print_str(w, "L_EBADRQC");
break;
case LIB9P_ERRNO_L_EBADSLT:
- fmt_state_puts(state, "L_EBADSLT");
+ fmt_print_str(w, "L_EBADSLT");
break;
case LIB9P_ERRNO_L_EBFONT:
- fmt_state_puts(state, "L_EBFONT");
+ fmt_print_str(w, "L_EBFONT");
break;
case LIB9P_ERRNO_L_ENOSTR:
- fmt_state_puts(state, "L_ENOSTR");
+ fmt_print_str(w, "L_ENOSTR");
break;
case LIB9P_ERRNO_L_ENODATA:
- fmt_state_puts(state, "L_ENODATA");
+ fmt_print_str(w, "L_ENODATA");
break;
case LIB9P_ERRNO_L_ETIME:
- fmt_state_puts(state, "L_ETIME");
+ fmt_print_str(w, "L_ETIME");
break;
case LIB9P_ERRNO_L_ENOSR:
- fmt_state_puts(state, "L_ENOSR");
+ fmt_print_str(w, "L_ENOSR");
break;
case LIB9P_ERRNO_L_ENONET:
- fmt_state_puts(state, "L_ENONET");
+ fmt_print_str(w, "L_ENONET");
break;
case LIB9P_ERRNO_L_ENOPKG:
- fmt_state_puts(state, "L_ENOPKG");
+ fmt_print_str(w, "L_ENOPKG");
break;
case LIB9P_ERRNO_L_EREMOTE:
- fmt_state_puts(state, "L_EREMOTE");
+ fmt_print_str(w, "L_EREMOTE");
break;
case LIB9P_ERRNO_L_ENOLINK:
- fmt_state_puts(state, "L_ENOLINK");
+ fmt_print_str(w, "L_ENOLINK");
break;
case LIB9P_ERRNO_L_EADV:
- fmt_state_puts(state, "L_EADV");
+ fmt_print_str(w, "L_EADV");
break;
case LIB9P_ERRNO_L_ESRMNT:
- fmt_state_puts(state, "L_ESRMNT");
+ fmt_print_str(w, "L_ESRMNT");
break;
case LIB9P_ERRNO_L_ECOMM:
- fmt_state_puts(state, "L_ECOMM");
+ fmt_print_str(w, "L_ECOMM");
break;
case LIB9P_ERRNO_L_EPROTO:
- fmt_state_puts(state, "L_EPROTO");
+ fmt_print_str(w, "L_EPROTO");
break;
case LIB9P_ERRNO_L_EMULTIHOP:
- fmt_state_puts(state, "L_EMULTIHOP");
+ fmt_print_str(w, "L_EMULTIHOP");
break;
case LIB9P_ERRNO_L_EDOTDOT:
- fmt_state_puts(state, "L_EDOTDOT");
+ fmt_print_str(w, "L_EDOTDOT");
break;
case LIB9P_ERRNO_L_EBADMSG:
- fmt_state_puts(state, "L_EBADMSG");
+ fmt_print_str(w, "L_EBADMSG");
break;
case LIB9P_ERRNO_L_EOVERFLOW:
- fmt_state_puts(state, "L_EOVERFLOW");
+ fmt_print_str(w, "L_EOVERFLOW");
break;
case LIB9P_ERRNO_L_ENOTUNIQ:
- fmt_state_puts(state, "L_ENOTUNIQ");
+ fmt_print_str(w, "L_ENOTUNIQ");
break;
case LIB9P_ERRNO_L_EBADFD:
- fmt_state_puts(state, "L_EBADFD");
+ fmt_print_str(w, "L_EBADFD");
break;
case LIB9P_ERRNO_L_EREMCHG:
- fmt_state_puts(state, "L_EREMCHG");
+ fmt_print_str(w, "L_EREMCHG");
break;
case LIB9P_ERRNO_L_ELIBACC:
- fmt_state_puts(state, "L_ELIBACC");
+ fmt_print_str(w, "L_ELIBACC");
break;
case LIB9P_ERRNO_L_ELIBBAD:
- fmt_state_puts(state, "L_ELIBBAD");
+ fmt_print_str(w, "L_ELIBBAD");
break;
case LIB9P_ERRNO_L_ELIBSCN:
- fmt_state_puts(state, "L_ELIBSCN");
+ fmt_print_str(w, "L_ELIBSCN");
break;
case LIB9P_ERRNO_L_ELIBMAX:
- fmt_state_puts(state, "L_ELIBMAX");
+ fmt_print_str(w, "L_ELIBMAX");
break;
case LIB9P_ERRNO_L_ELIBEXEC:
- fmt_state_puts(state, "L_ELIBEXEC");
+ fmt_print_str(w, "L_ELIBEXEC");
break;
case LIB9P_ERRNO_L_EILSEQ:
- fmt_state_puts(state, "L_EILSEQ");
+ fmt_print_str(w, "L_EILSEQ");
break;
case LIB9P_ERRNO_L_ERESTART:
- fmt_state_puts(state, "L_ERESTART");
+ fmt_print_str(w, "L_ERESTART");
break;
case LIB9P_ERRNO_L_ESTRPIPE:
- fmt_state_puts(state, "L_ESTRPIPE");
+ fmt_print_str(w, "L_ESTRPIPE");
break;
case LIB9P_ERRNO_L_EUSERS:
- fmt_state_puts(state, "L_EUSERS");
+ fmt_print_str(w, "L_EUSERS");
break;
case LIB9P_ERRNO_L_ENOTSOCK:
- fmt_state_puts(state, "L_ENOTSOCK");
+ fmt_print_str(w, "L_ENOTSOCK");
break;
case LIB9P_ERRNO_L_EDESTADDRREQ:
- fmt_state_puts(state, "L_EDESTADDRREQ");
+ fmt_print_str(w, "L_EDESTADDRREQ");
break;
case LIB9P_ERRNO_L_EMSGSIZE:
- fmt_state_puts(state, "L_EMSGSIZE");
+ fmt_print_str(w, "L_EMSGSIZE");
break;
case LIB9P_ERRNO_L_EPROTOTYPE:
- fmt_state_puts(state, "L_EPROTOTYPE");
+ fmt_print_str(w, "L_EPROTOTYPE");
break;
case LIB9P_ERRNO_L_ENOPROTOOPT:
- fmt_state_puts(state, "L_ENOPROTOOPT");
+ fmt_print_str(w, "L_ENOPROTOOPT");
break;
case LIB9P_ERRNO_L_EPROTONOSUPPORT:
- fmt_state_puts(state, "L_EPROTONOSUPPORT");
+ fmt_print_str(w, "L_EPROTONOSUPPORT");
break;
case LIB9P_ERRNO_L_ESOCKTNOSUPPORT:
- fmt_state_puts(state, "L_ESOCKTNOSUPPORT");
+ fmt_print_str(w, "L_ESOCKTNOSUPPORT");
break;
case LIB9P_ERRNO_L_EOPNOTSUPP:
- fmt_state_puts(state, "L_EOPNOTSUPP");
+ fmt_print_str(w, "L_EOPNOTSUPP");
break;
case LIB9P_ERRNO_L_EPFNOSUPPORT:
- fmt_state_puts(state, "L_EPFNOSUPPORT");
+ fmt_print_str(w, "L_EPFNOSUPPORT");
break;
case LIB9P_ERRNO_L_EAFNOSUPPORT:
- fmt_state_puts(state, "L_EAFNOSUPPORT");
+ fmt_print_str(w, "L_EAFNOSUPPORT");
break;
case LIB9P_ERRNO_L_EADDRINUSE:
- fmt_state_puts(state, "L_EADDRINUSE");
+ fmt_print_str(w, "L_EADDRINUSE");
break;
case LIB9P_ERRNO_L_EADDRNOTAVAIL:
- fmt_state_puts(state, "L_EADDRNOTAVAIL");
+ fmt_print_str(w, "L_EADDRNOTAVAIL");
break;
case LIB9P_ERRNO_L_ENETDOWN:
- fmt_state_puts(state, "L_ENETDOWN");
+ fmt_print_str(w, "L_ENETDOWN");
break;
case LIB9P_ERRNO_L_ENETUNREACH:
- fmt_state_puts(state, "L_ENETUNREACH");
+ fmt_print_str(w, "L_ENETUNREACH");
break;
case LIB9P_ERRNO_L_ENETRESET:
- fmt_state_puts(state, "L_ENETRESET");
+ fmt_print_str(w, "L_ENETRESET");
break;
case LIB9P_ERRNO_L_ECONNABORTED:
- fmt_state_puts(state, "L_ECONNABORTED");
+ fmt_print_str(w, "L_ECONNABORTED");
break;
case LIB9P_ERRNO_L_ECONNRESET:
- fmt_state_puts(state, "L_ECONNRESET");
+ fmt_print_str(w, "L_ECONNRESET");
break;
case LIB9P_ERRNO_L_ENOBUFS:
- fmt_state_puts(state, "L_ENOBUFS");
+ fmt_print_str(w, "L_ENOBUFS");
break;
case LIB9P_ERRNO_L_EISCONN:
- fmt_state_puts(state, "L_EISCONN");
+ fmt_print_str(w, "L_EISCONN");
break;
case LIB9P_ERRNO_L_ENOTCONN:
- fmt_state_puts(state, "L_ENOTCONN");
+ fmt_print_str(w, "L_ENOTCONN");
break;
case LIB9P_ERRNO_L_ESHUTDOWN:
- fmt_state_puts(state, "L_ESHUTDOWN");
+ fmt_print_str(w, "L_ESHUTDOWN");
break;
case LIB9P_ERRNO_L_ETOOMANYREFS:
- fmt_state_puts(state, "L_ETOOMANYREFS");
+ fmt_print_str(w, "L_ETOOMANYREFS");
break;
case LIB9P_ERRNO_L_ETIMEDOUT:
- fmt_state_puts(state, "L_ETIMEDOUT");
+ fmt_print_str(w, "L_ETIMEDOUT");
break;
case LIB9P_ERRNO_L_ECONNREFUSED:
- fmt_state_puts(state, "L_ECONNREFUSED");
+ fmt_print_str(w, "L_ECONNREFUSED");
break;
case LIB9P_ERRNO_L_EHOSTDOWN:
- fmt_state_puts(state, "L_EHOSTDOWN");
+ fmt_print_str(w, "L_EHOSTDOWN");
break;
case LIB9P_ERRNO_L_EHOSTUNREACH:
- fmt_state_puts(state, "L_EHOSTUNREACH");
+ fmt_print_str(w, "L_EHOSTUNREACH");
break;
case LIB9P_ERRNO_L_EALREADY:
- fmt_state_puts(state, "L_EALREADY");
+ fmt_print_str(w, "L_EALREADY");
break;
case LIB9P_ERRNO_L_EINPROGRESS:
- fmt_state_puts(state, "L_EINPROGRESS");
+ fmt_print_str(w, "L_EINPROGRESS");
break;
case LIB9P_ERRNO_L_ESTALE:
- fmt_state_puts(state, "L_ESTALE");
+ fmt_print_str(w, "L_ESTALE");
break;
case LIB9P_ERRNO_L_EUCLEAN:
- fmt_state_puts(state, "L_EUCLEAN");
+ fmt_print_str(w, "L_EUCLEAN");
break;
case LIB9P_ERRNO_L_ENOTNAM:
- fmt_state_puts(state, "L_ENOTNAM");
+ fmt_print_str(w, "L_ENOTNAM");
break;
case LIB9P_ERRNO_L_ENAVAIL:
- fmt_state_puts(state, "L_ENAVAIL");
+ fmt_print_str(w, "L_ENAVAIL");
break;
case LIB9P_ERRNO_L_EISNAM:
- fmt_state_puts(state, "L_EISNAM");
+ fmt_print_str(w, "L_EISNAM");
break;
case LIB9P_ERRNO_L_EREMOTEIO:
- fmt_state_puts(state, "L_EREMOTEIO");
+ fmt_print_str(w, "L_EREMOTEIO");
break;
case LIB9P_ERRNO_L_EDQUOT:
- fmt_state_puts(state, "L_EDQUOT");
+ fmt_print_str(w, "L_EDQUOT");
break;
case LIB9P_ERRNO_L_ENOMEDIUM:
- fmt_state_puts(state, "L_ENOMEDIUM");
+ fmt_print_str(w, "L_ENOMEDIUM");
break;
case LIB9P_ERRNO_L_EMEDIUMTYPE:
- fmt_state_puts(state, "L_EMEDIUMTYPE");
+ fmt_print_str(w, "L_EMEDIUMTYPE");
break;
case LIB9P_ERRNO_L_ECANCELED:
- fmt_state_puts(state, "L_ECANCELED");
+ fmt_print_str(w, "L_ECANCELED");
break;
case LIB9P_ERRNO_L_ENOKEY:
- fmt_state_puts(state, "L_ENOKEY");
+ fmt_print_str(w, "L_ENOKEY");
break;
case LIB9P_ERRNO_L_EKEYEXPIRED:
- fmt_state_puts(state, "L_EKEYEXPIRED");
+ fmt_print_str(w, "L_EKEYEXPIRED");
break;
case LIB9P_ERRNO_L_EKEYREVOKED:
- fmt_state_puts(state, "L_EKEYREVOKED");
+ fmt_print_str(w, "L_EKEYREVOKED");
break;
case LIB9P_ERRNO_L_EKEYREJECTED:
- fmt_state_puts(state, "L_EKEYREJECTED");
+ fmt_print_str(w, "L_EKEYREJECTED");
break;
case LIB9P_ERRNO_L_EOWNERDEAD:
- fmt_state_puts(state, "L_EOWNERDEAD");
+ fmt_print_str(w, "L_EOWNERDEAD");
break;
case LIB9P_ERRNO_L_ENOTRECOVERABLE:
- fmt_state_puts(state, "L_ENOTRECOVERABLE");
+ fmt_print_str(w, "L_ENOTRECOVERABLE");
break;
case LIB9P_ERRNO_L_ERFKILL:
- fmt_state_puts(state, "L_ERFKILL");
+ fmt_print_str(w, "L_ERFKILL");
break;
case LIB9P_ERRNO_L_EHWPOISON:
- fmt_state_puts(state, "L_EHWPOISON");
+ fmt_print_str(w, "L_EHWPOISON");
break;
default:
- fmt_state_printf(state, "%"PRIu32, *self);
+ fmt_print_base10(w, *self);
}
}
#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
#if CONFIG_9P_ENABLE_9P2000_L
-static void lib9p_super_magic_format(lib9p_super_magic_t *self, struct fmt_state *state) {
+[[maybe_unused]] static void fmt_print_super_magic(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, lib9p_super_magic_t *self) {
switch (*self) {
case LIB9P_SUPER_MAGIC_V9FS_MAGIC:
- fmt_state_puts(state, "V9FS_MAGIC");
+ fmt_print_str(w, "V9FS_MAGIC");
break;
default:
- fmt_state_printf(state, "%"PRIu32, *self);
+ fmt_print_base10(w, *self);
}
}
-static void lib9p_lo_format(lib9p_lo_t *self, struct fmt_state *state) {
+[[maybe_unused]] static void fmt_print_lo(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, lib9p_lo_t *self) {
bool empty = true;
- fmt_state_putchar(state, '(');
+ fmt_print_byte(w, '(');
if (*self & (UINT32_C(1)<<31)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<31");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<31");
empty = false;
}
if (*self & (UINT32_C(1)<<30)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<30");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<30");
empty = false;
}
if (*self & (UINT32_C(1)<<29)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<29");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<29");
empty = false;
}
if (*self & (UINT32_C(1)<<28)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<28");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<28");
empty = false;
}
if (*self & (UINT32_C(1)<<27)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<27");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<27");
empty = false;
}
if (*self & (UINT32_C(1)<<26)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<26");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<26");
empty = false;
}
if (*self & (UINT32_C(1)<<25)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<25");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<25");
empty = false;
}
if (*self & (UINT32_C(1)<<24)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<24");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<24");
empty = false;
}
if (*self & (UINT32_C(1)<<23)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<23");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<23");
empty = false;
}
if (*self & (UINT32_C(1)<<22)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<22");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<22");
empty = false;
}
if (*self & (UINT32_C(1)<<21)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<21");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<21");
empty = false;
}
if (*self & (UINT32_C(1)<<20)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "SYNC");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "SYNC");
empty = false;
}
if (*self & (UINT32_C(1)<<19)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "CLOEXEC");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "CLOEXEC");
empty = false;
}
if (*self & (UINT32_C(1)<<18)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "NOATIME");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "NOATIME");
empty = false;
}
if (*self & (UINT32_C(1)<<17)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "NOFOLLOW");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "NOFOLLOW");
empty = false;
}
if (*self & (UINT32_C(1)<<16)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "DIRECTORY");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "DIRECTORY");
empty = false;
}
if (*self & (UINT32_C(1)<<15)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "LARGEFILE");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "LARGEFILE");
empty = false;
}
if (*self & (UINT32_C(1)<<14)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "DIRECT");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "DIRECT");
empty = false;
}
if (*self & (UINT32_C(1)<<13)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "BSD_FASYNC");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "BSD_FASYNC");
empty = false;
}
if (*self & (UINT32_C(1)<<12)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "DSYNC");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "DSYNC");
empty = false;
}
if (*self & (UINT32_C(1)<<11)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "NONBLOCK");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "NONBLOCK");
empty = false;
}
if (*self & (UINT32_C(1)<<10)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "APPEND");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "APPEND");
empty = false;
}
if (*self & (UINT32_C(1)<<9)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "TRUNC");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "TRUNC");
empty = false;
}
if (*self & (UINT32_C(1)<<8)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "NOCTTY");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "NOCTTY");
empty = false;
}
if (*self & (UINT32_C(1)<<7)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "EXCL");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "EXCL");
empty = false;
}
if (*self & (UINT32_C(1)<<6)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "CREATE");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "CREATE");
empty = false;
}
if (*self & (UINT32_C(1)<<5)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<5");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<5");
empty = false;
}
if (*self & (UINT32_C(1)<<4)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<4");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<4");
empty = false;
}
if (*self & (UINT32_C(1)<<3)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<3");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<3");
empty = false;
}
if (*self & (UINT32_C(1)<<2)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<2");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<2");
empty = false;
}
switch (*self & LIB9P_LO_MODE_MASK) {
case LIB9P_LO_MODE_RDONLY:
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "MODE_RDONLY");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "MODE_RDONLY");
empty = false;
break;
case LIB9P_LO_MODE_WRONLY:
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "MODE_WRONLY");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "MODE_WRONLY");
empty = false;
break;
case LIB9P_LO_MODE_RDWR:
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "MODE_RDWR");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "MODE_RDWR");
empty = false;
break;
case LIB9P_LO_MODE_NOACCESS:
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "MODE_NOACCESS");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "MODE_NOACCESS");
empty = false;
break;
default:
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_printf(state, "%"PRIu32, *self & LIB9P_LO_MODE_MASK);
+ fmt_print_byte(w, '|');
+ fmt_print_base10(w, *self & LIB9P_LO_MODE_MASK);
empty = false;
}
if (empty)
- fmt_state_putchar(state, '0');
- fmt_state_putchar(state, ')');
+ fmt_print_byte(w, '0');
+ fmt_print_byte(w, ')');
}
-static void lib9p_dt_format(lib9p_dt_t *self, struct fmt_state *state) {
+[[maybe_unused]] static void fmt_print_dt(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, lib9p_dt_t *self) {
switch (*self) {
case LIB9P_DT_UNKNOWN:
- fmt_state_puts(state, "UNKNOWN");
+ fmt_print_str(w, "UNKNOWN");
break;
case LIB9P_DT_PIPE:
- fmt_state_puts(state, "PIPE");
+ fmt_print_str(w, "PIPE");
break;
case LIB9P_DT_CHAR_DEV:
- fmt_state_puts(state, "CHAR_DEV");
+ fmt_print_str(w, "CHAR_DEV");
break;
case LIB9P_DT_DIRECTORY:
- fmt_state_puts(state, "DIRECTORY");
+ fmt_print_str(w, "DIRECTORY");
break;
case LIB9P_DT_BLOCK_DEV:
- fmt_state_puts(state, "BLOCK_DEV");
+ fmt_print_str(w, "BLOCK_DEV");
break;
case LIB9P_DT_REGULAR:
- fmt_state_puts(state, "REGULAR");
+ fmt_print_str(w, "REGULAR");
break;
case LIB9P_DT_SYMLINK:
- fmt_state_puts(state, "SYMLINK");
+ fmt_print_str(w, "SYMLINK");
break;
case LIB9P_DT_SOCKET:
- fmt_state_puts(state, "SOCKET");
+ fmt_print_str(w, "SOCKET");
break;
case _LIB9P_DT_WHITEOUT:
- fmt_state_puts(state, "_WHITEOUT");
+ fmt_print_str(w, "_WHITEOUT");
break;
default:
- fmt_state_printf(state, "%"PRIu8, *self);
+ fmt_print_base10(w, *self);
}
}
-static void lib9p_mode_format(lib9p_mode_t *self, struct fmt_state *state) {
+[[maybe_unused]] static void fmt_print_mode(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, lib9p_mode_t *self) {
bool empty = true;
- fmt_state_putchar(state, '(');
+ fmt_print_byte(w, '(');
if (*self & (UINT32_C(1)<<31)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<31");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<31");
empty = false;
}
if (*self & (UINT32_C(1)<<30)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<30");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<30");
empty = false;
}
if (*self & (UINT32_C(1)<<29)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<29");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<29");
empty = false;
}
if (*self & (UINT32_C(1)<<28)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<28");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<28");
empty = false;
}
if (*self & (UINT32_C(1)<<27)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<27");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<27");
empty = false;
}
if (*self & (UINT32_C(1)<<26)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<26");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<26");
empty = false;
}
if (*self & (UINT32_C(1)<<25)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<25");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<25");
empty = false;
}
if (*self & (UINT32_C(1)<<24)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<24");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<24");
empty = false;
}
if (*self & (UINT32_C(1)<<23)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<23");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<23");
empty = false;
}
if (*self & (UINT32_C(1)<<22)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<22");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<22");
empty = false;
}
if (*self & (UINT32_C(1)<<21)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<21");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<21");
empty = false;
}
if (*self & (UINT32_C(1)<<20)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<20");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<20");
empty = false;
}
if (*self & (UINT32_C(1)<<19)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<19");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<19");
empty = false;
}
if (*self & (UINT32_C(1)<<18)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<18");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<18");
empty = false;
}
if (*self & (UINT32_C(1)<<17)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<17");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<17");
empty = false;
}
if (*self & (UINT32_C(1)<<16)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<16");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<16");
empty = false;
}
switch (*self & LIB9P_MODE_FMT_MASK) {
case LIB9P_MODE_FMT_PIPE:
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "FMT_PIPE");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "FMT_PIPE");
empty = false;
break;
case LIB9P_MODE_FMT_CHAR_DEV:
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "FMT_CHAR_DEV");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "FMT_CHAR_DEV");
empty = false;
break;
case LIB9P_MODE_FMT_DIRECTORY:
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "FMT_DIRECTORY");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "FMT_DIRECTORY");
empty = false;
break;
case LIB9P_MODE_FMT_BLOCK_DEV:
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "FMT_BLOCK_DEV");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "FMT_BLOCK_DEV");
empty = false;
break;
case LIB9P_MODE_FMT_REGULAR:
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "FMT_REGULAR");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "FMT_REGULAR");
empty = false;
break;
case LIB9P_MODE_FMT_SYMLINK:
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "FMT_SYMLINK");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "FMT_SYMLINK");
empty = false;
break;
case LIB9P_MODE_FMT_SOCKET:
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "FMT_SOCKET");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "FMT_SOCKET");
empty = false;
break;
default:
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_printf(state, "%"PRIu32, *self & LIB9P_MODE_FMT_MASK);
+ fmt_print_byte(w, '|');
+ fmt_print_base10(w, *self & LIB9P_MODE_FMT_MASK);
empty = false;
}
if (*self & (UINT32_C(1)<<11)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "PERM_SETGROUP");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "PERM_SETGROUP");
empty = false;
}
if (*self & (UINT32_C(1)<<10)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "PERM_SETUSER");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "PERM_SETUSER");
empty = false;
}
if (*self & (UINT32_C(1)<<9)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "PERM_STICKY");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "PERM_STICKY");
empty = false;
}
if (*self & (UINT32_C(1)<<8)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "PERM_OWNER_R");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "PERM_OWNER_R");
empty = false;
}
if (*self & (UINT32_C(1)<<7)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "PERM_OWNER_W");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "PERM_OWNER_W");
empty = false;
}
if (*self & (UINT32_C(1)<<6)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "PERM_OWNER_X");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "PERM_OWNER_X");
empty = false;
}
if (*self & (UINT32_C(1)<<5)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "PERM_GROUP_R");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "PERM_GROUP_R");
empty = false;
}
if (*self & (UINT32_C(1)<<4)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "PERM_GROUP_W");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "PERM_GROUP_W");
empty = false;
}
if (*self & (UINT32_C(1)<<3)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "PERM_GROUP_X");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "PERM_GROUP_X");
empty = false;
}
if (*self & (UINT32_C(1)<<2)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "PERM_OTHER_R");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "PERM_OTHER_R");
empty = false;
}
if (*self & (UINT32_C(1)<<1)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "PERM_OTHER_W");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "PERM_OTHER_W");
empty = false;
}
if (*self & (UINT32_C(1)<<0)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "PERM_OTHER_X");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "PERM_OTHER_X");
empty = false;
}
if (empty)
- fmt_state_putchar(state, '0');
- fmt_state_putchar(state, ')');
+ fmt_print_byte(w, '0');
+ fmt_print_byte(w, ')');
}
-static void lib9p_b4_format(lib9p_b4_t *self, struct fmt_state *state) {
+[[maybe_unused]] static void fmt_print_b4(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, lib9p_b4_t *self) {
switch (*self) {
case LIB9P_B4_FALSE:
- fmt_state_puts(state, "FALSE");
+ fmt_print_str(w, "FALSE");
break;
case LIB9P_B4_TRUE:
- fmt_state_puts(state, "TRUE");
+ fmt_print_str(w, "TRUE");
break;
default:
- fmt_state_printf(state, "%"PRIu32, *self);
+ fmt_print_base10(w, *self);
}
}
-static void lib9p_getattr_format(lib9p_getattr_t *self, struct fmt_state *state) {
+[[maybe_unused]] static void fmt_print_getattr(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, lib9p_getattr_t *self) {
bool empty = true;
- fmt_state_putchar(state, '(');
+ fmt_print_byte(w, '(');
if (*self & (UINT64_C(1)<<63)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<63");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<63");
empty = false;
}
if (*self & (UINT64_C(1)<<62)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<62");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<62");
empty = false;
}
if (*self & (UINT64_C(1)<<61)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<61");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<61");
empty = false;
}
if (*self & (UINT64_C(1)<<60)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<60");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<60");
empty = false;
}
if (*self & (UINT64_C(1)<<59)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<59");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<59");
empty = false;
}
if (*self & (UINT64_C(1)<<58)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<58");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<58");
empty = false;
}
if (*self & (UINT64_C(1)<<57)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<57");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<57");
empty = false;
}
if (*self & (UINT64_C(1)<<56)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<56");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<56");
empty = false;
}
if (*self & (UINT64_C(1)<<55)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<55");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<55");
empty = false;
}
if (*self & (UINT64_C(1)<<54)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<54");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<54");
empty = false;
}
if (*self & (UINT64_C(1)<<53)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<53");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<53");
empty = false;
}
if (*self & (UINT64_C(1)<<52)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<52");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<52");
empty = false;
}
if (*self & (UINT64_C(1)<<51)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<51");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<51");
empty = false;
}
if (*self & (UINT64_C(1)<<50)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<50");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<50");
empty = false;
}
if (*self & (UINT64_C(1)<<49)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<49");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<49");
empty = false;
}
if (*self & (UINT64_C(1)<<48)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<48");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<48");
empty = false;
}
if (*self & (UINT64_C(1)<<47)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<47");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<47");
empty = false;
}
if (*self & (UINT64_C(1)<<46)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<46");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<46");
empty = false;
}
if (*self & (UINT64_C(1)<<45)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<45");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<45");
empty = false;
}
if (*self & (UINT64_C(1)<<44)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<44");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<44");
empty = false;
}
if (*self & (UINT64_C(1)<<43)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<43");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<43");
empty = false;
}
if (*self & (UINT64_C(1)<<42)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<42");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<42");
empty = false;
}
if (*self & (UINT64_C(1)<<41)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<41");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<41");
empty = false;
}
if (*self & (UINT64_C(1)<<40)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<40");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<40");
empty = false;
}
if (*self & (UINT64_C(1)<<39)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<39");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<39");
empty = false;
}
if (*self & (UINT64_C(1)<<38)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<38");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<38");
empty = false;
}
if (*self & (UINT64_C(1)<<37)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<37");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<37");
empty = false;
}
if (*self & (UINT64_C(1)<<36)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<36");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<36");
empty = false;
}
if (*self & (UINT64_C(1)<<35)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<35");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<35");
empty = false;
}
if (*self & (UINT64_C(1)<<34)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<34");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<34");
empty = false;
}
if (*self & (UINT64_C(1)<<33)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<33");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<33");
empty = false;
}
if (*self & (UINT64_C(1)<<32)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<32");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<32");
empty = false;
}
if (*self & (UINT64_C(1)<<31)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<31");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<31");
empty = false;
}
if (*self & (UINT64_C(1)<<30)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<30");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<30");
empty = false;
}
if (*self & (UINT64_C(1)<<29)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<29");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<29");
empty = false;
}
if (*self & (UINT64_C(1)<<28)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<28");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<28");
empty = false;
}
if (*self & (UINT64_C(1)<<27)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<27");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<27");
empty = false;
}
if (*self & (UINT64_C(1)<<26)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<26");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<26");
empty = false;
}
if (*self & (UINT64_C(1)<<25)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<25");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<25");
empty = false;
}
if (*self & (UINT64_C(1)<<24)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<24");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<24");
empty = false;
}
if (*self & (UINT64_C(1)<<23)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<23");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<23");
empty = false;
}
if (*self & (UINT64_C(1)<<22)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<22");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<22");
empty = false;
}
if (*self & (UINT64_C(1)<<21)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<21");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<21");
empty = false;
}
if (*self & (UINT64_C(1)<<20)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<20");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<20");
empty = false;
}
if (*self & (UINT64_C(1)<<19)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<19");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<19");
empty = false;
}
if (*self & (UINT64_C(1)<<18)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<18");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<18");
empty = false;
}
if (*self & (UINT64_C(1)<<17)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<17");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<17");
empty = false;
}
if (*self & (UINT64_C(1)<<16)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<16");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<16");
empty = false;
}
if (*self & (UINT64_C(1)<<15)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<15");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<15");
empty = false;
}
if (*self & (UINT64_C(1)<<14)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<14");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<14");
empty = false;
}
if (*self & (UINT64_C(1)<<13)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "DATA_VERSION");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "DATA_VERSION");
empty = false;
}
if (*self & (UINT64_C(1)<<12)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "GEN");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "GEN");
empty = false;
}
if (*self & (UINT64_C(1)<<11)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "BTIME");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "BTIME");
empty = false;
}
if (*self & (UINT64_C(1)<<10)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "BLOCKS");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "BLOCKS");
empty = false;
}
if (*self & (UINT64_C(1)<<9)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "SIZE");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "SIZE");
empty = false;
}
if (*self & (UINT64_C(1)<<8)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "INO");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "INO");
empty = false;
}
if (*self & (UINT64_C(1)<<7)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "CTIME");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "CTIME");
empty = false;
}
if (*self & (UINT64_C(1)<<6)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "MTIME");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "MTIME");
empty = false;
}
if (*self & (UINT64_C(1)<<5)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "ATIME");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "ATIME");
empty = false;
}
if (*self & (UINT64_C(1)<<4)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "RDEV");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "RDEV");
empty = false;
}
if (*self & (UINT64_C(1)<<3)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "GID");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "GID");
empty = false;
}
if (*self & (UINT64_C(1)<<2)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "UID");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "UID");
empty = false;
}
if (*self & (UINT64_C(1)<<1)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "NLINK");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "NLINK");
empty = false;
}
if (*self & (UINT64_C(1)<<0)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "MODE");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "MODE");
empty = false;
}
if (empty)
- fmt_state_putchar(state, '0');
- fmt_state_putchar(state, ')');
+ fmt_print_byte(w, '0');
+ fmt_print_byte(w, ')');
}
-static void lib9p_setattr_format(lib9p_setattr_t *self, struct fmt_state *state) {
+[[maybe_unused]] static void fmt_print_setattr(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, lib9p_setattr_t *self) {
bool empty = true;
- fmt_state_putchar(state, '(');
+ fmt_print_byte(w, '(');
if (*self & (UINT32_C(1)<<31)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<31");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<31");
empty = false;
}
if (*self & (UINT32_C(1)<<30)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<30");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<30");
empty = false;
}
if (*self & (UINT32_C(1)<<29)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<29");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<29");
empty = false;
}
if (*self & (UINT32_C(1)<<28)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<28");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<28");
empty = false;
}
if (*self & (UINT32_C(1)<<27)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<27");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<27");
empty = false;
}
if (*self & (UINT32_C(1)<<26)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<26");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<26");
empty = false;
}
if (*self & (UINT32_C(1)<<25)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<25");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<25");
empty = false;
}
if (*self & (UINT32_C(1)<<24)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<24");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<24");
empty = false;
}
if (*self & (UINT32_C(1)<<23)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<23");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<23");
empty = false;
}
if (*self & (UINT32_C(1)<<22)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<22");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<22");
empty = false;
}
if (*self & (UINT32_C(1)<<21)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<21");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<21");
empty = false;
}
if (*self & (UINT32_C(1)<<20)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<20");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<20");
empty = false;
}
if (*self & (UINT32_C(1)<<19)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<19");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<19");
empty = false;
}
if (*self & (UINT32_C(1)<<18)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<18");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<18");
empty = false;
}
if (*self & (UINT32_C(1)<<17)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<17");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<17");
empty = false;
}
if (*self & (UINT32_C(1)<<16)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<16");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<16");
empty = false;
}
if (*self & (UINT32_C(1)<<15)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<15");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<15");
empty = false;
}
if (*self & (UINT32_C(1)<<14)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<14");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<14");
empty = false;
}
if (*self & (UINT32_C(1)<<13)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<13");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<13");
empty = false;
}
if (*self & (UINT32_C(1)<<12)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<12");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<12");
empty = false;
}
if (*self & (UINT32_C(1)<<11)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<11");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<11");
empty = false;
}
if (*self & (UINT32_C(1)<<10)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<10");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<10");
empty = false;
}
if (*self & (UINT32_C(1)<<9)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<9");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<9");
empty = false;
}
if (*self & (UINT32_C(1)<<8)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "MTIME_SET");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "MTIME_SET");
empty = false;
}
if (*self & (UINT32_C(1)<<7)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "ATIME_SET");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "ATIME_SET");
empty = false;
}
if (*self & (UINT32_C(1)<<6)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "CTIME");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "CTIME");
empty = false;
}
if (*self & (UINT32_C(1)<<5)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "MTIME");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "MTIME");
empty = false;
}
if (*self & (UINT32_C(1)<<4)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "ATIME");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "ATIME");
empty = false;
}
if (*self & (UINT32_C(1)<<3)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "SIZE");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "SIZE");
empty = false;
}
if (*self & (UINT32_C(1)<<2)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "GID");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "GID");
empty = false;
}
if (*self & (UINT32_C(1)<<1)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "UID");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "UID");
empty = false;
}
if (*self & (UINT32_C(1)<<0)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "MODE");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "MODE");
empty = false;
}
if (empty)
- fmt_state_putchar(state, '0');
- fmt_state_putchar(state, ')');
+ fmt_print_byte(w, '0');
+ fmt_print_byte(w, ')');
}
-static void lib9p_lock_type_format(lib9p_lock_type_t *self, struct fmt_state *state) {
+[[maybe_unused]] static void fmt_print_lock_type(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, lib9p_lock_type_t *self) {
switch (*self) {
case LIB9P_LOCK_TYPE_RDLCK:
- fmt_state_puts(state, "RDLCK");
+ fmt_print_str(w, "RDLCK");
break;
case LIB9P_LOCK_TYPE_WRLCK:
- fmt_state_puts(state, "WRLCK");
+ fmt_print_str(w, "WRLCK");
break;
case LIB9P_LOCK_TYPE_UNLCK:
- fmt_state_puts(state, "UNLCK");
+ fmt_print_str(w, "UNLCK");
break;
default:
- fmt_state_printf(state, "%"PRIu8, *self);
+ fmt_print_base10(w, *self);
}
}
-static void lib9p_lock_flags_format(lib9p_lock_flags_t *self, struct fmt_state *state) {
+[[maybe_unused]] static void fmt_print_lock_flags(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, lib9p_lock_flags_t *self) {
bool empty = true;
- fmt_state_putchar(state, '(');
+ fmt_print_byte(w, '(');
if (*self & (UINT32_C(1)<<31)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<31");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<31");
empty = false;
}
if (*self & (UINT32_C(1)<<30)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<30");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<30");
empty = false;
}
if (*self & (UINT32_C(1)<<29)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<29");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<29");
empty = false;
}
if (*self & (UINT32_C(1)<<28)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<28");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<28");
empty = false;
}
if (*self & (UINT32_C(1)<<27)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<27");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<27");
empty = false;
}
if (*self & (UINT32_C(1)<<26)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<26");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<26");
empty = false;
}
if (*self & (UINT32_C(1)<<25)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<25");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<25");
empty = false;
}
if (*self & (UINT32_C(1)<<24)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<24");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<24");
empty = false;
}
if (*self & (UINT32_C(1)<<23)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<23");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<23");
empty = false;
}
if (*self & (UINT32_C(1)<<22)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<22");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<22");
empty = false;
}
if (*self & (UINT32_C(1)<<21)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<21");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<21");
empty = false;
}
if (*self & (UINT32_C(1)<<20)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<20");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<20");
empty = false;
}
if (*self & (UINT32_C(1)<<19)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<19");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<19");
empty = false;
}
if (*self & (UINT32_C(1)<<18)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<18");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<18");
empty = false;
}
if (*self & (UINT32_C(1)<<17)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<17");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<17");
empty = false;
}
if (*self & (UINT32_C(1)<<16)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<16");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<16");
empty = false;
}
if (*self & (UINT32_C(1)<<15)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<15");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<15");
empty = false;
}
if (*self & (UINT32_C(1)<<14)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<14");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<14");
empty = false;
}
if (*self & (UINT32_C(1)<<13)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<13");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<13");
empty = false;
}
if (*self & (UINT32_C(1)<<12)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<12");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<12");
empty = false;
}
if (*self & (UINT32_C(1)<<11)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<11");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<11");
empty = false;
}
if (*self & (UINT32_C(1)<<10)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<10");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<10");
empty = false;
}
if (*self & (UINT32_C(1)<<9)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<9");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<9");
empty = false;
}
if (*self & (UINT32_C(1)<<8)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<8");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<8");
empty = false;
}
if (*self & (UINT32_C(1)<<7)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<7");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<7");
empty = false;
}
if (*self & (UINT32_C(1)<<6)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<6");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<6");
empty = false;
}
if (*self & (UINT32_C(1)<<5)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<5");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<5");
empty = false;
}
if (*self & (UINT32_C(1)<<4)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<4");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<4");
empty = false;
}
if (*self & (UINT32_C(1)<<3)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<3");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<3");
empty = false;
}
if (*self & (UINT32_C(1)<<2)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "1<<2");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "1<<2");
empty = false;
}
if (*self & (UINT32_C(1)<<1)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "RECLAIM");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "RECLAIM");
empty = false;
}
if (*self & (UINT32_C(1)<<0)) {
if (!empty)
- fmt_state_putchar(state, '|');
- fmt_state_puts(state, "BLOCK");
+ fmt_print_byte(w, '|');
+ fmt_print_str(w, "BLOCK");
empty = false;
}
if (empty)
- fmt_state_putchar(state, '0');
- fmt_state_putchar(state, ')');
+ fmt_print_byte(w, '0');
+ fmt_print_byte(w, ')');
}
-static void lib9p_lock_status_format(lib9p_lock_status_t *self, struct fmt_state *state) {
+[[maybe_unused]] static void fmt_print_lock_status(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, lib9p_lock_status_t *self) {
switch (*self) {
case LIB9P_LOCK_STATUS_SUCCESS:
- fmt_state_puts(state, "SUCCESS");
+ fmt_print_str(w, "SUCCESS");
break;
case LIB9P_LOCK_STATUS_BLOCKED:
- fmt_state_puts(state, "BLOCKED");
+ fmt_print_str(w, "BLOCKED");
break;
case LIB9P_LOCK_STATUS_ERROR:
- fmt_state_puts(state, "ERROR");
+ fmt_print_str(w, "ERROR");
break;
case LIB9P_LOCK_STATUS_GRACE:
- fmt_state_puts(state, "GRACE");
+ fmt_print_str(w, "GRACE");
break;
default:
- fmt_state_printf(state, "%"PRIu8, *self);
- }
-}
-
-static void lib9p_msg_Rlerror_format(struct lib9p_msg_Rlerror *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rlerror {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " errnum=");
- lib9p_errno_format(&self->errnum, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Tstatfs_format(struct lib9p_msg_Tstatfs *self, struct fmt_state *state) {
- fmt_state_puts(state, "Tstatfs {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " fid=");
- lib9p_fid_format(&self->fid, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rstatfs_format(struct lib9p_msg_Rstatfs *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rstatfs {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " type=");
- lib9p_super_magic_format(&self->type, state);
- fmt_state_puts(state, " bsize=");
- fmt_state_printf(state, "%"PRIu32, self->bsize);
- fmt_state_puts(state, " blocks=");
- fmt_state_printf(state, "%"PRIu64, self->blocks);
- fmt_state_puts(state, " bfree=");
- fmt_state_printf(state, "%"PRIu64, self->bfree);
- fmt_state_puts(state, " bavail=");
- fmt_state_printf(state, "%"PRIu64, self->bavail);
- fmt_state_puts(state, " files=");
- fmt_state_printf(state, "%"PRIu64, self->files);
- fmt_state_puts(state, " ffree=");
- fmt_state_printf(state, "%"PRIu64, self->ffree);
- fmt_state_puts(state, " fsid=");
- fmt_state_printf(state, "%"PRIu64, self->fsid);
- fmt_state_puts(state, " namelen=");
- fmt_state_printf(state, "%"PRIu32, self->namelen);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Tlopen_format(struct lib9p_msg_Tlopen *self, struct fmt_state *state) {
- fmt_state_puts(state, "Tlopen {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " fid=");
- lib9p_fid_format(&self->fid, state);
- fmt_state_puts(state, " flags=");
- lib9p_lo_format(&self->flags, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rlopen_format(struct lib9p_msg_Rlopen *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rlopen {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " qid=");
- lib9p_qid_format(&self->qid, state);
- fmt_state_puts(state, " iounit=");
- fmt_state_printf(state, "%"PRIu32, self->iounit);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Tlcreate_format(struct lib9p_msg_Tlcreate *self, struct fmt_state *state) {
- fmt_state_puts(state, "Tlcreate {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " fid=");
- lib9p_fid_format(&self->fid, state);
- fmt_state_puts(state, " name=");
- lib9p_s_format(&self->name, state);
- fmt_state_puts(state, " flags=");
- lib9p_lo_format(&self->flags, state);
- fmt_state_puts(state, " mode=");
- lib9p_mode_format(&self->mode, state);
- fmt_state_puts(state, " gid=");
- lib9p_nuid_format(&self->gid, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rlcreate_format(struct lib9p_msg_Rlcreate *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rlcreate {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " qid=");
- lib9p_qid_format(&self->qid, state);
- fmt_state_puts(state, " iounit=");
- fmt_state_printf(state, "%"PRIu32, self->iounit);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Tsymlink_format(struct lib9p_msg_Tsymlink *self, struct fmt_state *state) {
- fmt_state_puts(state, "Tsymlink {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " fid=");
- lib9p_fid_format(&self->fid, state);
- fmt_state_puts(state, " name=");
- lib9p_s_format(&self->name, state);
- fmt_state_puts(state, " symtgt=");
- lib9p_s_format(&self->symtgt, state);
- fmt_state_puts(state, " gid=");
- lib9p_nuid_format(&self->gid, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rsymlink_format(struct lib9p_msg_Rsymlink *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rsymlink {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " qid=");
- lib9p_qid_format(&self->qid, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Tmknod_format(struct lib9p_msg_Tmknod *self, struct fmt_state *state) {
- fmt_state_puts(state, "Tmknod {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " dfid=");
- lib9p_fid_format(&self->dfid, state);
- fmt_state_puts(state, " name=");
- lib9p_s_format(&self->name, state);
- fmt_state_puts(state, " mode=");
- lib9p_mode_format(&self->mode, state);
- fmt_state_puts(state, " major=");
- fmt_state_printf(state, "%"PRIu32, self->major);
- fmt_state_puts(state, " minor=");
- fmt_state_printf(state, "%"PRIu32, self->minor);
- fmt_state_puts(state, " gid=");
- lib9p_nuid_format(&self->gid, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rmknod_format(struct lib9p_msg_Rmknod *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rmknod {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " qid=");
- lib9p_qid_format(&self->qid, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Trename_format(struct lib9p_msg_Trename *self, struct fmt_state *state) {
- fmt_state_puts(state, "Trename {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " fid=");
- lib9p_fid_format(&self->fid, state);
- fmt_state_puts(state, " dfid=");
- lib9p_fid_format(&self->dfid, state);
- fmt_state_puts(state, " name=");
- lib9p_s_format(&self->name, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rrename_format(struct lib9p_msg_Rrename *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rrename {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Treadlink_format(struct lib9p_msg_Treadlink *self, struct fmt_state *state) {
- fmt_state_puts(state, "Treadlink {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " fid=");
- lib9p_fid_format(&self->fid, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rreadlink_format(struct lib9p_msg_Rreadlink *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rreadlink {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " target=");
- lib9p_s_format(&self->target, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Tgetattr_format(struct lib9p_msg_Tgetattr *self, struct fmt_state *state) {
- fmt_state_puts(state, "Tgetattr {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " fid=");
- lib9p_fid_format(&self->fid, state);
- fmt_state_puts(state, " request_mask=");
- lib9p_getattr_format(&self->request_mask, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rgetattr_format(struct lib9p_msg_Rgetattr *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rgetattr {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " valid=");
- lib9p_getattr_format(&self->valid, state);
- fmt_state_puts(state, " qid=");
- lib9p_qid_format(&self->qid, state);
- fmt_state_puts(state, " mode=");
- lib9p_mode_format(&self->mode, state);
- fmt_state_puts(state, " uid=");
- lib9p_nuid_format(&self->uid, state);
- fmt_state_puts(state, " gid=");
- lib9p_nuid_format(&self->gid, state);
- fmt_state_puts(state, " nlink=");
- fmt_state_printf(state, "%"PRIu64, self->nlink);
- fmt_state_puts(state, " rdev=");
- fmt_state_printf(state, "%"PRIu64, self->rdev);
- fmt_state_puts(state, " filesize=");
- fmt_state_printf(state, "%"PRIu64, self->filesize);
- fmt_state_puts(state, " blksize=");
- fmt_state_printf(state, "%"PRIu64, self->blksize);
- fmt_state_puts(state, " blocks=");
- fmt_state_printf(state, "%"PRIu64, self->blocks);
- fmt_state_puts(state, " atime_sec=");
- fmt_state_printf(state, "%"PRIu64, self->atime_sec);
- fmt_state_puts(state, " atime_nsec=");
- fmt_state_printf(state, "%"PRIu64, self->atime_nsec);
- fmt_state_puts(state, " mtime_sec=");
- fmt_state_printf(state, "%"PRIu64, self->mtime_sec);
- fmt_state_puts(state, " mtime_nsec=");
- fmt_state_printf(state, "%"PRIu64, self->mtime_nsec);
- fmt_state_puts(state, " ctime_sec=");
- fmt_state_printf(state, "%"PRIu64, self->ctime_sec);
- fmt_state_puts(state, " ctime_nsec=");
- fmt_state_printf(state, "%"PRIu64, self->ctime_nsec);
- fmt_state_puts(state, " btime_sec=");
- fmt_state_printf(state, "%"PRIu64, self->btime_sec);
- fmt_state_puts(state, " btime_nsec=");
- fmt_state_printf(state, "%"PRIu64, self->btime_nsec);
- fmt_state_puts(state, " gen=");
- fmt_state_printf(state, "%"PRIu64, self->gen);
- fmt_state_puts(state, " data_version=");
- fmt_state_printf(state, "%"PRIu64, self->data_version);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Tsetattr_format(struct lib9p_msg_Tsetattr *self, struct fmt_state *state) {
- fmt_state_puts(state, "Tsetattr {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " fid=");
- lib9p_fid_format(&self->fid, state);
- fmt_state_puts(state, " valid=");
- lib9p_setattr_format(&self->valid, state);
- fmt_state_puts(state, " mode=");
- lib9p_mode_format(&self->mode, state);
- fmt_state_puts(state, " uid=");
- lib9p_nuid_format(&self->uid, state);
- fmt_state_puts(state, " gid=");
- lib9p_nuid_format(&self->gid, state);
- fmt_state_puts(state, " filesize=");
- fmt_state_printf(state, "%"PRIu64, self->filesize);
- fmt_state_puts(state, " atime_sec=");
- fmt_state_printf(state, "%"PRIu64, self->atime_sec);
- fmt_state_puts(state, " atime_nsec=");
- fmt_state_printf(state, "%"PRIu64, self->atime_nsec);
- fmt_state_puts(state, " mtime_sec=");
- fmt_state_printf(state, "%"PRIu64, self->mtime_sec);
- fmt_state_puts(state, " mtime_nsec=");
- fmt_state_printf(state, "%"PRIu64, self->mtime_nsec);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rsetattr_format(struct lib9p_msg_Rsetattr *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rsetattr {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Txattrwalk_format(struct lib9p_msg_Txattrwalk *self, struct fmt_state *state) {
- fmt_state_puts(state, "Txattrwalk {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " fid=");
- lib9p_fid_format(&self->fid, state);
- fmt_state_puts(state, " newfid=");
- lib9p_fid_format(&self->newfid, state);
- fmt_state_puts(state, " name=");
- lib9p_s_format(&self->name, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rxattrwalk_format(struct lib9p_msg_Rxattrwalk *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rxattrwalk {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " attr_size=");
- fmt_state_printf(state, "%"PRIu64, self->attr_size);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Txattrcreate_format(struct lib9p_msg_Txattrcreate *self, struct fmt_state *state) {
- fmt_state_puts(state, "Txattrcreate {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " fid=");
- lib9p_fid_format(&self->fid, state);
- fmt_state_puts(state, " name=");
- lib9p_s_format(&self->name, state);
- fmt_state_puts(state, " attr_size=");
- fmt_state_printf(state, "%"PRIu64, self->attr_size);
- fmt_state_puts(state, " flags=");
- fmt_state_printf(state, "%"PRIu32, self->flags);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rxattrcreate_format(struct lib9p_msg_Rxattrcreate *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rxattrcreate {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Treaddir_format(struct lib9p_msg_Treaddir *self, struct fmt_state *state) {
- fmt_state_puts(state, "Treaddir {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " fid=");
- lib9p_fid_format(&self->fid, state);
- fmt_state_puts(state, " offset=");
- fmt_state_printf(state, "%"PRIu64, self->offset);
- fmt_state_puts(state, " count=");
- fmt_state_printf(state, "%"PRIu32, self->count);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rreaddir_format(struct lib9p_msg_Rreaddir *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rreaddir {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " count=");
- fmt_state_printf(state, "%"PRIu32, self->count);
- if (is_valid_utf8_without_nul((uint8_t *)self->data, (size_t)self->count)) {
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wformat"
-#pragma GCC diagnostic ignored "-Wformat-extra-args"
- fmt_state_printf(state, " data=%.*q%s",
- (int)(self->count < 50 ? self->count : 50),
- (char *)self->data,
- self->count < 50 ? "" : "...");
-#pragma GCC diagnostic pop
+ fmt_print_base10(w, *self);
+ }
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000_L */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_uninitialized
+[[maybe_unused]] static void fmt_print_s(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_s *self) {
+ fmt_print_qmem(w, self->utf8, self->len);
+}
+
+[[maybe_unused]] static void fmt_print_qid(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_qid *self) {
+ fmt_print_byte(w, '{');
+ fmt_print_str(w, " type=");
+ fmt_print_qt(w, ctx, &self->type);
+ fmt_print_str(w, " vers=");
+ fmt_print_base10(w, self->vers);
+ fmt_print_str(w, " path=");
+ fmt_print_base10(w, self->path);
+ fmt_print_str(w, " }");
+}
+
+#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
+[[maybe_unused]] static void fmt_print_Tflush(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Tflush *self) {
+ fmt_print_str(w, "Tflush {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " oldtag=");
+ fmt_print_base10(w, self->oldtag);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rflush(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rflush *self) {
+ fmt_print_str(w, "Rflush {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " }");
+}
+
+#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
+[[maybe_unused]] static void fmt_print_Topen(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Topen *self) {
+ fmt_print_str(w, "Topen {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " fid=");
+ fmt_print_fid(w, ctx, &self->fid);
+ fmt_print_str(w, " mode=");
+ fmt_print_o(w, ctx, &self->mode);
+ fmt_print_str(w, " }");
+}
+
+#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
+[[maybe_unused]] static void fmt_print_Tread(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Tread *self) {
+ fmt_print_str(w, "Tread {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " fid=");
+ fmt_print_fid(w, ctx, &self->fid);
+ fmt_print_str(w, " offset=");
+ fmt_print_base10(w, self->offset);
+ fmt_print_str(w, " count=");
+ fmt_print_base10(w, self->count);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rread(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rread *self) {
+ fmt_print_str(w, "Rread {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " count=");
+ fmt_print_base10(w, 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)
+ fmt_print_str(w, "...");
+ } else {
+ fmt_print_str(w, " data=<bytedata>");
+ }
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Twrite(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Twrite *self) {
+ fmt_print_str(w, "Twrite {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " fid=");
+ fmt_print_fid(w, ctx, &self->fid);
+ fmt_print_str(w, " offset=");
+ fmt_print_base10(w, self->offset);
+ fmt_print_str(w, " count=");
+ fmt_print_base10(w, 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)
+ fmt_print_str(w, "...");
+ } else {
+ fmt_print_str(w, " data=<bytedata>");
+ }
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rwrite(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rwrite *self) {
+ fmt_print_str(w, "Rwrite {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " count=");
+ fmt_print_base10(w, self->count);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Tclunk(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Tclunk *self) {
+ fmt_print_str(w, "Tclunk {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " fid=");
+ fmt_print_fid(w, ctx, &self->fid);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rclunk(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rclunk *self) {
+ fmt_print_str(w, "Rclunk {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Tremove(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Tremove *self) {
+ fmt_print_str(w, "Tremove {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " fid=");
+ fmt_print_fid(w, ctx, &self->fid);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rremove(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rremove *self) {
+ fmt_print_str(w, "Rremove {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " }");
+}
+
+#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
+[[maybe_unused]] static void fmt_print_Tstat(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Tstat *self) {
+ fmt_print_str(w, "Tstat {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " fid=");
+ fmt_print_fid(w, ctx, &self->fid);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rwstat(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rwstat *self) {
+ fmt_print_str(w, "Rwstat {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " }");
+}
+
+#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
+[[maybe_unused]] static void fmt_print_Topenfd(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Topenfd *self) {
+ fmt_print_str(w, "Topenfd {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " fid=");
+ fmt_print_fid(w, ctx, &self->fid);
+ fmt_print_str(w, " mode=");
+ fmt_print_o(w, ctx, &self->mode);
+ fmt_print_str(w, " }");
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
+#if CONFIG_9P_ENABLE_9P2000_L
+[[maybe_unused]] static void fmt_print_Rlerror(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rlerror *self) {
+ fmt_print_str(w, "Rlerror {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " errnum=");
+ fmt_print_errno(w, ctx, &self->errnum);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Tstatfs(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Tstatfs *self) {
+ fmt_print_str(w, "Tstatfs {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " fid=");
+ fmt_print_fid(w, ctx, &self->fid);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rstatfs(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rstatfs *self) {
+ fmt_print_str(w, "Rstatfs {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " type=");
+ fmt_print_super_magic(w, ctx, &self->type);
+ fmt_print_str(w, " bsize=");
+ fmt_print_base10(w, self->bsize);
+ fmt_print_str(w, " blocks=");
+ fmt_print_base10(w, self->blocks);
+ fmt_print_str(w, " bfree=");
+ fmt_print_base10(w, self->bfree);
+ fmt_print_str(w, " bavail=");
+ fmt_print_base10(w, self->bavail);
+ fmt_print_str(w, " files=");
+ fmt_print_base10(w, self->files);
+ fmt_print_str(w, " ffree=");
+ fmt_print_base10(w, self->ffree);
+ fmt_print_str(w, " fsid=");
+ fmt_print_base10(w, self->fsid);
+ fmt_print_str(w, " namelen=");
+ fmt_print_base10(w, self->namelen);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Tlopen(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Tlopen *self) {
+ fmt_print_str(w, "Tlopen {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " fid=");
+ fmt_print_fid(w, ctx, &self->fid);
+ fmt_print_str(w, " flags=");
+ fmt_print_lo(w, ctx, &self->flags);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rrename(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rrename *self) {
+ fmt_print_str(w, "Rrename {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Treadlink(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Treadlink *self) {
+ fmt_print_str(w, "Treadlink {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " fid=");
+ fmt_print_fid(w, ctx, &self->fid);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Tgetattr(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Tgetattr *self) {
+ fmt_print_str(w, "Tgetattr {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " fid=");
+ fmt_print_fid(w, ctx, &self->fid);
+ fmt_print_str(w, " request_mask=");
+ fmt_print_getattr(w, ctx, &self->request_mask);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Tsetattr(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Tsetattr *self) {
+ fmt_print_str(w, "Tsetattr {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " fid=");
+ fmt_print_fid(w, ctx, &self->fid);
+ fmt_print_str(w, " valid=");
+ fmt_print_setattr(w, ctx, &self->valid);
+ fmt_print_str(w, " mode=");
+ fmt_print_mode(w, ctx, &self->mode);
+ fmt_print_str(w, " uid=");
+ fmt_print_nuid(w, ctx, &self->uid);
+ fmt_print_str(w, " gid=");
+ fmt_print_nuid(w, ctx, &self->gid);
+ fmt_print_str(w, " filesize=");
+ fmt_print_base10(w, self->filesize);
+ fmt_print_str(w, " atime_sec=");
+ fmt_print_base10(w, self->atime_sec);
+ fmt_print_str(w, " atime_nsec=");
+ fmt_print_base10(w, self->atime_nsec);
+ fmt_print_str(w, " mtime_sec=");
+ fmt_print_base10(w, self->mtime_sec);
+ fmt_print_str(w, " mtime_nsec=");
+ fmt_print_base10(w, self->mtime_nsec);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rsetattr(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rsetattr *self) {
+ fmt_print_str(w, "Rsetattr {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rxattrwalk(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rxattrwalk *self) {
+ fmt_print_str(w, "Rxattrwalk {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " attr_size=");
+ fmt_print_base10(w, self->attr_size);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rxattrcreate(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rxattrcreate *self) {
+ fmt_print_str(w, "Rxattrcreate {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Treaddir(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Treaddir *self) {
+ fmt_print_str(w, "Treaddir {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " fid=");
+ fmt_print_fid(w, ctx, &self->fid);
+ fmt_print_str(w, " offset=");
+ fmt_print_base10(w, self->offset);
+ fmt_print_str(w, " count=");
+ fmt_print_base10(w, self->count);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rreaddir(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rreaddir *self) {
+ fmt_print_str(w, "Rreaddir {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " count=");
+ fmt_print_base10(w, 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)
+ fmt_print_str(w, "...");
} else {
- fmt_state_puts(state, " data=<bytedata>");
- }
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Tfsync_format(struct lib9p_msg_Tfsync *self, struct fmt_state *state) {
- fmt_state_puts(state, "Tfsync {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " fid=");
- lib9p_fid_format(&self->fid, state);
- fmt_state_puts(state, " datasync=");
- lib9p_b4_format(&self->datasync, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rfsync_format(struct lib9p_msg_Rfsync *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rfsync {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Tlock_format(struct lib9p_msg_Tlock *self, struct fmt_state *state) {
- fmt_state_puts(state, "Tlock {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " fid=");
- lib9p_fid_format(&self->fid, state);
- fmt_state_puts(state, " type=");
- lib9p_lock_type_format(&self->type, state);
- fmt_state_puts(state, " flags=");
- lib9p_lock_flags_format(&self->flags, state);
- fmt_state_puts(state, " start=");
- fmt_state_printf(state, "%"PRIu64, self->start);
- fmt_state_puts(state, " length=");
- fmt_state_printf(state, "%"PRIu64, self->length);
- fmt_state_puts(state, " proc_id=");
- fmt_state_printf(state, "%"PRIu32, self->proc_id);
- fmt_state_puts(state, " client_id=");
- lib9p_s_format(&self->client_id, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rlock_format(struct lib9p_msg_Rlock *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rlock {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " status=");
- lib9p_lock_status_format(&self->status, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Tgetlock_format(struct lib9p_msg_Tgetlock *self, struct fmt_state *state) {
- fmt_state_puts(state, "Tgetlock {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " fid=");
- lib9p_fid_format(&self->fid, state);
- fmt_state_puts(state, " type=");
- lib9p_lock_type_format(&self->type, state);
- fmt_state_puts(state, " start=");
- fmt_state_printf(state, "%"PRIu64, self->start);
- fmt_state_puts(state, " length=");
- fmt_state_printf(state, "%"PRIu64, self->length);
- fmt_state_puts(state, " proc_id=");
- fmt_state_printf(state, "%"PRIu32, self->proc_id);
- fmt_state_puts(state, " client_id=");
- lib9p_s_format(&self->client_id, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rgetlock_format(struct lib9p_msg_Rgetlock *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rgetlock {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " type=");
- lib9p_lock_type_format(&self->type, state);
- fmt_state_puts(state, " start=");
- fmt_state_printf(state, "%"PRIu64, self->start);
- fmt_state_puts(state, " length=");
- fmt_state_printf(state, "%"PRIu64, self->length);
- fmt_state_puts(state, " proc_id=");
- fmt_state_printf(state, "%"PRIu32, self->proc_id);
- fmt_state_puts(state, " client_id=");
- lib9p_s_format(&self->client_id, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Tlink_format(struct lib9p_msg_Tlink *self, struct fmt_state *state) {
- fmt_state_puts(state, "Tlink {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " dfid=");
- lib9p_fid_format(&self->dfid, state);
- fmt_state_puts(state, " fid=");
- lib9p_fid_format(&self->fid, state);
- fmt_state_puts(state, " name=");
- lib9p_s_format(&self->name, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rlink_format(struct lib9p_msg_Rlink *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rlink {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Tmkdir_format(struct lib9p_msg_Tmkdir *self, struct fmt_state *state) {
- fmt_state_puts(state, "Tmkdir {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " dfid=");
- lib9p_fid_format(&self->dfid, state);
- fmt_state_puts(state, " name=");
- lib9p_s_format(&self->name, state);
- fmt_state_puts(state, " mode=");
- lib9p_mode_format(&self->mode, state);
- fmt_state_puts(state, " gid=");
- lib9p_nuid_format(&self->gid, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rmkdir_format(struct lib9p_msg_Rmkdir *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rmkdir {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " qid=");
- lib9p_qid_format(&self->qid, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Trenameat_format(struct lib9p_msg_Trenameat *self, struct fmt_state *state) {
- fmt_state_puts(state, "Trenameat {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " olddirfid=");
- lib9p_fid_format(&self->olddirfid, state);
- fmt_state_puts(state, " oldname=");
- lib9p_s_format(&self->oldname, state);
- fmt_state_puts(state, " newdirfid=");
- lib9p_fid_format(&self->newdirfid, state);
- fmt_state_puts(state, " newname=");
- lib9p_s_format(&self->newname, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rrenameat_format(struct lib9p_msg_Rrenameat *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rrenameat {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Tunlinkat_format(struct lib9p_msg_Tunlinkat *self, struct fmt_state *state) {
- fmt_state_puts(state, "Tunlinkat {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " dirfd=");
- lib9p_fid_format(&self->dirfd, state);
- fmt_state_puts(state, " name=");
- lib9p_s_format(&self->name, state);
- fmt_state_puts(state, " flags=");
- fmt_state_printf(state, "%"PRIu32, self->flags);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Runlinkat_format(struct lib9p_msg_Runlinkat *self, struct fmt_state *state) {
- fmt_state_puts(state, "Runlinkat {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " }");
+ fmt_print_str(w, " data=<bytedata>");
+ }
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Tfsync(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Tfsync *self) {
+ fmt_print_str(w, "Tfsync {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " fid=");
+ fmt_print_fid(w, ctx, &self->fid);
+ fmt_print_str(w, " datasync=");
+ fmt_print_b4(w, ctx, &self->datasync);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rfsync(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rfsync *self) {
+ fmt_print_str(w, "Rfsync {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rlock(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rlock *self) {
+ fmt_print_str(w, "Rlock {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " status=");
+ fmt_print_lock_status(w, ctx, &self->status);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rlink(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rlink *self) {
+ fmt_print_str(w, "Rlink {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rrenameat(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rrenameat *self) {
+ fmt_print_str(w, "Rrenameat {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Runlinkat(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Runlinkat *self) {
+ fmt_print_str(w, "Runlinkat {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " }");
}
#endif /* CONFIG_9P_ENABLE_9P2000_L */
#if CONFIG_9P_ENABLE_9P2000_e
-static void lib9p_msg_Tsession_format(struct lib9p_msg_Tsession *self, struct fmt_state *state) {
- fmt_state_puts(state, "Tsession {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " key=");
- fmt_state_printf(state, "%"PRIu64, self->key);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rsession_format(struct lib9p_msg_Rsession *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rsession {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Tsread_format(struct lib9p_msg_Tsread *self, struct fmt_state *state) {
- fmt_state_puts(state, "Tsread {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " fid=");
- fmt_state_printf(state, "%"PRIu32, self->fid);
- fmt_state_puts(state, " nwname=");
- fmt_state_printf(state, "%"PRIu16, self->nwname);
- fmt_state_puts(state, " wname=[");
+[[maybe_unused]] static void fmt_print_Tsession(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Tsession *self) {
+ fmt_print_str(w, "Tsession {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " key=");
+ fmt_print_base10(w, self->key);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rsession(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rsession *self) {
+ fmt_print_str(w, "Rsession {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rsread(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rsread *self) {
+ fmt_print_str(w, "Rsread {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " count=");
+ fmt_print_base10(w, 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)
+ fmt_print_str(w, "...");
+ } else {
+ fmt_print_str(w, " data=<bytedata>");
+ }
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rswrite(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rswrite *self) {
+ fmt_print_str(w, "Rswrite {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " count=");
+ fmt_print_base10(w, self->count);
+ fmt_print_str(w, " }");
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000_e */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+[[maybe_unused]] void fmt_print_stat(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_stat *self) {
+ fmt_print_byte(w, '{');
+ fmt_print_str(w, " fstype=");
+ fmt_print_base10(w, self->fstype);
+ fmt_print_str(w, " fsdev=");
+ fmt_print_base10(w, self->fsdev);
+ fmt_print_str(w, " qid=");
+ fmt_print_qid(w, ctx, &self->qid);
+ fmt_print_str(w, " mode=");
+ fmt_print_dm(w, ctx, &self->mode);
+ fmt_print_str(w, " atime=");
+ fmt_print_base10(w, self->atime);
+ fmt_print_str(w, " mtime=");
+ fmt_print_base10(w, self->mtime);
+ fmt_print_str(w, " length=");
+ fmt_print_base10(w, self->length);
+ fmt_print_str(w, " name=");
+ fmt_print_s(w, ctx, &self->name);
+ fmt_print_str(w, " owner_uname=");
+ fmt_print_s(w, ctx, &self->owner_uname);
+ fmt_print_str(w, " owner_gname=");
+ fmt_print_s(w, ctx, &self->owner_gname);
+ fmt_print_str(w, " last_modifier_uname=");
+ fmt_print_s(w, ctx, &self->last_modifier_uname);
+#if CONFIG_9P_ENABLE_9P2000_u
+ fmt_print_str(w, " extension=");
+ fmt_print_s(w, ctx, &self->extension);
+ fmt_print_str(w, " owner_unum=");
+ fmt_print_nuid(w, ctx, &self->owner_unum);
+ fmt_print_str(w, " owner_gnum=");
+ fmt_print_nuid(w, ctx, &self->owner_gnum);
+ fmt_print_str(w, " last_modifier_unum=");
+ fmt_print_nuid(w, ctx, &self->last_modifier_unum);
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+ fmt_print_str(w, " }");
+}
+
+#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
+[[maybe_unused]] static void fmt_print_Tversion(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Tversion *self) {
+ fmt_print_str(w, "Tversion {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " max_msg_size=");
+ fmt_print_base10(w, self->max_msg_size);
+ fmt_print_str(w, " version=");
+ fmt_print_s(w, ctx, &self->version);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rversion(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rversion *self) {
+ fmt_print_str(w, "Rversion {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " max_msg_size=");
+ fmt_print_base10(w, self->max_msg_size);
+ fmt_print_str(w, " version=");
+ fmt_print_s(w, ctx, &self->version);
+ fmt_print_str(w, " }");
+}
+
+#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
+[[maybe_unused]] static void fmt_print_Tauth(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Tauth *self) {
+ fmt_print_str(w, "Tauth {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " afid=");
+ fmt_print_fid(w, ctx, &self->afid);
+ fmt_print_str(w, " uname=");
+ fmt_print_s(w, ctx, &self->uname);
+ fmt_print_str(w, " aname=");
+ fmt_print_s(w, ctx, &self->aname);
+#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u
+ fmt_print_str(w, " unum=");
+ fmt_print_nuid(w, ctx, &self->unum);
+#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rauth(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rauth *self) {
+ fmt_print_str(w, "Rauth {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " aqid=");
+ fmt_print_qid(w, ctx, &self->aqid);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Tattach(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Tattach *self) {
+ fmt_print_str(w, "Tattach {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " fid=");
+ fmt_print_fid(w, ctx, &self->fid);
+ fmt_print_str(w, " afid=");
+ fmt_print_fid(w, ctx, &self->afid);
+ fmt_print_str(w, " uname=");
+ fmt_print_s(w, ctx, &self->uname);
+ fmt_print_str(w, " aname=");
+ fmt_print_s(w, ctx, &self->aname);
+#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u
+ fmt_print_str(w, " unum=");
+ fmt_print_nuid(w, ctx, &self->unum);
+#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rattach(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rattach *self) {
+ fmt_print_str(w, "Rattach {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " qid=");
+ fmt_print_qid(w, ctx, &self->qid);
+ fmt_print_str(w, " }");
+}
+
+#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
+[[maybe_unused]] static void fmt_print_Rerror(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rerror *self) {
+ fmt_print_str(w, "Rerror {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " errstr=");
+ fmt_print_s(w, ctx, &self->errstr);
+#if CONFIG_9P_ENABLE_9P2000_u
+ fmt_print_str(w, " errnum=");
+ fmt_print_errno(w, ctx, &self->errnum);
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+ fmt_print_str(w, " }");
+}
+
+#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
+[[maybe_unused]] static void fmt_print_Twalk(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Twalk *self) {
+ fmt_print_str(w, "Twalk {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " fid=");
+ fmt_print_fid(w, ctx, &self->fid);
+ fmt_print_str(w, " newfid=");
+ fmt_print_fid(w, ctx, &self->newfid);
+ fmt_print_str(w, " nwname=");
+ fmt_print_base10(w, self->nwname);
+ fmt_print_str(w, " wname=[");
for (uint16_t i = 0; i < self->nwname; i++) {
if (i)
- fmt_state_putchar(state, ',');
- fmt_state_putchar(state, ' ');
- lib9p_s_format(&self->wname[i], state);
- }
- fmt_state_puts(state, " ]");
- fmt_state_puts(state, " }");
-}
-
-static void lib9p_msg_Rsread_format(struct lib9p_msg_Rsread *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rsread {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " count=");
- fmt_state_printf(state, "%"PRIu32, self->count);
- if (is_valid_utf8_without_nul((uint8_t *)self->data, (size_t)self->count)) {
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wformat"
-#pragma GCC diagnostic ignored "-Wformat-extra-args"
- fmt_state_printf(state, " data=%.*q%s",
- (int)(self->count < 50 ? self->count : 50),
- (char *)self->data,
- self->count < 50 ? "" : "...");
-#pragma GCC diagnostic pop
- } else {
- fmt_state_puts(state, " data=<bytedata>");
+ fmt_print_byte(w, ',');
+ fmt_print_byte(w, ' ');
+ fmt_print_s(w, ctx, &self->wname[i]);
+ }
+ fmt_print_str(w, " ]");
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rwalk(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rwalk *self) {
+ fmt_print_str(w, "Rwalk {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " nwqid=");
+ fmt_print_base10(w, self->nwqid);
+ fmt_print_str(w, " wqid=[");
+ for (uint16_t i = 0; i < self->nwqid; i++) {
+ if (i)
+ fmt_print_byte(w, ',');
+ fmt_print_byte(w, ' ');
+ fmt_print_qid(w, ctx, &self->wqid[i]);
}
- fmt_state_puts(state, " }");
+ fmt_print_str(w, " ]");
+ fmt_print_str(w, " }");
+}
+
+#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
+[[maybe_unused]] static void fmt_print_Ropen(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Ropen *self) {
+ fmt_print_str(w, "Ropen {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " qid=");
+ fmt_print_qid(w, ctx, &self->qid);
+ fmt_print_str(w, " iounit=");
+ fmt_print_base10(w, self->iounit);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Tcreate(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Tcreate *self) {
+ fmt_print_str(w, "Tcreate {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " fid=");
+ fmt_print_fid(w, ctx, &self->fid);
+ fmt_print_str(w, " name=");
+ fmt_print_s(w, ctx, &self->name);
+ fmt_print_str(w, " perm=");
+ fmt_print_dm(w, ctx, &self->perm);
+ fmt_print_str(w, " mode=");
+ fmt_print_o(w, ctx, &self->mode);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rcreate(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rcreate *self) {
+ fmt_print_str(w, "Rcreate {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " qid=");
+ fmt_print_qid(w, ctx, &self->qid);
+ fmt_print_str(w, " iounit=");
+ fmt_print_base10(w, self->iounit);
+ fmt_print_str(w, " }");
}
-static void lib9p_msg_Tswrite_format(struct lib9p_msg_Tswrite *self, struct fmt_state *state) {
- fmt_state_puts(state, "Tswrite {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " fid=");
- fmt_state_printf(state, "%"PRIu32, self->fid);
- fmt_state_puts(state, " nwname=");
- fmt_state_printf(state, "%"PRIu16, self->nwname);
- fmt_state_puts(state, " wname=[");
+#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
+[[maybe_unused]] static void fmt_print_Ropenfd(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Ropenfd *self) {
+ fmt_print_str(w, "Ropenfd {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " qid=");
+ fmt_print_qid(w, ctx, &self->qid);
+ fmt_print_str(w, " iounit=");
+ fmt_print_base10(w, self->iounit);
+ fmt_print_str(w, " unixfd=");
+ fmt_print_base10(w, self->unixfd);
+ fmt_print_str(w, " }");
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
+#if CONFIG_9P_ENABLE_9P2000_L
+[[maybe_unused]] static void fmt_print_Rlopen(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rlopen *self) {
+ fmt_print_str(w, "Rlopen {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " qid=");
+ fmt_print_qid(w, ctx, &self->qid);
+ fmt_print_str(w, " iounit=");
+ fmt_print_base10(w, self->iounit);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Tlcreate(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Tlcreate *self) {
+ fmt_print_str(w, "Tlcreate {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " fid=");
+ fmt_print_fid(w, ctx, &self->fid);
+ fmt_print_str(w, " name=");
+ fmt_print_s(w, ctx, &self->name);
+ fmt_print_str(w, " flags=");
+ fmt_print_lo(w, ctx, &self->flags);
+ fmt_print_str(w, " mode=");
+ fmt_print_mode(w, ctx, &self->mode);
+ fmt_print_str(w, " gid=");
+ fmt_print_nuid(w, ctx, &self->gid);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rlcreate(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rlcreate *self) {
+ fmt_print_str(w, "Rlcreate {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " qid=");
+ fmt_print_qid(w, ctx, &self->qid);
+ fmt_print_str(w, " iounit=");
+ fmt_print_base10(w, self->iounit);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Tsymlink(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Tsymlink *self) {
+ fmt_print_str(w, "Tsymlink {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " fid=");
+ fmt_print_fid(w, ctx, &self->fid);
+ fmt_print_str(w, " name=");
+ fmt_print_s(w, ctx, &self->name);
+ fmt_print_str(w, " symtgt=");
+ fmt_print_s(w, ctx, &self->symtgt);
+ fmt_print_str(w, " gid=");
+ fmt_print_nuid(w, ctx, &self->gid);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rsymlink(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rsymlink *self) {
+ fmt_print_str(w, "Rsymlink {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " qid=");
+ fmt_print_qid(w, ctx, &self->qid);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Tmknod(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Tmknod *self) {
+ fmt_print_str(w, "Tmknod {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " dfid=");
+ fmt_print_fid(w, ctx, &self->dfid);
+ fmt_print_str(w, " name=");
+ fmt_print_s(w, ctx, &self->name);
+ fmt_print_str(w, " mode=");
+ fmt_print_mode(w, ctx, &self->mode);
+ fmt_print_str(w, " major=");
+ fmt_print_base10(w, self->major);
+ fmt_print_str(w, " minor=");
+ fmt_print_base10(w, self->minor);
+ fmt_print_str(w, " gid=");
+ fmt_print_nuid(w, ctx, &self->gid);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rmknod(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rmknod *self) {
+ fmt_print_str(w, "Rmknod {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " qid=");
+ fmt_print_qid(w, ctx, &self->qid);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Trename(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Trename *self) {
+ fmt_print_str(w, "Trename {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " fid=");
+ fmt_print_fid(w, ctx, &self->fid);
+ fmt_print_str(w, " dfid=");
+ fmt_print_fid(w, ctx, &self->dfid);
+ fmt_print_str(w, " name=");
+ fmt_print_s(w, ctx, &self->name);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rreadlink(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rreadlink *self) {
+ fmt_print_str(w, "Rreadlink {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " target=");
+ fmt_print_s(w, ctx, &self->target);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rgetattr(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rgetattr *self) {
+ fmt_print_str(w, "Rgetattr {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " valid=");
+ fmt_print_getattr(w, ctx, &self->valid);
+ fmt_print_str(w, " qid=");
+ fmt_print_qid(w, ctx, &self->qid);
+ fmt_print_str(w, " mode=");
+ fmt_print_mode(w, ctx, &self->mode);
+ fmt_print_str(w, " uid=");
+ fmt_print_nuid(w, ctx, &self->uid);
+ fmt_print_str(w, " gid=");
+ fmt_print_nuid(w, ctx, &self->gid);
+ fmt_print_str(w, " nlink=");
+ fmt_print_base10(w, self->nlink);
+ fmt_print_str(w, " rdev=");
+ fmt_print_base10(w, self->rdev);
+ fmt_print_str(w, " filesize=");
+ fmt_print_base10(w, self->filesize);
+ fmt_print_str(w, " blksize=");
+ fmt_print_base10(w, self->blksize);
+ fmt_print_str(w, " blocks=");
+ fmt_print_base10(w, self->blocks);
+ fmt_print_str(w, " atime_sec=");
+ fmt_print_base10(w, self->atime_sec);
+ fmt_print_str(w, " atime_nsec=");
+ fmt_print_base10(w, self->atime_nsec);
+ fmt_print_str(w, " mtime_sec=");
+ fmt_print_base10(w, self->mtime_sec);
+ fmt_print_str(w, " mtime_nsec=");
+ fmt_print_base10(w, self->mtime_nsec);
+ fmt_print_str(w, " ctime_sec=");
+ fmt_print_base10(w, self->ctime_sec);
+ fmt_print_str(w, " ctime_nsec=");
+ fmt_print_base10(w, self->ctime_nsec);
+ fmt_print_str(w, " btime_sec=");
+ fmt_print_base10(w, self->btime_sec);
+ fmt_print_str(w, " btime_nsec=");
+ fmt_print_base10(w, self->btime_nsec);
+ fmt_print_str(w, " gen=");
+ fmt_print_base10(w, self->gen);
+ fmt_print_str(w, " data_version=");
+ fmt_print_base10(w, self->data_version);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Txattrwalk(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Txattrwalk *self) {
+ fmt_print_str(w, "Txattrwalk {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " fid=");
+ fmt_print_fid(w, ctx, &self->fid);
+ fmt_print_str(w, " newfid=");
+ fmt_print_fid(w, ctx, &self->newfid);
+ fmt_print_str(w, " name=");
+ fmt_print_s(w, ctx, &self->name);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Txattrcreate(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Txattrcreate *self) {
+ fmt_print_str(w, "Txattrcreate {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " fid=");
+ fmt_print_fid(w, ctx, &self->fid);
+ fmt_print_str(w, " name=");
+ fmt_print_s(w, ctx, &self->name);
+ fmt_print_str(w, " attr_size=");
+ fmt_print_base10(w, self->attr_size);
+ fmt_print_str(w, " flags=");
+ fmt_print_base10(w, self->flags);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Tlock(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Tlock *self) {
+ fmt_print_str(w, "Tlock {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " fid=");
+ fmt_print_fid(w, ctx, &self->fid);
+ fmt_print_str(w, " type=");
+ fmt_print_lock_type(w, ctx, &self->type);
+ fmt_print_str(w, " flags=");
+ fmt_print_lock_flags(w, ctx, &self->flags);
+ fmt_print_str(w, " start=");
+ fmt_print_base10(w, self->start);
+ fmt_print_str(w, " length=");
+ fmt_print_base10(w, self->length);
+ fmt_print_str(w, " proc_id=");
+ fmt_print_base10(w, self->proc_id);
+ fmt_print_str(w, " client_id=");
+ fmt_print_s(w, ctx, &self->client_id);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Tgetlock(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Tgetlock *self) {
+ fmt_print_str(w, "Tgetlock {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " fid=");
+ fmt_print_fid(w, ctx, &self->fid);
+ fmt_print_str(w, " type=");
+ fmt_print_lock_type(w, ctx, &self->type);
+ fmt_print_str(w, " start=");
+ fmt_print_base10(w, self->start);
+ fmt_print_str(w, " length=");
+ fmt_print_base10(w, self->length);
+ fmt_print_str(w, " proc_id=");
+ fmt_print_base10(w, self->proc_id);
+ fmt_print_str(w, " client_id=");
+ fmt_print_s(w, ctx, &self->client_id);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rgetlock(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rgetlock *self) {
+ fmt_print_str(w, "Rgetlock {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " type=");
+ fmt_print_lock_type(w, ctx, &self->type);
+ fmt_print_str(w, " start=");
+ fmt_print_base10(w, self->start);
+ fmt_print_str(w, " length=");
+ fmt_print_base10(w, self->length);
+ fmt_print_str(w, " proc_id=");
+ fmt_print_base10(w, self->proc_id);
+ fmt_print_str(w, " client_id=");
+ fmt_print_s(w, ctx, &self->client_id);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Tlink(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Tlink *self) {
+ fmt_print_str(w, "Tlink {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " dfid=");
+ fmt_print_fid(w, ctx, &self->dfid);
+ fmt_print_str(w, " fid=");
+ fmt_print_fid(w, ctx, &self->fid);
+ fmt_print_str(w, " name=");
+ fmt_print_s(w, ctx, &self->name);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Tmkdir(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Tmkdir *self) {
+ fmt_print_str(w, "Tmkdir {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " dfid=");
+ fmt_print_fid(w, ctx, &self->dfid);
+ fmt_print_str(w, " name=");
+ fmt_print_s(w, ctx, &self->name);
+ fmt_print_str(w, " mode=");
+ fmt_print_mode(w, ctx, &self->mode);
+ fmt_print_str(w, " gid=");
+ fmt_print_nuid(w, ctx, &self->gid);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Rmkdir(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rmkdir *self) {
+ fmt_print_str(w, "Rmkdir {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " qid=");
+ fmt_print_qid(w, ctx, &self->qid);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Trenameat(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Trenameat *self) {
+ fmt_print_str(w, "Trenameat {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " olddirfid=");
+ fmt_print_fid(w, ctx, &self->olddirfid);
+ fmt_print_str(w, " oldname=");
+ fmt_print_s(w, ctx, &self->oldname);
+ fmt_print_str(w, " newdirfid=");
+ fmt_print_fid(w, ctx, &self->newdirfid);
+ fmt_print_str(w, " newname=");
+ fmt_print_s(w, ctx, &self->newname);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Tunlinkat(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Tunlinkat *self) {
+ fmt_print_str(w, "Tunlinkat {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " dirfd=");
+ fmt_print_fid(w, ctx, &self->dirfd);
+ fmt_print_str(w, " name=");
+ fmt_print_s(w, ctx, &self->name);
+ fmt_print_str(w, " flags=");
+ fmt_print_base10(w, self->flags);
+ fmt_print_str(w, " }");
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000_L */
+#if CONFIG_9P_ENABLE_9P2000_e
+[[maybe_unused]] static void fmt_print_Tsread(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Tsread *self) {
+ fmt_print_str(w, "Tsread {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " fid=");
+ fmt_print_base10(w, self->fid);
+ fmt_print_str(w, " nwname=");
+ fmt_print_base10(w, self->nwname);
+ fmt_print_str(w, " wname=[");
for (uint16_t i = 0; i < self->nwname; i++) {
if (i)
- fmt_state_putchar(state, ',');
- fmt_state_putchar(state, ' ');
- lib9p_s_format(&self->wname[i], state);
- }
- fmt_state_puts(state, " ]");
- fmt_state_puts(state, " count=");
- fmt_state_printf(state, "%"PRIu32, self->count);
- if (is_valid_utf8_without_nul((uint8_t *)self->data, (size_t)self->count)) {
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wformat"
-#pragma GCC diagnostic ignored "-Wformat-extra-args"
- fmt_state_printf(state, " data=%.*q%s",
- (int)(self->count < 50 ? self->count : 50),
- (char *)self->data,
- self->count < 50 ? "" : "...");
-#pragma GCC diagnostic pop
+ fmt_print_byte(w, ',');
+ fmt_print_byte(w, ' ');
+ fmt_print_s(w, ctx, &self->wname[i]);
+ }
+ fmt_print_str(w, " ]");
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Tswrite(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Tswrite *self) {
+ fmt_print_str(w, "Tswrite {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " fid=");
+ fmt_print_base10(w, self->fid);
+ fmt_print_str(w, " nwname=");
+ fmt_print_base10(w, self->nwname);
+ fmt_print_str(w, " wname=[");
+ for (uint16_t i = 0; i < self->nwname; i++) {
+ if (i)
+ fmt_print_byte(w, ',');
+ fmt_print_byte(w, ' ');
+ fmt_print_s(w, ctx, &self->wname[i]);
+ }
+ fmt_print_str(w, " ]");
+ fmt_print_str(w, " count=");
+ fmt_print_base10(w, 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)
+ fmt_print_str(w, "...");
} else {
- fmt_state_puts(state, " data=<bytedata>");
+ fmt_print_str(w, " data=<bytedata>");
}
- fmt_state_puts(state, " }");
+ fmt_print_str(w, " }");
}
-static void lib9p_msg_Rswrite_format(struct lib9p_msg_Rswrite *self, struct fmt_state *state) {
- fmt_state_puts(state, "Rswrite {");
- fmt_state_puts(state, " tag=");
- lib9p_tag_format(&self->tag, state);
- fmt_state_puts(state, " count=");
- fmt_state_printf(state, "%"PRIu32, self->count);
- fmt_state_puts(state, " }");
-}
#endif /* CONFIG_9P_ENABLE_9P2000_e */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+[[maybe_unused]] static void fmt_print_Rstat(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Rstat *self) {
+ fmt_print_str(w, "Rstat {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " stat=");
+ fmt_print_stat(w, ctx, &self->stat);
+ fmt_print_str(w, " }");
+}
+
+[[maybe_unused]] static void fmt_print_Twstat(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, struct lib9p_msg_Twstat *self) {
+ fmt_print_str(w, "Twstat {");
+ fmt_print_str(w, " tag=");
+ fmt_print_tag(w, ctx, &self->tag);
+ fmt_print_str(w, " fid=");
+ fmt_print_fid(w, ctx, &self->fid);
+ fmt_print_str(w, " stat=");
+ fmt_print_stat(w, ctx, &self->stat);
+ fmt_print_str(w, " }");
+}
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
/* tables.h *******************************************************************/
const struct _lib9p_ver_tentry _lib9p_table_ver[LIB9P_VER_NUM] = {
- [LIB9P_VER_unknown] = {.name="unknown", .min_msg_size=9},
#if CONFIG_9P_ENABLE_9P2000
- [LIB9P_VER_9P2000] = {.name="9P2000", .min_msg_size=9},
+ [LIB9P_VER_9P2000] = {.name="9P2000", .min_Rerror_size=9, .min_Rread_size=11},
#endif /* CONFIG_9P_ENABLE_9P2000 */
#if CONFIG_9P_ENABLE_9P2000_L
- [LIB9P_VER_9P2000_L] = {.name="9P2000.L", .min_msg_size=11},
+ [LIB9P_VER_9P2000_L] = {.name="9P2000.L", .min_Rerror_size=11, .min_Rread_size=11},
#endif /* CONFIG_9P_ENABLE_9P2000_L */
#if CONFIG_9P_ENABLE_9P2000_e
- [LIB9P_VER_9P2000_e] = {.name="9P2000.e", .min_msg_size=9},
+ [LIB9P_VER_9P2000_e] = {.name="9P2000.e", .min_Rerror_size=9, .min_Rread_size=11},
#endif /* CONFIG_9P_ENABLE_9P2000_e */
#if CONFIG_9P_ENABLE_9P2000_p9p
- [LIB9P_VER_9P2000_p9p] = {.name="9P2000.p9p", .min_msg_size=9},
+ [LIB9P_VER_9P2000_p9p] = {.name="9P2000.p9p", .min_Rerror_size=9, .min_Rread_size=11},
#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
#if CONFIG_9P_ENABLE_9P2000_u
- [LIB9P_VER_9P2000_u] = {.name="9P2000.u", .min_msg_size=13},
+ [LIB9P_VER_9P2000_u] = {.name="9P2000.u", .min_Rerror_size=13, .min_Rread_size=11},
#endif /* CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_uninitialized
+ [LIB9P_VER_uninitialized] = {.name="uninitialized", .min_Rerror_size=9, .min_Rread_size=0},
+#endif /* CONFIG_9P_ENABLE_uninitialized */
};
-#define _MSG(typ) [LIB9P_TYP_##typ] = { \
- .name = #typ, \
- .box_as_fmt_formatter = (_box_as_fmt_formatter_fn_t)lo_box_lib9p_msg_##typ##_as_fmt_formatter, \
+#define _MSG(typ) [LIB9P_TYP_##typ] = { \
+ .name = #typ, \
+ .print = (_print_fn_t)fmt_print_##typ, \
}
const struct _lib9p_msg_tentry _lib9p_table_msg[LIB9P_VER_NUM][0x100] = {
- [LIB9P_VER_unknown] = {
- _MSG(Tversion),
- _MSG(Rversion),
- _MSG(Rerror),
- },
#if CONFIG_9P_ENABLE_9P2000
[LIB9P_VER_9P2000] = {
_MSG(Tversion),
@@ -8032,6 +7625,13 @@ const struct _lib9p_msg_tentry _lib9p_table_msg[LIB9P_VER_NUM][0x100] = {
_MSG(Rwstat),
},
#endif /* CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_uninitialized
+ [LIB9P_VER_uninitialized] = {
+ _MSG(Tversion),
+ _MSG(Rversion),
+ _MSG(Rerror),
+ },
+#endif /* CONFIG_9P_ENABLE_uninitialized */
};
#define _MSG_RECV(typ) [LIB9P_TYP_##typ/2] = { \
@@ -8043,9 +7643,6 @@ const struct _lib9p_msg_tentry _lib9p_table_msg[LIB9P_VER_NUM][0x100] = {
}
const struct _lib9p_recv_tentry _lib9p_table_Tmsg_recv[LIB9P_VER_NUM][0x80] = {
- [LIB9P_VER_unknown] = {
- _MSG_RECV(Tversion),
- },
#if CONFIG_9P_ENABLE_9P2000
[LIB9P_VER_9P2000] = {
_MSG_RECV(Tversion),
@@ -8150,13 +7747,14 @@ const struct _lib9p_recv_tentry _lib9p_table_Tmsg_recv[LIB9P_VER_NUM][0x80] = {
_MSG_RECV(Twstat),
},
#endif /* CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_uninitialized
+ [LIB9P_VER_uninitialized] = {
+ _MSG_RECV(Tversion),
+ },
+#endif /* CONFIG_9P_ENABLE_uninitialized */
};
const struct _lib9p_recv_tentry _lib9p_table_Rmsg_recv[LIB9P_VER_NUM][0x80] = {
- [LIB9P_VER_unknown] = {
- _MSG_RECV(Rversion),
- _MSG_RECV(Rerror),
- },
#if CONFIG_9P_ENABLE_9P2000
[LIB9P_VER_9P2000] = {
_MSG_RECV(Rversion),
@@ -8266,12 +7864,15 @@ const struct _lib9p_recv_tentry _lib9p_table_Rmsg_recv[LIB9P_VER_NUM][0x80] = {
_MSG_RECV(Rwstat),
},
#endif /* CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_uninitialized
+ [LIB9P_VER_uninitialized] = {
+ _MSG_RECV(Rversion),
+ _MSG_RECV(Rerror),
+ },
+#endif /* CONFIG_9P_ENABLE_uninitialized */
};
const struct _lib9p_send_tentry _lib9p_table_Tmsg_send[LIB9P_VER_NUM][0x80] = {
- [LIB9P_VER_unknown] = {
- _MSG_SEND(Tversion),
- },
#if CONFIG_9P_ENABLE_9P2000
[LIB9P_VER_9P2000] = {
_MSG_SEND(Tversion),
@@ -8376,13 +7977,14 @@ const struct _lib9p_send_tentry _lib9p_table_Tmsg_send[LIB9P_VER_NUM][0x80] = {
_MSG_SEND(Twstat),
},
#endif /* CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_uninitialized
+ [LIB9P_VER_uninitialized] = {
+ _MSG_SEND(Tversion),
+ },
+#endif /* CONFIG_9P_ENABLE_uninitialized */
};
const struct _lib9p_send_tentry _lib9p_table_Rmsg_send[LIB9P_VER_NUM][0x80] = {
- [LIB9P_VER_unknown] = {
- _MSG_SEND(Rversion),
- _MSG_SEND(Rerror),
- },
#if CONFIG_9P_ENABLE_9P2000
[LIB9P_VER_9P2000] = {
_MSG_SEND(Rversion),
@@ -8492,9 +8094,16 @@ const struct _lib9p_send_tentry _lib9p_table_Rmsg_send[LIB9P_VER_NUM][0x80] = {
_MSG_SEND(Rwstat),
},
#endif /* CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_uninitialized
+ [LIB9P_VER_uninitialized] = {
+ _MSG_SEND(Rversion),
+ _MSG_SEND(Rerror),
+ },
+#endif /* CONFIG_9P_ENABLE_uninitialized */
};
-LM_FLATTEN ssize_t _lib9p_stat_validate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes, uint32_t *ret_net_size) {
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+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) {
@@ -8503,3 +8112,4 @@ LM_FLATTEN void _lib9p_stat_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes,
LM_FLATTEN bool _lib9p_stat_marshal(struct lib9p_ctx *ctx, struct lib9p_stat *val, struct _marshal_ret *ret) {
return marshal_stat(ctx, val, ret);
}
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
diff --git a/lib9p/core_include/lib9p/_core_generated.h b/lib9p/core_include/lib9p/_core_generated.h
index 68eb636..3f87181 100644
--- a/lib9p/core_include/lib9p/_core_generated.h
+++ b/lib9p/core_include/lib9p/_core_generated.h
@@ -1,18 +1,11 @@
-/* Generated by `lib9p/core.gen lib9p/idl/2002-9P2000.9p lib9p/idl/2003-9P2000.p9p.9p lib9p/idl/2005-9P2000.u.9p lib9p/idl/2010-9P2000.L.9p lib9p/idl/2012-9P2000.e.9p`. DO NOT EDIT! */
+/* Generated by `lib9p/core.gen lib9p/idl/0000-uninitialized.9p lib9p/idl/2002-9P2000.9p lib9p/idl/2003-9P2000.p9p.9p lib9p/idl/2005-9P2000.u.9p lib9p/idl/2010-9P2000.L.9p lib9p/idl/2012-9P2000.e.9p`. DO NOT EDIT! */
#ifndef _LIB9P_CORE_H_
#error Do not include <lib9p/_core_generated.h> directly; include <lib9p/core.h> instead
#endif
-#include <stdint.h> /* for uint{n}_t types */
-
-#include <libfmt/fmt.h> /* for fmt_formatter */
-#include <libhw/generic/io.h> /* for struct iovec */
-
/* config *********************************************************************/
-#include "config.h"
-
#ifndef CONFIG_9P_ENABLE_9P2000
#error config.h must define CONFIG_9P_ENABLE_9P2000
#endif
@@ -40,28 +33,33 @@
#error config.h must define CONFIG_9P_ENABLE_9P2000_u
#endif
+#ifndef CONFIG_9P_ENABLE_uninitialized
+ #error config.h must define CONFIG_9P_ENABLE_uninitialized
+#endif
+
+#define _LIB9P_ENABLE_stat CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+
/* enum version ***************************************************************/
enum lib9p_version {
- LIB9P_VER_unknown = 0, /* "unknown" */
+ LIB9P_VER_uninitialized = 0, /* "uninitialized" */
#if CONFIG_9P_ENABLE_9P2000
- LIB9P_VER_9P2000, /* "9P2000" */
+ LIB9P_VER_9P2000, /* "9P2000" */
#endif /* CONFIG_9P_ENABLE_9P2000 */
#if CONFIG_9P_ENABLE_9P2000_L
- LIB9P_VER_9P2000_L, /* "9P2000.L" */
+ LIB9P_VER_9P2000_L, /* "9P2000.L" */
#endif /* CONFIG_9P_ENABLE_9P2000_L */
#if CONFIG_9P_ENABLE_9P2000_e
- LIB9P_VER_9P2000_e, /* "9P2000.e" */
+ LIB9P_VER_9P2000_e, /* "9P2000.e" */
#endif /* CONFIG_9P_ENABLE_9P2000_e */
#if CONFIG_9P_ENABLE_9P2000_p9p
- LIB9P_VER_9P2000_p9p, /* "9P2000.p9p" */
+ LIB9P_VER_9P2000_p9p, /* "9P2000.p9p" */
#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
#if CONFIG_9P_ENABLE_9P2000_u
- LIB9P_VER_9P2000_u, /* "9P2000.u" */
+ LIB9P_VER_9P2000_u, /* "9P2000.u" */
#endif /* CONFIG_9P_ENABLE_9P2000_u */
LIB9P_VER_NUM,
};
-LO_IMPLEMENTATION_H(fmt_formatter, enum lib9p_version, lib9p_version);
/* enum msg_type **************************************************************/
@@ -111,17 +109,19 @@ enum lib9p_msg_type { /* uint8_t */
LIB9P_TYP_Topenfd = 98,
LIB9P_TYP_Ropenfd = 99,
#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
-#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_uninitialized
LIB9P_TYP_Tversion = 100,
LIB9P_TYP_Rversion = 101,
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_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
LIB9P_TYP_Tauth = 102,
LIB9P_TYP_Rauth = 103,
LIB9P_TYP_Tattach = 104,
LIB9P_TYP_Rattach = 105,
#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
-#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_uninitialized
LIB9P_TYP_Rerror = 107,
-#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_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
LIB9P_TYP_Tflush = 108,
LIB9P_TYP_Rflush = 109,
@@ -159,26 +159,22 @@ enum lib9p_msg_type { /* uint8_t */
LIB9P_TYP_Rswrite = 155,
#endif /* CONFIG_9P_ENABLE_9P2000_e */
};
-LO_IMPLEMENTATION_H(fmt_formatter, enum lib9p_msg_type, lib9p_msg_type);
/* payload types **************************************************************/
-#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_uninitialized
/* size = 2 ; max_iov = 1 ; max_copy = 2 */
typedef uint16_t lib9p_tag_t;
-LO_IMPLEMENTATION_H(fmt_formatter, lib9p_tag_t, lib9p_tag);
#define LIB9P_TAG_NOTAG ((lib9p_tag_t)(UINT16_MAX))
/* size = 4 ; max_iov = 1 ; max_copy = 4 */
typedef uint32_t lib9p_fid_t;
-LO_IMPLEMENTATION_H(fmt_formatter, lib9p_fid_t, lib9p_fid);
#define LIB9P_FID_NOFID ((lib9p_fid_t)(UINT32_MAX))
-#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
-#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_uninitialized */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_uninitialized
/* size = 4 ; max_iov = 1 ; max_copy = 4 */
typedef uint32_t lib9p_dm_t;
-LO_IMPLEMENTATION_H(fmt_formatter, lib9p_dm_t, lib9p_dm);
/* bits */
#define LIB9P_DM_DIR ((lib9p_dm_t)(UINT32_C(1)<<31))
#define LIB9P_DM_APPEND ((lib9p_dm_t)(UINT32_C(1)<<30))
@@ -219,11 +215,10 @@ LO_IMPLEMENTATION_H(fmt_formatter, lib9p_dm_t, lib9p_dm);
/* masks */
#define LIB9P_DM_PERM_MASK ((lib9p_dm_t)(0b000000000000000000000111111111))
-#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
-#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_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 || CONFIG_9P_ENABLE_uninitialized
/* size = 1 ; max_iov = 1 ; max_copy = 1 */
typedef uint8_t lib9p_qt_t;
-LO_IMPLEMENTATION_H(fmt_formatter, lib9p_qt_t, lib9p_qt);
/* bits */
#define LIB9P_QT_DIR ((lib9p_qt_t)(UINT8_C(1)<<7))
#define LIB9P_QT_APPEND ((lib9p_qt_t)(UINT8_C(1)<<6))
@@ -238,11 +233,10 @@ LO_IMPLEMENTATION_H(fmt_formatter, lib9p_qt_t, lib9p_qt);
/* aliases */
#define LIB9P_QT_FILE ((lib9p_qt_t)(0))
-#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#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_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
/* size = 1 ; max_iov = 1 ; max_copy = 1 */
typedef uint8_t lib9p_o_t;
-LO_IMPLEMENTATION_H(fmt_formatter, lib9p_o_t, lib9p_o);
/* bits */
#define _LIB9P_O_UNUSED_7 ((lib9p_o_t)(UINT8_C(1)<<7))
#define LIB9P_O_RCLOSE ((lib9p_o_t)(UINT8_C(1)<<6))
@@ -265,12 +259,10 @@ LO_IMPLEMENTATION_H(fmt_formatter, lib9p_o_t, lib9p_o);
#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u
/* size = 4 ; max_iov = 1 ; max_copy = 4 */
typedef uint32_t lib9p_nuid_t;
-LO_IMPLEMENTATION_H(fmt_formatter, lib9p_nuid_t, lib9p_nuid);
#define LIB9P_NUID_NONUID ((lib9p_nuid_t)(UINT32_MAX))
/* size = 4 ; max_iov = 1 ; max_copy = 4 */
typedef uint32_t lib9p_errno_t;
-LO_IMPLEMENTATION_H(fmt_formatter, lib9p_errno_t, lib9p_errno);
#define LIB9P_ERRNO_NOERROR ((lib9p_errno_t)(0))
#define LIB9P_ERRNO_L_EPERM ((lib9p_errno_t)(1))
#define LIB9P_ERRNO_L_ENOENT ((lib9p_errno_t)(2))
@@ -408,12 +400,10 @@ LO_IMPLEMENTATION_H(fmt_formatter, lib9p_errno_t, lib9p_errno);
#if CONFIG_9P_ENABLE_9P2000_L
/* size = 4 ; max_iov = 1 ; max_copy = 4 */
typedef uint32_t lib9p_super_magic_t;
-LO_IMPLEMENTATION_H(fmt_formatter, lib9p_super_magic_t, lib9p_super_magic);
#define LIB9P_SUPER_MAGIC_V9FS_MAGIC ((lib9p_super_magic_t)(16914839))
/* size = 4 ; max_iov = 1 ; max_copy = 4 */
typedef uint32_t lib9p_lo_t;
-LO_IMPLEMENTATION_H(fmt_formatter, lib9p_lo_t, lib9p_lo);
/* bits */
#define _LIB9P_LO_UNUSED_31 ((lib9p_lo_t)(UINT32_C(1)<<31))
#define _LIB9P_LO_UNUSED_30 ((lib9p_lo_t)(UINT32_C(1)<<30))
@@ -458,7 +448,6 @@ LO_IMPLEMENTATION_H(fmt_formatter, lib9p_lo_t, lib9p_lo);
/* size = 1 ; max_iov = 1 ; max_copy = 1 */
typedef uint8_t lib9p_dt_t;
-LO_IMPLEMENTATION_H(fmt_formatter, lib9p_dt_t, lib9p_dt);
#define LIB9P_DT_UNKNOWN ((lib9p_dt_t)(0))
#define LIB9P_DT_PIPE ((lib9p_dt_t)(1))
#define LIB9P_DT_CHAR_DEV ((lib9p_dt_t)(2))
@@ -471,7 +460,6 @@ LO_IMPLEMENTATION_H(fmt_formatter, lib9p_dt_t, lib9p_dt);
/* size = 4 ; max_iov = 1 ; max_copy = 4 */
typedef uint32_t lib9p_mode_t;
-LO_IMPLEMENTATION_H(fmt_formatter, lib9p_mode_t, lib9p_mode);
/* bits */
#define _LIB9P_MODE_UNUSED_31 ((lib9p_mode_t)(UINT32_C(1)<<31))
#define _LIB9P_MODE_UNUSED_30 ((lib9p_mode_t)(UINT32_C(1)<<30))
@@ -519,13 +507,11 @@ LO_IMPLEMENTATION_H(fmt_formatter, lib9p_mode_t, lib9p_mode);
/* size = 4 ; max_iov = 1 ; max_copy = 4 */
typedef uint32_t lib9p_b4_t;
-LO_IMPLEMENTATION_H(fmt_formatter, lib9p_b4_t, lib9p_b4);
#define LIB9P_B4_FALSE ((lib9p_b4_t)(0))
#define LIB9P_B4_TRUE ((lib9p_b4_t)(1))
/* size = 8 ; max_iov = 1 ; max_copy = 8 */
typedef uint64_t lib9p_getattr_t;
-LO_IMPLEMENTATION_H(fmt_formatter, lib9p_getattr_t, lib9p_getattr);
/* bits */
#define _LIB9P_GETATTR_UNUSED_63 ((lib9p_getattr_t)(UINT64_C(1)<<63))
#define _LIB9P_GETATTR_UNUSED_62 ((lib9p_getattr_t)(UINT64_C(1)<<62))
@@ -597,7 +583,6 @@ LO_IMPLEMENTATION_H(fmt_formatter, lib9p_getattr_t, lib9p_getattr);
/* size = 4 ; max_iov = 1 ; max_copy = 4 */
typedef uint32_t lib9p_setattr_t;
-LO_IMPLEMENTATION_H(fmt_formatter, lib9p_setattr_t, lib9p_setattr);
/* bits */
#define _LIB9P_SETATTR_UNUSED_31 ((lib9p_setattr_t)(UINT32_C(1)<<31))
#define _LIB9P_SETATTR_UNUSED_30 ((lib9p_setattr_t)(UINT32_C(1)<<30))
@@ -634,14 +619,12 @@ LO_IMPLEMENTATION_H(fmt_formatter, lib9p_setattr_t, lib9p_setattr);
/* size = 1 ; max_iov = 1 ; max_copy = 1 */
typedef uint8_t lib9p_lock_type_t;
-LO_IMPLEMENTATION_H(fmt_formatter, lib9p_lock_type_t, lib9p_lock_type);
#define LIB9P_LOCK_TYPE_RDLCK ((lib9p_lock_type_t)(0))
#define LIB9P_LOCK_TYPE_WRLCK ((lib9p_lock_type_t)(1))
#define LIB9P_LOCK_TYPE_UNLCK ((lib9p_lock_type_t)(2))
/* size = 4 ; max_iov = 1 ; max_copy = 4 */
typedef uint32_t lib9p_lock_flags_t;
-LO_IMPLEMENTATION_H(fmt_formatter, lib9p_lock_flags_t, lib9p_lock_flags);
/* bits */
#define _LIB9P_LOCK_FLAGS_UNUSED_31 ((lib9p_lock_flags_t)(UINT32_C(1)<<31))
#define _LIB9P_LOCK_FLAGS_UNUSED_30 ((lib9p_lock_flags_t)(UINT32_C(1)<<30))
@@ -678,20 +661,18 @@ LO_IMPLEMENTATION_H(fmt_formatter, lib9p_lock_flags_t, lib9p_lock_flags);
/* size = 1 ; max_iov = 1 ; max_copy = 1 */
typedef uint8_t lib9p_lock_status_t;
-LO_IMPLEMENTATION_H(fmt_formatter, lib9p_lock_status_t, lib9p_lock_status);
#define LIB9P_LOCK_STATUS_SUCCESS ((lib9p_lock_status_t)(0))
#define LIB9P_LOCK_STATUS_BLOCKED ((lib9p_lock_status_t)(1))
#define LIB9P_LOCK_STATUS_ERROR ((lib9p_lock_status_t)(2))
#define LIB9P_LOCK_STATUS_GRACE ((lib9p_lock_status_t)(3))
#endif /* CONFIG_9P_ENABLE_9P2000_L */
-#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+#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;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_s, lib9p_s);
/* size = 13 ; max_iov = 1 ; max_copy = 13 */
struct lib9p_qid {
@@ -699,20 +680,19 @@ struct lib9p_qid {
uint32_t vers;
uint64_t path;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_qid, lib9p_qid);
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_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
/* size = 9 ; max_iov = 1 ; max_copy = 9 */
struct lib9p_msg_Tflush {
lib9p_tag_t tag;
uint16_t oldtag;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tflush, lib9p_msg_Tflush);
/* size = 7 ; max_iov = 1 ; max_copy = 7 */
struct lib9p_msg_Rflush {
lib9p_tag_t tag;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rflush, lib9p_msg_Rflush);
#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
@@ -722,7 +702,6 @@ struct lib9p_msg_Topen {
lib9p_fid_t fid;
lib9p_o_t mode;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Topen, lib9p_msg_Topen);
#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
@@ -733,58 +712,50 @@ struct lib9p_msg_Tread {
uint64_t offset;
uint32_t count;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tread, lib9p_msg_Tread);
/* min_size = 11 ; exp_size = 8,203 ; max_size = 2,147,483,658 ; max_iov = 2 ; max_copy = 11 */
struct lib9p_msg_Rread {
- lib9p_tag_t tag;
- uint32_t count;
- [[gnu::nonstring]] char *data;
+ lib9p_tag_t tag;
+ uint32_t count;
+ const void *data;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rread, lib9p_msg_Rread);
/* min_size = 23 ; exp_size = 8,215 ; max_size = 2,147,483,670 ; max_iov = 2 ; max_copy = 23 */
struct lib9p_msg_Twrite {
- lib9p_tag_t tag;
- lib9p_fid_t fid;
- uint64_t offset;
- uint32_t count;
- [[gnu::nonstring]] char *data;
+ lib9p_tag_t tag;
+ lib9p_fid_t fid;
+ uint64_t offset;
+ uint32_t count;
+ const void *data;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Twrite, lib9p_msg_Twrite);
/* size = 11 ; max_iov = 1 ; max_copy = 11 */
struct lib9p_msg_Rwrite {
lib9p_tag_t tag;
uint32_t count;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rwrite, lib9p_msg_Rwrite);
/* size = 11 ; max_iov = 1 ; max_copy = 11 */
struct lib9p_msg_Tclunk {
lib9p_tag_t tag;
lib9p_fid_t fid;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tclunk, lib9p_msg_Tclunk);
/* size = 7 ; max_iov = 1 ; max_copy = 7 */
struct lib9p_msg_Rclunk {
lib9p_tag_t tag;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rclunk, lib9p_msg_Rclunk);
/* size = 11 ; max_iov = 1 ; max_copy = 11 */
struct lib9p_msg_Tremove {
lib9p_tag_t tag;
lib9p_fid_t fid;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tremove, lib9p_msg_Tremove);
/* size = 7 ; max_iov = 1 ; max_copy = 7 */
struct lib9p_msg_Rremove {
lib9p_tag_t tag;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rremove, lib9p_msg_Rremove);
#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
@@ -793,13 +764,11 @@ struct lib9p_msg_Tstat {
lib9p_tag_t tag;
lib9p_fid_t fid;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tstat, lib9p_msg_Tstat);
/* size = 7 ; max_iov = 1 ; max_copy = 7 */
struct lib9p_msg_Rwstat {
lib9p_tag_t tag;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rwstat, lib9p_msg_Rwstat);
#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
#if CONFIG_9P_ENABLE_9P2000_p9p
@@ -809,7 +778,6 @@ struct lib9p_msg_Topenfd {
lib9p_fid_t fid;
lib9p_o_t mode;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Topenfd, lib9p_msg_Topenfd);
#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
#if CONFIG_9P_ENABLE_9P2000_L
@@ -818,14 +786,12 @@ struct lib9p_msg_Rlerror {
lib9p_tag_t tag;
lib9p_errno_t errnum;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rlerror, lib9p_msg_Rlerror);
/* size = 11 ; max_iov = 1 ; max_copy = 11 */
struct lib9p_msg_Tstatfs {
lib9p_tag_t tag;
lib9p_fid_t fid;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tstatfs, lib9p_msg_Tstatfs);
/* size = 67 ; max_iov = 1 ; max_copy = 67 */
struct lib9p_msg_Rstatfs {
@@ -840,7 +806,6 @@ struct lib9p_msg_Rstatfs {
uint64_t fsid;
uint32_t namelen;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rstatfs, lib9p_msg_Rstatfs);
/* size = 15 ; max_iov = 1 ; max_copy = 15 */
struct lib9p_msg_Tlopen {
@@ -848,20 +813,17 @@ struct lib9p_msg_Tlopen {
lib9p_fid_t fid;
lib9p_lo_t flags;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tlopen, lib9p_msg_Tlopen);
/* size = 7 ; max_iov = 1 ; max_copy = 7 */
struct lib9p_msg_Rrename {
lib9p_tag_t tag;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rrename, lib9p_msg_Rrename);
/* size = 11 ; max_iov = 1 ; max_copy = 11 */
struct lib9p_msg_Treadlink {
lib9p_tag_t tag;
lib9p_fid_t fid;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Treadlink, lib9p_msg_Treadlink);
/* size = 19 ; max_iov = 1 ; max_copy = 19 */
struct lib9p_msg_Tgetattr {
@@ -869,7 +831,6 @@ struct lib9p_msg_Tgetattr {
lib9p_fid_t fid;
lib9p_getattr_t request_mask;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tgetattr, lib9p_msg_Tgetattr);
/* size = 67 ; max_iov = 1 ; max_copy = 67 */
struct lib9p_msg_Tsetattr {
@@ -885,26 +846,22 @@ struct lib9p_msg_Tsetattr {
uint64_t mtime_sec;
uint64_t mtime_nsec;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tsetattr, lib9p_msg_Tsetattr);
/* size = 7 ; max_iov = 1 ; max_copy = 7 */
struct lib9p_msg_Rsetattr {
lib9p_tag_t tag;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rsetattr, lib9p_msg_Rsetattr);
/* size = 15 ; max_iov = 1 ; max_copy = 15 */
struct lib9p_msg_Rxattrwalk {
lib9p_tag_t tag;
uint64_t attr_size;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rxattrwalk, lib9p_msg_Rxattrwalk);
/* size = 7 ; max_iov = 1 ; max_copy = 7 */
struct lib9p_msg_Rxattrcreate {
lib9p_tag_t tag;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rxattrcreate, lib9p_msg_Rxattrcreate);
/* size = 23 ; max_iov = 1 ; max_copy = 23 */
struct lib9p_msg_Treaddir {
@@ -913,15 +870,13 @@ struct lib9p_msg_Treaddir {
uint64_t offset;
uint32_t count;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Treaddir, lib9p_msg_Treaddir);
/* min_size = 11 ; exp_size = 8,203 ; max_size = 4,294,967,306 (warning: >UINT32_MAX) ; max_iov = 2 ; max_copy = 11 */
struct lib9p_msg_Rreaddir {
- lib9p_tag_t tag;
- uint32_t count;
- [[gnu::nonstring]] char *data;
+ lib9p_tag_t tag;
+ uint32_t count;
+ const void *data;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rreaddir, lib9p_msg_Rreaddir);
/* size = 15 ; max_iov = 1 ; max_copy = 15 */
struct lib9p_msg_Tfsync {
@@ -929,38 +884,32 @@ struct lib9p_msg_Tfsync {
lib9p_fid_t fid;
lib9p_b4_t datasync;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tfsync, lib9p_msg_Tfsync);
/* size = 7 ; max_iov = 1 ; max_copy = 7 */
struct lib9p_msg_Rfsync {
lib9p_tag_t tag;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rfsync, lib9p_msg_Rfsync);
/* size = 8 ; max_iov = 1 ; max_copy = 8 */
struct lib9p_msg_Rlock {
lib9p_tag_t tag;
lib9p_lock_status_t status;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rlock, lib9p_msg_Rlock);
/* size = 7 ; max_iov = 1 ; max_copy = 7 */
struct lib9p_msg_Rlink {
lib9p_tag_t tag;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rlink, lib9p_msg_Rlink);
/* size = 7 ; max_iov = 1 ; max_copy = 7 */
struct lib9p_msg_Rrenameat {
lib9p_tag_t tag;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rrenameat, lib9p_msg_Rrenameat);
/* size = 7 ; max_iov = 1 ; max_copy = 7 */
struct lib9p_msg_Runlinkat {
lib9p_tag_t tag;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Runlinkat, lib9p_msg_Runlinkat);
#endif /* CONFIG_9P_ENABLE_9P2000_L */
#if CONFIG_9P_ENABLE_9P2000_e
@@ -969,28 +918,24 @@ struct lib9p_msg_Tsession {
lib9p_tag_t tag;
uint64_t key;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tsession, lib9p_msg_Tsession);
/* size = 7 ; max_iov = 1 ; max_copy = 7 */
struct lib9p_msg_Rsession {
lib9p_tag_t tag;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rsession, 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;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rsread, lib9p_msg_Rsread);
/* size = 11 ; max_iov = 1 ; max_copy = 11 */
struct lib9p_msg_Rswrite {
lib9p_tag_t tag;
uint32_t count;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rswrite, lib9p_msg_Rswrite);
#endif /* CONFIG_9P_ENABLE_9P2000_e */
#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
@@ -999,35 +944,33 @@ LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rswrite, lib9p_msg_Rswrite);
/* LIB9P_VER_9P2000_p9p: min_size = 49 ; exp_size = 157 ; max_size = 262,189 ; max_iov = 8 ; max_copy = 49 */
/* LIB9P_VER_9P2000_u : min_size = 63 ; exp_size = 198 ; max_size = 327,738 ; max_iov = 11 ; max_copy = 63 */
struct lib9p_stat {
- uint16_t kern_type;
- uint32_t kern_dev;
- struct lib9p_qid file_qid;
- lib9p_dm_t file_mode;
- uint32_t file_atime;
- uint32_t file_mtime;
- uint64_t file_size;
- struct lib9p_s file_name;
- struct lib9p_s file_owner_uid;
- struct lib9p_s file_owner_gid;
- struct lib9p_s file_last_modified_uid;
+ uint16_t fstype;
+ uint32_t fsdev;
+ struct lib9p_qid qid;
+ lib9p_dm_t mode;
+ uint32_t atime;
+ uint32_t mtime;
+ uint64_t length;
+ struct lib9p_s name;
+ struct lib9p_s owner_uname;
+ struct lib9p_s owner_gname;
+ struct lib9p_s last_modifier_uname;
#if CONFIG_9P_ENABLE_9P2000_u
- struct lib9p_s file_extension;
- lib9p_nuid_t file_owner_n_uid;
- lib9p_nuid_t file_owner_n_gid;
- lib9p_nuid_t file_last_modified_n_uid;
+ struct lib9p_s extension;
+ lib9p_nuid_t owner_unum;
+ lib9p_nuid_t owner_gnum;
+ lib9p_nuid_t last_modifier_unum;
#endif /* CONFIG_9P_ENABLE_9P2000_u */
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_stat, lib9p_stat);
#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
-#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+#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 = 13 ; exp_size = 40 ; max_size = 65,548 ; max_iov = 2 ; max_copy = 13 */
struct lib9p_msg_Tversion {
lib9p_tag_t tag;
uint32_t max_msg_size;
struct lib9p_s version;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tversion, lib9p_msg_Tversion);
/* min_size = 13 ; exp_size = 40 ; max_size = 65,548 ; max_iov = 2 ; max_copy = 13 */
struct lib9p_msg_Rversion {
@@ -1035,8 +978,9 @@ struct lib9p_msg_Rversion {
uint32_t max_msg_size;
struct lib9p_s version;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rversion, lib9p_msg_Rversion);
+#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
/* LIB9P_VER_9P2000 : min_size = 15 ; exp_size = 69 ; max_size = 131,085 ; max_iov = 4 ; max_copy = 15 */
/* LIB9P_VER_9P2000_L : min_size = 19 ; exp_size = 73 ; max_size = 131,089 ; max_iov = 5 ; max_copy = 19 */
/* LIB9P_VER_9P2000_e : min_size = 15 ; exp_size = 69 ; max_size = 131,085 ; max_iov = 4 ; max_copy = 15 */
@@ -1048,17 +992,15 @@ struct lib9p_msg_Tauth {
struct lib9p_s uname;
struct lib9p_s aname;
#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u
- lib9p_nuid_t n_uid;
+ lib9p_nuid_t unum;
#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tauth, lib9p_msg_Tauth);
/* size = 20 ; max_iov = 1 ; max_copy = 20 */
struct lib9p_msg_Rauth {
lib9p_tag_t tag;
struct lib9p_qid aqid;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rauth, lib9p_msg_Rauth);
/* LIB9P_VER_9P2000 : min_size = 19 ; exp_size = 73 ; max_size = 131,089 ; max_iov = 4 ; max_copy = 19 */
/* LIB9P_VER_9P2000_L : min_size = 23 ; exp_size = 77 ; max_size = 131,093 ; max_iov = 5 ; max_copy = 23 */
@@ -1072,24 +1014,23 @@ struct lib9p_msg_Tattach {
struct lib9p_s uname;
struct lib9p_s aname;
#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u
- lib9p_nuid_t n_uid;
+ lib9p_nuid_t unum;
#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tattach, lib9p_msg_Tattach);
/* size = 20 ; max_iov = 1 ; max_copy = 20 */
struct lib9p_msg_Rattach {
lib9p_tag_t tag;
struct lib9p_qid qid;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rattach, lib9p_msg_Rattach);
#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
-/* LIB9P_VER_9P2000 : min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */
-/* LIB9P_VER_9P2000_e : min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */
-/* LIB9P_VER_9P2000_p9p: min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */
-/* LIB9P_VER_9P2000_u : min_size = 13 ; exp_size = 40 ; max_size = 65,548 ; max_iov = 3 ; max_copy = 13 */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_uninitialized
+/* LIB9P_VER_9P2000 : min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */
+/* LIB9P_VER_9P2000_e : min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */
+/* LIB9P_VER_9P2000_p9p : min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */
+/* LIB9P_VER_9P2000_u : min_size = 13 ; exp_size = 40 ; max_size = 65,548 ; max_iov = 3 ; max_copy = 13 */
+/* LIB9P_VER_uninitialized: min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */
struct lib9p_msg_Rerror {
lib9p_tag_t tag;
struct lib9p_s errstr;
@@ -1097,9 +1038,8 @@ struct lib9p_msg_Rerror {
lib9p_errno_t errnum;
#endif /* CONFIG_9P_ENABLE_9P2000_u */
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rerror, lib9p_msg_Rerror);
-#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_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
/* min_size = 17 ; exp_size = 481 ; max_size = 1,048,609 ; max_iov = 32 ; max_copy = 49 */
struct lib9p_msg_Twalk {
@@ -1109,7 +1049,6 @@ struct lib9p_msg_Twalk {
uint16_t nwname;
struct lib9p_s *wname;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Twalk, lib9p_msg_Twalk);
/* min_size = 9 ; exp_size = 217 ; max_size = 217 ; max_iov = 1 ; max_copy = 217 */
struct lib9p_msg_Rwalk {
@@ -1117,7 +1056,6 @@ struct lib9p_msg_Rwalk {
uint16_t nwqid;
struct lib9p_qid *wqid;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rwalk, lib9p_msg_Rwalk);
#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
@@ -1127,7 +1065,6 @@ struct lib9p_msg_Ropen {
struct lib9p_qid qid;
uint32_t iounit;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Ropen, lib9p_msg_Ropen);
/* min_size = 18 ; exp_size = 45 ; max_size = 65,553 ; max_iov = 3 ; max_copy = 18 */
struct lib9p_msg_Tcreate {
@@ -1137,7 +1074,6 @@ struct lib9p_msg_Tcreate {
lib9p_dm_t perm;
lib9p_o_t mode;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tcreate, lib9p_msg_Tcreate);
/* size = 24 ; max_iov = 1 ; max_copy = 24 */
struct lib9p_msg_Rcreate {
@@ -1145,7 +1081,6 @@ struct lib9p_msg_Rcreate {
struct lib9p_qid qid;
uint32_t iounit;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rcreate, lib9p_msg_Rcreate);
#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
@@ -1156,7 +1091,6 @@ struct lib9p_msg_Ropenfd {
uint32_t iounit;
uint32_t unixfd;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Ropenfd, lib9p_msg_Ropenfd);
#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
#if CONFIG_9P_ENABLE_9P2000_L
@@ -1166,7 +1100,6 @@ struct lib9p_msg_Rlopen {
struct lib9p_qid qid;
uint32_t iounit;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rlopen, lib9p_msg_Rlopen);
/* min_size = 25 ; exp_size = 52 ; max_size = 65,560 ; max_iov = 3 ; max_copy = 25 */
struct lib9p_msg_Tlcreate {
@@ -1177,7 +1110,6 @@ struct lib9p_msg_Tlcreate {
lib9p_mode_t mode;
lib9p_nuid_t gid;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tlcreate, lib9p_msg_Tlcreate);
/* size = 24 ; max_iov = 1 ; max_copy = 24 */
struct lib9p_msg_Rlcreate {
@@ -1185,7 +1117,6 @@ struct lib9p_msg_Rlcreate {
struct lib9p_qid qid;
uint32_t iounit;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rlcreate, lib9p_msg_Rlcreate);
/* min_size = 19 ; exp_size = 73 ; max_size = 131,089 ; max_iov = 5 ; max_copy = 19 */
struct lib9p_msg_Tsymlink {
@@ -1195,14 +1126,12 @@ struct lib9p_msg_Tsymlink {
struct lib9p_s symtgt;
lib9p_nuid_t gid;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tsymlink, lib9p_msg_Tsymlink);
/* size = 20 ; max_iov = 1 ; max_copy = 20 */
struct lib9p_msg_Rsymlink {
lib9p_tag_t tag;
struct lib9p_qid qid;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rsymlink, lib9p_msg_Rsymlink);
/* min_size = 29 ; exp_size = 56 ; max_size = 65,564 ; max_iov = 3 ; max_copy = 29 */
struct lib9p_msg_Tmknod {
@@ -1214,14 +1143,12 @@ struct lib9p_msg_Tmknod {
uint32_t minor;
lib9p_nuid_t gid;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tmknod, lib9p_msg_Tmknod);
/* size = 20 ; max_iov = 1 ; max_copy = 20 */
struct lib9p_msg_Rmknod {
lib9p_tag_t tag;
struct lib9p_qid qid;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rmknod, lib9p_msg_Rmknod);
/* min_size = 17 ; exp_size = 44 ; max_size = 65,552 ; max_iov = 2 ; max_copy = 17 */
struct lib9p_msg_Trename {
@@ -1230,14 +1157,12 @@ struct lib9p_msg_Trename {
lib9p_fid_t dfid;
struct lib9p_s name;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Trename, lib9p_msg_Trename);
/* min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */
struct lib9p_msg_Rreadlink {
lib9p_tag_t tag;
struct lib9p_s target;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rreadlink, lib9p_msg_Rreadlink);
/* size = 160 ; max_iov = 1 ; max_copy = 160 */
struct lib9p_msg_Rgetattr {
@@ -1263,7 +1188,6 @@ struct lib9p_msg_Rgetattr {
uint64_t gen;
uint64_t data_version;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rgetattr, lib9p_msg_Rgetattr);
/* min_size = 17 ; exp_size = 44 ; max_size = 65,552 ; max_iov = 2 ; max_copy = 17 */
struct lib9p_msg_Txattrwalk {
@@ -1272,7 +1196,6 @@ struct lib9p_msg_Txattrwalk {
lib9p_fid_t newfid;
struct lib9p_s name;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Txattrwalk, lib9p_msg_Txattrwalk);
/* min_size = 25 ; exp_size = 52 ; max_size = 65,560 ; max_iov = 3 ; max_copy = 25 */
struct lib9p_msg_Txattrcreate {
@@ -1282,7 +1205,6 @@ struct lib9p_msg_Txattrcreate {
uint64_t attr_size;
uint32_t flags;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Txattrcreate, lib9p_msg_Txattrcreate);
/* min_size = 38 ; exp_size = 65 ; max_size = 65,573 ; max_iov = 2 ; max_copy = 38 */
struct lib9p_msg_Tlock {
@@ -1295,7 +1217,6 @@ struct lib9p_msg_Tlock {
uint32_t proc_id;
struct lib9p_s client_id;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tlock, lib9p_msg_Tlock);
/* min_size = 34 ; exp_size = 61 ; max_size = 65,569 ; max_iov = 2 ; max_copy = 34 */
struct lib9p_msg_Tgetlock {
@@ -1307,7 +1228,6 @@ struct lib9p_msg_Tgetlock {
uint32_t proc_id;
struct lib9p_s client_id;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tgetlock, lib9p_msg_Tgetlock);
/* min_size = 30 ; exp_size = 57 ; max_size = 65,565 ; max_iov = 2 ; max_copy = 30 */
struct lib9p_msg_Rgetlock {
@@ -1318,7 +1238,6 @@ struct lib9p_msg_Rgetlock {
uint32_t proc_id;
struct lib9p_s client_id;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rgetlock, lib9p_msg_Rgetlock);
/* min_size = 17 ; exp_size = 44 ; max_size = 65,552 ; max_iov = 2 ; max_copy = 17 */
struct lib9p_msg_Tlink {
@@ -1327,7 +1246,6 @@ struct lib9p_msg_Tlink {
lib9p_fid_t fid;
struct lib9p_s name;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tlink, lib9p_msg_Tlink);
/* min_size = 21 ; exp_size = 48 ; max_size = 65,556 ; max_iov = 3 ; max_copy = 21 */
struct lib9p_msg_Tmkdir {
@@ -1337,14 +1255,12 @@ struct lib9p_msg_Tmkdir {
lib9p_mode_t mode;
lib9p_nuid_t gid;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tmkdir, lib9p_msg_Tmkdir);
/* size = 20 ; max_iov = 1 ; max_copy = 20 */
struct lib9p_msg_Rmkdir {
lib9p_tag_t tag;
struct lib9p_qid qid;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rmkdir, lib9p_msg_Rmkdir);
/* min_size = 19 ; exp_size = 73 ; max_size = 131,089 ; max_iov = 4 ; max_copy = 19 */
struct lib9p_msg_Trenameat {
@@ -1354,7 +1270,6 @@ struct lib9p_msg_Trenameat {
lib9p_fid_t newdirfid;
struct lib9p_s newname;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Trenameat, lib9p_msg_Trenameat);
/* min_size = 17 ; exp_size = 44 ; max_size = 65,552 ; max_iov = 3 ; max_copy = 17 */
struct lib9p_msg_Tunlinkat {
@@ -1363,7 +1278,6 @@ struct lib9p_msg_Tunlinkat {
struct lib9p_s name;
uint32_t flags;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tunlinkat, lib9p_msg_Tunlinkat);
#endif /* CONFIG_9P_ENABLE_9P2000_L */
#if CONFIG_9P_ENABLE_9P2000_e
@@ -1374,18 +1288,16 @@ struct lib9p_msg_Tsread {
uint16_t nwname;
struct lib9p_s *wname;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tsread, lib9p_msg_Tsread);
/* min_size = 17 ; exp_size = 8,673 ; max_size = 8,589,934,607 (warning: >UINT32_MAX) ; max_iov = 2 + (CONFIG_9P_MAX_9P2000_e_WELEM * 2) ; max_copy = 17 + (CONFIG_9P_MAX_9P2000_e_WELEM * 2) */
struct lib9p_msg_Tswrite {
- lib9p_tag_t tag;
- uint32_t fid;
- uint16_t nwname;
- struct lib9p_s *wname;
- uint32_t count;
- [[gnu::nonstring]] char *data;
+ lib9p_tag_t tag;
+ uint32_t fid;
+ uint16_t nwname;
+ struct lib9p_s *wname;
+ uint32_t count;
+ const void *data;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tswrite, lib9p_msg_Tswrite);
#endif /* CONFIG_9P_ENABLE_9P2000_e */
#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
@@ -1397,7 +1309,6 @@ struct lib9p_msg_Rstat {
lib9p_tag_t tag;
struct lib9p_stat stat;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rstat, lib9p_msg_Rstat);
/* LIB9P_VER_9P2000 : min_size = 62 ; exp_size = 170 ; max_size = 262,202 ; max_iov = 8 ; max_copy = 62 */
/* LIB9P_VER_9P2000_e : min_size = 62 ; exp_size = 170 ; max_size = 262,202 ; max_iov = 8 ; max_copy = 62 */
@@ -1408,7 +1319,6 @@ struct lib9p_msg_Twstat {
lib9p_fid_t fid;
struct lib9p_stat stat;
};
-LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Twstat, lib9p_msg_Twstat);
#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
/* containers *****************************************************************/
@@ -1421,6 +1331,8 @@ LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Twstat, lib9p_msg_Twstat);
#else
#define LIB9P_TMSG_MAX_IOV 32
#endif
+#elif CONFIG_9P_ENABLE_uninitialized
+ #define LIB9P_TMSG_MAX_IOV 2
#endif
#if CONFIG_9P_ENABLE_9P2000_u
@@ -1441,28 +1353,32 @@ LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Twstat, lib9p_msg_Twstat);
#else
#define LIB9P_TMSG_MAX_COPY 62
#endif
+#elif CONFIG_9P_ENABLE_uninitialized
+ #define LIB9P_TMSG_MAX_COPY 13
#endif
#if CONFIG_9P_ENABLE_9P2000_u
#define LIB9P_RMSG_MAX_IOV 11
#elif CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p
#define LIB9P_RMSG_MAX_IOV 8
-#elif CONFIG_9P_ENABLE_9P2000_L
+#elif CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_uninitialized
#define LIB9P_RMSG_MAX_IOV 2
#endif
#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
#define LIB9P_RMSG_MAX_COPY 217
+#elif CONFIG_9P_ENABLE_uninitialized
+ #define LIB9P_RMSG_MAX_COPY 13
#endif
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 ff822ed..84ecd0f 100644
--- a/lib9p/core_include/lib9p/core.h
+++ b/lib9p/core_include/lib9p/core.h
@@ -7,17 +7,17 @@
#ifndef _LIB9P_CORE_H_
#define _LIB9P_CORE_H_
-#include <stdbool.h>
-#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 wr_iovec */
#include <libmisc/assert.h>
+#include <libmisc/fmt.h>
-#include <lib9p/_core_generated.h>
+#define CONFIG_9P_ENABLE_uninitialized 1
+#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 ******************************************************************/
@@ -31,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);
@@ -43,28 +43,14 @@ struct lib9p_ctx {
/* negotiated */
enum lib9p_version version;
uint32_t max_msg_size;
-
- /* state */
-#ifdef CONFIG_9P_ENABLE_9P2000_u
- 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);
-
-/** Write an static error into ctx, return -1. */
-int lib9p_error(struct lib9p_ctx *ctx, lib9p_errno_t linux_errno, char const *msg);
-/** Write a printf-style error into ctx, return -1. */
-int lib9p_errorf(struct lib9p_ctx *ctx, lib9p_errno_t linux_errno, char const *fmt, ...) [[gnu::format(printf, 3, 4)]];
-
/* misc utilities *************************************************************/
-uint32_t lib9p_version_min_msg_size(enum lib9p_version);
+uint32_t lib9p_version_min_Rerror_size(enum lib9p_version);
+uint32_t lib9p_version_min_Rread_size(enum lib9p_version);
-lo_interface fmt_formatter lo_box_lib9p_msg_as_fmt_formatter(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body);
+void fmt_print_lib9p_msg(lo_interface fmt_dest w, struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body);
/* main T-message functions ***************************************************/
@@ -76,23 +62,19 @@ lo_interface fmt_formatter lo_box_lib9p_msg_as_fmt_formatter(struct lib9p_ctx *c
* 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`.
@@ -118,54 +100,48 @@ 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 ************************************************/
-/** Assert that a `struct lib9p_stat` object looks valid. */
-static inline void lib9p_stat_assert(struct lib9p_stat stat) {
- assert( ((bool)(stat.file_mode & LIB9P_DM_DIR )) == ((bool)(stat.file_qid.type & LIB9P_QT_DIR )) );
- assert( ((bool)(stat.file_mode & LIB9P_DM_APPEND)) == ((bool)(stat.file_qid.type & LIB9P_QT_APPEND)) );
- assert( ((bool)(stat.file_mode & LIB9P_DM_EXCL )) == ((bool)(stat.file_qid.type & LIB9P_QT_EXCL )) );
- assert( ((bool)(stat.file_mode & LIB9P_DM_AUTH )) == ((bool)(stat.file_qid.type & LIB9P_QT_AUTH )) );
- assert( ((bool)(stat.file_mode & LIB9P_DM_TMP )) == ((bool)(stat.file_qid.type & LIB9P_QT_TMP )) );
- assert( (stat.file_size == 0) || !(stat.file_mode & LIB9P_DM_DIR) );
-}
+#if _LIB9P_ENABLE_stat
+
+void fmt_print_lib9p_stat(lo_interface fmt_dest w, struct lib9p_ctx *ctx, struct lib9p_stat *stat);
/**
* 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`.
@@ -190,16 +166,15 @@ 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);
+#endif
#endif /* _LIB9P_CORE_H_ */
diff --git a/lib9p/core_tables.c b/lib9p/core_tables.c
deleted file mode 100644
index a04a5f0..0000000
--- a/lib9p/core_tables.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/* lib9p/core_tables.c - Access tables of version and message information
- *
- * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-#include <string.h>
-
-#include <libmisc/endian.h>
-#include <libmisc/log.h> /* for const_byte_str() */
-
-#include "core_tables.h"
-
-/* 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 *************************************************************/
-
-const char *lib9p_version_str(enum lib9p_version ver) {
- assert_ver(ver);
- return _lib9p_table_ver[ver].name;
-}
-
-uint32_t lib9p_version_min_msg_size(enum lib9p_version ver) {
- assert_ver(ver);
- return _lib9p_table_ver[ver].min_msg_size;
-}
-
-const char *lib9p_msgtype_str(enum lib9p_version ver, enum lib9p_msg_type typ) {
- assert_ver(ver);
- assert_typ(typ);
- return _lib9p_table_msg[ver][typ].name ?: const_byte_str(typ);
-}
-
-lo_interface fmt_formatter lo_box_lib9p_msg_as_fmt_formatter(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].box_as_fmt_formatter);
- return _lib9p_table_msg[ctx->version][typ].box_as_fmt_formatter(body);
-}
-
-/* main message functions *****************************************************/
-
-static
-ssize_t _lib9p_validate(uint8_t xxx_low_typ_bit,
- const char *xxx_errmsg,
- const struct _lib9p_recv_tentry xxx_table[LIB9P_VER_NUM][0x80],
- struct lib9p_ctx *ctx, uint8_t *net_bytes) {
- 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 != xxx_low_typ_bit)
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EOPNOTSUPP, "%s: message_type=%s", xxx_errmsg,
- lib9p_msgtype_str(ctx->version, typ));
- struct _lib9p_recv_tentry tentry = xxx_table[ctx->version][typ/2];
- if (!tentry.validate)
- return lib9p_errorf(ctx, LIB9P_ERRNO_L_EOPNOTSUPP, "unknown message type: %s (protocol_version=%s)",
- lib9p_msgtype_str(ctx->version, typ), lib9p_version_str(ctx->version));
-
- /* Now use the message-type-specific tentry to process the whole thing. */
- return tentry.validate(ctx, net_size, net_bytes);
-}
-
-ssize_t lib9p_Tmsg_validate(struct lib9p_ctx *ctx, uint8_t *net_bytes) {
- return _lib9p_validate(0, "expected a T-message but got an R-message", _lib9p_table_Tmsg_recv,
- ctx, net_bytes);
-}
-
-ssize_t lib9p_Rmsg_validate(struct lib9p_ctx *ctx, uint8_t *net_bytes) {
- return _lib9p_validate(1, "expected an R-message but got a T-message", _lib9p_table_Rmsg_recv,
- ctx, net_bytes);
-}
-
-static
-void _lib9p_unmarshal(const struct _lib9p_recv_tentry xxx_table[LIB9P_VER_NUM][0x80],
- struct lib9p_ctx *ctx, uint8_t *net_bytes,
- enum lib9p_msg_type *ret_typ, void *ret_body) {
- assert_ver(ctx->version);
- enum lib9p_msg_type typ = net_bytes[4];
- *ret_typ = typ;
- struct _lib9p_recv_tentry tentry = xxx_table[ctx->version][typ/2];
- assert(tentry.unmarshal);
-
- tentry.unmarshal(ctx, net_bytes, ret_body);
-}
-
-void lib9p_Tmsg_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes,
- enum lib9p_msg_type *ret_typ, void *ret_body) {
- _lib9p_unmarshal(_lib9p_table_Tmsg_recv,
- ctx, net_bytes, ret_typ, ret_body);
-}
-
-void lib9p_Rmsg_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes,
- enum lib9p_msg_type *ret_typ, void *ret_body) {
- _lib9p_unmarshal(_lib9p_table_Rmsg_recv,
- ctx, net_bytes, ret_typ, ret_body);
-}
-
-static
-bool _lib9p_marshal(const struct _lib9p_send_tentry xxx_table[LIB9P_VER_NUM][0x80],
- struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body,
- size_t *ret_iov_cnt, struct iovec *ret_iov, uint8_t *ret_copied) {
- assert_ver(ctx->version);
- assert_typ(typ);
- struct _marshal_ret ret = {
- .net_iov_cnt = 1,
- .net_iov = ret_iov,
- .net_copied_size = 0,
- .net_copied = ret_copied,
- };
- struct _lib9p_send_tentry tentry = xxx_table[ctx->version][typ/2];
- assert(tentry.marshal);
-
- bool ret_erred = tentry.marshal(ctx, body, &ret);
- if (ret_iov[ret.net_iov_cnt-1].iov_len == 0)
- ret.net_iov_cnt--;
- *ret_iov_cnt = ret.net_iov_cnt;
- return ret_erred;
-}
-
-bool lib9p_Tmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body,
- struct lib9p_Tmsg_send_buf *ret) {
- assert(typ % 2 == 0);
- memset(ret, 0, sizeof(*ret));
- return _lib9p_marshal(_lib9p_table_Tmsg_send,
- ctx, typ, body,
- &ret->iov_cnt, ret->iov, ret->copied);
-}
-
-bool lib9p_Rmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body,
- struct lib9p_Rmsg_send_buf *ret) {
- assert(typ % 2 == 1);
- memset(ret, 0, sizeof(*ret));
- return _lib9p_marshal(_lib9p_table_Rmsg_send,
- ctx, typ, body,
- &ret->iov_cnt, ret->iov, ret->copied);
-}
-
-/* `struct lib9p_stat` helpers ************************************************/
-
-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) {
- ssize_t host_size = _lib9p_stat_validate(ctx, net_size, net_bytes, ret_net_size);
- if (host_size < 0)
- return true;
- if (ret_host_size)
- *ret_host_size = (size_t)host_size;
- return false;
-}
-
-void lib9p_stat_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes,
- struct lib9p_stat *ret) {
- _lib9p_stat_unmarshal(ctx, net_bytes, ret);
-}
-
-uint32_t lib9p_stat_marshal(struct lib9p_ctx *ctx, uint32_t max_net_size, struct lib9p_stat *obj,
- uint8_t *ret_bytes) {
- struct lib9p_ctx _ctx = *ctx;
- _ctx.max_msg_size = max_net_size;
-
- struct iovec iov = {0};
- struct _marshal_ret ret = {
- .net_iov_cnt = 1,
- .net_iov = &iov,
- .net_copied_size = 0,
- .net_copied = ret_bytes,
- };
- if (_lib9p_stat_marshal(&_ctx, obj, &ret))
- return 0;
- return ret.net_iov[0].iov_len;
-}
diff --git a/lib9p/core_tables.h b/lib9p/core_tables.h
index 2c5f745..94cdbe1 100644
--- a/lib9p/core_tables.h
+++ b/lib9p/core_tables.h
@@ -13,20 +13,21 @@
struct _lib9p_ver_tentry {
const char *name;
- uint32_t min_msg_size;
+ uint32_t min_Rerror_size;
+ uint32_t min_Rread_size;
};
extern const struct _lib9p_ver_tentry _lib9p_table_ver[LIB9P_VER_NUM];
/* message ********************************************************************/
-typedef lo_interface fmt_formatter (*_box_as_fmt_formatter_fn_t)(void *host_val);
+typedef void (*_print_fn_t)(lo_interface fmt_dest, struct lib9p_ctx *, void *);
struct _lib9p_msg_tentry {
- const char *name;
- _box_as_fmt_formatter_fn_t box_as_fmt_formatter;
+ const char *name;
+ _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;
@@ -35,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;
};
@@ -52,8 +53,10 @@ extern const struct _lib9p_send_tentry _lib9p_table_Rmsg_send[LIB9P_VER_NUM][0x8
/* stat ***********************************************************************/
-ssize_t _lib9p_stat_validate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes, uint32_t *ret_net_size);
+#if _LIB9P_ENABLE_stat
+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
#endif /* _LIB9P_CORE_TABLES_H_ */
diff --git a/lib9p/core_utf8.h b/lib9p/core_utf8.h
deleted file mode 100644
index 636d4eb..0000000
--- a/lib9p/core_utf8.h
+++ /dev/null
@@ -1,34 +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_
-
-static inline bool _is_valid_utf8(uint8_t *str, size_t len, bool forbid_nul) {
- uint32_t ch;
- uint8_t chlen;
- assert(str);
- 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/0000-uninitialized.9p b/lib9p/idl/0000-uninitialized.9p
new file mode 100644
index 0000000..193cb19
--- /dev/null
+++ b/lib9p/idl/0000-uninitialized.9p
@@ -0,0 +1,13 @@
+# lib9p/idl/0000-uninitialized.9p - Defs for bootstrapping
+#
+# Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+version "uninitialized"
+
+# For the actual protocol.
+from ./2002-9P2000.9p import s, tag
+from ./2002-9P2000.9p import Tversion, Rversion, Rerror
+
+# For srv.h
+from ./2002-9P2000.9p import dm, qt, qid, fid
diff --git a/lib9p/idl/1992-9P0.9p.wip b/lib9p/idl/1992-9P0.9p.wip
index 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/2002-9P2000.9p b/lib9p/idl/2002-9P2000.9p
index 13393c6..712ffea 100644
--- a/lib9p/idl/2002-9P2000.9p
+++ b/lib9p/idl/2002-9P2000.9p
@@ -91,18 +91,26 @@ bitfield qt = 1
struct qid = "type[qt] vers[4] path[8]"
# stat - file status
-struct stat = "stat_size[2,val=end-&kern_type]"
- "kern_type[2]"
- "kern_dev[4]"
- "file_qid[qid]"
- "file_mode[dm]"
- "file_atime[4]"
- "file_mtime[4]"
- "file_size[8]"
- "file_name[s]"
- "file_owner_uid[s]"
- "file_owner_gid[s]"
- "file_last_modified_uid[s]"
+struct stat = "_stat_size[2,val=end-&fstype]"
+ # fstype and fsdev are documented simply as "for kernel
+ # use". The are ignored by Plan 9's in-kernel 9P
+ # client; mntdirfix() overwrites them with fstype='M'
+ # and fsdev=nonce. Processes may observe values other
+ # than fstype='M', as 'M' is used for actual 9P servers,
+ # while other values are used for in-kernel device
+ # servers (such as '|' for pipes, or 'I' for the IP
+ # stack).
+ "fstype[2]" # filesystem type
+ "fsdev[4]" # filesystem instance/subtype
+ "qid[qid]"
+ "mode[dm]"
+ "atime[4]"
+ "mtime[4]"
+ "length[8]" # 0 for directories
+ "name[s]"
+ "owner_uname[s]"
+ "owner_gname[s]"
+ "last_modifier_uname[s]"
# "O"pen flags (flags to pass to Topen and Tcreate)
# Unused bits *must* be 0.
diff --git a/lib9p/idl/2005-9P2000.u.9p b/lib9p/idl/2005-9P2000.u.9p
index 1d630f9..446385c 100644
--- a/lib9p/idl/2005-9P2000.u.9p
+++ b/lib9p/idl/2005-9P2000.u.9p
@@ -17,13 +17,13 @@ num nuid = 4
num errno = 4
"NOERROR = 0"
-struct stat += "file_extension[s]"
- "file_owner_n_uid[nuid]"
- "file_owner_n_gid[nuid]"
- "file_last_modified_n_uid[nuid]"
+struct stat += "extension[s]"
+ "owner_unum[nuid]"
+ "owner_gnum[nuid]"
+ "last_modifier_unum[nuid]"
-msg Tauth += "n_uid[nuid]"
-msg Tattach += "n_uid[nuid]"
+msg Tauth += "unum[nuid]"
+msg Tattach += "unum[nuid]"
msg Rerror += "errnum[errno]"
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 7e2bab0..3e4de91 100644
--- a/lib9p/srv.c
+++ b/lib9p/srv.c
@@ -4,23 +4,16 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-#include <alloca.h>
-#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,24 +34,35 @@
#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 ********************************************************************/
bool lib9p_srv_flush_requested(struct lib9p_srv_ctx *ctx) {
assert(ctx);
- return _lib9p_srv_flushch_can_send(&ctx->flushch);
+ return cr_chan_can_send(&ctx->flush_ch);
}
-void lib9p_srv_acknowledge_flush(struct lib9p_srv_ctx *ctx) {
- assert(ctx);
- assert(_lib9p_srv_flushch_can_send(&ctx->flushch));
- lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_ECANCELED, "request canceled by flush");
- _lib9p_srv_flushch_send(&ctx->flushch, true);
-}
+#define req_debug(...) \
+ log_debugln( \
+ "cid=", cr_getcid(), ": ", \
+ lib9p_msgtype_str(ctx->basectx.version, ctx->net_bytes[4]), "(tag=", ctx->tag, "): ", \
+ __VA_ARGS__)
/* 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,
@@ -86,11 +92,12 @@ struct srv_pathinfo {
#define FIDFLAG_OPEN_R (1<<0)
#define FIDFLAG_OPEN_W (1<<1)
#define FIDFLAG_RCLOSE (1<<2)
+#define FIDFLAG_APPEND (1<<3)
#define FIDFLAG_OPEN (FIDFLAG_OPEN_R|FIDFLAG_OPEN_W)
struct srv_fidinfo {
srv_path_t path;
- struct lib9p_srv_authinfo *authinfo;
+ struct lib9p_srv_userid *user;
uint8_t flags;
enum srv_filetype type;
union {
@@ -101,6 +108,7 @@ struct srv_fidinfo {
lo_interface lib9p_srv_dio io;
size_t idx;
uint64_t off;
+ struct lib9p_srv_dirent buffered_dirent;
} dir;
struct {
struct lib9p_s aname;
@@ -108,6 +116,7 @@ struct srv_fidinfo {
} auth;
};
};
+DECLARE_ERROR_OR_(struct srv_fidinfo *, srv_fidinfop);
/* contexts **************************************
*
@@ -123,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;
};
@@ -138,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 */
@@ -149,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)
@@ -157,44 +165,66 @@ 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_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);
/* TODO actually check user and group instead of just assuming "other". */
- uint8_t mode = (uint8_t)(stat->file_mode & 07);
+ uint8_t mode = (uint8_t)(stat->mode & 07);
return mode & action;
}
-struct lib9p_srv_authinfo *srv_authinfo_new(struct lib9p_s uname, lib9p_nuid_t uid) {
- struct lib9p_srv_authinfo *ret = malloc(sizeof(struct lib9p_srv_authinfo) + uname.len);
- if (!ret)
- return NULL;
- ret->uid = uid;
- ret->uname.len = uname.len;
- ret->uname.utf8 = (void *)&ret[1];
- memcpy(ret->uname.utf8, uname.utf8, uname.len);
+[[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 = (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 = end_dat;
ret->refcount = 1;
return ret;
}
+#if !(CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L)
+#define srv_userid_new(name, num) srv_userid_new(name)
+#endif
-struct lib9p_srv_authinfo *srv_authinfo_decref(struct lib9p_srv_authinfo *authinfo) {
- assert(authinfo);
- assert(authinfo->refcount);
- authinfo->refcount--;
- if (!authinfo->refcount) {
- free(authinfo);
- return NULL;
- }
- return authinfo;
+static struct lib9p_srv_userid *srv_userid_decref(struct lib9p_srv_userid *userid) {
+ assert(userid);
+ assert(userid->refcount);
+ userid->refcount--;
+ if (!userid->refcount)
+ free(userid);
+ return NULL;
}
-struct lib9p_srv_authinfo *srv_authinfo_incref(struct lib9p_srv_authinfo *authinfo) {
- assert(authinfo);
- authinfo->refcount++;
- return authinfo;
+static struct lib9p_srv_userid *srv_userid_incref(struct lib9p_srv_userid *userid) {
+ assert(userid);
+ userid->refcount++;
+ return userid;
}
/**
@@ -204,9 +234,10 @@ struct lib9p_srv_authinfo *srv_authinfo_incref(struct lib9p_srv_authinfo *authin
*
* 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));
@@ -238,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 (;;) {
@@ -256,32 +287,23 @@ 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, bool remove) {
- struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, fid);
+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);
+
struct srv_pathinfo *pathinfo = map_load(&ctx->parent_sess->paths, fidinfo->path);
assert(pathinfo);
- if (remove) {
- if (pathinfo->parent_dir == fidinfo->path) {
- lib9p_errorf(&ctx->basectx,
- LIB9P_ERRNO_L_EBUSY, "cannot remove root");
- goto clunk;
- }
- struct srv_pathinfo *parent = map_load(&ctx->parent_sess->paths, pathinfo->parent_dir);
- assert(parent);
- struct lib9p_stat parent_stat = LO_CALL(parent->file, stat, ctx);
- if (!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");
- goto clunk;
- }
- LO_CALL(pathinfo->file, remove, ctx);
- }
+ if (remove)
+ err = LO_CALL(pathinfo->file, remove, ctx);
- clunk:
if (fidinfo->flags & FIDFLAG_OPEN) {
switch (fidinfo->type) {
case SRV_FILETYPE_DIR:
@@ -296,9 +318,13 @@ static inline void srv_fid_del(struct srv_req *ctx, lib9p_fid_t fid, bool remove
}
pathinfo->io_refcount--;
}
- fidinfo->authinfo = srv_authinfo_decref(fidinfo->authinfo);
+ fidinfo->user = srv_userid_decref(fidinfo->user);
srv_path_decref(ctx, fidinfo->path);
map_del(&ctx->parent_sess->fids, fid);
+
+ ctx->user = srv_userid_decref(ctx->user);
+
+ return err;
}
/**
@@ -306,7 +332,8 @@ static inline void srv_fid_del(struct srv_req *ctx, lib9p_fid_t fid, bool remove
* 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);
@@ -323,22 +350,20 @@ static inline struct srv_fidinfo *srv_fid_store(struct srv_req *ctx, lib9p_fid_t
assert(old_fidinfo->type == SRV_FILETYPE_DIR);
assert(old_fidinfo->flags == 0);
- old_fidinfo->authinfo = srv_authinfo_decref(old_fidinfo->authinfo);
+ old_fidinfo->user = srv_userid_decref(old_fidinfo->user);
srv_path_decref(ctx, old_fidinfo->path);
map_del(&ctx->parent_sess->fids, fid);
} else {
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EBADF, "FID already in use");
- return NULL;
+ 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){
- .path = qid.path,
- .type = srv_qid_filetype(qid),
- .authinfo = srv_authinfo_incref(ctx->authinfo),
+ .path = qid.path,
+ .type = srv_qid_filetype(qid),
+ .user = srv_userid_incref(ctx->user),
});
assert(fidinfo);
- return fidinfo;
+ return ERROR_NEW_VAL(srv_fidinfop, fidinfo);
}
/* base utilities *************************************************************/
@@ -349,82 +374,81 @@ static void srv_msglog(struct srv_req *req, enum lib9p_msg_type typ, void *hostm
srv->msglog(req, typ, hostmsg);
return;
}
- /* It sucks that %v trips -Wformat and -Wformat-extra-args
- * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47781 */
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wformat"
-#pragma GCC diagnostic ignored "-Wformat-extra-args"
- infof("%c %v", typ % 2 ? '<' : '>', lo_box_lib9p_msg_as_fmt_formatter(&req->basectx, typ, hostmsg));
-#pragma GCC diagnostic pop
+ 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_errorf errorf
-
-static void srv_respond_error(struct srv_req *req) {
-#if CONFIG_9P_ENABLE_9P2000_u
- 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
};
struct srv_sess *sess = req->parent_sess;
- /* XXX: This assumes that a version's min_msg_size is the
- * Rerror overhead. That's true for the current
- * implementation of core_gen, but is a sneaky assumption. */
- uint32_t overhead = lib9p_version_min_msg_size(sess->version);
+ 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;
+ error marshal_err = srv_write_Rmsg(req, LIB9P_TYP_Rerror, &host);
+ assert(ERROR_IS_NULL(marshal_err));
- lib9p_Rmsg_marshal(&req->basectx,
- LIB9P_TYP_Rerror, &host,
- &net);
-
- srv_msglog(req, LIB9P_TYP_Rerror, &host);
- r = srv_write_Rmsg(req, &net);
- if (r < 0)
- srv_nonrespond_errorf("write: %s", 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_errorf("read: %s", net_strerror(-r));
- return true;
- } else if (r == 0) {
- if (*done != 0)
- srv_nonrespond_errorf("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;
}
@@ -437,114 +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_errorf("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)
- _lib9p_srv_reqch_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 handle_message(struct srv_req *ctx);
+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,
- .version = LIB9P_VER_unknown,
+ 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_errorf("T-message is impossibly small");
+ 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_errorf(&req.basectx,
- LIB9P_ERRNO_L_EMSGSIZE, "T-message larger than %s limit (%zu > %"PRIu32")",
- sess.initialized ? "negotiated" : "server",
- goal,
- sess.max_msg_size);
- srv_respond_error(&req);
+ 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, */
- handle_message(&req);
+ lib9p_srv_worker_Tversion(req);
else
/* ...but usually in another coroutine. */
- _lib9p_srv_reqch_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);
- map_free(&sess.reqs);
-
- MAP_FOREACH(&sess.fids, fid, fidinfo) {
- struct srv_req req = {
- .basectx = {
- .version = sess.version,
- .max_msg_size = sess.max_msg_size,
- },
- .parent_sess = &sess,
- };
- srv_fid_del(&req, fid, false);
- if (lib9p_ctx_has_error(&req.basectx))
- errorf("clunk: %.*s", CONFIG_9P_MAX_ERR_SIZE, req.basectx.err_msg);
+ 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);
+
+ /* Cleanup `sess->fids`. */
+ *req = (struct srv_req){
+ .basectx = {
+ .version = sess->version,
+ .max_msg_size = sess->max_msg_size,
+ },
+ .parent_sess = sess,
+ };
+ 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 ************************************************************/
@@ -560,10 +596,10 @@ void lib9p_srv_worker_loop(struct lib9p_srv *srv) {
for (;;) {
/* Receive the request from the reader coroutine. ************/
- rpc_handle = _lib9p_srv_reqch_recv_req(&srv->_reqch);
+ rpc_handle = cr_rpc_recv_req(&srv->reqch);
if (!rpc_handle.req) {
srv->writers--;
- _lib9p_srv_reqch_send_resp(rpc_handle, 0);
+ cr_rpc_send_resp(rpc_handle, 0);
return;
}
/* Copy the request from the reader coroutine's
@@ -574,25 +610,18 @@ void lib9p_srv_worker_loop(struct lib9p_srv *srv) {
assert(reqpp && *reqpp == &req);
/* Notify the reader coroutine that we're done with
* its data. */
- _lib9p_srv_reqch_send_resp(rpc_handle, 0);
+ cr_rpc_send_resp(rpc_handle, 0);
/* Process the request. **************************************/
- handle_message(&req);
-
- /* Release resources. ****************************************/
- while (_lib9p_srv_flushch_can_send(&req.flushch))
- _lib9p_srv_flushch_send(&req.flushch, false);
- map_del(&req.parent_sess->reqs, req.tag);
- if (req.parent_sess->closing && !map_len(&req.parent_sess->reqs))
- cr_unpause(req.parent_sess->parent_conn->reader);
+ lib9p_srv_worker(&req);
}
}
#define _HANDLER_PROTO(typ) \
static void handle_T##typ(struct srv_req *, \
- struct lib9p_msg_T##typ *, \
- struct lib9p_msg_R##typ *)
+ struct lib9p_msg_T##typ *)
_HANDLER_PROTO(version);
+#if _LIB9P_ENABLE_stat
_HANDLER_PROTO(auth);
_HANDLER_PROTO(attach);
_HANDLER_PROTO(flush);
@@ -605,6 +634,7 @@ _HANDLER_PROTO(clunk);
_HANDLER_PROTO(remove);
_HANDLER_PROTO(stat);
_HANDLER_PROTO(wstat);
+#endif
#if CONFIG_9P_ENABLE_9P2000_p9p
_HANDLER_PROTO(openfd);
#endif
@@ -614,82 +644,139 @@ _HANDLER_PROTO(sread);
_HANDLER_PROTO(swrite);
#endif
-typedef void (*tmessage_handler)(struct srv_req *, void *, void *);
-
-static tmessage_handler tmessage_handlers[0x100] = {
- [LIB9P_TYP_Tversion] = (tmessage_handler)handle_Tversion,
- [LIB9P_TYP_Tauth] = (tmessage_handler)handle_Tauth,
- [LIB9P_TYP_Tattach] = (tmessage_handler)handle_Tattach,
- [LIB9P_TYP_Tflush] = (tmessage_handler)handle_Tflush,
- [LIB9P_TYP_Twalk] = (tmessage_handler)handle_Twalk,
- [LIB9P_TYP_Topen] = (tmessage_handler)handle_Topen,
- [LIB9P_TYP_Tcreate] = (tmessage_handler)handle_Tcreate,
- [LIB9P_TYP_Tread] = (tmessage_handler)handle_Tread,
- [LIB9P_TYP_Twrite] = (tmessage_handler)handle_Twrite,
- [LIB9P_TYP_Tclunk] = (tmessage_handler)handle_Tclunk,
- [LIB9P_TYP_Tremove] = (tmessage_handler)handle_Tremove,
- [LIB9P_TYP_Tstat] = (tmessage_handler)handle_Tstat,
- [LIB9P_TYP_Twstat] = (tmessage_handler)handle_Twstat,
+void lib9p_srv_worker(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. ********************************************************/
+#define CASE(typ) case LIB9P_TYP_##typ: handle_##typ(ctx, (void *)host_req); break
+ LM_PARTIAL_SWITCH (typ) {
+#if _LIB9P_ENABLE_stat
+ CASE(Tauth);
+ CASE(Tattach);
+ CASE(Tflush);
+ CASE(Twalk);
+ CASE(Topen);
+ CASE(Tcreate);
+ CASE(Tread);
+ CASE(Twrite);
+ CASE(Tclunk);
+ CASE(Tremove);
+ CASE(Tstat);
+ CASE(Twstat);
+#endif
#if CONFIG_9P_ENABLE_9P2000_p9p
- [LIB9P_TYP_Topenfd] = (tmessage_handler)handle_Topenfd,
+ CASE(Topenfd);
#endif
#if CONFIG_9P_ENABLE_9P2000_e
- [LIB9P_TYP_Tsession] = (tmessage_handler)handle_Tsession,
- [LIB9P_TYP_Tsread] = (tmessage_handler)handle_Tsread,
- [LIB9P_TYP_Tswrite] = (tmessage_handler)handle_Tswrite,
+ CASE(Tsession);
+ CASE(Tsread);
+ CASE(Tswrite);
#endif
-};
+#undef CASE
+ default:
+ assert_notreached("lib9p_Tmsg_validate() should have rejected unknown typ");
+ }
+ 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 handle_message(struct srv_req *ctx) {
- uint8_t *host_req = NULL;
- uint8_t host_resp[CONFIG_9P_SRV_MAX_HOSTMSG_SIZE];
+static void lib9p_srv_worker_Tversion(struct srv_req *ctx) {
+ [[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)
- goto write;
- host_req = calloc(1, host_size);
- assert(host_req);
+ /* 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. */
- tmessage_handlers[typ](ctx, (void *)host_req, (void *)host_resp);
-
- write:
- if (lib9p_ctx_has_error(&ctx->basectx))
- srv_respond_error(ctx);
- else {
- struct lib9p_Rmsg_send_buf net_resp;
- if (lib9p_Rmsg_marshal(&ctx->basectx,
- typ+1, host_resp,
- &net_resp))
- goto write;
- srv_msglog(ctx, typ+1, &host_resp);
- srv_write_Rmsg(ctx, &net_resp);
+ /* 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 (host_req)
- free(host_req);
+ 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 (!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);
+ err = srv_write_Rmsg(ctx, resp_typ, host_resp);
+ if (!ERROR_IS_NULL(err))
+ goto error;
+ }
+ ctx->responded = true;
+}
+#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, req, resp) do { \
- assert(ctx); \
- assert(req); \
- assert(resp); \
- resp->tag = req->tag; \
- } while (0)
+#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,
- struct lib9p_msg_Rversion *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Tversion *req) {
+ srv_handler_common(ctx, version, req);
- enum lib9p_version version = LIB9P_VER_unknown;
+ enum lib9p_version version = LIB9P_VER_uninitialized;
if (req->version.len >= 6 &&
req->version.utf8[0] == '9' &&
@@ -699,7 +786,9 @@ static void handle_Tversion(struct srv_req *ctx,
'0' <= req->version.utf8[4] && req->version.utf8[4] <= '9' &&
'0' <= req->version.utf8[5] && req->version.utf8[5] <= '9' &&
(req->version.len == 6 || req->version.utf8[6] == '.')) {
+#if CONFIG_9P_ENABLE_9P2000
version = LIB9P_VER_9P2000;
+#endif
#if CONFIG_9P_ENABLE_9P2000_p9p
struct lib9p_srv *srv = ctx->parent_sess->parent_conn->parent_srv;
if (srv->type_assert_unix && !LO_IS_NULL(srv->type_assert_unix(ctx->parent_sess->parent_conn->fd)))
@@ -715,20 +804,23 @@ static void handle_Tversion(struct srv_req *ctx,
#endif
}
- uint32_t min_msg_size = lib9p_version_min_msg_size(version);
+ /* XXX: There are good arguments that min_msg_size should be
+ * something larger than max(rerror.min_size(),
+ * rread.min_size()+1). */
+ 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_errorf(&ctx->basectx,
- LIB9P_ERRNO_L_EDOM, "requested max_msg_size is less than minimum for %s (%"PRIu32" < %"PRIu32")",
- lib9p_version_str(version), req->max_msg_size, min_msg_size);
- return;
+ 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");
+ resp.version = lib9p_str("9P2000");
#endif
- resp->max_msg_size = (CONFIG_9P_SRV_MAX_MSG_SIZE < req->max_msg_size)
+ resp.max_msg_size = (CONFIG_9P_SRV_MAX_MSG_SIZE < req->max_msg_size)
? CONFIG_9P_SRV_MAX_MSG_SIZE
: req->max_msg_size;
@@ -736,112 +828,110 @@ 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 *list = alloca(sizeof(struct cr_select_arg) * map_len(&ctx->parent_sess->reqs));
+ 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;
- bool flushed;
MAP_FOREACH(&ctx->parent_sess->reqs, tag, reqpp) {
- list[i] = CR_SELECT_RECV(&((*reqpp)->flushch), &flushed);
+ enum _lib9p_srv_flush_result flushed;
+ args[i++] = CR_SELECT_RECV(&((*reqpp)->flush_ch), &flushed);
}
assert(i == map_len(&ctx->parent_sess->reqs));
- cr_select_v(i, list);
+ cr_select_v(i, args);
}
+ free(args);
}
- if (map_len(&ctx->parent_sess->fids)) {
- /* Close all FIDs. */
- MAP_FOREACH(&ctx->parent_sess->fids, fid, fidinfo) {
- handle_Tclunk(ctx,
- &(struct lib9p_msg_Tclunk){.fid = fid},
- &(struct lib9p_msg_Rclunk){});
+ /* Close all FIDs. */
+ MAP_FOREACH(&ctx->parent_sess->fids, fid, fidinfo) {
+ error fiderr = srv_fid_del(ctx, fid, fidinfo, false);
+ if (!ERROR_IS_NULL(fiderr)) {
+ srv_nonrespond_error("clunk: ", (error, fiderr));
+ error_cleanup(&fiderr);
}
}
/* Replace the old session with the new session. */
ctx->parent_sess->version = version;
- ctx->parent_sess->max_msg_size = resp->max_msg_size;
+ ctx->parent_sess->max_msg_size = resp.max_msg_size;
+
+ tversion_return:
+ srv_respond(ctx, version, &resp, err);
}
+#if _LIB9P_ENABLE_stat
static void handle_Tauth(struct srv_req *ctx,
- struct lib9p_msg_Tauth *req,
- struct lib9p_msg_Rauth *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Tauth *req) {
+ srv_handler_common(ctx, auth, req);
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");
- return;
+ err = error_new(E_POSIX_EOPNOTSUPP, "authentication not required");
+ goto tauth_return;
}
- ctx->authinfo = srv_authinfo_new(req->uname, req->n_uid);
+ ctx->user = srv_userid_new(req->uname, req->unum);
- srv->auth(ctx, req->aname);
+ err = srv->auth(ctx, req->aname);
+ if (!ERROR_IS_NULL(err))
+ goto tauth_return;
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EOPNOTSUPP, "TODO: auth not implemented");
+ err = error_new(E_POSIX_EOPNOTSUPP, "TODO: auth not implemented");
- if (lib9p_ctx_has_error(&ctx->basectx))
- ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
+ tauth_return:
+ 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,
- struct lib9p_msg_Tattach *req,
- struct lib9p_msg_Rattach *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Tattach *req) {
+ srv_handler_common(ctx, attach, req);
if (req->fid == LIB9P_FID_NOFID) {
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EBADF, "cannot assign to NOFID");
- return;
+ err = error_new(E_POSIX_EBADF, "cannot assign to NOFID");
+ goto tattach_return;
}
struct lib9p_srv *srv = ctx->parent_sess->parent_conn->parent_srv;
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");
- else if (!lib9p_str_eq(afid->authinfo->uname, req->uname))
- lib9p_errorf(&ctx->basectx,
- LIB9P_ERRNO_L_EACCES, "FID provided as auth-file is for user=\"%.*s\" and cannot be used for user=\"%.*s\"",
- afid->authinfo->uname.len, afid->authinfo->uname.utf8,
- req->uname.len, req->uname.utf8);
-#if CONFIG_9P_ENABLE_9P2000_u
- else if (afid->authinfo->uid != req->n_uid)
- lib9p_errorf(&ctx->basectx,
- LIB9P_ERRNO_L_EACCES, "FID provided as auth-file is for user=%"PRIu32" and cannot be used for user=%"PRIu32,
- afid->authinfo->uid, req->n_uid);
+ 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))
+ 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)
+ 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_errorf(&ctx->basectx,
- LIB9P_ERRNO_L_EACCES, "FID provided as auth-file is for tree=\"%.*s\" and cannot be used for tree=\"%.*s\"",
- afid->auth.aname.len, afid->auth.aname.utf8,
- req->aname.len, req->aname.utf8);
+ 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))
- return;
- ctx->authinfo = srv_authinfo_incref(afid->authinfo);
+ 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");
- return;
+ err = error_new(E_POSIX_EACCES, "FID provided as auth-file, but no auth-file is required");
+ goto tattach_return;
}
- ctx->authinfo = srv_authinfo_new(req->uname, req->n_uid);
+ 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)) {
- ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
- return;
+ 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);
@@ -850,134 +940,151 @@ 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);
- ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
- return;
+ goto tattach_return;
}
- ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
- resp->qid = root_qid;
- return;
+ resp.qid = root_qid;
+ tattach_return:
+ if (ctx->user)
+ ctx->user = srv_userid_decref(ctx->user);
+ srv_respond(ctx, attach, &resp, err);
}
static void handle_Tflush(struct srv_req *ctx,
- struct lib9p_msg_Tflush *req,
- struct lib9p_msg_Rflush *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Tflush *req) {
+ srv_handler_common(ctx, flush, req);
struct srv_req **oldreqp = map_load(&ctx->parent_sess->reqs, req->oldtag);
- if (oldreqp)
- _lib9p_srv_flushch_recv(&((*oldreqp)->flushch));
+ if (oldreqp) {
+ struct srv_req *oldreq = *oldreqp;
+ enum _lib9p_srv_flush_result res = _LIB9P_SRV_FLUSH_RFLUSH;
+ switch (cr_select_l(CR_SELECT_RECV(&oldreq->flush_ch, &res),
+ CR_SELECT_SEND(&ctx->flush_ch, &res))) {
+ case 0: /* original request returned */
+ req_debug("original request (tag=", req->oldtag, ") returned");
+ if (res == _LIB9P_SRV_FLUSH_SILENT) {
+ ctx->responded = true;
+ return;
+ }
+ break;
+ case 1: /* flush itself got flushed */
+ ctx->responded = true;
+ return;
+ }
+ }
+ srv_respond(ctx, flush, &resp, err);
}
static void handle_Twalk(struct srv_req *ctx,
- struct lib9p_msg_Twalk *req,
- struct lib9p_msg_Rwalk *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Twalk *req) {
+ srv_handler_common(ctx, walk, req);
if (req->newfid == LIB9P_FID_NOFID) {
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EBADF, "cannot assign to NOFID");
- return;
+ 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_errorf(&ctx->basectx,
- LIB9P_ERRNO_L_EBADF, "bad file number %"PRIu32, req->fid);
- return;
+ 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");
- return;
+ err = error_new(E_POSIX_EALREADY, "cannot walk on FID open for I/O");
+ goto twalk_return;
}
- ctx->authinfo = srv_authinfo_incref(fidinfo->authinfo);
+ ctx->user = srv_userid_incref(fidinfo->user);
struct srv_pathinfo *pathinfo = map_load(&ctx->parent_sess->paths, fidinfo->path);
assert(pathinfo);
pathinfo->gc_refcount++;
- resp->wqid = (struct lib9p_qid *)(&resp[1]);
- for (resp->nwqid = 0; resp->nwqid < req->nwname; resp->nwqid++) {
+ 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;
}
struct srv_pathinfo *new_pathinfo;
- if (lib9p_str_eq(req->wname[resp->nwqid], lib9p_str(".."))) {
+ if (lib9p_str_eq(req->wname[resp.nwqid], lib9p_str(".."))) {
new_pathinfo = map_load(&ctx->parent_sess->paths, pathinfo->parent_dir);
assert(new_pathinfo);
new_pathinfo->gc_refcount++;
} else {
- 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_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_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;
}
}
- resp->wqid[resp->nwqid] = LO_CALL(new_pathinfo->file, qid);
+ resp.wqid[resp.nwqid] = LO_CALL(new_pathinfo->file, qid);
srv_path_decref(ctx, LO_CALL(pathinfo->file, qid).path);
pathinfo = new_pathinfo;
}
- if (resp->nwqid == req->nwname) {
- if (!srv_fid_store(ctx, req->newfid, pathinfo, req->newfid == req->fid))
+ if (resp.nwqid == req->nwname) {
+ 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);
+ if (resp.nwqid > 0)
+ error_cleanup(&err);
}
- ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
+ twalk_return:
+ if (ctx->user)
+ ctx->user = srv_userid_decref(ctx->user);
+ srv_respond(ctx, walk, &resp, err);
+ if (resp.wqid)
+ free(resp.wqid);
}
static void handle_Topen(struct srv_req *ctx,
- struct lib9p_msg_Topen *req,
- struct lib9p_msg_Ropen *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Topen *req) {
+ srv_handler_common(ctx, open, req);
/* Check that the FID is valid for this. */
struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid);
if (!fidinfo) {
- lib9p_errorf(&ctx->basectx,
- LIB9P_ERRNO_L_EBADF, "bad file number %"PRIu32, req->fid);
- return;
+ 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");
- return;
+ 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");
- return;
+ err = error_new(E_POSIX_EISDIR, "directories cannot be written, executed, truncated, or removed-on-close");
+ goto topen_return;
}
}
- ctx->authinfo = srv_authinfo_incref(fidinfo->authinfo);
+ ctx->user = srv_userid_incref(fidinfo->user);
/* Variables. */
lib9p_o_t reqmode = req->mode;
@@ -989,28 +1096,29 @@ 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_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_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_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_stat_assert(stat);
- if ((stat.file_mode & LIB9P_DM_EXCL) && pathinfo->io_refcount) {
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EEXIST, "exclusive file is already opened");
+ lib9p_srv_stat_assert(&stat);
+ if ((stat.mode & LIB9P_DM_EXCL) && pathinfo->io_refcount) {
+ err = error_new(E_POSIX_EEXIST, "exclusive file is already opened");
goto topen_return;
}
- if (stat.file_mode & LIB9P_DM_APPEND)
+ if (stat.mode & LIB9P_DM_APPEND) {
+ fidflags |= FIDFLAG_APPEND;
reqmode = reqmode & ~LIB9P_O_TRUNC;
+ }
uint8_t perm_bits = 0;
bool rd = false, wr = false;
switch (reqmode & LIB9P_O_MODE_MASK) {
@@ -1031,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;
}
@@ -1042,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:
@@ -1076,216 +1189,413 @@ static void handle_Topen(struct srv_req *ctx,
fidflags |= FIDFLAG_OPEN_W;
pathinfo->io_refcount++;
fidinfo->flags = fidflags;
- resp->qid = qid;
- resp->iounit = iounit;
+ resp.qid = qid;
+ resp.iounit = iounit;
topen_return:
- ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
+ if (ctx->user)
+ ctx->user = srv_userid_decref(ctx->user);
+ srv_respond(ctx, open, &resp, err);
}
static void handle_Tcreate(struct srv_req *ctx,
- struct lib9p_msg_Tcreate *req,
- struct lib9p_msg_Rcreate *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Tcreate *req) {
+ srv_handler_common(ctx, create, req);
+
+ err = error_new(E_POSIX_EOPNOTSUPP, "create not (yet?) implemented");
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EOPNOTSUPP, "create not (yet?) implemented");
+ srv_respond(ctx, create, &resp, err);
+}
+
+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,
+#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,
- struct lib9p_msg_Rread *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Tread *req) {
+ 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_errorf(&ctx->basectx,
- LIB9P_ERRNO_L_EBADF, "bad file number %"PRIu32, req->fid);
+ 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");
+ srv_respond(ctx, read, NULL, error_new(E_POSIX_EINVAL, "FID not open for reading"));
return;
}
/* Do it. */
- ctx->authinfo = srv_authinfo_incref(fidinfo->authinfo);
+ ctx->user = srv_userid_incref(fidinfo->user);
switch (fidinfo->type) {
case SRV_FILETYPE_DIR:
- /* Translate byte-offset to object-index. */
- size_t idx;
- if (req->offset == 0)
- idx = 0;
- else if (req->offset == fidinfo->dir.off)
- idx = fidinfo->dir.idx;
- else {
- lib9p_errorf(&ctx->basectx,
- LIB9P_ERRNO_L_EINVAL, "invalid offset (must be 0 or %"PRIu64"): %"PRIu64,
- fidinfo->dir.off, req->offset);
- ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
- return;
- }
- /* Do it. */
- resp->data = (char *)(&resp[1]);
- size_t num = LO_CALL(fidinfo->dir.io, dread, ctx, (uint8_t *)resp->data, req->count, idx);
- /* Translate object-count back to byte-count. */
- uint32_t len = 0;
- for (size_t i = 0; i < num; i++) {
- uint32_t i_len;
- lib9p_stat_validate(&ctx->basectx, req->count, &((uint8_t *)resp->data)[len], &i_len, NULL);
- len += i_len;
- }
- resp->count = len;
- /* Remember. */
- fidinfo->dir.idx = idx+num;
- fidinfo->dir.off = req->offset + len;
+#if _LIB9P_ENABLE_stat
+ 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:
- struct iovec iov;
- LO_CALL(fidinfo->file.io, pread, ctx, req->count, req->offset, &iov);
- if (!lib9p_ctx_has_error(&ctx->basectx)) {
- resp->count = iov.iov_len;
- resp->data = iov.iov_base;
- if (resp->count > req->count)
- resp->count = req->count;
- }
+ handle_read_file(ctx, fidinfo, req->offset, req->count);
break;
case SRV_FILETYPE_AUTH:
assert_notreached("TODO: auth not yet implemented");
break;
}
- ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
+ 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;
+ }
+ 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_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);
+ 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;
+ }
+ }
+
+ /* 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;
+ }
+ 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;
+ }
+ srv_respond(ctx, read, NULL,
+ error_new(E_POSIX_ERANGE, "stat object does not fit into negotiated max message size"));
+ return;
+ }
+ resp.count += nbytes;
+ fidinfo->dir.idx++;
+ fidinfo->dir.off += nbytes;
+ fidinfo->dir.buffered_dirent = (struct lib9p_srv_dirent){};
+ }
+ srv_respond(ctx, read, &resp, ERROR_NULL);
+}
+#endif
+
static void handle_Twrite(struct srv_req *ctx,
- struct lib9p_msg_Twrite *req,
- struct lib9p_msg_Rwrite *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Twrite *req) {
+ srv_handler_common(ctx, write, req);
/* TODO: serialize simultaneous writes to the same FID */
/* Check that the FID is valid for this. */
struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid);
if (!fidinfo) {
- lib9p_errorf(&ctx->basectx,
- LIB9P_ERRNO_L_EBADF, "bad file number %"PRIu32, req->fid);
- return;
+ 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");
- return;
+ err = error_new(E_POSIX_EINVAL, "FID not open for writing");
+ goto twrite_return;
}
+ if (fidinfo->flags & FIDFLAG_APPEND)
+ req->offset = 0;
/* Do it. */
- ctx->authinfo = srv_authinfo_incref(fidinfo->authinfo);
- resp->count = LO_CALL(fidinfo->file.io, pwrite, ctx, req->data, req->count, req->offset);
- ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
+ ctx->user = srv_userid_incref(fidinfo->user);
+ 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, err);
}
static void handle_Tclunk(struct srv_req *ctx,
- struct lib9p_msg_Tclunk *req,
- struct lib9p_msg_Rclunk *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Tclunk *req) {
+ srv_handler_common_no_err(ctx, clunk, req);
struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid);
if (!fidinfo) {
- lib9p_errorf(&ctx->basectx,
- LIB9P_ERRNO_L_EBADF, "bad file number %"PRIu32, req->fid);
+ srv_respond(ctx, clunk, NULL, error_new(E_POSIX_EBADF, "bad file number ", req->fid));
return;
}
- ctx->authinfo = srv_authinfo_incref(fidinfo->authinfo);
- srv_fid_del(ctx, req->fid, false);
- ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
+ 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);
}
static void handle_Tremove(struct srv_req *ctx,
- struct lib9p_msg_Tremove *req,
- struct lib9p_msg_Rremove *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Tremove *req) {
+ srv_handler_common(ctx, remove, req);
struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid);
if (!fidinfo) {
- lib9p_errorf(&ctx->basectx,
- LIB9P_ERRNO_L_EBADF, "bad file number %"PRIu32, req->fid);
- return;
+ err = error_new(E_POSIX_EBADF, "bad file number ", req->fid);
+ goto tremove_return;
+ }
+
+ bool remove = true;
+ struct srv_pathinfo *pathinfo = map_load(&ctx->parent_sess->paths, fidinfo->path);
+ assert(pathinfo);
+ if (pathinfo->parent_dir == fidinfo->path) {
+ 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);
+ 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;
}
- ctx->authinfo = srv_authinfo_incref(fidinfo->authinfo);
- srv_fid_del(ctx, req->fid, true);
- ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
+ tremove_main:
+ srv_fid_del(ctx, req->fid, fidinfo, remove);
+ tremove_return:
+ srv_respond(ctx, remove, &resp, err);
}
static void handle_Tstat(struct srv_req *ctx,
- struct lib9p_msg_Tstat *req,
- struct lib9p_msg_Rstat *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Tstat *req) {
+ srv_handler_common(ctx, stat, req);
struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid);
if (!fidinfo) {
- lib9p_errorf(&ctx->basectx,
- LIB9P_ERRNO_L_EBADF, "bad file number %"PRIu32, req->fid);
- return;
+ 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->authinfo = srv_authinfo_incref(fidinfo->authinfo);
- resp->stat = LO_CALL(pathinfo->file, stat, ctx);
- if (!lib9p_ctx_has_error(&ctx->basectx))
- lib9p_stat_assert(resp->stat);
- ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
+ ctx->user = srv_userid_incref(fidinfo->user);
+ 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, err);
}
static void handle_Twstat(struct srv_req *ctx,
- struct lib9p_msg_Twstat *req,
- struct lib9p_msg_Rwstat *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Twstat *req) {
+ srv_handler_common(ctx, wstat, req);
+
+ err = error_new(E_POSIX_EOPNOTSUPP, "wstat not (yet?) implemented");
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EOPNOTSUPP, "wstat not (yet?) implemented");
+ srv_respond(ctx, wstat, &resp, err);
}
+#endif
#if CONFIG_9P_ENABLE_9P2000_p9p
static void handle_Topenfd(struct srv_req *ctx,
- struct lib9p_msg_Topenfd *req,
- struct lib9p_msg_Ropenfd *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Topenfd *req) {
+ srv_handler_common(ctx, openfd, req);
+
+ err = error_new(E_POSIX_EOPNOTSUPP, "openfd not (yet?) implemented");
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EOPNOTSUPP, "openfd not (yet?) implemented");
+ srv_respond(ctx, openfd, &resp, err);
}
#endif
#if CONFIG_9P_ENABLE_9P2000_e
static void handle_Tsession(struct srv_req *ctx,
- struct lib9p_msg_Tsession *req,
- struct lib9p_msg_Rsession *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Tsession *req) {
+ srv_handler_common(ctx, session, req);
+
+ err = error_new(E_POSIX_EOPNOTSUPP, "session not (yet?) implemented");
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EOPNOTSUPP, "session not (yet?) implemented");
+ srv_respond(ctx, session, &resp, err);
}
static void handle_Tsread(struct srv_req *ctx,
- struct lib9p_msg_Tsread *req,
- struct lib9p_msg_Rsread *resp) {
- srv_handler_common(ctx, req, resp);
+ 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, err);
}
static void handle_Tswrite(struct srv_req *ctx,
- struct lib9p_msg_Tswrite *req,
- struct lib9p_msg_Rswrite *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Tswrite *req) {
+ srv_handler_common(ctx, swrite, req);
+
+ err = error_new(E_POSIX_EOPNOTSUPP, "swrite not (yet?) implemented");
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EOPNOTSUPP, "swrite not (yet?) implemented");
+ 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 db5be41..cea1d79 100644
--- a/lib9p/srv_include/lib9p/srv.h
+++ b/lib9p/srv_include/lib9p/srv.h
@@ -7,57 +7,156 @@
#ifndef _LIB9P_SRV_H_
#define _LIB9P_SRV_H_
-#include <libcr/coroutine.h>
-#include <libcr_ipc/rpc.h>
#include <libcr_ipc/chan.h>
+#include <libcr_ipc/rpc.h>
#include <libhw/generic/net.h>
#include <libmisc/assert.h>
+#include <libmisc/obj.h>
#include <libmisc/private.h>
-#include <libobj/obj.h>
#include <lib9p/core.h>
-/* context ********************************************************************/
+#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);
-CR_CHAN_DECLARE(_lib9p_srv_flushch, bool);
+/* context ********************************************************************/
-struct lib9p_srv_authinfo {
- lib9p_nuid_t uid;
- struct lib9p_s uname;
+struct lib9p_srv_userid {
+ struct lib9p_s name;
+#if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L
+ lib9p_nuid_t num;
+#endif
BEGIN_PRIVATE(LIB9P_SRV_H);
unsigned int refcount;
END_PRIVATE(LIB9P_SRV_H);
};
+enum _lib9p_srv_flush_result {
+ _LIB9P_SRV_FLUSH_RFLUSH,
+ _LIB9P_SRV_FLUSH_SILENT,
+};
+
+CR_CHAN_DECLARE(_lib9p_srv_flush_ch, enum _lib9p_srv_flush_result);
+
struct lib9p_srv_ctx {
struct lib9p_ctx basectx;
- struct lib9p_srv_authinfo *authinfo;
+ struct lib9p_srv_userid *user;
BEGIN_PRIVATE(LIB9P_SRV_H);
- struct _lib9p_srv_sess *parent_sess;
- lib9p_tag_t tag;
- uint8_t *net_bytes;
- _lib9p_srv_flushch_t flushch;
+ struct _lib9p_srv_sess *parent_sess;
+ lib9p_tag_t tag;
+ uint8_t *net_bytes;
+ _lib9p_srv_flush_ch_t flush_ch; /* flushers for this req _read_ from here */
+ bool responded;
END_PRIVATE(LIB9P_SRV_H);
};
+/**
+ * Return whether there is an outstanding Tflush or Tversion
+ * cancellation of this request. After becoming true, this may go
+ * back to false if the Tflush itself is flushed.
+ *
+ * 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);
-void lib9p_srv_acknowledge_flush(struct lib9p_srv_ctx *ctx);
+/* version-independent stat ***************************************************/
+
+struct lib9p_srv_stat {
+ struct lib9p_qid qid;
+ lib9p_dm_t mode;
+ uint32_t atime_sec; /* BUG: u32 seconds means a 2106 problem */
+#if CONFIG_9P_ENABLE_9P2000_L
+ uint32_t atime_nsec;
+#endif
+ uint32_t mtime_sec; /* BUG: u32 seconds means a 2106 problem */
+#if CONFIG_9P_ENABLE_9P2000_L
+ uint32_t mtime_nsec;
+ uint32_t ctime_sec; /* BUG: u32 seconds means a 2106 problem */
+ uint32_t ctime_nsec;
+ uint32_t btime_sec; /* BUG: u32 seconds means a 2106 problem */
+ uint32_t btime_nsec;
+#endif
+ uint64_t size;
+ struct lib9p_s name;
+ struct lib9p_srv_userid owner_uid;
+ struct lib9p_srv_userid owner_gid;
+ struct lib9p_srv_userid last_modifier_uid;
+#if CONFIG_9P_ENABLE_9P2000_u
+ struct lib9p_s extension;
+#endif
+};
+
+#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 ******************************************************/
-lo_interface lib9p_srv_fio;
-lo_interface lib9p_srv_dio;
+struct lib9p_srv_dirent {
+ struct lib9p_qid qid;
+ struct lib9p_s name;
+};
+DECLARE_ERROR_OR_(struct lib9p_srv_dirent, lib9p_srv_dirent);
-/* FIXME: I don't like that the pointers returned by stat() and
- * pread() have to remain live after they return. Perhaps a
- * `respond()`-callback? But that just reads as gross in C.
- *
- * FIXME: It would be nice if pread() could return more than 1 iovec.
+/* 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_file_LO_IFACE \
+#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 **********************************************/ \
\
/** \
@@ -81,65 +180,41 @@ lo_interface lib9p_srv_dio;
\
/* non-"opened" generic I/O *****************************************/ \
\
- LO_FUNC(struct lib9p_stat , stat , struct lib9p_srv_ctx *) \
- LO_FUNC(void , wstat , struct lib9p_srv_ctx *, \
- struct lib9p_stat new) \
- LO_FUNC(void , remove , struct lib9p_srv_ctx *) \
+ /** Strings returned from stat() must remain valid until free(). */ \
+ 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(error , remove , struct lib9p_srv_ctx *) \
\
/* non-"opened" directory I/O ***************************************/ \
\
- LO_FUNC(lo_interface lib9p_srv_file, dwalk , struct lib9p_srv_ctx *, \
- struct lib9p_s childname) \
- LO_FUNC(lo_interface lib9p_srv_file, dcreate, struct lib9p_srv_ctx *, \
- struct lib9p_s childname, \
- lib9p_dm_t perm, \
- lib9p_o_t flags) \
+ LO_FUNC(lib9p_srv_file_or_error , dwalk , struct lib9p_srv_ctx *, \
+ struct lib9p_s childname) \
+ 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, \
+ lib9p_dm_t perm) \
\
/* open() for I/O ***************************************************/ \
\
- LO_FUNC(lo_interface lib9p_srv_fio , fopen , struct lib9p_srv_ctx *, \
- bool rd, bool wr, \
- bool trunc) \
- LO_FUNC(lo_interface lib9p_srv_dio , dopen , struct lib9p_srv_ctx *)
-LO_INTERFACE(lib9p_srv_file);
-
-#define lib9p_srv_fio_LO_IFACE \
- LO_FUNC(struct lib9p_qid , qid ) \
- LO_FUNC(void , iofree ) \
- LO_FUNC(uint32_t , iounit ) \
- LO_FUNC(void , pread , struct lib9p_srv_ctx *, \
- uint32_t byte_count, \
- uint64_t byte_offset, \
- struct iovec *ret) \
- LO_FUNC(uint32_t , pwrite , struct lib9p_srv_ctx *, \
- void *buf, \
- uint32_t byte_count, \
- uint64_t byte_offset)
-LO_INTERFACE(lib9p_srv_fio);
-
-/* FIXME: The dio interface just feels clunky. I'm not in a rush to
- * change it because util9p_static_dir is already implemented and I
- * don't anticipate the sbc-harness needing another dio
- * implementation. But if I wanted lib9p to be used outside of
- * sbc-harness, this is one of the first things that I'd want to
- * change.
- */
-#define lib9p_srv_dio_LO_IFACE \
- LO_FUNC(struct lib9p_qid , qid ) \
- LO_FUNC(void , iofree ) \
- LO_FUNC(size_t /* <- obj cnt */ , dread , struct lib9p_srv_ctx *, \
- uint8_t *buf, \
- /* num bytes -> */ uint32_t byte_count, \
- /* starting at this object -> */ size_t obj_offset)
-LO_INTERFACE(lib9p_srv_dio);
+ LO_FUNC(lib9p_srv_fio_or_error , fopen , struct lib9p_srv_ctx *, \
+ bool rd, bool wr, \
+ bool trunc) \
+ LO_FUNC(lib9p_srv_dio_or_error , dopen , struct lib9p_srv_ctx *)
+LO_INTERFACE(lib9p_srv_file); /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-#define LIB9P_SRV_NOTDIR(TYP, NAM) \
- static lo_interface lib9p_srv_file NAM##_dwalk (TYP *, struct lib9p_srv_ctx *, struct lib9p_s) { assert_notreached("not a directory"); } \
- static lo_interface lib9p_srv_file NAM##_dcreate(TYP *, struct lib9p_srv_ctx *, struct lib9p_s, lib9p_dm_t, lib9p_o_t) { assert_notreached("not a directory"); } \
- static lo_interface lib9p_srv_dio NAM##_dopen (TYP *, struct lib9p_srv_ctx *) { assert_notreached("not a directory"); }
+#define LIB9P_SRV_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 ****************************************************/
@@ -155,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
@@ -166,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);
};
@@ -203,24 +278,36 @@ 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 L_ERANGE R-message does not fit into max_msg_size
+ * @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);
-
-
/**
- * In a loop, service requests to the `struct lib9p_srv *srv` argument
- * that have been read by lib9p_srv_accept_and_read_loop() /
- * lib9p_srv_read(). A "NULL" request causes the function to return.
+ * In a loop, call lib9p_srv_worker() to service requests to the
+ * `struct lib9p_srv *srv` argument that have been read by
+ * lib9p_srv_accept_and_read_loop() / lib9p_srv_read(). A "NULL"
+ * request causes the function to return.
*
* @param srv: The server configuration and state; has an associated
* pool of lib9p_srv_accept_and_read_loop() coroutines.
*/
void lib9p_srv_worker_loop(struct lib9p_srv *srv);
+/**
+ * You should probably not call this directly; you should probably use
+ * lib9p_srv_worker_loop().
+ *
+ * Handle and send a response to a single request.
+ *
+ * @param req: The request to handle.
+ *
+ * Errors that this function itself may send to clients:
+ *
+ * @errno E_POSIX_ERANGE R-message does not fit into max_msg_size
+ */
+void lib9p_srv_worker(struct lib9p_srv_ctx *req);
+
#endif /* _LIB9P_SRV_H_ */
diff --git a/lib9p/tests/client_config/config.h b/lib9p/tests/client_config/config.h
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 4532655..6d7fb50 100644
--- a/lib9p/tests/test_compile.c
+++ b/lib9p/tests/test_compile.c
@@ -2,429 +2,1254 @@
#include <lib9p/core.h>
int main(void) {
- [[gnu::unused]] uint64_t x;
- x = LIB9P_TAG_NOTAG;
- x = LIB9P_FID_NOFID;
- x = LIB9P_DM_DIR;
- x = LIB9P_DM_APPEND;
- x = LIB9P_DM_EXCL;
- x = _LIB9P_DM_PLAN9_MOUNT;
- x = LIB9P_DM_AUTH;
- x = LIB9P_DM_TMP;
- x = _LIB9P_DM_UNUSED_25;
- x = _LIB9P_DM_UNUSED_24;
- x = LIB9P_DM_DEVICE;
- x = _LIB9P_DM_UNUSED_22;
- x = LIB9P_DM_PIPE;
- x = LIB9P_DM_SOCKET;
- x = LIB9P_DM_SETUID;
- x = LIB9P_DM_SETGID;
- x = _LIB9P_DM_UNUSED_17;
- x = _LIB9P_DM_UNUSED_16;
- x = _LIB9P_DM_UNUSED_15;
- x = _LIB9P_DM_UNUSED_14;
- x = _LIB9P_DM_UNUSED_13;
- x = _LIB9P_DM_UNUSED_12;
- x = _LIB9P_DM_UNUSED_11;
- x = _LIB9P_DM_UNUSED_10;
- x = _LIB9P_DM_UNUSED_9;
- x = LIB9P_DM_OWNER_R;
- x = LIB9P_DM_OWNER_W;
- x = LIB9P_DM_OWNER_X;
- x = LIB9P_DM_GROUP_R;
- x = LIB9P_DM_GROUP_W;
- x = LIB9P_DM_GROUP_X;
- x = LIB9P_DM_OTHER_R;
- x = LIB9P_DM_OTHER_W;
- x = LIB9P_DM_OTHER_X;
- x = LIB9P_DM_PERM_MASK;
- x = LIB9P_QT_DIR;
- x = LIB9P_QT_APPEND;
- x = LIB9P_QT_EXCL;
- x = _LIB9P_QT_PLAN9_MOUNT;
- x = LIB9P_QT_AUTH;
- x = LIB9P_QT_TMP;
- x = LIB9P_QT_SYMLINK;
- x = _LIB9P_QT_UNUSED_0;
- x = LIB9P_QT_FILE;
- x = _LIB9P_O_UNUSED_7;
- x = LIB9P_O_RCLOSE;
- x = _LIB9P_O_RESERVED_CEXEC;
- x = LIB9P_O_TRUNC;
- x = _LIB9P_O_UNUSED_3;
- x = _LIB9P_O_UNUSED_2;
- x = LIB9P_O_FLAG_MASK;
- x = LIB9P_O_MODE_READ;
- x = LIB9P_O_MODE_WRITE;
- x = LIB9P_O_MODE_RDWR;
- x = LIB9P_O_MODE_EXEC;
- x = LIB9P_O_MODE_MASK;
- x = LIB9P_NUID_NONUID;
- x = LIB9P_ERRNO_NOERROR;
- x = LIB9P_ERRNO_L_EPERM;
- x = LIB9P_ERRNO_L_ENOENT;
- x = LIB9P_ERRNO_L_ESRCH;
- x = LIB9P_ERRNO_L_EINTR;
- x = LIB9P_ERRNO_L_EIO;
- x = LIB9P_ERRNO_L_ENXIO;
- x = LIB9P_ERRNO_L_E2BIG;
- x = LIB9P_ERRNO_L_ENOEXEC;
- x = LIB9P_ERRNO_L_EBADF;
- x = LIB9P_ERRNO_L_ECHILD;
- x = LIB9P_ERRNO_L_EAGAIN;
- x = LIB9P_ERRNO_L_ENOMEM;
- x = LIB9P_ERRNO_L_EACCES;
- x = LIB9P_ERRNO_L_EFAULT;
- x = LIB9P_ERRNO_L_ENOTBLK;
- x = LIB9P_ERRNO_L_EBUSY;
- x = LIB9P_ERRNO_L_EEXIST;
- x = LIB9P_ERRNO_L_EXDEV;
- x = LIB9P_ERRNO_L_ENODEV;
- x = LIB9P_ERRNO_L_ENOTDIR;
- x = LIB9P_ERRNO_L_EISDIR;
- x = LIB9P_ERRNO_L_EINVAL;
- x = LIB9P_ERRNO_L_ENFILE;
- x = LIB9P_ERRNO_L_EMFILE;
- x = LIB9P_ERRNO_L_ENOTTY;
- x = LIB9P_ERRNO_L_ETXTBSY;
- x = LIB9P_ERRNO_L_EFBIG;
- x = LIB9P_ERRNO_L_ENOSPC;
- x = LIB9P_ERRNO_L_ESPIPE;
- x = LIB9P_ERRNO_L_EROFS;
- x = LIB9P_ERRNO_L_EMLINK;
- x = LIB9P_ERRNO_L_EPIPE;
- x = LIB9P_ERRNO_L_EDOM;
- x = LIB9P_ERRNO_L_ERANGE;
- x = LIB9P_ERRNO_L_EDEADLK;
- x = LIB9P_ERRNO_L_ENAMETOOLONG;
- x = LIB9P_ERRNO_L_ENOLCK;
- x = LIB9P_ERRNO_L_ENOSYS;
- x = LIB9P_ERRNO_L_ENOTEMPTY;
- x = LIB9P_ERRNO_L_ELOOP;
- x = LIB9P_ERRNO_L_ENOMSG;
- x = LIB9P_ERRNO_L_EIDRM;
- x = LIB9P_ERRNO_L_ECHRNG;
- x = LIB9P_ERRNO_L_EL2NSYNC;
- x = LIB9P_ERRNO_L_EL3HLT;
- x = LIB9P_ERRNO_L_EL3RST;
- x = LIB9P_ERRNO_L_ELNRNG;
- x = LIB9P_ERRNO_L_EUNATCH;
- x = LIB9P_ERRNO_L_ENOCSI;
- x = LIB9P_ERRNO_L_EL2HLT;
- x = LIB9P_ERRNO_L_EBADE;
- x = LIB9P_ERRNO_L_EBADR;
- x = LIB9P_ERRNO_L_EXFULL;
- x = LIB9P_ERRNO_L_ENOANO;
- x = LIB9P_ERRNO_L_EBADRQC;
- x = LIB9P_ERRNO_L_EBADSLT;
- x = LIB9P_ERRNO_L_EBFONT;
- x = LIB9P_ERRNO_L_ENOSTR;
- x = LIB9P_ERRNO_L_ENODATA;
- x = LIB9P_ERRNO_L_ETIME;
- x = LIB9P_ERRNO_L_ENOSR;
- x = LIB9P_ERRNO_L_ENONET;
- x = LIB9P_ERRNO_L_ENOPKG;
- x = LIB9P_ERRNO_L_EREMOTE;
- x = LIB9P_ERRNO_L_ENOLINK;
- x = LIB9P_ERRNO_L_EADV;
- x = LIB9P_ERRNO_L_ESRMNT;
- x = LIB9P_ERRNO_L_ECOMM;
- x = LIB9P_ERRNO_L_EPROTO;
- x = LIB9P_ERRNO_L_EMULTIHOP;
- x = LIB9P_ERRNO_L_EDOTDOT;
- x = LIB9P_ERRNO_L_EBADMSG;
- x = LIB9P_ERRNO_L_EOVERFLOW;
- x = LIB9P_ERRNO_L_ENOTUNIQ;
- x = LIB9P_ERRNO_L_EBADFD;
- x = LIB9P_ERRNO_L_EREMCHG;
- x = LIB9P_ERRNO_L_ELIBACC;
- x = LIB9P_ERRNO_L_ELIBBAD;
- x = LIB9P_ERRNO_L_ELIBSCN;
- x = LIB9P_ERRNO_L_ELIBMAX;
- x = LIB9P_ERRNO_L_ELIBEXEC;
- x = LIB9P_ERRNO_L_EILSEQ;
- x = LIB9P_ERRNO_L_ERESTART;
- x = LIB9P_ERRNO_L_ESTRPIPE;
- x = LIB9P_ERRNO_L_EUSERS;
- x = LIB9P_ERRNO_L_ENOTSOCK;
- x = LIB9P_ERRNO_L_EDESTADDRREQ;
- x = LIB9P_ERRNO_L_EMSGSIZE;
- x = LIB9P_ERRNO_L_EPROTOTYPE;
- x = LIB9P_ERRNO_L_ENOPROTOOPT;
- x = LIB9P_ERRNO_L_EPROTONOSUPPORT;
- x = LIB9P_ERRNO_L_ESOCKTNOSUPPORT;
- x = LIB9P_ERRNO_L_EOPNOTSUPP;
- x = LIB9P_ERRNO_L_EPFNOSUPPORT;
- x = LIB9P_ERRNO_L_EAFNOSUPPORT;
- x = LIB9P_ERRNO_L_EADDRINUSE;
- x = LIB9P_ERRNO_L_EADDRNOTAVAIL;
- x = LIB9P_ERRNO_L_ENETDOWN;
- x = LIB9P_ERRNO_L_ENETUNREACH;
- x = LIB9P_ERRNO_L_ENETRESET;
- x = LIB9P_ERRNO_L_ECONNABORTED;
- x = LIB9P_ERRNO_L_ECONNRESET;
- x = LIB9P_ERRNO_L_ENOBUFS;
- x = LIB9P_ERRNO_L_EISCONN;
- x = LIB9P_ERRNO_L_ENOTCONN;
- x = LIB9P_ERRNO_L_ESHUTDOWN;
- x = LIB9P_ERRNO_L_ETOOMANYREFS;
- x = LIB9P_ERRNO_L_ETIMEDOUT;
- x = LIB9P_ERRNO_L_ECONNREFUSED;
- x = LIB9P_ERRNO_L_EHOSTDOWN;
- x = LIB9P_ERRNO_L_EHOSTUNREACH;
- x = LIB9P_ERRNO_L_EALREADY;
- x = LIB9P_ERRNO_L_EINPROGRESS;
- x = LIB9P_ERRNO_L_ESTALE;
- x = LIB9P_ERRNO_L_EUCLEAN;
- x = LIB9P_ERRNO_L_ENOTNAM;
- x = LIB9P_ERRNO_L_ENAVAIL;
- x = LIB9P_ERRNO_L_EISNAM;
- x = LIB9P_ERRNO_L_EREMOTEIO;
- x = LIB9P_ERRNO_L_EDQUOT;
- x = LIB9P_ERRNO_L_ENOMEDIUM;
- x = LIB9P_ERRNO_L_EMEDIUMTYPE;
- x = LIB9P_ERRNO_L_ECANCELED;
- x = LIB9P_ERRNO_L_ENOKEY;
- x = LIB9P_ERRNO_L_EKEYEXPIRED;
- x = LIB9P_ERRNO_L_EKEYREVOKED;
- x = LIB9P_ERRNO_L_EKEYREJECTED;
- x = LIB9P_ERRNO_L_EOWNERDEAD;
- x = LIB9P_ERRNO_L_ENOTRECOVERABLE;
- x = LIB9P_ERRNO_L_ERFKILL;
- x = LIB9P_ERRNO_L_EHWPOISON;
- x = LIB9P_SUPER_MAGIC_V9FS_MAGIC;
- x = _LIB9P_LO_UNUSED_31;
- x = _LIB9P_LO_UNUSED_30;
- x = _LIB9P_LO_UNUSED_29;
- x = _LIB9P_LO_UNUSED_28;
- x = _LIB9P_LO_UNUSED_27;
- x = _LIB9P_LO_UNUSED_26;
- x = _LIB9P_LO_UNUSED_25;
- x = _LIB9P_LO_UNUSED_24;
- x = _LIB9P_LO_UNUSED_23;
- x = _LIB9P_LO_UNUSED_22;
- x = _LIB9P_LO_UNUSED_21;
- x = LIB9P_LO_SYNC;
- x = LIB9P_LO_CLOEXEC;
- x = LIB9P_LO_NOATIME;
- x = LIB9P_LO_NOFOLLOW;
- x = LIB9P_LO_DIRECTORY;
- x = LIB9P_LO_LARGEFILE;
- x = LIB9P_LO_DIRECT;
- x = LIB9P_LO_BSD_FASYNC;
- x = LIB9P_LO_DSYNC;
- x = LIB9P_LO_NONBLOCK;
- x = LIB9P_LO_APPEND;
- x = LIB9P_LO_TRUNC;
- x = LIB9P_LO_NOCTTY;
- x = LIB9P_LO_EXCL;
- x = LIB9P_LO_CREATE;
- x = _LIB9P_LO_UNUSED_5;
- x = _LIB9P_LO_UNUSED_4;
- x = _LIB9P_LO_UNUSED_3;
- x = _LIB9P_LO_UNUSED_2;
- x = LIB9P_LO_FLAG_MASK;
- x = LIB9P_LO_MODE_RDONLY;
- x = LIB9P_LO_MODE_WRONLY;
- x = LIB9P_LO_MODE_RDWR;
- x = LIB9P_LO_MODE_NOACCESS;
- x = LIB9P_LO_MODE_MASK;
- x = LIB9P_DT_UNKNOWN;
- x = LIB9P_DT_PIPE;
- x = LIB9P_DT_CHAR_DEV;
- x = LIB9P_DT_DIRECTORY;
- x = LIB9P_DT_BLOCK_DEV;
- x = LIB9P_DT_REGULAR;
- x = LIB9P_DT_SYMLINK;
- x = LIB9P_DT_SOCKET;
- x = _LIB9P_DT_WHITEOUT;
- x = _LIB9P_MODE_UNUSED_31;
- x = _LIB9P_MODE_UNUSED_30;
- x = _LIB9P_MODE_UNUSED_29;
- x = _LIB9P_MODE_UNUSED_28;
- x = _LIB9P_MODE_UNUSED_27;
- x = _LIB9P_MODE_UNUSED_26;
- x = _LIB9P_MODE_UNUSED_25;
- x = _LIB9P_MODE_UNUSED_24;
- x = _LIB9P_MODE_UNUSED_23;
- x = _LIB9P_MODE_UNUSED_22;
- x = _LIB9P_MODE_UNUSED_21;
- x = _LIB9P_MODE_UNUSED_20;
- x = _LIB9P_MODE_UNUSED_19;
- x = _LIB9P_MODE_UNUSED_18;
- x = _LIB9P_MODE_UNUSED_17;
- x = _LIB9P_MODE_UNUSED_16;
- x = LIB9P_MODE_PERM_SETGROUP;
- x = LIB9P_MODE_PERM_SETUSER;
- x = LIB9P_MODE_PERM_STICKY;
- x = LIB9P_MODE_PERM_OWNER_R;
- x = LIB9P_MODE_PERM_OWNER_W;
- x = LIB9P_MODE_PERM_OWNER_X;
- x = LIB9P_MODE_PERM_GROUP_R;
- x = LIB9P_MODE_PERM_GROUP_W;
- x = LIB9P_MODE_PERM_GROUP_X;
- x = LIB9P_MODE_PERM_OTHER_R;
- x = LIB9P_MODE_PERM_OTHER_W;
- x = LIB9P_MODE_PERM_OTHER_X;
- x = LIB9P_MODE_PERM_MASK;
- x = LIB9P_MODE_FMT_PIPE;
- x = LIB9P_MODE_FMT_CHAR_DEV;
- x = LIB9P_MODE_FMT_DIRECTORY;
- x = LIB9P_MODE_FMT_BLOCK_DEV;
- x = LIB9P_MODE_FMT_REGULAR;
- x = LIB9P_MODE_FMT_SYMLINK;
- x = LIB9P_MODE_FMT_SOCKET;
- x = LIB9P_MODE_FMT_MASK;
- x = LIB9P_B4_FALSE;
- x = LIB9P_B4_TRUE;
- x = _LIB9P_GETATTR_UNUSED_63;
- x = _LIB9P_GETATTR_UNUSED_62;
- x = _LIB9P_GETATTR_UNUSED_61;
- x = _LIB9P_GETATTR_UNUSED_60;
- x = _LIB9P_GETATTR_UNUSED_59;
- x = _LIB9P_GETATTR_UNUSED_58;
- x = _LIB9P_GETATTR_UNUSED_57;
- x = _LIB9P_GETATTR_UNUSED_56;
- x = _LIB9P_GETATTR_UNUSED_55;
- x = _LIB9P_GETATTR_UNUSED_54;
- x = _LIB9P_GETATTR_UNUSED_53;
- x = _LIB9P_GETATTR_UNUSED_52;
- x = _LIB9P_GETATTR_UNUSED_51;
- x = _LIB9P_GETATTR_UNUSED_50;
- x = _LIB9P_GETATTR_UNUSED_49;
- x = _LIB9P_GETATTR_UNUSED_48;
- x = _LIB9P_GETATTR_UNUSED_47;
- x = _LIB9P_GETATTR_UNUSED_46;
- x = _LIB9P_GETATTR_UNUSED_45;
- x = _LIB9P_GETATTR_UNUSED_44;
- x = _LIB9P_GETATTR_UNUSED_43;
- x = _LIB9P_GETATTR_UNUSED_42;
- x = _LIB9P_GETATTR_UNUSED_41;
- x = _LIB9P_GETATTR_UNUSED_40;
- x = _LIB9P_GETATTR_UNUSED_39;
- x = _LIB9P_GETATTR_UNUSED_38;
- x = _LIB9P_GETATTR_UNUSED_37;
- x = _LIB9P_GETATTR_UNUSED_36;
- x = _LIB9P_GETATTR_UNUSED_35;
- x = _LIB9P_GETATTR_UNUSED_34;
- x = _LIB9P_GETATTR_UNUSED_33;
- x = _LIB9P_GETATTR_UNUSED_32;
- x = _LIB9P_GETATTR_UNUSED_31;
- x = _LIB9P_GETATTR_UNUSED_30;
- x = _LIB9P_GETATTR_UNUSED_29;
- x = _LIB9P_GETATTR_UNUSED_28;
- x = _LIB9P_GETATTR_UNUSED_27;
- x = _LIB9P_GETATTR_UNUSED_26;
- x = _LIB9P_GETATTR_UNUSED_25;
- x = _LIB9P_GETATTR_UNUSED_24;
- x = _LIB9P_GETATTR_UNUSED_23;
- x = _LIB9P_GETATTR_UNUSED_22;
- x = _LIB9P_GETATTR_UNUSED_21;
- x = _LIB9P_GETATTR_UNUSED_20;
- x = _LIB9P_GETATTR_UNUSED_19;
- x = _LIB9P_GETATTR_UNUSED_18;
- x = _LIB9P_GETATTR_UNUSED_17;
- x = _LIB9P_GETATTR_UNUSED_16;
- x = _LIB9P_GETATTR_UNUSED_15;
- x = _LIB9P_GETATTR_UNUSED_14;
- x = LIB9P_GETATTR_DATA_VERSION;
- x = LIB9P_GETATTR_GEN;
- x = LIB9P_GETATTR_BTIME;
- x = LIB9P_GETATTR_BLOCKS;
- x = LIB9P_GETATTR_SIZE;
- x = LIB9P_GETATTR_INO;
- x = LIB9P_GETATTR_CTIME;
- x = LIB9P_GETATTR_MTIME;
- x = LIB9P_GETATTR_ATIME;
- x = LIB9P_GETATTR_RDEV;
- x = LIB9P_GETATTR_GID;
- x = LIB9P_GETATTR_UID;
- x = LIB9P_GETATTR_NLINK;
- x = LIB9P_GETATTR_MODE;
- x = LIB9P_GETATTR_BASIC;
- x = LIB9P_GETATTR_ALL;
- x = _LIB9P_SETATTR_UNUSED_31;
- x = _LIB9P_SETATTR_UNUSED_30;
- x = _LIB9P_SETATTR_UNUSED_29;
- x = _LIB9P_SETATTR_UNUSED_28;
- x = _LIB9P_SETATTR_UNUSED_27;
- x = _LIB9P_SETATTR_UNUSED_26;
- x = _LIB9P_SETATTR_UNUSED_25;
- x = _LIB9P_SETATTR_UNUSED_24;
- x = _LIB9P_SETATTR_UNUSED_23;
- x = _LIB9P_SETATTR_UNUSED_22;
- x = _LIB9P_SETATTR_UNUSED_21;
- x = _LIB9P_SETATTR_UNUSED_20;
- x = _LIB9P_SETATTR_UNUSED_19;
- x = _LIB9P_SETATTR_UNUSED_18;
- x = _LIB9P_SETATTR_UNUSED_17;
- x = _LIB9P_SETATTR_UNUSED_16;
- x = _LIB9P_SETATTR_UNUSED_15;
- x = _LIB9P_SETATTR_UNUSED_14;
- x = _LIB9P_SETATTR_UNUSED_13;
- x = _LIB9P_SETATTR_UNUSED_12;
- x = _LIB9P_SETATTR_UNUSED_11;
- x = _LIB9P_SETATTR_UNUSED_10;
- x = _LIB9P_SETATTR_UNUSED_9;
- x = LIB9P_SETATTR_MTIME_SET;
- x = LIB9P_SETATTR_ATIME_SET;
- x = LIB9P_SETATTR_CTIME;
- x = LIB9P_SETATTR_MTIME;
- x = LIB9P_SETATTR_ATIME;
- x = LIB9P_SETATTR_SIZE;
- x = LIB9P_SETATTR_GID;
- x = LIB9P_SETATTR_UID;
- x = LIB9P_SETATTR_MODE;
- x = LIB9P_LOCK_TYPE_RDLCK;
- x = LIB9P_LOCK_TYPE_WRLCK;
- x = LIB9P_LOCK_TYPE_UNLCK;
- x = _LIB9P_LOCK_FLAGS_UNUSED_31;
- x = _LIB9P_LOCK_FLAGS_UNUSED_30;
- x = _LIB9P_LOCK_FLAGS_UNUSED_29;
- x = _LIB9P_LOCK_FLAGS_UNUSED_28;
- x = _LIB9P_LOCK_FLAGS_UNUSED_27;
- x = _LIB9P_LOCK_FLAGS_UNUSED_26;
- x = _LIB9P_LOCK_FLAGS_UNUSED_25;
- x = _LIB9P_LOCK_FLAGS_UNUSED_24;
- x = _LIB9P_LOCK_FLAGS_UNUSED_23;
- x = _LIB9P_LOCK_FLAGS_UNUSED_22;
- x = _LIB9P_LOCK_FLAGS_UNUSED_21;
- x = _LIB9P_LOCK_FLAGS_UNUSED_20;
- x = _LIB9P_LOCK_FLAGS_UNUSED_19;
- x = _LIB9P_LOCK_FLAGS_UNUSED_18;
- x = _LIB9P_LOCK_FLAGS_UNUSED_17;
- x = _LIB9P_LOCK_FLAGS_UNUSED_16;
- x = _LIB9P_LOCK_FLAGS_UNUSED_15;
- x = _LIB9P_LOCK_FLAGS_UNUSED_14;
- x = _LIB9P_LOCK_FLAGS_UNUSED_13;
- x = _LIB9P_LOCK_FLAGS_UNUSED_12;
- x = _LIB9P_LOCK_FLAGS_UNUSED_11;
- x = _LIB9P_LOCK_FLAGS_UNUSED_10;
- x = _LIB9P_LOCK_FLAGS_UNUSED_9;
- x = _LIB9P_LOCK_FLAGS_UNUSED_8;
- x = _LIB9P_LOCK_FLAGS_UNUSED_7;
- x = _LIB9P_LOCK_FLAGS_UNUSED_6;
- x = _LIB9P_LOCK_FLAGS_UNUSED_5;
- x = _LIB9P_LOCK_FLAGS_UNUSED_4;
- x = _LIB9P_LOCK_FLAGS_UNUSED_3;
- x = _LIB9P_LOCK_FLAGS_UNUSED_2;
- x = LIB9P_LOCK_FLAGS_RECLAIM;
- x = LIB9P_LOCK_FLAGS_BLOCK;
- x = LIB9P_LOCK_STATUS_SUCCESS;
- x = LIB9P_LOCK_STATUS_BLOCKED;
- x = LIB9P_LOCK_STATUS_ERROR;
- x = LIB9P_LOCK_STATUS_GRACE;
- x = LIB9P_TMSG_MAX_IOV;
- x = LIB9P_TMSG_MAX_IOV;
- x = LIB9P_TMSG_MAX_COPY;
- x = LIB9P_TMSG_MAX_COPY;
- x = LIB9P_TMSG_MAX_COPY;
- x = LIB9P_TMSG_MAX_COPY;
- x = LIB9P_TMSG_MAX_COPY;
- x = LIB9P_TMSG_MAX_COPY;
- x = LIB9P_RMSG_MAX_IOV;
- x = LIB9P_RMSG_MAX_IOV;
- x = LIB9P_RMSG_MAX_IOV;
- x = LIB9P_RMSG_MAX_COPY;
- return 0;
+ [[maybe_unused]] uint64_t x;
+#ifdef LIB9P_B4_FALSE
+ x = LIB9P_B4_FALSE;
+#endif
+#ifdef LIB9P_B4_TRUE
+ x = LIB9P_B4_TRUE;
+#endif
+#ifdef LIB9P_DM_APPEND
+ x = LIB9P_DM_APPEND;
+#endif
+#ifdef LIB9P_DM_AUTH
+ x = LIB9P_DM_AUTH;
+#endif
+#ifdef LIB9P_DM_DEVICE
+ x = LIB9P_DM_DEVICE;
+#endif
+#ifdef LIB9P_DM_DIR
+ x = LIB9P_DM_DIR;
+#endif
+#ifdef LIB9P_DM_EXCL
+ x = LIB9P_DM_EXCL;
+#endif
+#ifdef LIB9P_DM_GROUP_R
+ x = LIB9P_DM_GROUP_R;
+#endif
+#ifdef LIB9P_DM_GROUP_W
+ x = LIB9P_DM_GROUP_W;
+#endif
+#ifdef LIB9P_DM_GROUP_X
+ x = LIB9P_DM_GROUP_X;
+#endif
+#ifdef LIB9P_DM_OTHER_R
+ x = LIB9P_DM_OTHER_R;
+#endif
+#ifdef LIB9P_DM_OTHER_W
+ x = LIB9P_DM_OTHER_W;
+#endif
+#ifdef LIB9P_DM_OTHER_X
+ x = LIB9P_DM_OTHER_X;
+#endif
+#ifdef LIB9P_DM_OWNER_R
+ x = LIB9P_DM_OWNER_R;
+#endif
+#ifdef LIB9P_DM_OWNER_W
+ x = LIB9P_DM_OWNER_W;
+#endif
+#ifdef LIB9P_DM_OWNER_X
+ x = LIB9P_DM_OWNER_X;
+#endif
+#ifdef LIB9P_DM_PERM_MASK
+ x = LIB9P_DM_PERM_MASK;
+#endif
+#ifdef LIB9P_DM_PIPE
+ x = LIB9P_DM_PIPE;
+#endif
+#ifdef LIB9P_DM_SETGID
+ x = LIB9P_DM_SETGID;
+#endif
+#ifdef LIB9P_DM_SETUID
+ x = LIB9P_DM_SETUID;
+#endif
+#ifdef LIB9P_DM_SOCKET
+ x = LIB9P_DM_SOCKET;
+#endif
+#ifdef LIB9P_DM_TMP
+ x = LIB9P_DM_TMP;
+#endif
+#ifdef LIB9P_DT_BLOCK_DEV
+ x = LIB9P_DT_BLOCK_DEV;
+#endif
+#ifdef LIB9P_DT_CHAR_DEV
+ x = LIB9P_DT_CHAR_DEV;
+#endif
+#ifdef LIB9P_DT_DIRECTORY
+ x = LIB9P_DT_DIRECTORY;
+#endif
+#ifdef LIB9P_DT_PIPE
+ x = LIB9P_DT_PIPE;
+#endif
+#ifdef LIB9P_DT_REGULAR
+ x = LIB9P_DT_REGULAR;
+#endif
+#ifdef LIB9P_DT_SOCKET
+ x = LIB9P_DT_SOCKET;
+#endif
+#ifdef LIB9P_DT_SYMLINK
+ x = LIB9P_DT_SYMLINK;
+#endif
+#ifdef LIB9P_DT_UNKNOWN
+ x = LIB9P_DT_UNKNOWN;
+#endif
+#ifdef LIB9P_ERRNO_L_E2BIG
+ x = LIB9P_ERRNO_L_E2BIG;
+#endif
+#ifdef LIB9P_ERRNO_L_EACCES
+ x = LIB9P_ERRNO_L_EACCES;
+#endif
+#ifdef LIB9P_ERRNO_L_EADDRINUSE
+ x = LIB9P_ERRNO_L_EADDRINUSE;
+#endif
+#ifdef LIB9P_ERRNO_L_EADDRNOTAVAIL
+ x = LIB9P_ERRNO_L_EADDRNOTAVAIL;
+#endif
+#ifdef LIB9P_ERRNO_L_EADV
+ x = LIB9P_ERRNO_L_EADV;
+#endif
+#ifdef LIB9P_ERRNO_L_EAFNOSUPPORT
+ x = LIB9P_ERRNO_L_EAFNOSUPPORT;
+#endif
+#ifdef LIB9P_ERRNO_L_EAGAIN
+ x = LIB9P_ERRNO_L_EAGAIN;
+#endif
+#ifdef LIB9P_ERRNO_L_EALREADY
+ x = LIB9P_ERRNO_L_EALREADY;
+#endif
+#ifdef LIB9P_ERRNO_L_EBADE
+ x = LIB9P_ERRNO_L_EBADE;
+#endif
+#ifdef LIB9P_ERRNO_L_EBADF
+ x = LIB9P_ERRNO_L_EBADF;
+#endif
+#ifdef LIB9P_ERRNO_L_EBADFD
+ x = LIB9P_ERRNO_L_EBADFD;
+#endif
+#ifdef LIB9P_ERRNO_L_EBADMSG
+ x = LIB9P_ERRNO_L_EBADMSG;
+#endif
+#ifdef LIB9P_ERRNO_L_EBADR
+ x = LIB9P_ERRNO_L_EBADR;
+#endif
+#ifdef LIB9P_ERRNO_L_EBADRQC
+ x = LIB9P_ERRNO_L_EBADRQC;
+#endif
+#ifdef LIB9P_ERRNO_L_EBADSLT
+ x = LIB9P_ERRNO_L_EBADSLT;
+#endif
+#ifdef LIB9P_ERRNO_L_EBFONT
+ x = LIB9P_ERRNO_L_EBFONT;
+#endif
+#ifdef LIB9P_ERRNO_L_EBUSY
+ x = LIB9P_ERRNO_L_EBUSY;
+#endif
+#ifdef LIB9P_ERRNO_L_ECANCELED
+ x = LIB9P_ERRNO_L_ECANCELED;
+#endif
+#ifdef LIB9P_ERRNO_L_ECHILD
+ x = LIB9P_ERRNO_L_ECHILD;
+#endif
+#ifdef LIB9P_ERRNO_L_ECHRNG
+ x = LIB9P_ERRNO_L_ECHRNG;
+#endif
+#ifdef LIB9P_ERRNO_L_ECOMM
+ x = LIB9P_ERRNO_L_ECOMM;
+#endif
+#ifdef LIB9P_ERRNO_L_ECONNABORTED
+ x = LIB9P_ERRNO_L_ECONNABORTED;
+#endif
+#ifdef LIB9P_ERRNO_L_ECONNREFUSED
+ x = LIB9P_ERRNO_L_ECONNREFUSED;
+#endif
+#ifdef LIB9P_ERRNO_L_ECONNRESET
+ x = LIB9P_ERRNO_L_ECONNRESET;
+#endif
+#ifdef LIB9P_ERRNO_L_EDEADLK
+ x = LIB9P_ERRNO_L_EDEADLK;
+#endif
+#ifdef LIB9P_ERRNO_L_EDESTADDRREQ
+ x = LIB9P_ERRNO_L_EDESTADDRREQ;
+#endif
+#ifdef LIB9P_ERRNO_L_EDOM
+ x = LIB9P_ERRNO_L_EDOM;
+#endif
+#ifdef LIB9P_ERRNO_L_EDOTDOT
+ x = LIB9P_ERRNO_L_EDOTDOT;
+#endif
+#ifdef LIB9P_ERRNO_L_EDQUOT
+ x = LIB9P_ERRNO_L_EDQUOT;
+#endif
+#ifdef LIB9P_ERRNO_L_EEXIST
+ x = LIB9P_ERRNO_L_EEXIST;
+#endif
+#ifdef LIB9P_ERRNO_L_EFAULT
+ x = LIB9P_ERRNO_L_EFAULT;
+#endif
+#ifdef LIB9P_ERRNO_L_EFBIG
+ x = LIB9P_ERRNO_L_EFBIG;
+#endif
+#ifdef LIB9P_ERRNO_L_EHOSTDOWN
+ x = LIB9P_ERRNO_L_EHOSTDOWN;
+#endif
+#ifdef LIB9P_ERRNO_L_EHOSTUNREACH
+ x = LIB9P_ERRNO_L_EHOSTUNREACH;
+#endif
+#ifdef LIB9P_ERRNO_L_EHWPOISON
+ x = LIB9P_ERRNO_L_EHWPOISON;
+#endif
+#ifdef LIB9P_ERRNO_L_EIDRM
+ x = LIB9P_ERRNO_L_EIDRM;
+#endif
+#ifdef LIB9P_ERRNO_L_EILSEQ
+ x = LIB9P_ERRNO_L_EILSEQ;
+#endif
+#ifdef LIB9P_ERRNO_L_EINPROGRESS
+ x = LIB9P_ERRNO_L_EINPROGRESS;
+#endif
+#ifdef LIB9P_ERRNO_L_EINTR
+ x = LIB9P_ERRNO_L_EINTR;
+#endif
+#ifdef LIB9P_ERRNO_L_EINVAL
+ x = LIB9P_ERRNO_L_EINVAL;
+#endif
+#ifdef LIB9P_ERRNO_L_EIO
+ x = LIB9P_ERRNO_L_EIO;
+#endif
+#ifdef LIB9P_ERRNO_L_EISCONN
+ x = LIB9P_ERRNO_L_EISCONN;
+#endif
+#ifdef LIB9P_ERRNO_L_EISDIR
+ x = LIB9P_ERRNO_L_EISDIR;
+#endif
+#ifdef LIB9P_ERRNO_L_EISNAM
+ x = LIB9P_ERRNO_L_EISNAM;
+#endif
+#ifdef LIB9P_ERRNO_L_EKEYEXPIRED
+ x = LIB9P_ERRNO_L_EKEYEXPIRED;
+#endif
+#ifdef LIB9P_ERRNO_L_EKEYREJECTED
+ x = LIB9P_ERRNO_L_EKEYREJECTED;
+#endif
+#ifdef LIB9P_ERRNO_L_EKEYREVOKED
+ x = LIB9P_ERRNO_L_EKEYREVOKED;
+#endif
+#ifdef LIB9P_ERRNO_L_EL2HLT
+ x = LIB9P_ERRNO_L_EL2HLT;
+#endif
+#ifdef LIB9P_ERRNO_L_EL2NSYNC
+ x = LIB9P_ERRNO_L_EL2NSYNC;
+#endif
+#ifdef LIB9P_ERRNO_L_EL3HLT
+ x = LIB9P_ERRNO_L_EL3HLT;
+#endif
+#ifdef LIB9P_ERRNO_L_EL3RST
+ x = LIB9P_ERRNO_L_EL3RST;
+#endif
+#ifdef LIB9P_ERRNO_L_ELIBACC
+ x = LIB9P_ERRNO_L_ELIBACC;
+#endif
+#ifdef LIB9P_ERRNO_L_ELIBBAD
+ x = LIB9P_ERRNO_L_ELIBBAD;
+#endif
+#ifdef LIB9P_ERRNO_L_ELIBEXEC
+ x = LIB9P_ERRNO_L_ELIBEXEC;
+#endif
+#ifdef LIB9P_ERRNO_L_ELIBMAX
+ x = LIB9P_ERRNO_L_ELIBMAX;
+#endif
+#ifdef LIB9P_ERRNO_L_ELIBSCN
+ x = LIB9P_ERRNO_L_ELIBSCN;
+#endif
+#ifdef LIB9P_ERRNO_L_ELNRNG
+ x = LIB9P_ERRNO_L_ELNRNG;
+#endif
+#ifdef LIB9P_ERRNO_L_ELOOP
+ x = LIB9P_ERRNO_L_ELOOP;
+#endif
+#ifdef LIB9P_ERRNO_L_EMEDIUMTYPE
+ x = LIB9P_ERRNO_L_EMEDIUMTYPE;
+#endif
+#ifdef LIB9P_ERRNO_L_EMFILE
+ x = LIB9P_ERRNO_L_EMFILE;
+#endif
+#ifdef LIB9P_ERRNO_L_EMLINK
+ x = LIB9P_ERRNO_L_EMLINK;
+#endif
+#ifdef LIB9P_ERRNO_L_EMSGSIZE
+ x = LIB9P_ERRNO_L_EMSGSIZE;
+#endif
+#ifdef LIB9P_ERRNO_L_EMULTIHOP
+ x = LIB9P_ERRNO_L_EMULTIHOP;
+#endif
+#ifdef LIB9P_ERRNO_L_ENAMETOOLONG
+ x = LIB9P_ERRNO_L_ENAMETOOLONG;
+#endif
+#ifdef LIB9P_ERRNO_L_ENAVAIL
+ x = LIB9P_ERRNO_L_ENAVAIL;
+#endif
+#ifdef LIB9P_ERRNO_L_ENETDOWN
+ x = LIB9P_ERRNO_L_ENETDOWN;
+#endif
+#ifdef LIB9P_ERRNO_L_ENETRESET
+ x = LIB9P_ERRNO_L_ENETRESET;
+#endif
+#ifdef LIB9P_ERRNO_L_ENETUNREACH
+ x = LIB9P_ERRNO_L_ENETUNREACH;
+#endif
+#ifdef LIB9P_ERRNO_L_ENFILE
+ x = LIB9P_ERRNO_L_ENFILE;
+#endif
+#ifdef LIB9P_ERRNO_L_ENOANO
+ x = LIB9P_ERRNO_L_ENOANO;
+#endif
+#ifdef LIB9P_ERRNO_L_ENOBUFS
+ x = LIB9P_ERRNO_L_ENOBUFS;
+#endif
+#ifdef LIB9P_ERRNO_L_ENOCSI
+ x = LIB9P_ERRNO_L_ENOCSI;
+#endif
+#ifdef LIB9P_ERRNO_L_ENODATA
+ x = LIB9P_ERRNO_L_ENODATA;
+#endif
+#ifdef LIB9P_ERRNO_L_ENODEV
+ x = LIB9P_ERRNO_L_ENODEV;
+#endif
+#ifdef LIB9P_ERRNO_L_ENOENT
+ x = LIB9P_ERRNO_L_ENOENT;
+#endif
+#ifdef LIB9P_ERRNO_L_ENOEXEC
+ x = LIB9P_ERRNO_L_ENOEXEC;
+#endif
+#ifdef LIB9P_ERRNO_L_ENOKEY
+ x = LIB9P_ERRNO_L_ENOKEY;
+#endif
+#ifdef LIB9P_ERRNO_L_ENOLCK
+ x = LIB9P_ERRNO_L_ENOLCK;
+#endif
+#ifdef LIB9P_ERRNO_L_ENOLINK
+ x = LIB9P_ERRNO_L_ENOLINK;
+#endif
+#ifdef LIB9P_ERRNO_L_ENOMEDIUM
+ x = LIB9P_ERRNO_L_ENOMEDIUM;
+#endif
+#ifdef LIB9P_ERRNO_L_ENOMEM
+ x = LIB9P_ERRNO_L_ENOMEM;
+#endif
+#ifdef LIB9P_ERRNO_L_ENOMSG
+ x = LIB9P_ERRNO_L_ENOMSG;
+#endif
+#ifdef LIB9P_ERRNO_L_ENONET
+ x = LIB9P_ERRNO_L_ENONET;
+#endif
+#ifdef LIB9P_ERRNO_L_ENOPKG
+ x = LIB9P_ERRNO_L_ENOPKG;
+#endif
+#ifdef LIB9P_ERRNO_L_ENOPROTOOPT
+ x = LIB9P_ERRNO_L_ENOPROTOOPT;
+#endif
+#ifdef LIB9P_ERRNO_L_ENOSPC
+ x = LIB9P_ERRNO_L_ENOSPC;
+#endif
+#ifdef LIB9P_ERRNO_L_ENOSR
+ x = LIB9P_ERRNO_L_ENOSR;
+#endif
+#ifdef LIB9P_ERRNO_L_ENOSTR
+ x = LIB9P_ERRNO_L_ENOSTR;
+#endif
+#ifdef LIB9P_ERRNO_L_ENOSYS
+ x = LIB9P_ERRNO_L_ENOSYS;
+#endif
+#ifdef LIB9P_ERRNO_L_ENOTBLK
+ x = LIB9P_ERRNO_L_ENOTBLK;
+#endif
+#ifdef LIB9P_ERRNO_L_ENOTCONN
+ x = LIB9P_ERRNO_L_ENOTCONN;
+#endif
+#ifdef LIB9P_ERRNO_L_ENOTDIR
+ x = LIB9P_ERRNO_L_ENOTDIR;
+#endif
+#ifdef LIB9P_ERRNO_L_ENOTEMPTY
+ x = LIB9P_ERRNO_L_ENOTEMPTY;
+#endif
+#ifdef LIB9P_ERRNO_L_ENOTNAM
+ x = LIB9P_ERRNO_L_ENOTNAM;
+#endif
+#ifdef LIB9P_ERRNO_L_ENOTRECOVERABLE
+ x = LIB9P_ERRNO_L_ENOTRECOVERABLE;
+#endif
+#ifdef LIB9P_ERRNO_L_ENOTSOCK
+ x = LIB9P_ERRNO_L_ENOTSOCK;
+#endif
+#ifdef LIB9P_ERRNO_L_ENOTTY
+ x = LIB9P_ERRNO_L_ENOTTY;
+#endif
+#ifdef LIB9P_ERRNO_L_ENOTUNIQ
+ x = LIB9P_ERRNO_L_ENOTUNIQ;
+#endif
+#ifdef LIB9P_ERRNO_L_ENXIO
+ x = LIB9P_ERRNO_L_ENXIO;
+#endif
+#ifdef LIB9P_ERRNO_L_EOPNOTSUPP
+ x = LIB9P_ERRNO_L_EOPNOTSUPP;
+#endif
+#ifdef LIB9P_ERRNO_L_EOVERFLOW
+ x = LIB9P_ERRNO_L_EOVERFLOW;
+#endif
+#ifdef LIB9P_ERRNO_L_EOWNERDEAD
+ x = LIB9P_ERRNO_L_EOWNERDEAD;
+#endif
+#ifdef LIB9P_ERRNO_L_EPERM
+ x = LIB9P_ERRNO_L_EPERM;
+#endif
+#ifdef LIB9P_ERRNO_L_EPFNOSUPPORT
+ x = LIB9P_ERRNO_L_EPFNOSUPPORT;
+#endif
+#ifdef LIB9P_ERRNO_L_EPIPE
+ x = LIB9P_ERRNO_L_EPIPE;
+#endif
+#ifdef LIB9P_ERRNO_L_EPROTO
+ x = LIB9P_ERRNO_L_EPROTO;
+#endif
+#ifdef LIB9P_ERRNO_L_EPROTONOSUPPORT
+ x = LIB9P_ERRNO_L_EPROTONOSUPPORT;
+#endif
+#ifdef LIB9P_ERRNO_L_EPROTOTYPE
+ x = LIB9P_ERRNO_L_EPROTOTYPE;
+#endif
+#ifdef LIB9P_ERRNO_L_ERANGE
+ x = LIB9P_ERRNO_L_ERANGE;
+#endif
+#ifdef LIB9P_ERRNO_L_EREMCHG
+ x = LIB9P_ERRNO_L_EREMCHG;
+#endif
+#ifdef LIB9P_ERRNO_L_EREMOTE
+ x = LIB9P_ERRNO_L_EREMOTE;
+#endif
+#ifdef LIB9P_ERRNO_L_EREMOTEIO
+ x = LIB9P_ERRNO_L_EREMOTEIO;
+#endif
+#ifdef LIB9P_ERRNO_L_ERESTART
+ x = LIB9P_ERRNO_L_ERESTART;
+#endif
+#ifdef LIB9P_ERRNO_L_ERFKILL
+ x = LIB9P_ERRNO_L_ERFKILL;
+#endif
+#ifdef LIB9P_ERRNO_L_EROFS
+ x = LIB9P_ERRNO_L_EROFS;
+#endif
+#ifdef LIB9P_ERRNO_L_ESHUTDOWN
+ x = LIB9P_ERRNO_L_ESHUTDOWN;
+#endif
+#ifdef LIB9P_ERRNO_L_ESOCKTNOSUPPORT
+ x = LIB9P_ERRNO_L_ESOCKTNOSUPPORT;
+#endif
+#ifdef LIB9P_ERRNO_L_ESPIPE
+ x = LIB9P_ERRNO_L_ESPIPE;
+#endif
+#ifdef LIB9P_ERRNO_L_ESRCH
+ x = LIB9P_ERRNO_L_ESRCH;
+#endif
+#ifdef LIB9P_ERRNO_L_ESRMNT
+ x = LIB9P_ERRNO_L_ESRMNT;
+#endif
+#ifdef LIB9P_ERRNO_L_ESTALE
+ x = LIB9P_ERRNO_L_ESTALE;
+#endif
+#ifdef LIB9P_ERRNO_L_ESTRPIPE
+ x = LIB9P_ERRNO_L_ESTRPIPE;
+#endif
+#ifdef LIB9P_ERRNO_L_ETIME
+ x = LIB9P_ERRNO_L_ETIME;
+#endif
+#ifdef LIB9P_ERRNO_L_ETIMEDOUT
+ x = LIB9P_ERRNO_L_ETIMEDOUT;
+#endif
+#ifdef LIB9P_ERRNO_L_ETOOMANYREFS
+ x = LIB9P_ERRNO_L_ETOOMANYREFS;
+#endif
+#ifdef LIB9P_ERRNO_L_ETXTBSY
+ x = LIB9P_ERRNO_L_ETXTBSY;
+#endif
+#ifdef LIB9P_ERRNO_L_EUCLEAN
+ x = LIB9P_ERRNO_L_EUCLEAN;
+#endif
+#ifdef LIB9P_ERRNO_L_EUNATCH
+ x = LIB9P_ERRNO_L_EUNATCH;
+#endif
+#ifdef LIB9P_ERRNO_L_EUSERS
+ x = LIB9P_ERRNO_L_EUSERS;
+#endif
+#ifdef LIB9P_ERRNO_L_EXDEV
+ x = LIB9P_ERRNO_L_EXDEV;
+#endif
+#ifdef LIB9P_ERRNO_L_EXFULL
+ x = LIB9P_ERRNO_L_EXFULL;
+#endif
+#ifdef LIB9P_ERRNO_NOERROR
+ x = LIB9P_ERRNO_NOERROR;
+#endif
+#ifdef LIB9P_FID_NOFID
+ x = LIB9P_FID_NOFID;
+#endif
+#ifdef LIB9P_GETATTR_ALL
+ x = LIB9P_GETATTR_ALL;
+#endif
+#ifdef LIB9P_GETATTR_ATIME
+ x = LIB9P_GETATTR_ATIME;
+#endif
+#ifdef LIB9P_GETATTR_BASIC
+ x = LIB9P_GETATTR_BASIC;
+#endif
+#ifdef LIB9P_GETATTR_BLOCKS
+ x = LIB9P_GETATTR_BLOCKS;
+#endif
+#ifdef LIB9P_GETATTR_BTIME
+ x = LIB9P_GETATTR_BTIME;
+#endif
+#ifdef LIB9P_GETATTR_CTIME
+ x = LIB9P_GETATTR_CTIME;
+#endif
+#ifdef LIB9P_GETATTR_DATA_VERSION
+ x = LIB9P_GETATTR_DATA_VERSION;
+#endif
+#ifdef LIB9P_GETATTR_GEN
+ x = LIB9P_GETATTR_GEN;
+#endif
+#ifdef LIB9P_GETATTR_GID
+ x = LIB9P_GETATTR_GID;
+#endif
+#ifdef LIB9P_GETATTR_INO
+ x = LIB9P_GETATTR_INO;
+#endif
+#ifdef LIB9P_GETATTR_MODE
+ x = LIB9P_GETATTR_MODE;
+#endif
+#ifdef LIB9P_GETATTR_MTIME
+ x = LIB9P_GETATTR_MTIME;
+#endif
+#ifdef LIB9P_GETATTR_NLINK
+ x = LIB9P_GETATTR_NLINK;
+#endif
+#ifdef LIB9P_GETATTR_RDEV
+ x = LIB9P_GETATTR_RDEV;
+#endif
+#ifdef LIB9P_GETATTR_SIZE
+ x = LIB9P_GETATTR_SIZE;
+#endif
+#ifdef LIB9P_GETATTR_UID
+ x = LIB9P_GETATTR_UID;
+#endif
+#ifdef LIB9P_LOCK_FLAGS_BLOCK
+ x = LIB9P_LOCK_FLAGS_BLOCK;
+#endif
+#ifdef LIB9P_LOCK_FLAGS_RECLAIM
+ x = LIB9P_LOCK_FLAGS_RECLAIM;
+#endif
+#ifdef LIB9P_LOCK_STATUS_BLOCKED
+ x = LIB9P_LOCK_STATUS_BLOCKED;
+#endif
+#ifdef LIB9P_LOCK_STATUS_ERROR
+ x = LIB9P_LOCK_STATUS_ERROR;
+#endif
+#ifdef LIB9P_LOCK_STATUS_GRACE
+ x = LIB9P_LOCK_STATUS_GRACE;
+#endif
+#ifdef LIB9P_LOCK_STATUS_SUCCESS
+ x = LIB9P_LOCK_STATUS_SUCCESS;
+#endif
+#ifdef LIB9P_LOCK_TYPE_RDLCK
+ x = LIB9P_LOCK_TYPE_RDLCK;
+#endif
+#ifdef LIB9P_LOCK_TYPE_UNLCK
+ x = LIB9P_LOCK_TYPE_UNLCK;
+#endif
+#ifdef LIB9P_LOCK_TYPE_WRLCK
+ x = LIB9P_LOCK_TYPE_WRLCK;
+#endif
+#ifdef LIB9P_LO_APPEND
+ x = LIB9P_LO_APPEND;
+#endif
+#ifdef LIB9P_LO_BSD_FASYNC
+ x = LIB9P_LO_BSD_FASYNC;
+#endif
+#ifdef LIB9P_LO_CLOEXEC
+ x = LIB9P_LO_CLOEXEC;
+#endif
+#ifdef LIB9P_LO_CREATE
+ x = LIB9P_LO_CREATE;
+#endif
+#ifdef LIB9P_LO_DIRECT
+ x = LIB9P_LO_DIRECT;
+#endif
+#ifdef LIB9P_LO_DIRECTORY
+ x = LIB9P_LO_DIRECTORY;
+#endif
+#ifdef LIB9P_LO_DSYNC
+ x = LIB9P_LO_DSYNC;
+#endif
+#ifdef LIB9P_LO_EXCL
+ x = LIB9P_LO_EXCL;
+#endif
+#ifdef LIB9P_LO_FLAG_MASK
+ x = LIB9P_LO_FLAG_MASK;
+#endif
+#ifdef LIB9P_LO_LARGEFILE
+ x = LIB9P_LO_LARGEFILE;
+#endif
+#ifdef LIB9P_LO_MODE_MASK
+ x = LIB9P_LO_MODE_MASK;
+#endif
+#ifdef LIB9P_LO_MODE_NOACCESS
+ x = LIB9P_LO_MODE_NOACCESS;
+#endif
+#ifdef LIB9P_LO_MODE_RDONLY
+ x = LIB9P_LO_MODE_RDONLY;
+#endif
+#ifdef LIB9P_LO_MODE_RDWR
+ x = LIB9P_LO_MODE_RDWR;
+#endif
+#ifdef LIB9P_LO_MODE_WRONLY
+ x = LIB9P_LO_MODE_WRONLY;
+#endif
+#ifdef LIB9P_LO_NOATIME
+ x = LIB9P_LO_NOATIME;
+#endif
+#ifdef LIB9P_LO_NOCTTY
+ x = LIB9P_LO_NOCTTY;
+#endif
+#ifdef LIB9P_LO_NOFOLLOW
+ x = LIB9P_LO_NOFOLLOW;
+#endif
+#ifdef LIB9P_LO_NONBLOCK
+ x = LIB9P_LO_NONBLOCK;
+#endif
+#ifdef LIB9P_LO_SYNC
+ x = LIB9P_LO_SYNC;
+#endif
+#ifdef LIB9P_LO_TRUNC
+ x = LIB9P_LO_TRUNC;
+#endif
+#ifdef LIB9P_MODE_FMT_BLOCK_DEV
+ x = LIB9P_MODE_FMT_BLOCK_DEV;
+#endif
+#ifdef LIB9P_MODE_FMT_CHAR_DEV
+ x = LIB9P_MODE_FMT_CHAR_DEV;
+#endif
+#ifdef LIB9P_MODE_FMT_DIRECTORY
+ x = LIB9P_MODE_FMT_DIRECTORY;
+#endif
+#ifdef LIB9P_MODE_FMT_MASK
+ x = LIB9P_MODE_FMT_MASK;
+#endif
+#ifdef LIB9P_MODE_FMT_PIPE
+ x = LIB9P_MODE_FMT_PIPE;
+#endif
+#ifdef LIB9P_MODE_FMT_REGULAR
+ x = LIB9P_MODE_FMT_REGULAR;
+#endif
+#ifdef LIB9P_MODE_FMT_SOCKET
+ x = LIB9P_MODE_FMT_SOCKET;
+#endif
+#ifdef LIB9P_MODE_FMT_SYMLINK
+ x = LIB9P_MODE_FMT_SYMLINK;
+#endif
+#ifdef LIB9P_MODE_PERM_GROUP_R
+ x = LIB9P_MODE_PERM_GROUP_R;
+#endif
+#ifdef LIB9P_MODE_PERM_GROUP_W
+ x = LIB9P_MODE_PERM_GROUP_W;
+#endif
+#ifdef LIB9P_MODE_PERM_GROUP_X
+ x = LIB9P_MODE_PERM_GROUP_X;
+#endif
+#ifdef LIB9P_MODE_PERM_MASK
+ x = LIB9P_MODE_PERM_MASK;
+#endif
+#ifdef LIB9P_MODE_PERM_OTHER_R
+ x = LIB9P_MODE_PERM_OTHER_R;
+#endif
+#ifdef LIB9P_MODE_PERM_OTHER_W
+ x = LIB9P_MODE_PERM_OTHER_W;
+#endif
+#ifdef LIB9P_MODE_PERM_OTHER_X
+ x = LIB9P_MODE_PERM_OTHER_X;
+#endif
+#ifdef LIB9P_MODE_PERM_OWNER_R
+ x = LIB9P_MODE_PERM_OWNER_R;
+#endif
+#ifdef LIB9P_MODE_PERM_OWNER_W
+ x = LIB9P_MODE_PERM_OWNER_W;
+#endif
+#ifdef LIB9P_MODE_PERM_OWNER_X
+ x = LIB9P_MODE_PERM_OWNER_X;
+#endif
+#ifdef LIB9P_MODE_PERM_SETGROUP
+ x = LIB9P_MODE_PERM_SETGROUP;
+#endif
+#ifdef LIB9P_MODE_PERM_SETUSER
+ x = LIB9P_MODE_PERM_SETUSER;
+#endif
+#ifdef LIB9P_MODE_PERM_STICKY
+ x = LIB9P_MODE_PERM_STICKY;
+#endif
+#ifdef LIB9P_NUID_NONUID
+ x = LIB9P_NUID_NONUID;
+#endif
+#ifdef LIB9P_O_FLAG_MASK
+ x = LIB9P_O_FLAG_MASK;
+#endif
+#ifdef LIB9P_O_MODE_EXEC
+ x = LIB9P_O_MODE_EXEC;
+#endif
+#ifdef LIB9P_O_MODE_MASK
+ x = LIB9P_O_MODE_MASK;
+#endif
+#ifdef LIB9P_O_MODE_RDWR
+ x = LIB9P_O_MODE_RDWR;
+#endif
+#ifdef LIB9P_O_MODE_READ
+ x = LIB9P_O_MODE_READ;
+#endif
+#ifdef LIB9P_O_MODE_WRITE
+ x = LIB9P_O_MODE_WRITE;
+#endif
+#ifdef LIB9P_O_RCLOSE
+ x = LIB9P_O_RCLOSE;
+#endif
+#ifdef LIB9P_O_TRUNC
+ x = LIB9P_O_TRUNC;
+#endif
+#ifdef LIB9P_QT_APPEND
+ x = LIB9P_QT_APPEND;
+#endif
+#ifdef LIB9P_QT_AUTH
+ x = LIB9P_QT_AUTH;
+#endif
+#ifdef LIB9P_QT_DIR
+ x = LIB9P_QT_DIR;
+#endif
+#ifdef LIB9P_QT_EXCL
+ x = LIB9P_QT_EXCL;
+#endif
+#ifdef LIB9P_QT_FILE
+ x = LIB9P_QT_FILE;
+#endif
+#ifdef LIB9P_QT_SYMLINK
+ x = LIB9P_QT_SYMLINK;
+#endif
+#ifdef LIB9P_QT_TMP
+ x = LIB9P_QT_TMP;
+#endif
+#ifdef LIB9P_RMSG_MAX_COPY
+ x = LIB9P_RMSG_MAX_COPY;
+#endif
+#ifdef LIB9P_RMSG_MAX_IOV
+ x = LIB9P_RMSG_MAX_IOV;
+#endif
+#ifdef LIB9P_SETATTR_ATIME
+ x = LIB9P_SETATTR_ATIME;
+#endif
+#ifdef LIB9P_SETATTR_ATIME_SET
+ x = LIB9P_SETATTR_ATIME_SET;
+#endif
+#ifdef LIB9P_SETATTR_CTIME
+ x = LIB9P_SETATTR_CTIME;
+#endif
+#ifdef LIB9P_SETATTR_GID
+ x = LIB9P_SETATTR_GID;
+#endif
+#ifdef LIB9P_SETATTR_MODE
+ x = LIB9P_SETATTR_MODE;
+#endif
+#ifdef LIB9P_SETATTR_MTIME
+ x = LIB9P_SETATTR_MTIME;
+#endif
+#ifdef LIB9P_SETATTR_MTIME_SET
+ x = LIB9P_SETATTR_MTIME_SET;
+#endif
+#ifdef LIB9P_SETATTR_SIZE
+ x = LIB9P_SETATTR_SIZE;
+#endif
+#ifdef LIB9P_SETATTR_UID
+ x = LIB9P_SETATTR_UID;
+#endif
+#ifdef LIB9P_SUPER_MAGIC_V9FS_MAGIC
+ x = LIB9P_SUPER_MAGIC_V9FS_MAGIC;
+#endif
+#ifdef LIB9P_TAG_NOTAG
+ x = LIB9P_TAG_NOTAG;
+#endif
+#ifdef LIB9P_TMSG_MAX_COPY
+ x = LIB9P_TMSG_MAX_COPY;
+#endif
+#ifdef LIB9P_TMSG_MAX_IOV
+ x = LIB9P_TMSG_MAX_IOV;
+#endif
+#ifdef _LIB9P_DM_PLAN9_MOUNT
+ x = _LIB9P_DM_PLAN9_MOUNT;
+#endif
+#ifdef _LIB9P_DM_UNUSED_10
+ x = _LIB9P_DM_UNUSED_10;
+#endif
+#ifdef _LIB9P_DM_UNUSED_11
+ x = _LIB9P_DM_UNUSED_11;
+#endif
+#ifdef _LIB9P_DM_UNUSED_12
+ x = _LIB9P_DM_UNUSED_12;
+#endif
+#ifdef _LIB9P_DM_UNUSED_13
+ x = _LIB9P_DM_UNUSED_13;
+#endif
+#ifdef _LIB9P_DM_UNUSED_14
+ x = _LIB9P_DM_UNUSED_14;
+#endif
+#ifdef _LIB9P_DM_UNUSED_15
+ x = _LIB9P_DM_UNUSED_15;
+#endif
+#ifdef _LIB9P_DM_UNUSED_16
+ x = _LIB9P_DM_UNUSED_16;
+#endif
+#ifdef _LIB9P_DM_UNUSED_17
+ x = _LIB9P_DM_UNUSED_17;
+#endif
+#ifdef _LIB9P_DM_UNUSED_22
+ x = _LIB9P_DM_UNUSED_22;
+#endif
+#ifdef _LIB9P_DM_UNUSED_24
+ x = _LIB9P_DM_UNUSED_24;
+#endif
+#ifdef _LIB9P_DM_UNUSED_25
+ x = _LIB9P_DM_UNUSED_25;
+#endif
+#ifdef _LIB9P_DM_UNUSED_9
+ x = _LIB9P_DM_UNUSED_9;
+#endif
+#ifdef _LIB9P_DT_WHITEOUT
+ x = _LIB9P_DT_WHITEOUT;
+#endif
+#ifdef _LIB9P_ENABLE_stat
+ x = _LIB9P_ENABLE_stat;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_14
+ x = _LIB9P_GETATTR_UNUSED_14;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_15
+ x = _LIB9P_GETATTR_UNUSED_15;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_16
+ x = _LIB9P_GETATTR_UNUSED_16;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_17
+ x = _LIB9P_GETATTR_UNUSED_17;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_18
+ x = _LIB9P_GETATTR_UNUSED_18;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_19
+ x = _LIB9P_GETATTR_UNUSED_19;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_20
+ x = _LIB9P_GETATTR_UNUSED_20;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_21
+ x = _LIB9P_GETATTR_UNUSED_21;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_22
+ x = _LIB9P_GETATTR_UNUSED_22;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_23
+ x = _LIB9P_GETATTR_UNUSED_23;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_24
+ x = _LIB9P_GETATTR_UNUSED_24;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_25
+ x = _LIB9P_GETATTR_UNUSED_25;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_26
+ x = _LIB9P_GETATTR_UNUSED_26;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_27
+ x = _LIB9P_GETATTR_UNUSED_27;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_28
+ x = _LIB9P_GETATTR_UNUSED_28;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_29
+ x = _LIB9P_GETATTR_UNUSED_29;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_30
+ x = _LIB9P_GETATTR_UNUSED_30;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_31
+ x = _LIB9P_GETATTR_UNUSED_31;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_32
+ x = _LIB9P_GETATTR_UNUSED_32;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_33
+ x = _LIB9P_GETATTR_UNUSED_33;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_34
+ x = _LIB9P_GETATTR_UNUSED_34;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_35
+ x = _LIB9P_GETATTR_UNUSED_35;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_36
+ x = _LIB9P_GETATTR_UNUSED_36;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_37
+ x = _LIB9P_GETATTR_UNUSED_37;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_38
+ x = _LIB9P_GETATTR_UNUSED_38;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_39
+ x = _LIB9P_GETATTR_UNUSED_39;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_40
+ x = _LIB9P_GETATTR_UNUSED_40;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_41
+ x = _LIB9P_GETATTR_UNUSED_41;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_42
+ x = _LIB9P_GETATTR_UNUSED_42;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_43
+ x = _LIB9P_GETATTR_UNUSED_43;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_44
+ x = _LIB9P_GETATTR_UNUSED_44;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_45
+ x = _LIB9P_GETATTR_UNUSED_45;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_46
+ x = _LIB9P_GETATTR_UNUSED_46;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_47
+ x = _LIB9P_GETATTR_UNUSED_47;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_48
+ x = _LIB9P_GETATTR_UNUSED_48;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_49
+ x = _LIB9P_GETATTR_UNUSED_49;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_50
+ x = _LIB9P_GETATTR_UNUSED_50;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_51
+ x = _LIB9P_GETATTR_UNUSED_51;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_52
+ x = _LIB9P_GETATTR_UNUSED_52;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_53
+ x = _LIB9P_GETATTR_UNUSED_53;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_54
+ x = _LIB9P_GETATTR_UNUSED_54;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_55
+ x = _LIB9P_GETATTR_UNUSED_55;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_56
+ x = _LIB9P_GETATTR_UNUSED_56;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_57
+ x = _LIB9P_GETATTR_UNUSED_57;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_58
+ x = _LIB9P_GETATTR_UNUSED_58;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_59
+ x = _LIB9P_GETATTR_UNUSED_59;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_60
+ x = _LIB9P_GETATTR_UNUSED_60;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_61
+ x = _LIB9P_GETATTR_UNUSED_61;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_62
+ x = _LIB9P_GETATTR_UNUSED_62;
+#endif
+#ifdef _LIB9P_GETATTR_UNUSED_63
+ x = _LIB9P_GETATTR_UNUSED_63;
+#endif
+#ifdef _LIB9P_LOCK_FLAGS_UNUSED_10
+ x = _LIB9P_LOCK_FLAGS_UNUSED_10;
+#endif
+#ifdef _LIB9P_LOCK_FLAGS_UNUSED_11
+ x = _LIB9P_LOCK_FLAGS_UNUSED_11;
+#endif
+#ifdef _LIB9P_LOCK_FLAGS_UNUSED_12
+ x = _LIB9P_LOCK_FLAGS_UNUSED_12;
+#endif
+#ifdef _LIB9P_LOCK_FLAGS_UNUSED_13
+ x = _LIB9P_LOCK_FLAGS_UNUSED_13;
+#endif
+#ifdef _LIB9P_LOCK_FLAGS_UNUSED_14
+ x = _LIB9P_LOCK_FLAGS_UNUSED_14;
+#endif
+#ifdef _LIB9P_LOCK_FLAGS_UNUSED_15
+ x = _LIB9P_LOCK_FLAGS_UNUSED_15;
+#endif
+#ifdef _LIB9P_LOCK_FLAGS_UNUSED_16
+ x = _LIB9P_LOCK_FLAGS_UNUSED_16;
+#endif
+#ifdef _LIB9P_LOCK_FLAGS_UNUSED_17
+ x = _LIB9P_LOCK_FLAGS_UNUSED_17;
+#endif
+#ifdef _LIB9P_LOCK_FLAGS_UNUSED_18
+ x = _LIB9P_LOCK_FLAGS_UNUSED_18;
+#endif
+#ifdef _LIB9P_LOCK_FLAGS_UNUSED_19
+ x = _LIB9P_LOCK_FLAGS_UNUSED_19;
+#endif
+#ifdef _LIB9P_LOCK_FLAGS_UNUSED_2
+ x = _LIB9P_LOCK_FLAGS_UNUSED_2;
+#endif
+#ifdef _LIB9P_LOCK_FLAGS_UNUSED_20
+ x = _LIB9P_LOCK_FLAGS_UNUSED_20;
+#endif
+#ifdef _LIB9P_LOCK_FLAGS_UNUSED_21
+ x = _LIB9P_LOCK_FLAGS_UNUSED_21;
+#endif
+#ifdef _LIB9P_LOCK_FLAGS_UNUSED_22
+ x = _LIB9P_LOCK_FLAGS_UNUSED_22;
+#endif
+#ifdef _LIB9P_LOCK_FLAGS_UNUSED_23
+ x = _LIB9P_LOCK_FLAGS_UNUSED_23;
+#endif
+#ifdef _LIB9P_LOCK_FLAGS_UNUSED_24
+ x = _LIB9P_LOCK_FLAGS_UNUSED_24;
+#endif
+#ifdef _LIB9P_LOCK_FLAGS_UNUSED_25
+ x = _LIB9P_LOCK_FLAGS_UNUSED_25;
+#endif
+#ifdef _LIB9P_LOCK_FLAGS_UNUSED_26
+ x = _LIB9P_LOCK_FLAGS_UNUSED_26;
+#endif
+#ifdef _LIB9P_LOCK_FLAGS_UNUSED_27
+ x = _LIB9P_LOCK_FLAGS_UNUSED_27;
+#endif
+#ifdef _LIB9P_LOCK_FLAGS_UNUSED_28
+ x = _LIB9P_LOCK_FLAGS_UNUSED_28;
+#endif
+#ifdef _LIB9P_LOCK_FLAGS_UNUSED_29
+ x = _LIB9P_LOCK_FLAGS_UNUSED_29;
+#endif
+#ifdef _LIB9P_LOCK_FLAGS_UNUSED_3
+ x = _LIB9P_LOCK_FLAGS_UNUSED_3;
+#endif
+#ifdef _LIB9P_LOCK_FLAGS_UNUSED_30
+ x = _LIB9P_LOCK_FLAGS_UNUSED_30;
+#endif
+#ifdef _LIB9P_LOCK_FLAGS_UNUSED_31
+ x = _LIB9P_LOCK_FLAGS_UNUSED_31;
+#endif
+#ifdef _LIB9P_LOCK_FLAGS_UNUSED_4
+ x = _LIB9P_LOCK_FLAGS_UNUSED_4;
+#endif
+#ifdef _LIB9P_LOCK_FLAGS_UNUSED_5
+ x = _LIB9P_LOCK_FLAGS_UNUSED_5;
+#endif
+#ifdef _LIB9P_LOCK_FLAGS_UNUSED_6
+ x = _LIB9P_LOCK_FLAGS_UNUSED_6;
+#endif
+#ifdef _LIB9P_LOCK_FLAGS_UNUSED_7
+ x = _LIB9P_LOCK_FLAGS_UNUSED_7;
+#endif
+#ifdef _LIB9P_LOCK_FLAGS_UNUSED_8
+ x = _LIB9P_LOCK_FLAGS_UNUSED_8;
+#endif
+#ifdef _LIB9P_LOCK_FLAGS_UNUSED_9
+ x = _LIB9P_LOCK_FLAGS_UNUSED_9;
+#endif
+#ifdef _LIB9P_LO_UNUSED_2
+ x = _LIB9P_LO_UNUSED_2;
+#endif
+#ifdef _LIB9P_LO_UNUSED_21
+ x = _LIB9P_LO_UNUSED_21;
+#endif
+#ifdef _LIB9P_LO_UNUSED_22
+ x = _LIB9P_LO_UNUSED_22;
+#endif
+#ifdef _LIB9P_LO_UNUSED_23
+ x = _LIB9P_LO_UNUSED_23;
+#endif
+#ifdef _LIB9P_LO_UNUSED_24
+ x = _LIB9P_LO_UNUSED_24;
+#endif
+#ifdef _LIB9P_LO_UNUSED_25
+ x = _LIB9P_LO_UNUSED_25;
+#endif
+#ifdef _LIB9P_LO_UNUSED_26
+ x = _LIB9P_LO_UNUSED_26;
+#endif
+#ifdef _LIB9P_LO_UNUSED_27
+ x = _LIB9P_LO_UNUSED_27;
+#endif
+#ifdef _LIB9P_LO_UNUSED_28
+ x = _LIB9P_LO_UNUSED_28;
+#endif
+#ifdef _LIB9P_LO_UNUSED_29
+ x = _LIB9P_LO_UNUSED_29;
+#endif
+#ifdef _LIB9P_LO_UNUSED_3
+ x = _LIB9P_LO_UNUSED_3;
+#endif
+#ifdef _LIB9P_LO_UNUSED_30
+ x = _LIB9P_LO_UNUSED_30;
+#endif
+#ifdef _LIB9P_LO_UNUSED_31
+ x = _LIB9P_LO_UNUSED_31;
+#endif
+#ifdef _LIB9P_LO_UNUSED_4
+ x = _LIB9P_LO_UNUSED_4;
+#endif
+#ifdef _LIB9P_LO_UNUSED_5
+ x = _LIB9P_LO_UNUSED_5;
+#endif
+#ifdef _LIB9P_MODE_UNUSED_16
+ x = _LIB9P_MODE_UNUSED_16;
+#endif
+#ifdef _LIB9P_MODE_UNUSED_17
+ x = _LIB9P_MODE_UNUSED_17;
+#endif
+#ifdef _LIB9P_MODE_UNUSED_18
+ x = _LIB9P_MODE_UNUSED_18;
+#endif
+#ifdef _LIB9P_MODE_UNUSED_19
+ x = _LIB9P_MODE_UNUSED_19;
+#endif
+#ifdef _LIB9P_MODE_UNUSED_20
+ x = _LIB9P_MODE_UNUSED_20;
+#endif
+#ifdef _LIB9P_MODE_UNUSED_21
+ x = _LIB9P_MODE_UNUSED_21;
+#endif
+#ifdef _LIB9P_MODE_UNUSED_22
+ x = _LIB9P_MODE_UNUSED_22;
+#endif
+#ifdef _LIB9P_MODE_UNUSED_23
+ x = _LIB9P_MODE_UNUSED_23;
+#endif
+#ifdef _LIB9P_MODE_UNUSED_24
+ x = _LIB9P_MODE_UNUSED_24;
+#endif
+#ifdef _LIB9P_MODE_UNUSED_25
+ x = _LIB9P_MODE_UNUSED_25;
+#endif
+#ifdef _LIB9P_MODE_UNUSED_26
+ x = _LIB9P_MODE_UNUSED_26;
+#endif
+#ifdef _LIB9P_MODE_UNUSED_27
+ x = _LIB9P_MODE_UNUSED_27;
+#endif
+#ifdef _LIB9P_MODE_UNUSED_28
+ x = _LIB9P_MODE_UNUSED_28;
+#endif
+#ifdef _LIB9P_MODE_UNUSED_29
+ x = _LIB9P_MODE_UNUSED_29;
+#endif
+#ifdef _LIB9P_MODE_UNUSED_30
+ x = _LIB9P_MODE_UNUSED_30;
+#endif
+#ifdef _LIB9P_MODE_UNUSED_31
+ x = _LIB9P_MODE_UNUSED_31;
+#endif
+#ifdef _LIB9P_O_RESERVED_CEXEC
+ x = _LIB9P_O_RESERVED_CEXEC;
+#endif
+#ifdef _LIB9P_O_UNUSED_2
+ x = _LIB9P_O_UNUSED_2;
+#endif
+#ifdef _LIB9P_O_UNUSED_3
+ x = _LIB9P_O_UNUSED_3;
+#endif
+#ifdef _LIB9P_O_UNUSED_7
+ x = _LIB9P_O_UNUSED_7;
+#endif
+#ifdef _LIB9P_QT_PLAN9_MOUNT
+ x = _LIB9P_QT_PLAN9_MOUNT;
+#endif
+#ifdef _LIB9P_QT_UNUSED_0
+ x = _LIB9P_QT_UNUSED_0;
+#endif
+#ifdef _LIB9P_SETATTR_UNUSED_10
+ x = _LIB9P_SETATTR_UNUSED_10;
+#endif
+#ifdef _LIB9P_SETATTR_UNUSED_11
+ x = _LIB9P_SETATTR_UNUSED_11;
+#endif
+#ifdef _LIB9P_SETATTR_UNUSED_12
+ x = _LIB9P_SETATTR_UNUSED_12;
+#endif
+#ifdef _LIB9P_SETATTR_UNUSED_13
+ x = _LIB9P_SETATTR_UNUSED_13;
+#endif
+#ifdef _LIB9P_SETATTR_UNUSED_14
+ x = _LIB9P_SETATTR_UNUSED_14;
+#endif
+#ifdef _LIB9P_SETATTR_UNUSED_15
+ x = _LIB9P_SETATTR_UNUSED_15;
+#endif
+#ifdef _LIB9P_SETATTR_UNUSED_16
+ x = _LIB9P_SETATTR_UNUSED_16;
+#endif
+#ifdef _LIB9P_SETATTR_UNUSED_17
+ x = _LIB9P_SETATTR_UNUSED_17;
+#endif
+#ifdef _LIB9P_SETATTR_UNUSED_18
+ x = _LIB9P_SETATTR_UNUSED_18;
+#endif
+#ifdef _LIB9P_SETATTR_UNUSED_19
+ x = _LIB9P_SETATTR_UNUSED_19;
+#endif
+#ifdef _LIB9P_SETATTR_UNUSED_20
+ x = _LIB9P_SETATTR_UNUSED_20;
+#endif
+#ifdef _LIB9P_SETATTR_UNUSED_21
+ x = _LIB9P_SETATTR_UNUSED_21;
+#endif
+#ifdef _LIB9P_SETATTR_UNUSED_22
+ x = _LIB9P_SETATTR_UNUSED_22;
+#endif
+#ifdef _LIB9P_SETATTR_UNUSED_23
+ x = _LIB9P_SETATTR_UNUSED_23;
+#endif
+#ifdef _LIB9P_SETATTR_UNUSED_24
+ x = _LIB9P_SETATTR_UNUSED_24;
+#endif
+#ifdef _LIB9P_SETATTR_UNUSED_25
+ x = _LIB9P_SETATTR_UNUSED_25;
+#endif
+#ifdef _LIB9P_SETATTR_UNUSED_26
+ x = _LIB9P_SETATTR_UNUSED_26;
+#endif
+#ifdef _LIB9P_SETATTR_UNUSED_27
+ x = _LIB9P_SETATTR_UNUSED_27;
+#endif
+#ifdef _LIB9P_SETATTR_UNUSED_28
+ x = _LIB9P_SETATTR_UNUSED_28;
+#endif
+#ifdef _LIB9P_SETATTR_UNUSED_29
+ x = _LIB9P_SETATTR_UNUSED_29;
+#endif
+#ifdef _LIB9P_SETATTR_UNUSED_30
+ x = _LIB9P_SETATTR_UNUSED_30;
+#endif
+#ifdef _LIB9P_SETATTR_UNUSED_31
+ x = _LIB9P_SETATTR_UNUSED_31;
+#endif
+#ifdef _LIB9P_SETATTR_UNUSED_9
+ x = _LIB9P_SETATTR_UNUSED_9;
+#endif
+ return 0;
}
diff --git a/lib9p/tests/test_compile.c.gen b/lib9p/tests/test_compile.c.gen
index 1289943..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 ' [[gnu::unused]] uint64_t x;'
- sed -nE 's/^\s*#\s*define\s*(\S[^ (]*)\s.*/ x = \1;/p' <"$generated_h"
- 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 f899dfa..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
@@ -7,13 +7,20 @@
#ifndef _CONFIG_H_
#define _CONFIG_H_
-#define CONFIG_9P_MAX_ERR_SIZE 128
+/* 9P *************************************************************************/
+
#define CONFIG_9P_MAX_9P2000_e_WELEM 16
-#define CONFIG_9P_ENABLE_9P2000 1 /* bool */
-#define CONFIG_9P_ENABLE_9P2000_u 1 /* bool */
-#define CONFIG_9P_ENABLE_9P2000_e 1 /* bool */
-#define CONFIG_9P_ENABLE_9P2000_L 1 /* bool */
-#define CONFIG_9P_ENABLE_9P2000_p9p 1 /* bool */
+/* 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_NAME_LEN 16
+#define CONFIG_COROUTINE_MEASURE_STACK 1 /* bool */
#endif /* _CONFIG_H_ */
diff --git a/lib9p/tests/test_server/CMakeLists.txt b/lib9p/tests/test_server/CMakeLists.txt
index b659373..bdb46e2 100644
--- a/lib9p/tests/test_server/CMakeLists.txt
+++ b/lib9p/tests/test_server/CMakeLists.txt
@@ -9,8 +9,8 @@ if (PICO_PLATFORM STREQUAL "host")
add_library(test_server_objs OBJECT
main.c
+ fs_flush.c
fs_shutdown.c
- fs_slowread.c
fs_whoami.c
)
target_include_directories(test_server_objs PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/config)
@@ -25,13 +25,13 @@ target_link_libraries(test_server_objs
# Analyze the stack ############################################################
-add_stack_analysis(test_server_stack.c test_server_objs)
+#add_stack_analysis(stack.c test_server_objs)
# Link #########################################################################
add_executable(test_server)
target_sources(test_server PRIVATE
- test_server_stack.c
+ #stack.c
"$<TARGET_OBJECTS:test_server_objs>"
)
diff --git a/lib9p/tests/test_server/config/config.h b/lib9p/tests/test_server/config/config.h
index d9cf008..4350529 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/test/test_server
*
* Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
@@ -12,7 +12,15 @@
/* 9P *************************************************************************/
-#define CONFIG_9P_MAX_ERR_SIZE 128 /* 128 is what Plan 9 4e uses */
+#define CONFIG_9P_ENABLE_9P2000 1 /* bool */
+#define CONFIG_9P_ENABLE_9P2000_u 1 /* bool */
+#define CONFIG_9P_ENABLE_9P2000_e 0 /* bool */
+#define CONFIG_9P_ENABLE_9P2000_L 0 /* bool */
+#define CONFIG_9P_ENABLE_9P2000_p9p 0 /* bool */
+
+/* 9P_SRV *********************************************************************/
+
+#define CONFIG_9P_SRV_DEBUG 1 /* bool */
/**
* This max-msg-size is sized so that a Twrite message can return
@@ -32,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)
@@ -39,12 +48,6 @@
*/
#define CONFIG_9P_SRV_MAX_HOSTMSG_SIZE CONFIG_9P_SRV_MAX_MSG_SIZE+16
-#define CONFIG_9P_ENABLE_9P2000 1 /* bool */
-#define CONFIG_9P_ENABLE_9P2000_u 1 /* bool */
-#define CONFIG_9P_ENABLE_9P2000_e 0 /* bool */
-#define CONFIG_9P_ENABLE_9P2000_L 0 /* bool */
-#define CONFIG_9P_ENABLE_9P2000_p9p 0 /* bool */
-
/* COROUTINE ******************************************************************/
#define CONFIG_COROUTINE_STACK_SIZE_DEFAULT (32*1024)
diff --git a/lib9p/tests/test_server/fs_flush.c b/lib9p/tests/test_server/fs_flush.c
new file mode 100644
index 0000000..c8152d4
--- /dev/null
+++ b/lib9p/tests/test_server/fs_flush.c
@@ -0,0 +1,128 @@
+/* lib9p/tests/test_server/fs_flush.c - flush-* API endpoints
+ *
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <libmisc/alloc.h>
+
+#define IMPLEMENTATION_FOR_LIB9P_SRV_H YES /* for ctx->flush_ch */
+#include "fs_flush.h"
+
+LO_IMPLEMENTATION_C(lib9p_srv_file, struct flush_file, flush_file);
+
+struct flush_fio {
+ struct flush_file *parent;
+};
+LO_IMPLEMENTATION_STATIC(lib9p_srv_fio, struct flush_fio, flush_fio);
+
+/* srv_file *******************************************************************/
+
+void flush_file_free(struct flush_file *self) {
+ assert(self);
+}
+struct lib9p_qid flush_file_qid(struct flush_file *self) {
+ assert(self);
+ return (struct lib9p_qid){
+ .type = LIB9P_QT_FILE,
+ .vers = 1,
+ .path = self->pathnum,
+ };
+}
+
+error flush_file_stat(struct flush_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_srv_stat *out) {
+ assert(self);
+ assert(ctx);
+ assert(out);
+
+ *out = ((struct lib9p_srv_stat){
+ .qid = flush_file_qid(self),
+ .mode = 0444,
+ .atime_sec = UTIL9P_ATIME,
+ .mtime_sec = UTIL9P_MTIME,
+ .size = 6,
+ .name = lib9p_str(self->name),
+ .owner_uid = { .name = lib9p_str("root"), .num = 0 },
+ .owner_gid = { .name = lib9p_str("root"), .num = 0 },
+ .last_modifier_uid = { .name = lib9p_str("root"), .num = 0 },
+ .extension = lib9p_str(NULL),
+ });
+ return ERROR_NULL;
+}
+error flush_file_wstat(struct flush_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_srv_stat) {
+ assert(self);
+ assert(ctx);
+ return error_new(E_POSIX_EROFS, "cannot wstat API file");
+}
+error flush_file_remove(struct flush_file *self, struct lib9p_srv_ctx *ctx) {
+ assert(self);
+ assert(ctx);
+ return error_new(E_POSIX_EROFS, "cannot remove API file");
+}
+
+LIB9P_SRV_NOTDIR(, struct flush_file, flush_file);
+
+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 ERROR_NEW_VAL(lib9p_srv_fio, LO_BOX(lib9p_srv_fio, ret));
+}
+
+/* srv_fio ********************************************************************/
+
+static void flush_fio_iofree(struct flush_fio *self) {
+ assert(self);
+ free(self);
+}
+
+static struct lib9p_qid flush_fio_ioqid(struct flush_fio *self) {
+ assert(self);
+ return flush_file_qid(self->parent);
+}
+
+static uint32_t flush_fio_iounit(struct flush_fio *self) {
+ assert(self);
+ return 0;
+}
+
+static uint32_t_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 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);
+
+ /* Wait for first Tflush */
+ while (!lib9p_srv_flush_requested(ctx))
+ cr_yield();
+
+ /* Wait for the specified number of Tflush (may be higher *or*
+ * lower than 1; lower would mean that the first Tflush needs
+ * to be flushed itself). */
+ while (cr_chan_num_waiters(&ctx->flush_ch) != self->parent->flush_cnt)
+ cr_yield();
+
+ /* Yield one more time, just because. */
+ cr_yield();
+
+ /* Return */
+ switch (self->parent->flush_behavior) {
+ case FLUSH_READ:
+ return io_write(dst, "Sloth\n", 6 < byte_count ? 6 : byte_count).err;
+ case FLUSH_ERROR:
+ return error_new(E_POSIX_EAGAIN, "request canceled by flush");
+ case FLUSH_SILENT:
+ return error_new(E_POSIX_ECANCELED, "request canceled by flush");
+ default:
+ assert_notreached("invalid flush_behavior");
+ }
+}
diff --git a/lib9p/tests/test_server/fs_flush.h b/lib9p/tests/test_server/fs_flush.h
new file mode 100644
index 0000000..023434b
--- /dev/null
+++ b/lib9p/tests/test_server/fs_flush.h
@@ -0,0 +1,26 @@
+/* lib9p/tests/test_server/fs_flush.h - flush-* API endpoints
+ *
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#ifndef _LIB9P_TESTS_TEST_SERVER_FS_FLUSH_H_
+#define _LIB9P_TESTS_TEST_SERVER_FS_FLUSH_H_
+
+#include <libhw/host_net.h>
+#include <util9p/static.h>
+
+struct flush_file {
+ char *name;
+ uint64_t pathnum;
+
+ unsigned int flush_cnt;
+ enum {
+ FLUSH_READ,
+ FLUSH_ERROR,
+ FLUSH_SILENT,
+ } flush_behavior;
+};
+LO_IMPLEMENTATION_H(lib9p_srv_file, struct flush_file, flush_file);
+
+#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 e872b78..53a243b 100644
--- a/lib9p/tests/test_server/fs_shutdown.c
+++ b/lib9p/tests/test_server/fs_shutdown.c
@@ -4,74 +4,71 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-#include <stdlib.h>
+#include <libmisc/alloc.h>
#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,
+ .type = LIB9P_QT_FILE | LIB9P_QT_APPEND,
.vers = 1,
.path = self->pathnum,
};
}
-static struct lib9p_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_stat){
- .kern_type = 0,
- .kern_dev = 0,
- .file_qid = shutdown_file_qid(self),
- .file_mode = 0222,
- .file_atime = UTIL9P_ATIME,
- .file_mtime = UTIL9P_MTIME,
- .file_size = 0,
- .file_name = lib9p_str(self->name),
- .file_owner_uid = lib9p_str("root"),
- .file_owner_gid = lib9p_str("root"),
- .file_last_modified_uid = lib9p_str("root"),
- .file_extension = lib9p_str(NULL),
- .file_owner_n_uid = 0,
- .file_owner_n_gid = 0,
- .file_last_modified_n_uid = 0,
- };
+ assert(out);
+
+ *out = ((struct lib9p_srv_stat){
+ .qid = shutdown_file_qid(self),
+ .mode = 0222 | LIB9P_DM_APPEND,
+ .atime_sec = UTIL9P_ATIME,
+ .mtime_sec = UTIL9P_MTIME,
+ .size = 0,
+ .name = lib9p_str(self->name),
+ .owner_uid = { .name=lib9p_str("root"), .num=0 },
+ .owner_gid = { .name=lib9p_str("root"), .num=0 },
+ .last_modifier_uid = { .name=lib9p_str("root"), .num=0 },
+ .extension = lib9p_str(NULL),
+ });
+ return ERROR_NULL;
}
-static void shutdown_file_wstat(struct shutdown_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_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 = malloc(sizeof(struct shutdown_fio));
+ 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 ********************************************************************/
@@ -81,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);
}
@@ -91,18 +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 LM_UNUSED(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_slowread.c b/lib9p/tests/test_server/fs_slowread.c
deleted file mode 100644
index c94fba0..0000000
--- a/lib9p/tests/test_server/fs_slowread.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/* lib9p/tests/test_server/fs_slowread.c - slowread API endpoint
- *
- * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-#include <stdlib.h>
-
-#include "fs_slowread.h"
-
-LO_IMPLEMENTATION_C(lib9p_srv_file, struct slowread_file, slowread_file, static);
-
-struct slowread_fio {
- struct slowread_file *parent;
-};
-LO_IMPLEMENTATION_H(lib9p_srv_fio, struct slowread_fio, slowread_fio);
-LO_IMPLEMENTATION_C(lib9p_srv_fio, struct slowread_fio, slowread_fio, static);
-
-/* srv_file *******************************************************************/
-
-static void slowread_file_free(struct slowread_file *self) {
- assert(self);
-}
-static struct lib9p_qid slowread_file_qid(struct slowread_file *self) {
- assert(self);
- return (struct lib9p_qid){
- .type = LIB9P_QT_FILE,
- .vers = 1,
- .path = self->pathnum,
- };
-}
-
-static struct lib9p_stat slowread_file_stat(struct slowread_file *self, struct lib9p_srv_ctx *ctx) {
- assert(self);
- assert(ctx);
- return (struct lib9p_stat){
- .kern_type = 0,
- .kern_dev = 0,
- .file_qid = slowread_file_qid(self),
- .file_mode = 0444,
- .file_atime = UTIL9P_ATIME,
- .file_mtime = UTIL9P_MTIME,
- .file_size = 6,
- .file_name = lib9p_str(self->name),
- .file_owner_uid = lib9p_str("root"),
- .file_owner_gid = lib9p_str("root"),
- .file_last_modified_uid = lib9p_str("root"),
- .file_extension = lib9p_str(NULL),
- .file_owner_n_uid = 0,
- .file_owner_n_gid = 0,
- .file_last_modified_n_uid = 0,
- };
-}
-static void slowread_file_wstat(struct slowread_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_stat) {
- assert(self);
- assert(ctx);
- lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "cannot wstat API file");
-}
-static void slowread_file_remove(struct slowread_file *self, struct lib9p_srv_ctx *ctx) {
- assert(self);
- assert(ctx);
- lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "cannot remove API file");
-}
-
-LIB9P_SRV_NOTDIR(struct slowread_file, slowread_file)
-
-static lo_interface lib9p_srv_fio slowread_file_fopen(struct slowread_file *self, struct lib9p_srv_ctx *ctx, bool, bool, bool) {
- assert(self);
- assert(ctx);
-
- struct slowread_fio *ret = malloc(sizeof(struct slowread_fio));
- ret->parent = self;
-
- return lo_box_slowread_fio_as_lib9p_srv_fio(ret);
-}
-
-/* srv_fio ********************************************************************/
-
-static void slowread_fio_iofree(struct slowread_fio *self) {
- assert(self);
- free(self);
-}
-
-static struct lib9p_qid slowread_fio_qid(struct slowread_fio *self) {
- assert(self);
- return slowread_file_qid(self->parent);
-}
-
-static uint32_t slowread_fio_iounit(struct slowread_fio *self) {
- assert(self);
- return 0;
-}
-
-static uint32_t slowread_fio_pwrite(struct slowread_fio *LM_UNUSED(self),
- struct lib9p_srv_ctx *LM_UNUSED(ctx),
- void *LM_UNUSED(buf), uint32_t LM_UNUSED(byte_count),
- uint64_t LM_UNUSED(offset)) {
- assert_notreached("not writable");
-}
-static void slowread_fio_pread(struct slowread_fio *self, struct lib9p_srv_ctx *ctx,
- uint32_t byte_count, uint64_t LM_UNUSED(byte_offset),
- struct iovec *ret) {
- assert(self);
- assert(ctx);
- assert(ret);
-
- while (!lib9p_srv_flush_requested(ctx))
- cr_yield();
- if (self->parent->flushable)
- lib9p_srv_acknowledge_flush(ctx);
- else
- *ret = (struct iovec){
- .iov_base = "Sloth\n",
- .iov_len = 6 < byte_count ? 6 : byte_count,
- };
-}
diff --git a/lib9p/tests/test_server/fs_slowread.h b/lib9p/tests/test_server/fs_slowread.h
deleted file mode 100644
index ef4b65f..0000000
--- a/lib9p/tests/test_server/fs_slowread.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/* lib9p/tests/test_server/fs_slowread.h - slowread API endpoint
- *
- * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-#ifndef _LIB9P_TESTS_TEST_SERVER_FS_SLOWREAD_H_
-#define _LIB9P_TESTS_TEST_SERVER_FS_SLOWREAD_H_
-
-#include <util9p/static.h>
-#include <libhw/host_net.h>
-
-struct slowread_file {
- char *name;
- uint64_t pathnum;
-
- bool flushable;
-};
-LO_IMPLEMENTATION_H(lib9p_srv_file, struct slowread_file, slowread_file);
-#define lo_box_slowread_file_as_lib9p_srv_file(obj) util9p_box(slowread_file, obj)
-
-#endif /* _LIB9P_TESTS_TEST_SERVER_FS_SLOWREAD_H_ */
diff --git a/lib9p/tests/test_server/fs_whoami.c b/lib9p/tests/test_server/fs_whoami.c
index 560e31f..a07fdba 100644
--- a/lib9p/tests/test_server/fs_whoami.c
+++ b/lib9p/tests/test_server/fs_whoami.c
@@ -4,27 +4,29 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-#include <stdio.h> /* for snprintf() */
-#include <stdlib.h> /* for malloc(), 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);
- assert(ctx->authinfo);
+ assert(ctx->user);
size_t len = 0;
- uint32_t uid = ctx->authinfo->uid;
+ uint32_t uid = ctx->user->num;
while (uid) {
len++;
uid /= 10;
@@ -32,16 +34,16 @@ size_t whoami_len(struct lib9p_srv_ctx *ctx) {
if (!len)
len++;
len += 2;
- len += ctx->authinfo->uname.len;
+ len += ctx->user->name.len;
return len;
}
/* 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,
@@ -50,51 +52,48 @@ static struct lib9p_qid whoami_file_qid(struct whoami_file *self) {
};
}
-static struct lib9p_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);
-
- return (struct lib9p_stat){
- .kern_type = 0,
- .kern_dev = 0,
- .file_qid = whoami_file_qid(self),
- .file_mode = 0444,
- .file_atime = UTIL9P_ATIME,
- .file_mtime = UTIL9P_MTIME,
- .file_size = whoami_len(ctx),
- .file_name = lib9p_str(self->name),
- .file_owner_uid = lib9p_str("root"),
- .file_owner_gid = lib9p_str("root"),
- .file_last_modified_uid = lib9p_str("root"),
- .file_extension = lib9p_str(NULL),
- .file_owner_n_uid = 0,
- .file_owner_n_gid = 0,
- .file_last_modified_n_uid = 0,
- };
+ assert(out);
+
+ *out = ((struct lib9p_srv_stat){
+ .qid = whoami_file_qid(self),
+ .mode = 0444,
+ .atime_sec = UTIL9P_ATIME,
+ .mtime_sec = UTIL9P_MTIME,
+ .size = whoami_len(ctx),
+ .name = lib9p_str(self->name),
+ .owner_uid = { .name=lib9p_str("root"), .num=0 },
+ .owner_gid = { .name=lib9p_str("root"), .num=0 },
+ .last_modifier_uid = { .name=lib9p_str("root"), .num=0 },
+ .extension = lib9p_str(NULL),
+ });
+ return ERROR_NULL;
}
-static void whoami_file_wstat(struct whoami_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_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);
- struct whoami_fio *ret = malloc(sizeof(struct whoami_fio));
+ struct whoami_fio *ret = heap_alloc(1, struct whoami_fio);
ret->parent = self;
ret->buf_len = 0;
ret->buf = NULL;
- return lo_box_whoami_fio_as_lib9p_srv_fio(ret);
+ return ERROR_NEW_VAL(lib9p_srv_fio, LO_BOX(lib9p_srv_fio, ret));
}
/* srv_fio ********************************************************************/
@@ -106,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);
@@ -117,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) {
@@ -136,21 +133,15 @@ static void whoami_fio_pread(struct whoami_fio *self, struct lib9p_srv_ctx *ctx,
self->buf_len = data_size+1;
}
snprintf(self->buf, self->buf_len, "%"PRIu32" %.*s\n",
- ctx->authinfo->uid, ctx->authinfo->uname.len, ctx->authinfo->uname.utf8);
+ 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 0705747..2519372 100644
--- a/lib9p/tests/test_server/main.c
+++ b/lib9p/tests/test_server/main.c
@@ -4,24 +4,27 @@
* 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"
+#include "fs_flush.h"
#include "fs_shutdown.h"
-#include "fs_slowread.h"
#include "fs_whoami.h"
+#include "static.h"
/* configuration **************************************************************/
@@ -36,11 +39,11 @@
/* 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);
-const char *hexdig = "0123456789abcdef";
+static const char *hexdig = "0123456789abcdef";
-struct {
+static struct {
uint16_t port;
struct hostnet_tcp_listener listeners[_CONFIG_9P_MAX_CONNS];
struct lib9p_srv srv;
@@ -67,7 +70,7 @@ struct {
__VA_OPT__(,) __VA_ARGS__ \
}))
-struct lib9p_srv_file root =
+static struct lib9p_srv_file root =
STATIC_DIR(1, "",
STATIC_DIR(2, "Documentation",
STATIC_FILE(3, "x", Documentation_x_txt),
@@ -76,15 +79,16 @@ struct lib9p_srv_file root =
API_FILE(5, "shutdown", shutdown,
.listeners = globals.listeners,
.nlisteners = LM_ARRAY_LEN(globals.listeners)),
- API_FILE(6, "slowread", slowread,
- .flushable = false),
- API_FILE(7, "slowread-flushable", slowread,
- .flushable = true),
API_FILE(8, "whoami", whoami),
+ API_FILE(9, "flush-read", flush, .flush_cnt=1, .flush_behavior=FLUSH_READ),
+ API_FILE(10, "flush-error", flush, .flush_cnt=1, .flush_behavior=FLUSH_ERROR),
+ API_FILE(11, "flush-silent", flush, .flush_cnt=1, .flush_behavior=FLUSH_SILENT),
+ API_FILE(12, "flush-slowsilent", flush, .flush_cnt=2, .flush_behavior=FLUSH_SILENT),
+ API_FILE(13, "flush-slowread", flush, .flush_cnt=0, .flush_behavior=FLUSH_READ),
);
-static lo_interface lib9p_srv_file get_root(struct lib9p_srv_ctx *LM_UNUSED(ctx), struct lib9p_s LM_UNUSED(treename)) {
- 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 ***********************************************************************/
@@ -95,7 +99,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();
}
@@ -116,50 +120,53 @@ 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();
}
-static void log_fct(char character, void *_stream) {
- FILE *stream = _stream;
- putc(character, stream);
- putchar(character);
+struct tstlog_stdout {};
+LO_IMPLEMENTATION_STATIC(fmt_dest, struct tstlog_stdout, tstlog_stdout);
+
+static size_t tstlog_bytes = 0;
+
+static void tstlog_stdout_putb(struct tstlog_stdout *, uint8_t b) {
+ putc(b, globals.logstream);
+ putchar(b);
+ tstlog_bytes++;
+}
+
+static size_t tstlog_stdout_tell(struct tstlog_stdout *) {
+ return tstlog_bytes;
}
-static void log_msg(struct lib9p_srv_ctx *ctx, enum lib9p_msg_type typ, void *hostmsg) {
- /* It sucks that %v trips -Wformat and -Wformat-extra-args
- * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47781 */
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wformat"
-#pragma GCC diagnostic ignored "-Wformat-extra-args"
- fmt_fctprintf(log_fct, globals.logstream,
- "%c %v\n", typ % 2 ? '<' : '>',
- lo_box_lib9p_msg_as_fmt_formatter(&ctx->basectx, typ, hostmsg));
-#pragma GCC diagnostic pop
+static lo_interface fmt_dest tstlog_dest = { .vtable = &_lo_tstlog_stdout_fmt_dest_vtable };
+
+static void tstlog_msg(struct lib9p_srv_ctx *ctx, enum lib9p_msg_type typ, void *hostmsg) {
+ fmt_print(tstlog_dest, typ % 2 ? "< " : "> ", (lib9p_msg, &ctx->basectx, typ, hostmsg), "\n");
fflush(globals.logstream);
}
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");
- globals.srv.msglog = log_msg;
+ __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-p9p b/lib9p/tests/testclient-p9p
index 9c9fb5e..09ce746 100755
--- a/lib9p/tests/testclient-p9p
+++ b/lib9p/tests/testclient-p9p
@@ -25,9 +25,12 @@ out=$("${client[@]}" ls -l '')
expect_lines \
'd-r-xr-xr-x M 0 root root 0 Oct 7 2024 Documentation' \
'--r--r--r-- M 0 root root 166 Oct 7 2024 README.md' \
- '---w--w--w- M 0 root root 0 Oct 7 2024 shutdown' \
- '--r--r--r-- M 0 root root 6 Oct 7 2024 slowread' \
- '--r--r--r-- M 0 root root 6 Oct 7 2024 slowread-flushable' \
+ '--r--r--r-- M 0 root root 6 Oct 7 2024 flush-error' \
+ '--r--r--r-- M 0 root root 6 Oct 7 2024 flush-read' \
+ '--r--r--r-- M 0 root root 6 Oct 7 2024 flush-silent' \
+ '--r--r--r-- M 0 root root 6 Oct 7 2024 flush-slowread' \
+ '--r--r--r-- M 0 root root 6 Oct 7 2024 flush-slowsilent' \
+ 'a--w--w--w- M 0 root root 0 Oct 7 2024 shutdown' \
'--r--r--r-- M 0 root root 9 Oct 7 2024 whoami'
out=$("${client[@]}" ls -l 'Documentation/')
diff --git a/lib9p/tests/testclient-p9p.explog b/lib9p/tests/testclient-p9p.explog
index e5901d2..54f1e4b 100644
--- a/lib9p/tests/testclient-p9p.explog
+++ b/lib9p/tests/testclient-p9p.explog
@@ -4,14 +4,14 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
> Tversion { tag=NOTAG max_msg_size=8192 version="9P2000" }
< Rversion { tag=NOTAG max_msg_size=4120 version="9P2000" }
-> Tauth { tag=0 afid=0 uname="nobody" aname="" n_uid=0 }
+> Tauth { tag=0 afid=0 uname="nobody" aname="" unum=0 }
< Rerror { tag=0 errstr="authentication not required" errnum=L_EOPNOTSUPP }
-> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" n_uid=0 }
+> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" unum=0 }
< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } }
> Twalk { tag=0 fid=0 newfid=1 nwname=0 wname=[ ] }
< Rwalk { tag=0 nwqid=0 wqid=[ ] }
> Tstat { tag=0 fid=1 }
-< Rstat { tag=0 stat={ kern_type=0 kern_dev=0 file_qid={ type=(DIR) vers=1 path=1 } file_mode=(DIR|0555) file_atime=1728337905 file_mtime=1728337904 file_size=0 file_name="" file_owner_uid="root" file_owner_gid="root" file_last_modified_uid="root" file_extension="" file_owner_n_uid=0 file_owner_n_gid=0 file_last_modified_n_uid=0 } }
+< Rstat { tag=0 stat={ fstype=0 fsdev=0 qid={ type=(DIR) vers=1 path=1 } mode=(DIR|0555) atime=1728337905 mtime=1728337904 length=0 name="" owner_uname="root" owner_gname="root" last_modifier_uname="root" extension="" owner_unum=0 owner_gnum=0 last_modifier_unum=0 } }
> Tclunk { tag=0 fid=1 }
< Rclunk { tag=0 }
> Twalk { tag=0 fid=0 newfid=1 nwname=0 wname=[ ] }
@@ -19,21 +19,21 @@
> Topen { tag=0 fid=1 mode=(MODE_READ) }
< Ropen { tag=0 qid={ type=(DIR) vers=1 path=1 } iounit=0 }
> Tread { tag=0 fid=1 offset=0 count=4096 }
-< Rread { tag=0 count=428 data=<bytedata> }
-> Tread { tag=0 fid=1 offset=428 count=4096 }
+< Rread { tag=0 count=648 data=<bytedata> }
+> Tread { tag=0 fid=1 offset=648 count=4096 }
< Rread { tag=0 count=0 data="" }
> Tclunk { tag=0 fid=1 }
< Rclunk { tag=0 }
> Tversion { tag=NOTAG max_msg_size=8192 version="9P2000" }
< Rversion { tag=NOTAG max_msg_size=4120 version="9P2000" }
-> Tauth { tag=0 afid=0 uname="nobody" aname="" n_uid=0 }
+> Tauth { tag=0 afid=0 uname="nobody" aname="" unum=0 }
< Rerror { tag=0 errstr="authentication not required" errnum=L_EOPNOTSUPP }
-> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" n_uid=0 }
+> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" unum=0 }
< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } }
> Twalk { tag=0 fid=0 newfid=1 nwname=1 wname=[ "Documentation" ] }
< Rwalk { tag=0 nwqid=1 wqid=[ { type=(DIR) vers=1 path=2 } ] }
> Tstat { tag=0 fid=1 }
-< Rstat { tag=0 stat={ kern_type=0 kern_dev=0 file_qid={ type=(DIR) vers=1 path=2 } file_mode=(DIR|0555) file_atime=1728337905 file_mtime=1728337904 file_size=0 file_name="Documentation" file_owner_uid="root" file_owner_gid="root" file_last_modified_uid="root" file_extension="" file_owner_n_uid=0 file_owner_n_gid=0 file_last_modified_n_uid=0 } }
+< Rstat { tag=0 stat={ fstype=0 fsdev=0 qid={ type=(DIR) vers=1 path=2 } mode=(DIR|0555) atime=1728337905 mtime=1728337904 length=0 name="Documentation" owner_uname="root" owner_gname="root" last_modifier_uname="root" extension="" owner_unum=0 owner_gnum=0 last_modifier_unum=0 } }
> Tclunk { tag=0 fid=1 }
< Rclunk { tag=0 }
> Twalk { tag=0 fid=0 newfid=1 nwname=1 wname=[ "Documentation" ] }
@@ -48,9 +48,9 @@
< Rclunk { tag=0 }
> Tversion { tag=NOTAG max_msg_size=8192 version="9P2000" }
< Rversion { tag=NOTAG max_msg_size=4120 version="9P2000" }
-> Tauth { tag=0 afid=0 uname="nobody" aname="" n_uid=0 }
+> Tauth { tag=0 afid=0 uname="nobody" aname="" unum=0 }
< Rerror { tag=0 errstr="authentication not required" errnum=L_EOPNOTSUPP }
-> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" n_uid=0 }
+> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" unum=0 }
< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } }
> Twalk { tag=0 fid=0 newfid=1 nwname=1 wname=[ "README.md" ] }
< Rwalk { tag=0 nwqid=1 wqid=[ { type=(0) vers=1 path=4 } ] }
@@ -64,9 +64,9 @@
< Rclunk { tag=0 }
> Tversion { tag=NOTAG max_msg_size=8192 version="9P2000" }
< Rversion { tag=NOTAG max_msg_size=4120 version="9P2000" }
-> Tauth { tag=0 afid=0 uname="nobody" aname="" n_uid=0 }
+> Tauth { tag=0 afid=0 uname="nobody" aname="" unum=0 }
< Rerror { tag=0 errstr="authentication not required" errnum=L_EOPNOTSUPP }
-> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" n_uid=0 }
+> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" unum=0 }
< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } }
> Twalk { tag=0 fid=0 newfid=1 nwname=2 wname=[ "Documentation", "x" ] }
< Rwalk { tag=0 nwqid=2 wqid=[ { type=(DIR) vers=1 path=2 }, { type=(0) vers=1 path=3 } ] }
@@ -80,26 +80,26 @@
< Rclunk { tag=0 }
> Tversion { tag=NOTAG max_msg_size=8192 version="9P2000" }
< Rversion { tag=NOTAG max_msg_size=4120 version="9P2000" }
-> Tauth { tag=0 afid=0 uname="nobody" aname="" n_uid=0 }
+> Tauth { tag=0 afid=0 uname="nobody" aname="" unum=0 }
< Rerror { tag=0 errstr="authentication not required" errnum=L_EOPNOTSUPP }
-> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" n_uid=0 }
+> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" unum=0 }
< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } }
> Twalk { tag=0 fid=0 newfid=1 nwname=2 wname=[ "Documentation", "x" ] }
< Rwalk { tag=0 nwqid=2 wqid=[ { type=(DIR) vers=1 path=2 }, { type=(0) vers=1 path=3 } ] }
> Tstat { tag=0 fid=1 }
-< Rstat { tag=0 stat={ kern_type=0 kern_dev=0 file_qid={ type=(0) vers=1 path=3 } file_mode=(0444) file_atime=1728337905 file_mtime=1728337904 file_size=166 file_name="x" file_owner_uid="root" file_owner_gid="root" file_last_modified_uid="root" file_extension="" file_owner_n_uid=0 file_owner_n_gid=0 file_last_modified_n_uid=0 } }
+< Rstat { tag=0 stat={ fstype=0 fsdev=0 qid={ type=(0) vers=1 path=3 } mode=(0444) atime=1728337905 mtime=1728337904 length=166 name="x" owner_uname="root" owner_gname="root" last_modifier_uname="root" extension="" owner_unum=0 owner_gnum=0 last_modifier_unum=0 } }
> Tclunk { tag=0 fid=1 }
< Rclunk { tag=0 }
> Tversion { tag=NOTAG max_msg_size=8192 version="9P2000" }
< Rversion { tag=NOTAG max_msg_size=4120 version="9P2000" }
-> Tauth { tag=0 afid=0 uname="nobody" aname="" n_uid=0 }
+> Tauth { tag=0 afid=0 uname="nobody" aname="" unum=0 }
< Rerror { tag=0 errstr="authentication not required" errnum=L_EOPNOTSUPP }
-> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" n_uid=0 }
+> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" unum=0 }
< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } }
> Twalk { tag=0 fid=0 newfid=1 nwname=1 wname=[ "shutdown" ] }
-< Rwalk { tag=0 nwqid=1 wqid=[ { type=(0) vers=1 path=5 } ] }
+< Rwalk { tag=0 nwqid=1 wqid=[ { type=(APPEND) vers=1 path=5 } ] }
> Topen { tag=0 fid=1 mode=(TRUNC|MODE_WRITE) }
-< Ropen { tag=0 qid={ type=(0) vers=1 path=5 } iounit=0 }
+< Ropen { tag=0 qid={ type=(APPEND) vers=1 path=5 } iounit=0 }
> Twrite { tag=0 fid=1 offset=0 count=2 data="1\n" }
< Rwrite { tag=0 count=2 }
> Tclunk { tag=0 fid=1 }
diff --git a/lib9p/tests/testclient-sess.c b/lib9p/tests/testclient-sess.c
index ded70d1..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,
@@ -95,9 +98,9 @@ int main(int argc, char *argv[]) {
send9p(Tversion, .tag=0, .max_msg_size=(8*1024), .version=lib9p_str("9P2000.u"));
recv9p(); /* Rversion */
ctx.version = LIB9P_VER_9P2000_u;
- send9p(Tattach, .tag=0, .fid=0, .afid=LIB9P_FID_NOFID, .uname=lib9p_str("alice"), .n_uid=1000, .aname=lib9p_str(""));
+ send9p(Tattach, .tag=0, .fid=0, .afid=LIB9P_FID_NOFID, .uname=lib9p_str("alice"), .unum=1000, .aname=lib9p_str(""));
recv9p(); /* Rattach */
- send9p(Tattach, .tag=0, .fid=1, .afid=LIB9P_FID_NOFID, .uname=lib9p_str("bob"), .n_uid=1001, .aname=lib9p_str(""));
+ send9p(Tattach, .tag=0, .fid=1, .afid=LIB9P_FID_NOFID, .uname=lib9p_str("bob"), .unum=1001, .aname=lib9p_str(""));
recv9p(); /* Rattach */
wname[0] = lib9p_str("whoami"); send9p(Twalk, .tag=0, .fid=0, .newfid=2, .nwname=1, .wname=wname);
recv9p(); /* Rwalk */
@@ -170,29 +173,62 @@ int main(int argc, char *argv[]) {
recv9p(); /* Rattach */
/* flush, but original response comes back first */
- wname[0] = lib9p_str("slowread"); send9p(Twalk, .tag=0, .fid=0, .newfid=1, .nwname=1, .wname=wname);
+ wname[0] = lib9p_str("flush-read"); send9p(Twalk, .tag=0, .fid=0, .newfid=1, .nwname=1, .wname=wname);
recv9p(); /* Rwalk */
send9p(Topen, .tag=0, .fid=1, .mode=LIB9P_O_MODE_READ);
recv9p(); /* Ropen */
- send9p(Tread, .tag=1, .fid=1, .offset=0, .count=6);
- send9p(Tflush, .tag=2, .oldtag=1);
+ send9p(Tread, .tag=0, .fid=1, .offset=0, .count=10);
+ send9p(Tflush, .tag=1, .oldtag=0);
recv9p(); /* Rread */
recv9p(); /* Rflush */
/* flush, original request is aborted with error */
- wname[0] = lib9p_str("slowread-flushable"); send9p(Twalk, .tag=1, .fid=0, .newfid=2, .nwname=1, .wname=wname);
+ wname[0] = lib9p_str("flush-error"); send9p(Twalk, .tag=0, .fid=0, .newfid=2, .nwname=1, .wname=wname);
recv9p(); /* Rwalk */
send9p(Topen, .tag=0, .fid=2, .mode=LIB9P_O_MODE_READ);
recv9p(); /* Ropen */
- send9p(Tread, .tag=1, .fid=2, .offset=0, .count=6);
- send9p(Tflush, .tag=2, .oldtag=1);
+ send9p(Tread, .tag=0, .fid=2, .offset=0, .count=10);
+ send9p(Tflush, .tag=1, .oldtag=0);
recv9p(); /* Rerror */
recv9p(); /* Rflush */
+ /* flush, original request is aborted without error */
+ wname[0] = lib9p_str("flush-silent"); send9p(Twalk, .tag=0, .fid=0, .newfid=3, .nwname=1, .wname=wname);
+ recv9p(); /* Rwalk */
+ send9p(Topen, .tag=0, .fid=3, .mode=LIB9P_O_MODE_READ);
+ recv9p(); /* Ropen */
+ send9p(Tread, .tag=0, .fid=3, .offset=0, .count=10);
+ send9p(Tflush, .tag=1, .oldtag=0);
+ recv9p(); /* Rflush */
+
+ /* multiflush, original request is aborted without error */
+ wname[0] = lib9p_str("flush-slowsilent"); send9p(Twalk, .tag=0, .fid=0, .newfid=4, .nwname=1, .wname=wname);
+ recv9p(); /* Rwalk */
+ send9p(Topen, .tag=0, .fid=4, .mode=LIB9P_O_MODE_READ);
+ recv9p(); /* Ropen */
+ send9p(Tread, .tag=0, .fid=4, .offset=0, .count=10);
+ send9p(Tflush, .tag=1, .oldtag=0);
+ send9p(Tflush, .tag=2, .oldtag=0);
+ recv9p(); /* Rflush */
+
+ /* flush, but flush is flushed */
+ wname[0] = lib9p_str("flush-slowread"); send9p(Twalk, .tag=0, .fid=0, .newfid=5, .nwname=1, .wname=wname);
+ recv9p(); /* Rwalk */
+ send9p(Topen, .tag=0, .fid=5, .mode=LIB9P_O_MODE_READ);
+ recv9p(); /* Ropen */
+ send9p(Tread, .tag=0, .fid=5, .offset=0, .count=10);
+ send9p(Tflush, .tag=1, .oldtag=0);
+ send9p(Tflush, .tag=2, .oldtag=1);
+ recv9p(); /* Rflush */
+ recv9p(); /* Rread */
+
/* flush, unknown tag */
send9p(Tflush, .tag=0, .oldtag=99);
recv9p(); /* Rflush */
+ /* flushed by Tversion */
+ send9p(Tread, .tag=0, .fid=3, .offset=0, .count=10);
+
/* shutdown ***********************************************************/
send9p(Tversion, .tag=0, .max_msg_size=(8*1024), .version=lib9p_str("9P2000"));
recv9p(); /* Rversion */
diff --git a/lib9p/tests/testclient-sess.explog b/lib9p/tests/testclient-sess.explog
index 3e2209a..ec8d9c9 100644
--- a/lib9p/tests/testclient-sess.explog
+++ b/lib9p/tests/testclient-sess.explog
@@ -14,9 +14,9 @@
# ext version, users ###########################################################
> Tversion { tag=0 max_msg_size=8192 version="9P2000.u" }
< Rversion { tag=0 max_msg_size=4120 version="9P2000.u" }
-> Tattach { tag=0 fid=0 afid=NOFID uname="alice" aname="" n_uid=1000 }
+> Tattach { tag=0 fid=0 afid=NOFID uname="alice" aname="" unum=1000 }
< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } }
-> Tattach { tag=0 fid=1 afid=NOFID uname="bob" aname="" n_uid=1001 }
+> Tattach { tag=0 fid=1 afid=NOFID uname="bob" aname="" unum=1001 }
< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } }
> Twalk { tag=0 fid=0 newfid=2 nwname=1 wname=[ "whoami" ] }
< Rwalk { tag=0 nwqid=1 wqid=[ { type=(0) vers=1 path=8 } ] }
@@ -34,7 +34,7 @@
# walk #########################################################################
> Tversion { tag=0 max_msg_size=8192 version="9P2000" }
< Rversion { tag=0 max_msg_size=4120 version="9P2000" }
-> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" n_uid=0 }
+> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" unum=0 }
< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } }
# dup
@@ -83,41 +83,74 @@
# flush ########################################################################
> Tversion { tag=0 max_msg_size=8192 version="9P2000" }
< Rversion { tag=0 max_msg_size=4120 version="9P2000" }
-> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" n_uid=0 }
+> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" unum=0 }
< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } }
# flush, but original response comes back first
-> Twalk { tag=0 fid=0 newfid=1 nwname=1 wname=[ "slowread" ] }
-< Rwalk { tag=0 nwqid=1 wqid=[ { type=(0) vers=1 path=6 } ] }
+> Twalk { tag=0 fid=0 newfid=1 nwname=1 wname=[ "flush-read" ] }
+< Rwalk { tag=0 nwqid=1 wqid=[ { type=(0) vers=1 path=9 } ] }
> Topen { tag=0 fid=1 mode=(MODE_READ) }
-< Ropen { tag=0 qid={ type=(0) vers=1 path=6 } iounit=0 }
-> Tread { tag=1 fid=1 offset=0 count=6 }
-> Tflush { tag=2 oldtag=1 }
-< Rread { tag=1 count=6 data="Sloth\n" }
+< Ropen { tag=0 qid={ type=(0) vers=1 path=9 } iounit=0 }
+> Tread { tag=0 fid=1 offset=0 count=10 }
+> Tflush { tag=1 oldtag=0 }
+< Rread { tag=0 count=6 data="Sloth\n" }
+< Rflush { tag=1 }
+
+# flush, original request is aborted with error
+> Twalk { tag=0 fid=0 newfid=2 nwname=1 wname=[ "flush-error" ] }
+< Rwalk { tag=0 nwqid=1 wqid=[ { type=(0) vers=1 path=10 } ] }
+> Topen { tag=0 fid=2 mode=(MODE_READ) }
+< Ropen { tag=0 qid={ type=(0) vers=1 path=10 } iounit=0 }
+> Tread { tag=0 fid=2 offset=0 count=10 }
+> Tflush { tag=1 oldtag=0 }
+< Rerror { tag=0 errstr="request canceled by flush" errnum=L_EAGAIN }
+< Rflush { tag=1 }
+
+# flush, original request is aborted without error
+> Twalk { tag=0 fid=0 newfid=3 nwname=1 wname=[ "flush-silent" ] }
+< Rwalk { tag=0 nwqid=1 wqid=[ { type=(0) vers=1 path=11 } ] }
+> Topen { tag=0 fid=3 mode=(MODE_READ) }
+< Ropen { tag=0 qid={ type=(0) vers=1 path=11 } iounit=0 }
+> Tread { tag=0 fid=3 offset=0 count=10 }
+> Tflush { tag=1 oldtag=0 }
+< Rflush { tag=1 }
+
+# multiflush, original request is aborted without error
+> Twalk { tag=0 fid=0 newfid=4 nwname=1 wname=[ "flush-slowsilent" ] }
+< Rwalk { tag=0 nwqid=1 wqid=[ { type=(0) vers=1 path=12 } ] }
+> Topen { tag=0 fid=4 mode=(MODE_READ) }
+< Ropen { tag=0 qid={ type=(0) vers=1 path=12 } iounit=0 }
+> Tread { tag=0 fid=4 offset=0 count=10 }
+> Tflush { tag=1 oldtag=0 }
+> Tflush { tag=2 oldtag=0 }
< Rflush { tag=2 }
-# flush, succeeds
-> Twalk { tag=1 fid=0 newfid=2 nwname=1 wname=[ "slowread-flushable" ] }
-< Rwalk { tag=1 nwqid=1 wqid=[ { type=(0) vers=1 path=7 } ] }
-> Topen { tag=0 fid=2 mode=(MODE_READ) }
-< Ropen { tag=0 qid={ type=(0) vers=1 path=7 } iounit=0 }
-> Tread { tag=1 fid=2 offset=0 count=6 }
+# flush, but flush is flushed
+> Twalk { tag=0 fid=0 newfid=5 nwname=1 wname=[ "flush-slowread" ] }
+< Rwalk { tag=0 nwqid=1 wqid=[ { type=(0) vers=1 path=13 } ] }
+> Topen { tag=0 fid=5 mode=(MODE_READ) }
+< Ropen { tag=0 qid={ type=(0) vers=1 path=13 } iounit=0 }
+> Tread { tag=0 fid=5 offset=0 count=10 }
+> Tflush { tag=1 oldtag=0 }
> Tflush { tag=2 oldtag=1 }
< Rflush { tag=2 }
-< Rerror { tag=1 errstr="request canceled by flush" errnum=L_ECANCELED }
+< Rread { tag=0 count=6 data="Sloth\n" }
# flush, unknown tag
> Tflush { tag=0 oldtag=99 }
< Rflush { tag=0 }
+# flushed by Tversion
+> Tread { tag=0 fid=3 offset=0 count=10 }
+
# shutdown #####################################################################
> Tversion { tag=0 max_msg_size=8192 version="9P2000" }
< Rversion { tag=0 max_msg_size=4120 version="9P2000" }
-> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" n_uid=0 }
+> 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=(0) vers=1 path=5 } ] }
+< 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=(0) vers=1 path=5 } iounit=0 }
+< Ropen { tag=0 qid={ type=(APPEND) vers=1 path=5 } iounit=0 }
> Twrite { tag=0 fid=0 offset=0 count=2 data="1\n" }
< Rwrite { tag=0 count=2 }
diff --git a/lib9p_util/include/util9p/static.h b/lib9p_util/include/util9p/static.h
index 0b391b8..4bb24c4 100644
--- a/lib9p_util/include/util9p/static.h
+++ b/lib9p_util/include/util9p/static.h
@@ -9,18 +9,12 @@
#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
/* Common *********************************************************************/
-typedef struct {
+struct _util9p_static_common {
char *u_name;
uint32_t u_num;
char *g_name;
@@ -32,7 +26,7 @@ typedef struct {
char *name;
lib9p_dm_t perm;
uint32_t atime, mtime;
-} _util9p_static_common;
+};
#define UTIL9P_STATIC_COMMON(PATH, STRNAME, MODE) \
{ \
@@ -50,36 +44,34 @@ typedef struct {
/* Dir ************************************************************************/
struct util9p_static_dir {
- _util9p_static_common;
+ struct _util9p_static_common c;
/* NULL-terminated */
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){ \
- ._util9p_static_common = UTIL9P_STATIC_COMMON(PATH, STRNAME, 0555), \
- .members = { __VA_ARGS__ LO_NULL(lib9p_srv_file) }, \
+#define UTIL9P_STATIC_DIR(PATH, STRNAME, ...) \
+ lo_box_util9p_static_dir_as_lib9p_srv_file(&((struct util9p_static_dir){ \
+ .c = UTIL9P_STATIC_COMMON(PATH, STRNAME, 0555), \
+ .members = { __VA_ARGS__ LO_NULL(lib9p_srv_file) }, \
}))
/* File ***********************************************************************/
struct util9p_static_file {
- _util9p_static_common;
+ struct _util9p_static_common c;
char *data_start; /* must not be NULL */
char *data_end; /* may be NULL, in which case data_size is used */
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){ \
- ._util9p_static_common = UTIL9P_STATIC_COMMON(PATH, STRNAME, 0444), \
- __VA_ARGS__ \
+#define UTIL9P_STATIC_FILE(PATH, STRNAME, ...) \
+ lo_box_util9p_static_file_as_lib9p_srv_file(&((struct util9p_static_file){ \
+ .c = UTIL9P_STATIC_COMMON(PATH, STRNAME, 0444), \
+ __VA_ARGS__ \
}))
#endif /* _UTIL9P_STATIC_H_ */
diff --git a/lib9p_util/static.c b/lib9p_util/static.c
index 4fba35a..338e9c9 100644
--- a/lib9p_util/static.c
+++ b/lib9p_util/static.c
@@ -9,146 +9,134 @@
#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){
.type = LIB9P_QT_DIR,
.vers = 1,
- .path = self->pathnum,
+ .path = self->c.pathnum,
};
}
-static struct lib9p_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_stat){
- .kern_type = 0,
- .kern_dev = 0,
- .file_qid = util9p_static_dir_qid(self),
- .file_mode = LIB9P_DM_DIR | (self->perm & 0555),
- .file_atime = self->atime,
- .file_mtime = self->mtime,
- .file_size = 0,
- .file_name = lib9p_str(self->name),
- .file_owner_uid = lib9p_str(self->u_name),
- .file_owner_gid = lib9p_str(self->g_name),
- .file_last_modified_uid = lib9p_str(self->m_name),
- .file_extension = lib9p_str(NULL),
- .file_owner_n_uid = self->u_num,
- .file_owner_n_gid = self->g_num,
- .file_last_modified_n_uid = self->m_num,
- };
-}
-static void util9p_static_dir_wstat(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx,
- struct lib9p_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,
+ .mtime_sec = self->c.mtime,
+ .size = 0,
+ .name = lib9p_str(self->c.name),
+ .owner_uid = { .name = lib9p_str(self->c.u_name), .num = self->c.u_num },
+ .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;
+}
+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_stat stat = LO_CALL(file, stat, ctx);
- if (lib9p_ctx_has_error(&ctx->basectx))
- break;
- lib9p_stat_assert(stat);
- if (lib9p_str_eq(stat.file_name, childname))
- return file;
+ 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 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),
- lib9p_dm_t LM_UNUSED(perm), lib9p_o_t LM_UNUSED(flags)) {
+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 struct lib9p_qid util9p_static_dio_ioqid(struct util9p_static_dir *self) {
+ return util9p_static_dir_qid(self);
}
-static void util9p_static_dir_iofree(struct util9p_static_dir *self) {
+static void util9p_static_dio_iofree(struct util9p_static_dir *self) {
assert(self);
}
-static size_t util9p_static_dir_dread(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx,
- uint8_t *buf,
- uint32_t byte_count,
- size_t _obj_offset) {
+static 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);
- uint32_t byte_offset = 0;
- size_t obj_offset = _obj_offset;
- while (!LO_IS_NULL(self->members[obj_offset])) {
- lo_interface lib9p_srv_file file = self->members[obj_offset];
- struct lib9p_stat stat = LO_CALL(file, stat, ctx);
- if (lib9p_ctx_has_error(&ctx->basectx))
- break;
- lib9p_stat_assert(stat);
- uint32_t nbytes = lib9p_stat_marshal(&ctx->basectx, byte_count-byte_offset, &stat,
- &buf[byte_offset]);
- if (!nbytes) {
- if (obj_offset == _obj_offset)
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_ERANGE, "stat object does not fit into negotiated max message size");
- break;
- }
- byte_offset += nbytes;
- obj_offset++;
- }
- return obj_offset - _obj_offset;
+ lo_interface lib9p_srv_file file = self->members[idx];
+ if (LO_IS_NULL(file))
+ return ERROR_NEW_VAL(lib9p_srv_dirent, (struct lib9p_srv_dirent){});
+
+ 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 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){
.type = LIB9P_QT_FILE,
.vers = 1,
- .path = self->pathnum,
+ .path = self->c.pathnum,
};
}
@@ -164,89 +152,83 @@ static inline size_t util9p_static_file_size(struct util9p_static_file *file) {
}
-static struct lib9p_stat util9p_static_file_stat(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx) {
+error util9p_static_file_stat(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_srv_stat *out) {
assert(self);
assert(ctx);
-
- return (struct lib9p_stat){
- .kern_type = 0,
- .kern_dev = 0,
- .file_qid = util9p_static_file_qid(self),
- .file_mode = self->perm & 0444,
- .file_atime = self->atime,
- .file_mtime = self->mtime,
- .file_size = (uint64_t)util9p_static_file_size(self),
- .file_name = lib9p_str(self->name),
- .file_owner_uid = lib9p_str(self->u_name),
- .file_owner_gid = lib9p_str(self->g_name),
- .file_last_modified_uid = lib9p_str(self->m_name),
- .file_extension = lib9p_str(NULL),
- .file_owner_n_uid = self->u_num,
- .file_owner_n_gid = self->g_num,
- .file_last_modified_n_uid = self->m_num,
- };
-}
-static void util9p_static_file_wstat(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx,
- struct lib9p_stat) {
+ assert(out);
+
+ *out = ((struct lib9p_srv_stat){
+ .qid = util9p_static_file_qid(self),
+ .mode = self->c.perm & 0444,
+ .atime_sec = self->c.atime,
+ .mtime_sec = self->c.mtime,
+ .size = (uint64_t)util9p_static_file_size(self),
+ .name = lib9p_str(self->c.name),
+ .owner_uid = { .name = lib9p_str(self->c.u_name), .num = self->c.u_num },
+ .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;
+}
+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 void util9p_static_file_iofree(struct util9p_static_file *self) {
+
+static struct lib9p_qid util9p_static_fio_ioqid(struct util9p_static_file *self) {
+ return util9p_static_file_qid(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 bf44219..182e85c 100644
--- a/libcr/coroutine.c
+++ b/libcr/coroutine.c
@@ -349,7 +349,7 @@ static_assert(CONFIG_COROUTINE_NUM > 1);
uintptr_t sp;
#endif
} cr_plat_jmp_buf;
- static void _cr_plat_setjmp_pre(cr_plat_jmp_buf *env [[gnu::unused]]) {
+ static void _cr_plat_setjmp_pre(cr_plat_jmp_buf *env [[maybe_unused]]) {
#if CONFIG_COROUTINE_MEASURE_STACK
env->sp = cr_plat_get_sp();
#endif
@@ -399,6 +399,7 @@ struct coroutine {
#if CONFIG_COROUTINE_VALGRIND
unsigned stack_id;
#endif
+ bool stack_free;
/* 4. env ***************************************************/
cr_plat_jmp_buf env;
@@ -457,7 +458,7 @@ static cr_plat_jmp_buf coroutine_gdb_env;
* coroutine_ringbuf queue.
*/
-static struct coroutine coroutine_table[CONFIG_COROUTINE_NUM] = {0};
+static struct coroutine coroutine_table[CONFIG_COROUTINE_NUM] = {};
static struct {
/* tail == head means empty */
/* buf[tail] is the next thing to run */
@@ -468,7 +469,7 @@ static struct {
* we don't have to worry about funny wrap-around behavior
* when head or tail overflow. */
cid_t buf[LM_NEXT_POWER_OF_2(CONFIG_COROUTINE_NUM)];
-} coroutine_ringbuf = {0};
+} coroutine_ringbuf = {};
static cid_t coroutine_running = 0;
static size_t coroutine_cnt = 0;
@@ -547,17 +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);
- debugf("coroutine_add_with_stack_size(%zu, \"%s\", %p, %p)...",
- stack_size, name, fn, args);
if (!coroutine_initialized) {
cr_plat_init();
@@ -567,7 +566,7 @@ cid_t coroutine_add_with_stack_size(size_t stack_size,
cid_t child = coroutine_allocate_cid();
if (!child)
return 0;
- debugf("...child=%zu", child);
+ log_debugln("...child=", child);
/* 1. state *************************************************/
coroutine_table[child-1].state = CR_INITIALIZING;
@@ -578,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;
- infof("allocing \"%s\" stack with size %zu+2*%zu=%zu",
- name, stack_size, 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);
- infof("... done, stack is [0x%p,0x%p)",
- 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_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 + 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 ***************************************************/
@@ -603,13 +614,13 @@ 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
;
- debugf("...stack =%p", coroutine_table[child-1].stack);
- debugf("...stack_base=%p", stack_base);
+ log_debugln("...stack_base=", (ptr, stack_base));
/* run until cr_begin() */
cr_plat_call_with_stack(stack_base, fn, args);
assert_notreached("should cr_begin() instead of returning");
@@ -623,14 +634,37 @@ 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) {
- debugf("coroutine_main()");
+ log_debugln("coroutine_main()");
if (!coroutine_initialized) {
cr_plat_init();
coroutine_initialized = true;
@@ -664,8 +698,9 @@ 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);
- coroutine_table[coroutine_running-1] = (struct coroutine){0};
+ if (coroutine_table[coroutine_running-1].stack_free)
+ free(coroutine_table[coroutine_running-1].stack);
+ coroutine_table[coroutine_running-1] = (struct coroutine){};
coroutine_cnt--;
}
coroutine_running = 0;
@@ -675,7 +710,7 @@ void coroutine_main(void) {
/* cr_*() *********************************************************************/
void cr_begin(void) {
- debugf("cid=%zu: cr_begin()", coroutine_running);
+ log_debugln("cid=", coroutine_running, ": cr_begin()");
assert_cid_state(coroutine_running, state == CR_INITIALIZING);
bool saved = cr_save_and_disable_interrupts();
@@ -686,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
@@ -707,7 +742,7 @@ static inline void _cr_yield() {
}
void cr_yield(void) {
- debugf("cid=%zu: cr_yield()", coroutine_running);
+ log_debugln("cid=", coroutine_running ,": cr_yield()");
assert(!cr_plat_is_in_intrhandler());
assert_cid_state(coroutine_running, state == CR_RUNNING);
@@ -719,7 +754,7 @@ void cr_yield(void) {
}
void cr_pause_and_yield(void) {
- debugf("cid=%zu: cr_pause_and_yield()", coroutine_running);
+ log_debugln("cid=", coroutine_running, ": cr_pause_and_yield()");
assert(!cr_plat_is_in_intrhandler());
assert_cid_state(coroutine_running, state == CR_RUNNING);
@@ -730,7 +765,7 @@ void cr_pause_and_yield(void) {
}
[[noreturn]] void cr_exit(void) {
- debugf("cid=%zu: cr_exit()", coroutine_running);
+ log_debugln("cid=", coroutine_running, ": cr_exit()");
assert(!cr_plat_is_in_intrhandler());
assert_cid_state(coroutine_running, state == CR_RUNNING);
@@ -747,7 +782,7 @@ static void _cr_unpause(cid_t cid) {
}
void cr_unpause(cid_t cid) {
- debugf("cr_unpause(%zu)", cid);
+ log_debugln("cr_unpause(", cid, ")");
assert(!cr_plat_is_in_intrhandler());
assert_cid_state(coroutine_running, state == CR_RUNNING);
@@ -757,7 +792,7 @@ void cr_unpause(cid_t cid) {
}
void cr_unpause_from_intrhandler(cid_t cid) {
- debugf("cr_unpause_from_intrhandler(%zu)", cid);
+ log_debugln("cr_unpause_from_intrhandler(", cid, ")");
assert(cr_plat_is_in_intrhandler());
_cr_unpause(cid);
diff --git a/libcr/include/libcr/coroutine.h b/libcr/include/libcr/coroutine.h
index 2505782..f0e6e61 100644
--- a/libcr/include/libcr/coroutine.h
+++ b/libcr/include/libcr/coroutine.h
@@ -26,8 +26,7 @@
#ifndef _LIBCR_COROUTINE_H_
#define _LIBCR_COROUTINE_H_
-#include <stddef.h> /* for size_t */
-#include <stdbool.h> /* for bool */
+#include <stddef.h> /* for size_t */
/* Configuration **************************************************************/
@@ -36,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 *******************************************************************/
@@ -81,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.
*
@@ -92,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.c b/libcr/tests/test_matrix.c
index 1f23455..eaa4bdc 100644
--- a/libcr/tests/test_matrix.c
+++ b/libcr/tests/test_matrix.c
@@ -1,6 +1,6 @@
/* libcr/tests/test_matrix.c - Tests for libcr
*
- * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
@@ -8,14 +8,14 @@
int a = 1;
-COROUTINE cr_init(void *) {
+COROUTINE init_cr(void *) {
cr_begin();
a = 2;
cr_end();
}
int main() {
- coroutine_add("init", cr_init, NULL);
+ coroutine_add("init", init_cr, NULL);
coroutine_main();
if (a != 2)
return 1;
diff --git a/libcr/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 6ccfa44..b52dab1 100644
--- a/libcr_ipc/chan.c
+++ b/libcr_ipc/chan.c
@@ -4,60 +4,22 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-#include <alloca.h> /* for alloca() */
-#include <string.h> /* for memcpy() */
+#include <string.h> /* for memcpy() */
#include <libcr/coroutine.h> /* for cid_t, cr_* */
#include <libmisc/assert.h>
#include <libmisc/rand.h>
+#define IMPLEMENTATION_FOR_LIBCR_IPC_CHAN_H YES
#include <libcr_ipc/chan.h>
-/* base channels **************************************************************/
-
-struct cr_chan_waiter {
- lm_dll_node;
+struct _cr_select_waiter {
cid_t cid;
- void *val_ptr;
- void (*dequeue)(void *, size_t);
- void *dequeue_arg1;
- size_t dequeue_arg2;
-};
-
-void cr_chan_dequeue(void *_ch, size_t) {
- struct _cr_chan *ch = _ch;
- lm_dll_pop_from_front(&ch->waiters);
-}
-
-void _cr_chan_xfer(enum _cr_chan_waiter_typ self_typ, struct _cr_chan *ch, void *val_ptr, size_t val_size) {
- assert(ch);
- assert(val_ptr);
+ struct _cr_select_arg_list_node *arg_vec;
+ size_t arg_cnt;
- if (ch->waiters.front && ch->waiter_typ != self_typ) { /* non-blocking fast-path */
- /* Copy. */
- struct cr_chan_waiter *front = lm_dll_node_cast(struct cr_chan_waiter, ch->waiters.front);
- if (self_typ == _CR_CHAN_SENDER)
- memcpy(front->val_ptr, val_ptr, val_size);
- else
- memcpy(val_ptr, front->val_ptr, val_size);
- cr_unpause(front->cid);
- front->dequeue(front->dequeue_arg1,
- front->dequeue_arg2);
- cr_yield();
- } else { /* blocking slow-path */
- struct cr_chan_waiter self = {
- .cid = cr_getcid(),
- .val_ptr = val_ptr,
- .dequeue = cr_chan_dequeue,
- .dequeue_arg1 = ch,
- };
- lm_dll_push_to_rear(&ch->waiters, &self);
- ch->waiter_typ = self_typ;
- cr_pause_and_yield();
- }
-}
-
-/* select *********************************************************************/
+ size_t ret;
+};
enum cr_select_class {
CR_SELECT_CLASS_DEFAULT,
@@ -65,40 +27,26 @@ enum cr_select_class {
CR_SELECT_CLASS_NONBLOCK,
};
-struct cr_select_waiters {
- size_t cnt;
- struct cr_select_arg *args;
- struct cr_chan_waiter *nodes;
-};
-
-static inline enum cr_select_class cr_select_getclass(struct cr_select_arg arg) {
- switch (arg.op) {
+static inline enum cr_select_class cr_select_getclass(struct _cr_select_arg *arg) {
+ switch (arg->op) {
case _CR_SELECT_OP_RECV:
- if (arg.ch->waiters.front && arg.ch->waiter_typ == _CR_CHAN_SENDER)
+ if (arg->ch->waiters.front && arg->ch->waiters.front->val.op == _CR_SELECT_OP_SEND)
return CR_SELECT_CLASS_NONBLOCK;
else
return CR_SELECT_CLASS_BLOCKING;
case _CR_SELECT_OP_SEND:
- if (arg.ch->waiters.front && arg.ch->waiter_typ == _CR_CHAN_RECVER)
+ if (arg->ch->waiters.front && arg->ch->waiters.front->val.op == _CR_SELECT_OP_RECV)
return CR_SELECT_CLASS_NONBLOCK;
else
return CR_SELECT_CLASS_BLOCKING;
case _CR_SELECT_OP_DEFAULT:
return CR_SELECT_CLASS_DEFAULT;
default:
- assert_notreached("invalid arg.op");
+ assert_notreached("invalid arg->op");
}
}
-void cr_select_dequeue(void *_waiters, size_t idx) {
- struct cr_select_waiters *waiters = _waiters;
- for (size_t i = 0; i < waiters->cnt; i++)
- lm_dll_remove(&(waiters->args[i].ch->waiters),
- &(waiters->nodes[i]));
- waiters->cnt = idx;
-}
-
-size_t cr_select_v(size_t arg_cnt, struct cr_select_arg arg_vec[]) {
+size_t cr_select_v(size_t arg_cnt, struct _cr_select_arg_list_node arg_vec[]) {
size_t cnt_blocking = 0;
size_t cnt_nonblock = 0;
size_t cnt_default = 0;
@@ -108,7 +56,7 @@ size_t cr_select_v(size_t arg_cnt, struct cr_select_arg arg_vec[]) {
cr_assert_in_coroutine();
for (size_t i = 0; i < arg_cnt; i++) {
- switch (cr_select_getclass(arg_vec[i])) {
+ switch (cr_select_getclass(&arg_vec[i].val)) {
case CR_SELECT_CLASS_BLOCKING:
cnt_blocking++;
break;
@@ -122,46 +70,65 @@ size_t cr_select_v(size_t arg_cnt, struct cr_select_arg arg_vec[]) {
}
if (cnt_nonblock) {
- size_t choice = rand_uint63n(cnt_nonblock);
- for (size_t i = 0, seen = 0; i < arg_cnt; i++) {
- if (cr_select_getclass(arg_vec[i]) == CR_SELECT_CLASS_NONBLOCK) {
- if (seen == choice) {
- _cr_chan_xfer(arg_vec[i].op == _CR_SELECT_OP_RECV
- ? _CR_CHAN_RECVER
- : _CR_CHAN_SENDER,
- arg_vec[i].ch,
- arg_vec[i].val_ptr,
- arg_vec[i].val_siz);
- return i;
- }
+ size_t choice_among_nonblock = rand_uint63n(cnt_nonblock);
+ size_t choice_among_all = arg_cnt;
+ for (size_t i = 0, seen = 0; i < choice_among_all; i++) {
+ if (cr_select_getclass(&arg_vec[i].val) == CR_SELECT_CLASS_NONBLOCK) {
+ if (seen == choice_among_nonblock)
+ choice_among_all = i;
seen++;
}
}
- assert_notreached("should have returned from inside for() loop");
+ assert(choice_among_all < arg_cnt);
+
+ struct _cr_select_arg *this = &arg_vec[choice_among_all].val;
+ assert(this->ch->waiters.front);
+ struct _cr_select_arg *other = &this->ch->waiters.front->val;
+ assert(this->val_siz == other->val_siz);
+ assert(this->ch == other->ch);
+ switch (this->op) {
+ case _CR_SELECT_OP_SEND:
+ assert(other->op == _CR_SELECT_OP_RECV);
+ memcpy(other->val_ptr, this->val_ptr, this->val_siz);
+ break;
+ case _CR_SELECT_OP_RECV:
+ assert(other->op == _CR_SELECT_OP_SEND);
+ memcpy(this->val_ptr, other->val_ptr, this->val_siz);
+ break;
+ case _CR_SELECT_OP_DEFAULT:
+ assert_notreached("_CR_SELECT_OP_DEFAULT is not CR_SELECT_CLASS_NONBLOCK");
+ }
+ struct _cr_select_waiter *waiter = other->waiter;
+ for (size_t i = 0; i < waiter->arg_cnt; i++) {
+ waiter->arg_vec[i].val.ch->nwaiters--;
+ dlist_remove(&waiter->arg_vec[i].val.ch->waiters, &waiter->arg_vec[i]);
+ if (&waiter->arg_vec[i].val == other)
+ waiter->ret = i;
+ }
+ cr_unpause(waiter->cid);
+ cr_yield();
+ return choice_among_all;
}
if (cnt_default) {
for (size_t i = 0; i < arg_cnt; i++)
- if (cr_select_getclass(arg_vec[i]) == CR_SELECT_CLASS_DEFAULT)
+ if (cr_select_getclass(&arg_vec[i].val) == CR_SELECT_CLASS_DEFAULT)
return i;
assert_notreached("should have returned from inside for() loop");
}
- struct cr_select_waiters waiters = {
- .cnt = arg_cnt,
- .args = arg_vec,
- .nodes = alloca(sizeof(struct cr_chan_waiter) * arg_cnt),
+ assert(cnt_blocking && cnt_blocking == arg_cnt);
+
+ struct _cr_select_waiter waiter = {
+ .cid = cr_getcid(),
+ .arg_vec = arg_vec,
+ .arg_cnt = arg_cnt,
};
for (size_t i = 0; i < arg_cnt; i++) {
- waiters.nodes[i] = (struct cr_chan_waiter){
- .cid = cr_getcid(),
- .val_ptr = arg_vec[i].val_ptr,
- .dequeue = cr_select_dequeue,
- .dequeue_arg1 = &waiters,
- .dequeue_arg2 = i,
- };
- lm_dll_push_to_rear(&arg_vec[i].ch->waiters, &waiters.nodes[i]);
+ arg_vec[i].val.waiter = &waiter;
+ arg_vec[i].val.ch->nwaiters++;
+ dlist_push_to_rear(&arg_vec[i].val.ch->waiters, &arg_vec[i]);
}
cr_pause_and_yield();
- return waiters.cnt;
+ return waiter.ret;
}
diff --git a/libcr_ipc/include/libcr_ipc/chan.h b/libcr_ipc/include/libcr_ipc/chan.h
index 80acdb8..1755a97 100644
--- a/libcr_ipc/include/libcr_ipc/chan.h
+++ b/libcr_ipc/include/libcr_ipc/chan.h
@@ -7,19 +7,15 @@
#ifndef _LIBCR_IPC_CHAN_H_
#define _LIBCR_IPC_CHAN_H_
-#include <stdbool.h> /* for bool */
-#include <stddef.h> /* for size_t */
+#include <stddef.h> /* for size_t */
-#include <libmisc/linkedlist.h> /* for lm_dll_root */
-#include <libmisc/macro.h> /* for LM_CAT2_() */
+#include <libmisc/linkedlist.h> /* for DLIST_DECLARE() */
+#include <libmisc/private.h>
/* base channels **************************************************************/
/**
- * CR_CHAN_DECLARE(NAME, VAL_T) declares the following type and
- * methods:
- *
- * type:
+ * CR_CHAN_DECLARE(NAME, VAL_T) declares the following type:
*
* / **
* * A NAME##_t is a fair unbuffered channel that transports
@@ -32,143 +28,163 @@
* * something from an interrupt handler.
* * /
* typedef ... NAME##_t;
+ */
+#define CR_CHAN_DECLARE(NAME, VAL_T) \
+ typedef struct { \
+ struct _cr_chan core; \
+ VAL_T val_typ[0]; \
+ } NAME##_t
+
+/**
+ * cr_chan_send(ch, val) sends `val` over `ch`.
*
- * methods:
+ * @runs_in coroutine
+ * @cr_pauses maybe
+ * @cr_yields always
*
- * / **
- * * NAME##_send(ch, val) sends `val` over `ch`.
- * *
- * * @runs_in coroutine
- * * @cr_pauses maybe
- * * @cr_yields always
- * * /
- * void NAME##_send(NAME##_t *ch, VAL_T val);
+ * void cr_chan_send(NAME##_t *ch, VAL_T val);
+ */
+#define cr_chan_send(CH, VAL) do { \
+ typeof((CH)->val_typ[0]) _val_lvalue = VAL; \
+ (void)cr_select_l(CR_SELECT_SEND(CH, &_val_lvalue)); \
+} while (0)
+
+/**
+ * cr_chan_recv(ch) reads and returns a value from ch.
*
- * / **
- * * NAME##_recv(ch) reads and returns a value from ch.
- * *
- * * @runs_in coroutine
- * * @cr_pauses maybe
- * * @cr_yields always
- * * /
- * VAL_T NAME##_recv(NAME##_t *ch);
+ * @runs_in coroutine
+ * @cr_pauses maybe
+ * @cr_yields always
*
- * / **
- * * NAME##_can_send(ch) returns whether NAME##_send(ch, val)
- * * would run without pausing.
- * *
- * * @runs_in coroutine
- * * @cr_pauses never
- * * @cr_yields never
- * * /
- * bool NAME##_can_send(NAME##_t *ch);
+ * VAL_T cr_chan_recv(NAME##_T ch);
+ */
+#define cr_chan_recv(CH) ({ \
+ typeof((CH)->val_typ[0]) _val_lvalue; \
+ (void)cr_select_l(CR_SELECT_RECV(CH, &_val_lvalue)); \
+ _val_lvalue; \
+})
+
+/**
+ * cr_chan_can_send(ch) returns whether cr_chan_send(ch, val) would
+ * run without pausing.
*
- * / **
- * * NAME##_can_recv(ch) returns whether NAME##_recv(ch) would
- * * return without pausing.
- * *
- * * @runs_in coroutine
- * * @cr_pauses never
- * * @cr_yields never
- * * /
- * NAME##_can_recv(NAME##_t *ch);
+ * @runs_in coroutine
+ * @cr_pauses never
+ * @cr_yields never
+ *
+ * bool cr_chan_can_send(NAME##_t *ch);
*/
-#define CR_CHAN_DECLARE(NAME, VAL_T) \
- typedef struct { \
- struct _cr_chan core; \
- VAL_T vals[0]; \
- } NAME##_t; \
- \
- static inline void NAME##_send(NAME##_t *ch, VAL_T val) { \
- cr_assert_in_coroutine(); \
- _cr_chan_xfer(_CR_CHAN_SENDER, &ch->core, &val, sizeof(val)); \
- } \
- \
- static inline VAL_T NAME##_recv(NAME##_t *ch) { \
- cr_assert_in_coroutine(); \
- VAL_T val; \
- _cr_chan_xfer(_CR_CHAN_RECVER, &ch->core, &val, sizeof(val)); \
- return val; \
- } \
- \
- static inline bool NAME##_can_send(NAME##_t *ch) { \
- cr_assert_in_coroutine(); \
- return ch->core.waiters.front && \
- ch->core.waiter_typ == _CR_CHAN_RECVER; \
- } \
- \
- static inline bool NAME##_can_recv(NAME##_t *ch) { \
- cr_assert_in_coroutine(); \
- return ch->core.waiters.front && \
- ch->core.waiter_typ == _CR_CHAN_SENDER; \
- } \
- \
- extern int LM_CAT2_(_CR_CHAN_FORCE_SEMICOLON_, __COUNTER__)
-
-enum _cr_chan_waiter_typ {
- _CR_CHAN_SENDER,
- _CR_CHAN_RECVER,
-};
+#define cr_chan_can_send(CH) ({ \
+ cr_assert_in_coroutine(); \
+ (bool)((CH)->core.waiters.front && \
+ (CH)->core.waiters.front->val.op == _CR_SELECT_OP_RECV); \
+})
+/**
+ * cr_chan_can_recv(ch) returns whether cr_chan_recv(ch) would return
+ * without pausing.
+ *
+ * @runs_in coroutine
+ * @cr_pauses never
+ * @cr_yields never
+ *
+ * bool cr_chan_can_recv(NAME##_t *ch);
+ */
+#define cr_chan_can_recv(CH) ({ \
+ cr_assert_in_coroutine(); \
+ (bool)((CH)->core.waiters.front && \
+ (CH)->core.waiters.front->val.op == _CR_SELECT_OP_SEND); \
+})
+
+/**
+ * cr_chan_num_waiters(ch) returns the number of coroutines currently
+ * blocked on the channel.
+ *
+ * @runs_in coroutine
+ * @cr_pauses never
+ * @cr_yields never
+ *
+ * size_t cr_chan_num_waiters(NAME##_t *ch);
+ */
+#define cr_chan_num_waiters(CH) ({ \
+ cr_assert_in_coroutine(); \
+ ((CH)->core.nwaiters); \
+})
+
+DLIST_DECLARE(_cr_select_arg_list);
struct _cr_chan {
- enum _cr_chan_waiter_typ waiter_typ;
- lm_dll_root waiters;
+ struct _cr_select_arg_list waiters;
+ size_t nwaiters;
};
-void _cr_chan_xfer(enum _cr_chan_waiter_typ self_typ, struct _cr_chan *ch, void *val_ptr, size_t val_size);
-
/* cr_select arguments ********************************************************/
/**
* Do not populate cr_select_arg yourself; use the
* CR_SELECT_{RECV,SEND,DEFAULT} macros.
*/
-struct cr_select_arg {
+struct _cr_select_waiter;
+struct _cr_select_arg {
enum {
_CR_SELECT_OP_RECV,
_CR_SELECT_OP_SEND,
_CR_SELECT_OP_DEFAULT,
- } op;
- struct _cr_chan *ch;
- void *val_ptr;
- size_t val_siz;
+ } op;
+ struct _cr_chan *ch;
+ void *val_ptr;
+ size_t val_siz;
+ BEGIN_PRIVATE(LIBCR_IPC_CHAN_H);
+ struct _cr_select_waiter *waiter;
+ END_PRIVATE(LIBCR_IPC_CHAN_H);
};
+DLIST_DECLARE_NODE(_cr_select_arg_list, struct _cr_select_arg);
+#define cr_select_arg _cr_select_arg_list_node
+
+#define CR_SELECT_RECV(CH, VALP) ((struct cr_select_arg){ .val = { \
+ .op = _CR_SELECT_OP_RECV, \
+ .ch = &((CH)->core), \
+ /* The _valp temporary variable is to get the compiler to check that \
+ * the types are compatible. */ \
+ .val_ptr = ({ typeof((CH)->val_typ[0]) *_valp = VALP; _valp; }), \
+ .val_siz = sizeof((CH)->val_typ[0]), \
+}})
-#define CR_SELECT_RECV(CH, VALP) \
- /* The _valp temporary variable is to get the compiler to check that \
- * the types are compatible. */ \
- ((struct cr_select_arg){ \
- .op = _CR_SELECT_OP_RECV, \
- .ch = &((CH)->core), \
- .val_ptr = ({ typeof((CH)->vals[0]) *_valp = VALP; _valp; }), \
- .val_siz = sizeof((CH)->vals[0]), \
- })
/* BUG: It's bogus that CR_SELECT_SEND takes VALP instead of VAL, but
* since we need an address, taking VAL would introduce uncomfortable
* questions about where VAL sits on the stack. */
-#define CR_SELECT_SEND(CH, VALP) \
- /* The _valp temporary variable is to get the compiler to check that \
- * the types are compatible. */ \
- ((struct cr_select_arg){ \
- .op = _CR_SELECT_OP_SEND, \
- .ch = &((CH)->core), \
- .val_ptr = ({ typeof((CH)->vals[0]) *_valp = VALP; _valp; }), \
- .val_siz = sizeof((CH)->vals[0]), \
- })
-#define CR_SELECT_DEFAULT \
- ((struct cr_select_arg){ \
- .op = _CR_SELECT_OP_DEFAULT, \
- })
+#define CR_SELECT_SEND(CH, VALP) ((struct cr_select_arg){ .val = { \
+ .op = _CR_SELECT_OP_SEND, \
+ .ch = &((CH)->core), \
+ /* The _valp temporary variable is to get the compiler to check that \
+ * the types are compatible. */ \
+ .val_ptr = ({ typeof((CH)->val_typ[0]) *_valp = VALP; _valp; }), \
+ .val_siz = sizeof((CH)->val_typ[0]), \
+}})
+
+#define CR_SELECT_DEFAULT ((struct cr_select_arg){ .val = { \
+ .op = _CR_SELECT_OP_DEFAULT, \
+}})
/* cr_select_v(arg_cnt, arg_vec) **********************************************/
+/**
+ * @runs_in coroutine
+ * @cr_pauses maybe
+ * @cr_yields always
+ */
size_t cr_select_v(size_t arg_cnt, struct cr_select_arg arg_vec[]);
/* cr_select_l(arg1, arg2, arg3, ...) ******************************************/
-#define cr_select_l(...) ({ \
- struct cr_select_arg _cr_select_args[] = { __VA_ARGS__ }; \
- cr_select_v(sizeof(_cr_select_args)/sizeof(_cr_select_args[0])); \
+/**
+ * @runs_in coroutine
+ * @cr_pauses maybe
+ * @cr_yields always
+ */
+#define cr_select_l(...) ({ \
+ struct cr_select_arg _cr_select_args[] = { __VA_ARGS__ }; \
+ cr_select_v(sizeof(_cr_select_args)/sizeof(_cr_select_args[0]), \
+ _cr_select_args); \
})
#endif /* _LIBCR_IPC_CHAN_H_ */
diff --git a/libcr_ipc/include/libcr_ipc/mutex.h b/libcr_ipc/include/libcr_ipc/mutex.h
index 0f3c9c2..05a6b2e 100644
--- a/libcr_ipc/include/libcr_ipc/mutex.h
+++ b/libcr_ipc/include/libcr_ipc/mutex.h
@@ -7,11 +7,11 @@
#ifndef _LIBCR_IPC_MUTEX_H_
#define _LIBCR_IPC_MUTEX_H_
-#include <stdbool.h> /* for bool */
-
-#include <libmisc/linkedlist.h>
+#include <libmisc/linkedlist.h> /* for SLIST_DECLARE() */
#include <libmisc/private.h>
+SLIST_DECLARE(_cr_mutex_waiter_list);
+
/**
* A cr_mutex_t is a fair mutex.
*
@@ -22,8 +22,8 @@
*/
typedef struct {
BEGIN_PRIVATE(LIBCR_IPC_MUTEX_H);
- bool locked;
- lm_sll_root waiters;
+ bool locked;
+ struct _cr_mutex_waiter_list waiters;
END_PRIVATE(LIBCR_IPC_MUTEX_H);
} cr_mutex_t;
diff --git a/libcr_ipc/include/libcr_ipc/rpc.h b/libcr_ipc/include/libcr_ipc/rpc.h
index f091685..85ebdb3 100644
--- a/libcr_ipc/include/libcr_ipc/rpc.h
+++ b/libcr_ipc/include/libcr_ipc/rpc.h
@@ -7,16 +7,11 @@
#ifndef _LIBCR_IPC_RPC_H_
#define _LIBCR_IPC_RPC_H_
-#include <stdbool.h> /* for bool */
-
-#include <libmisc/linkedlist.h> /* for lm_sll_root */
-#include <libmisc/macro.h> /* for LM_CAT2_() */
+#include <libcr/coroutine.h> /* for cid_t */
+#include <libmisc/linkedlist.h> /* for SLIST_DECLARE() */
/**
- * CR_RPC_DECLARE(NAME, REQ_T, RESP_T) declares the following types
- * and methods:
- *
- * type:
+ * CR_RPC_DECLARE(NAME, REQ_T, RESP_T) declares the following types:
*
* / **
* * A NAME##_t is a fair rpc-channel on which the requester submits a
@@ -38,114 +33,109 @@
* * the response RESP_T to the correct requester. `REQ_T req` is the
* * only public member.
* typedef struct { REQ_T req; ... } NAME##_req_t;
+ */
+#define CR_RPC_DECLARE(NAME, REQ_T, RESP_T) \
+ typedef struct { \
+ REQ_T req; \
+ \
+ RESP_T *_resp; /* where to write resp to */ \
+ cid_t _requester; \
+ } NAME##_req_t; \
+ \
+ typedef struct { \
+ struct _cr_rpc core; \
+ NAME##_req_t handle_typ[0]; \
+ } NAME##_t
+
+/* Methods for NAME##_t *******************************************************/
+
+/**
+ * cr_rpc_send_req(ch, req) submits the `req` request over `ch` and
+ * returns the response.
*
- * methods:
+ * @runs_in coroutine
+ * @cr_pauses always
+ * @cr_yields always
*
- * / **
- * * NAME##_send_req(ch, req) submits the `req` request over `ch` and
- * * returns the response.
- * *
- * * @runs_in coroutine
- * * @cr_pauses always
- * * @cr_yields always
- * * /
- * RESP_T NAME##_send_req(NAME##_t *ch, REQ_T req);
+ * RESP_T cr_rpc_send_req(NAME##_t *ch, REQ_T req);
+ */
+#define cr_rpc_send_req(CH, REQ) ({ \
+ cr_assert_in_coroutine(); \
+ typeof((CH)->handle_typ[0].req) _req_lvalue = REQ; \
+ typeof(*(CH)->handle_typ[0]._resp) _resp_lvalue; \
+ _cr_rpc_send_req(&(CH)->core, \
+ &_req_lvalue, sizeof(_req_lvalue), \
+ &_resp_lvalue); \
+ _resp_lvalue; \
+})
+
+/**
+ * cr_rpc_recv_req(ch) reads a request from ch, and returns a
+ * NAME##_req_t handle wrapping that request.
*
- * / **
- * * NAME##_recv_req(ch) reads a request from ch, and returns a
- * * NAME##_req_t handle wrapping that request.
- * *
- * * @runs_in coroutine
- * * @cr_pauses maybe
- * * @cr_yields maybe
- * * /
- * NAME##_req_t NAME##_recv_req(NAME##_t *ch);
+ * @runs_in coroutine
+ * @cr_pauses maybe
+ * @cr_yields maybe
*
- * / **
- * * NAME##_can_recv_req(ch) returns whether NAME##_recv_req(ch)
- * * would return without pausing.
- * *
- * * @runs_in coroutine
- * * @cr_pauses never
- * * @cr_yields never
- * * /
- * bool NAME##_can_recv_req(NAME##_t *ch);
+ * NAME##_req_t cr_rcp_recv_req(NAME##_t *ch);
+ */
+#define cr_rpc_recv_req(CH) ({ \
+ cr_assert_in_coroutine(); \
+ typeof((CH)->handle_typ[0]) ret; \
+ _cr_rpc_recv_req(&(CH)->core, \
+ &ret.req, sizeof(ret.req), \
+ (void **)&ret._resp, \
+ &ret._requester); \
+ ret; \
+})
+
+/**
+ * cr_rpc_can_recv_req(ch) returns whether NAME##_recv_req(ch)
+ * would return without pausing.
*
- * type:
+ * @runs_in coroutine
+ * @cr_pauses never
+ * @cr_yields never
*
- * / **
- * * A NAME##_req_t is a handle that wraps a REQ_T, and is a channel
- * * that a response may be written to.
- * * /
- * typedef ... NAME##_req_t;
+ * bool cr_rpc_can_recv_req(NAME##_t *ch);
+ */
+#define cr_rpc_can_recv_req(CH) ({ \
+ cr_assert_in_coroutine(); \
+ (bool)((CH)->core.waiters.front && \
+ (CH)->core.waiter_typ == _CR_RPC_REQUESTER); \
+})
+
+/* Methods for NAME##_req_t ***************************************************/
+
+/**
+ * cr_rpc_send_resp(req, resp) sends the given response to the given
+ * request.
*
- * methods:
+ * @runs_in coroutine
+ * @cr_pauses never
+ * @cr_yields always
*
- * / **
- * * cr_rpc_send_resp(req, resp) sends the given response to the given
- * * request.
- * *
- * * @runs_in coroutine
- * * @cr_pauses never
- * * @cr_yields always
- * * /
- * void NAME##_send_resp(NAME##_req_t req, RESP_T resp);
+ * void cr_rpc_send_resp(NAME##_req_t req, RESP_T resp);
*/
-#define CR_RPC_DECLARE(NAME, REQ_T, RESP_T) \
- typedef struct { \
- REQ_T req; \
- \
- RESP_T *_resp; /* where to write resp to */ \
- cid_t _requester; \
- } NAME##_req_t; \
- \
- typedef struct { \
- struct _cr_rpc core; \
- NAME##_req_t handle[0]; \
- } NAME##_t; \
- \
- static inline RESP_T NAME##_send_req(NAME##_t *ch, REQ_T req) { \
- cr_assert_in_coroutine(); \
- RESP_T resp; \
- _cr_rpc_send_req(&ch->core, \
- &req, sizeof(req), \
- &resp); \
- return resp; \
- } \
- \
- static inline NAME##_req_t NAME##_recv_req(NAME##_t *ch) { \
- cr_assert_in_coroutine(); \
- NAME##_req_t ret; \
- _cr_rpc_recv_req(&ch->core, \
- &ret.req, sizeof(ret.req), \
- (void **)&ret._resp, \
- &ret._requester); \
- return ret; \
- } \
- \
- static inline bool NAME##_can_recv_req(NAME##_t *ch) { \
- cr_assert_in_coroutine(); \
- return ch->core.waiters.front && \
- ch->core.waiter_typ == _CR_RPC_REQUESTER; \
- } \
- \
- static inline void NAME##_send_resp(NAME##_req_t req, RESP_T resp) { \
- cr_assert_in_coroutine(); \
- *(req._resp) = resp; \
- cr_unpause(req._requester); \
- cr_yield(); \
- } \
- \
- extern int LM_CAT2_(_CR_RPC_FORCE_SEMICOLON_, __COUNTER__)
+#define cr_rpc_send_resp(REQ, RESP) { \
+ cr_assert_in_coroutine(); \
+ *((REQ)._resp) = RESP; \
+ cr_unpause(REQ._requester); \
+ cr_yield(); \
+} while (0)
+
+/* Background details *********************************************************/
enum _cr_rpc_waiter_typ {
_CR_RPC_REQUESTER,
_CR_RPC_RESPONDER,
};
+SLIST_DECLARE(_cr_rpc_waiter_list);
+
struct _cr_rpc {
enum _cr_rpc_waiter_typ waiter_typ;
- lm_sll_root waiters;
+ struct _cr_rpc_waiter_list waiters;
};
void _cr_rpc_send_req(struct _cr_rpc *ch, void *req_ptr, size_t req_size, void *resp_ptr);
diff --git a/libcr_ipc/include/libcr_ipc/rwmutex.h b/libcr_ipc/include/libcr_ipc/rwmutex.h
index d48abe9..12ee863 100644
--- a/libcr_ipc/include/libcr_ipc/rwmutex.h
+++ b/libcr_ipc/include/libcr_ipc/rwmutex.h
@@ -7,11 +7,11 @@
#ifndef _LIBCR_IPC_RWMUTEX_H_
#define _LIBCR_IPC_RWMUTEX_H_
-#include <stdbool.h>
-
-#include <libmisc/linkedlist.h>
+#include <libmisc/linkedlist.h> /* for SLIST_DECLARE() */
#include <libmisc/private.h>
+SLIST_DECLARE(_cr_rwmutex_waiter_list);
+
/**
* A cr_rwmutex_t is a fair read/write mutex.
*
@@ -25,10 +25,10 @@
*/
typedef struct {
BEGIN_PRIVATE(LIBCR_IPC_RWMUTEX_H);
- unsigned nreaders;
- bool locked;
- bool unpausing;
- lm_sll_root waiters;
+ unsigned nreaders;
+ bool locked;
+ bool unpausing;
+ struct _cr_rwmutex_waiter_list waiters;
END_PRIVATE(LIBCR_IPC_RWMUTEX_H);
} cr_rwmutex_t;
diff --git a/libcr_ipc/include/libcr_ipc/sema.h b/libcr_ipc/include/libcr_ipc/sema.h
index cc387f4..236e9af 100644
--- a/libcr_ipc/include/libcr_ipc/sema.h
+++ b/libcr_ipc/include/libcr_ipc/sema.h
@@ -7,11 +7,11 @@
#ifndef _LIBCR_IPC_SEMA_H_
#define _LIBCR_IPC_SEMA_H_
-#include <stdbool.h>
-
-#include <libmisc/linkedlist.h>
+#include <libmisc/linkedlist.h> /* for SLIST_DECLARE() */
#include <libmisc/private.h>
+SLIST_DECLARE(_cr_sema_waiter_list);
+
/**
* A cr_sema_t is a fair unbounded[1] counting semaphore.
*
@@ -19,9 +19,9 @@
*/
typedef struct {
BEGIN_PRIVATE(LIBCR_IPC_SEMA_H);
- unsigned int cnt;
- bool unpausing;
- lm_sll_root waiters;
+ unsigned int cnt;
+ bool unpausing;
+ struct _cr_sema_waiter_list waiters;
END_PRIVATE(LIBCR_IPC_SEMA_H);
} cr_sema_t;
diff --git a/libcr_ipc/mutex.c b/libcr_ipc/mutex.c
index b0ebe05..1b4e626 100644
--- a/libcr_ipc/mutex.c
+++ b/libcr_ipc/mutex.c
@@ -5,14 +5,15 @@
*/
#include <libcr/coroutine.h> /* for cid_t, cr_* */
+#include <libmisc/assert.h>
#define IMPLEMENTATION_FOR_LIBCR_IPC_MUTEX_H YES
#include <libcr_ipc/mutex.h>
struct cr_mutex_waiter {
- lm_sll_node;
cid_t cid;
};
+SLIST_DECLARE_NODE(_cr_mutex_waiter_list, struct cr_mutex_waiter);
void cr_mutex_lock(cr_mutex_t *mu) {
assert(mu);
@@ -21,10 +22,10 @@ void cr_mutex_lock(cr_mutex_t *mu) {
if (!mu->locked) /* non-blocking fast-path */
mu->locked = true;
else { /* blocking slow-path */
- struct cr_mutex_waiter self = {
+ struct _cr_mutex_waiter_list_node self = { .val = {
.cid = cr_getcid(),
- };
- lm_sll_push_to_rear(&mu->waiters, &self);
+ }};
+ slist_push_to_rear(&mu->waiters, &self);
cr_pause_and_yield();
}
assert(mu->locked);
@@ -36,8 +37,8 @@ void cr_mutex_unlock(cr_mutex_t *mu) {
assert(mu->locked);
if (mu->waiters.front) {
- cr_unpause(lm_sll_node_cast(struct cr_mutex_waiter, mu->waiters.front)->cid);
- lm_sll_pop_from_front(&mu->waiters);
+ cr_unpause(mu->waiters.front->val.cid);
+ slist_pop_from_front(&mu->waiters);
} else
mu->locked = false;
}
diff --git a/libcr_ipc/rpc.c b/libcr_ipc/rpc.c
index 6d9422f..b1b7674 100644
--- a/libcr_ipc/rpc.c
+++ b/libcr_ipc/rpc.c
@@ -4,26 +4,29 @@
* 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>
#include <libcr_ipc/rpc.h>
struct cr_rpc_requester {
- lm_sll_node;
cid_t cid;
void *req_ptr; /* where to read req from */
void *resp_ptr; /* where to write resp to */
};
-
struct cr_rpc_responder {
- lm_sll_node;
/* before enqueued | after dequeued */
/* -------------------+-------------------- */
cid_t cid; /* responder cid | requester cid */
void *ptr; /* where to write req | where to write resp */
};
+union cr_rpc_waiter {
+ struct cr_rpc_requester requester;
+ struct cr_rpc_responder responder;
+};
+SLIST_DECLARE_NODE(_cr_rpc_waiter_list, union cr_rpc_waiter);
void _cr_rpc_send_req(struct _cr_rpc *ch, void *req_ptr, size_t req_size, void *resp_ptr) {
assert(ch);
@@ -31,9 +34,8 @@ void _cr_rpc_send_req(struct _cr_rpc *ch, void *req_ptr, size_t req_size, void *
assert(resp_ptr);
if (ch->waiters.front && ch->waiter_typ != _CR_RPC_REQUESTER) { /* fast-path (still blocks) */
- struct cr_rpc_responder *responder =
- lm_sll_node_cast(struct cr_rpc_responder, ch->waiters.front);
- lm_sll_pop_from_front(&ch->waiters);
+ struct cr_rpc_responder *responder = &ch->waiters.front->val.responder;
+ slist_pop_from_front(&ch->waiters);
/* Copy the req to the responder's stack. */
memcpy(responder->ptr, req_ptr, req_size);
/* Notify the responder that we have done so. */
@@ -43,12 +45,12 @@ void _cr_rpc_send_req(struct _cr_rpc *ch, void *req_ptr, size_t req_size, void *
/* Wait for the responder to set `*resp_ptr`. */
cr_pause_and_yield();
} else { /* blocking slow-path */
- struct cr_rpc_requester self = {
+ struct _cr_rpc_waiter_list_node self = { .val = { .requester = {
.cid = cr_getcid(),
.req_ptr = req_ptr,
.resp_ptr = resp_ptr,
- };
- lm_sll_push_to_rear(&ch->waiters, &self);
+ }}};
+ slist_push_to_rear(&ch->waiters, &self);
/* Wait for a responder to both copy our req and sed
* `*resp_ptr`. */
cr_pause_and_yield();
@@ -62,22 +64,21 @@ void _cr_rpc_recv_req(struct _cr_rpc *ch, void *req_ptr, size_t req_size, void *
assert(ret_requester);
if (ch->waiters.front && ch->waiter_typ != _CR_RPC_RESPONDER) { /* non-blocking fast-path */
- struct cr_rpc_requester *requester =
- lm_sll_node_cast(struct cr_rpc_requester, ch->waiters.front);
- lm_sll_pop_from_front(&ch->waiters);
+ struct cr_rpc_requester *requester = &ch->waiters.front->val.requester;
+ slist_pop_from_front(&ch->waiters);
memcpy(req_ptr, requester->req_ptr, req_size);
*ret_requester = requester->cid;
*ret_resp_ptr = requester->resp_ptr;
} else { /* blocking slow-path */
- struct cr_rpc_responder self = {
+ struct _cr_rpc_waiter_list_node self = { .val = { .responder = {
.cid = cr_getcid(),
.ptr = req_ptr,
- };
- lm_sll_push_to_rear(&ch->waiters, &self);
+ }}};
+ slist_push_to_rear(&ch->waiters, &self);
ch->waiter_typ = _CR_RPC_RESPONDER;
cr_pause_and_yield();
- *ret_requester = self.cid;
- *ret_resp_ptr = self.ptr;
+ *ret_requester = self.val.responder.cid;
+ *ret_resp_ptr = self.val.responder.ptr;
}
}
diff --git a/libcr_ipc/rwmutex.c b/libcr_ipc/rwmutex.c
index 4c5da81..191b7fe 100644
--- a/libcr_ipc/rwmutex.c
+++ b/libcr_ipc/rwmutex.c
@@ -5,31 +5,32 @@
*/
#include <libcr/coroutine.h> /* for cid_t, cr_* */
+#include <libmisc/assert.h>
#define IMPLEMENTATION_FOR_LIBCR_IPC_RWMUTEX_H YES
#include <libcr_ipc/rwmutex.h>
struct cr_rwmutex_waiter {
- lm_sll_node;
bool is_reader;
cid_t cid;
};
+SLIST_DECLARE_NODE(_cr_rwmutex_waiter_list, struct cr_rwmutex_waiter);
void cr_rwmutex_lock(cr_rwmutex_t *mu) {
assert(mu);
cr_assert_in_coroutine();
- struct cr_rwmutex_waiter self = {
+ struct _cr_rwmutex_waiter_list_node self = { .val = {
.is_reader = false,
.cid = cr_getcid(),
- };
- lm_sll_push_to_rear(&mu->waiters, &self);
- if (mu->waiters.front != &self.lm_sll_node || mu->locked)
+ }};
+ slist_push_to_rear(&mu->waiters, &self);
+ if (mu->waiters.front != &self || mu->locked)
cr_pause_and_yield();
- assert(mu->waiters.front == &self.lm_sll_node);
+ assert(mu->waiters.front == &self);
/* We now hold the lock (and are mu->waiters.front). */
- lm_sll_pop_from_front(&mu->waiters);
+ slist_pop_from_front(&mu->waiters);
assert(mu->nreaders == 0);
mu->locked = true;
mu->unpausing = false;
@@ -39,24 +40,23 @@ void cr_rwmutex_rlock(cr_rwmutex_t *mu) {
assert(mu);
cr_assert_in_coroutine();
- struct cr_rwmutex_waiter self = {
+ struct _cr_rwmutex_waiter_list_node self = { .val = {
.is_reader = true,
.cid = cr_getcid(),
- };
- lm_sll_push_to_rear(&mu->waiters, &self);
- if (mu->waiters.front != &self.lm_sll_node || (mu->locked && mu->nreaders == 0))
+ }};
+ slist_push_to_rear(&mu->waiters, &self);
+ if (mu->waiters.front != &self || (mu->locked && mu->nreaders == 0))
cr_pause_and_yield();
- assert(mu->waiters.front == &self.lm_sll_node);
+ assert(mu->waiters.front == &self);
/* We now hold the lock (and are mu->waiters.front). */
- lm_sll_pop_from_front(&mu->waiters);
+ slist_pop_from_front(&mu->waiters);
mu->nreaders++;
mu->locked = true;
- struct cr_rwmutex_waiter *waiter =
- lm_sll_node_cast(struct cr_rwmutex_waiter, mu->waiters.front);
- if (waiter && waiter->is_reader) {
+ struct _cr_rwmutex_waiter_list_node *waiter = mu->waiters.front;
+ if (waiter && waiter->val.is_reader) {
assert(mu->unpausing);
- cr_unpause(waiter->cid);
+ cr_unpause(waiter->val.cid);
} else {
mu->unpausing = false;
}
@@ -70,10 +70,9 @@ void cr_rwmutex_unlock(cr_rwmutex_t *mu) {
assert(mu->nreaders == 0);
assert(!mu->unpausing);
if (mu->waiters.front) {
- struct cr_rwmutex_waiter *waiter =
- lm_sll_node_cast(struct cr_rwmutex_waiter, mu->waiters.front);
+ struct _cr_rwmutex_waiter_list_node *waiter = mu->waiters.front;
mu->unpausing = true;
- cr_unpause(waiter->cid);
+ cr_unpause(waiter->val.cid);
} else {
mu->locked = false;
}
@@ -88,11 +87,10 @@ void cr_rwmutex_runlock(cr_rwmutex_t *mu) {
mu->nreaders--;
if (mu->nreaders == 0 && !mu->unpausing) {
if (mu->waiters.front) {
- struct cr_rwmutex_waiter *waiter =
- lm_sll_node_cast(struct cr_rwmutex_waiter, mu->waiters.front);
- assert(!waiter->is_reader);
+ struct _cr_rwmutex_waiter_list_node *waiter = mu->waiters.front;
+ assert(!waiter->val.is_reader);
mu->unpausing = true;
- cr_unpause(waiter->cid);
+ cr_unpause(waiter->val.cid);
} else {
mu->locked = false;
}
diff --git a/libcr_ipc/sema.c b/libcr_ipc/sema.c
index cb984b6..f2ac9b6 100644
--- a/libcr_ipc/sema.c
+++ b/libcr_ipc/sema.c
@@ -5,14 +5,15 @@
*/
#include <libcr/coroutine.h> /* for cid_t, cr_* */
+#include <libmisc/assert.h>
#define IMPLEMENTATION_FOR_LIBCR_IPC_SEMA_H YES
#include <libcr_ipc/sema.h>
struct cr_sema_waiter {
- lm_sll_node;
- cid_t cid;
+ cid_t cid;
};
+SLIST_DECLARE_NODE(_cr_sema_waiter_list, struct cr_sema_waiter);
void cr_sema_signal(cr_sema_t *sema) {
assert(sema);
@@ -21,8 +22,7 @@ void cr_sema_signal(cr_sema_t *sema) {
bool saved = cr_save_and_disable_interrupts();
sema->cnt++;
if (sema->waiters.front && !sema->unpausing) {
- cr_unpause(
- lm_sll_node_cast(struct cr_sema_waiter, sema->waiters.front)->cid);
+ cr_unpause(sema->waiters.front->val.cid);
sema->unpausing = true;
}
cr_restore_interrupts(saved);
@@ -34,8 +34,7 @@ void cr_sema_signal_from_intrhandler(cr_sema_t *sema) {
sema->cnt++;
if (sema->waiters.front && !sema->unpausing) {
- cr_unpause_from_intrhandler(
- lm_sll_node_cast(struct cr_sema_waiter, sema->waiters.front)->cid);
+ cr_unpause_from_intrhandler(sema->waiters.front->val.cid);
sema->unpausing = true;
}
}
@@ -46,18 +45,17 @@ void cr_sema_wait(cr_sema_t *sema) {
bool saved = cr_save_and_disable_interrupts();
- struct cr_sema_waiter self = {
+ struct _cr_sema_waiter_list_node self = { .val = {
.cid = cr_getcid(),
- };
- lm_sll_push_to_rear(&sema->waiters, &self);
- if (sema->waiters.front != &self.lm_sll_node || !sema->cnt)
+ }};
+ slist_push_to_rear(&sema->waiters, &self);
+ if (sema->waiters.front != &self || !sema->cnt)
cr_pause_and_yield();
- assert(sema->waiters.front == &self.lm_sll_node && sema->cnt);
- lm_sll_pop_from_front(&sema->waiters);
+ assert(sema->waiters.front == &self && sema->cnt);
+ slist_pop_from_front(&sema->waiters);
sema->cnt--;
if (sema->cnt && sema->waiters.front)
- cr_unpause(
- lm_sll_node_cast(struct cr_sema_waiter, sema->waiters.front)->cid);
+ cr_unpause(sema->waiters.front->val.cid);
else
sema->unpausing = false;
cr_restore_interrupts(saved);
diff --git a/libcr_ipc/tests/config.h b/libcr_ipc/tests/config.h
index 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 9b6f018..ee1751f 100644
--- a/libcr_ipc/tests/test_chan.c
+++ b/libcr_ipc/tests/test_chan.c
@@ -11,39 +11,121 @@
CR_CHAN_DECLARE(intchan, int);
-COROUTINE cr_producer(void *_ch) {
+/* test 1 *********************************************************************/
+
+COROUTINE test1_producer_cr(void *_ch) {
intchan_t *ch = _ch;
cr_begin();
- intchan_send(ch, 1);
+ cr_chan_send(ch, 1);
- while (!intchan_can_send(ch))
+ while (!cr_chan_can_send(ch))
cr_yield();
- intchan_send(ch, 2);
-
+ cr_chan_send(ch, 2);
cr_end();
}
-COROUTINE cr_consumer(void *_ch) {
+COROUTINE test1_consumer_cr(void *_ch) {
int x;
intchan_t *ch = _ch;
cr_begin();
- x = intchan_recv(ch);
+ x = cr_chan_recv(ch);
test_assert(x == 1);
- x = intchan_recv(ch);
+ x = cr_chan_recv(ch);
test_assert(x == 2);
cr_end();
}
+/* 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() {
- intchan_t ch = {0};
- coroutine_add("producer", cr_producer, &ch);
- coroutine_add("consumer", cr_consumer, &ch);
+ printf("== test 1 =========================================\n");
+ intchan_t 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.c b/libcr_ipc/tests/test_mutex.c
index 43714c9..d08315d 100644
--- a/libcr_ipc/tests/test_mutex.c
+++ b/libcr_ipc/tests/test_mutex.c
@@ -11,7 +11,7 @@
int counter = 0;
-COROUTINE cr_worker(void *_mu) {
+COROUTINE worker_cr(void *_mu) {
cr_mutex_t *mu = _mu;
cr_begin();
@@ -29,8 +29,8 @@ COROUTINE cr_worker(void *_mu) {
int main() {
cr_mutex_t mu = {};
- coroutine_add("a", cr_worker, &mu);
- coroutine_add("b", cr_worker, &mu);
+ coroutine_add("a", worker_cr, &mu);
+ coroutine_add("b", worker_cr, &mu);
coroutine_main();
test_assert(counter == 200);
return 0;
diff --git a/libcr_ipc/tests/test_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.c b/libcr_ipc/tests/test_rpc.c
index 1e3c471..ee88f47 100644
--- a/libcr_ipc/tests/test_rpc.c
+++ b/libcr_ipc/tests/test_rpc.c
@@ -14,46 +14,46 @@ CR_RPC_DECLARE(intrpc, int, int);
/* Test that the RPC is fair, have worker1 start waiting first, and
* ensure that it gets the first request. */
-COROUTINE cr_caller(void *_ch) {
+COROUTINE caller_cr(void *_ch) {
intrpc_t *ch = _ch;
cr_begin();
- int resp = intrpc_send_req(ch, 1);
+ int resp = cr_rpc_send_req(ch, 1);
test_assert(resp == 2);
- resp = intrpc_send_req(ch, 3);
+ resp = cr_rpc_send_req(ch, 3);
test_assert(resp == 4);
cr_exit();
}
-COROUTINE cr_worker1(void *_ch) {
+COROUTINE worker1_cr(void *_ch) {
intrpc_t *ch = _ch;
cr_begin();
- intrpc_req_t req = intrpc_recv_req(ch);
+ intrpc_req_t req = cr_rpc_recv_req(ch);
test_assert(req.req == 1);
- intrpc_send_resp(req, 2);
+ cr_rpc_send_resp(req, 2);
cr_exit();
}
-COROUTINE cr_worker2(void *_ch) {
+COROUTINE worker2_cr(void *_ch) {
intrpc_t *ch = _ch;
cr_begin();
- intrpc_req_t req = intrpc_recv_req(ch);
+ intrpc_req_t req = cr_rpc_recv_req(ch);
test_assert(req.req == 3);
- intrpc_send_resp(req, 4);
+ cr_rpc_send_resp(req, 4);
cr_exit();
}
int main() {
- intrpc_t ch = {0};
- coroutine_add("worker1", cr_worker1, &ch);
- coroutine_add("caller", cr_caller, &ch);
- coroutine_add("worker2", cr_worker2, &ch);
+ intrpc_t ch = {};
+ coroutine_add("worker1", worker1_cr, &ch);
+ coroutine_add("caller", caller_cr, &ch);
+ coroutine_add("worker2", worker2_cr, &ch);
coroutine_main();
return 0;
}
diff --git a/libcr_ipc/tests/test_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.c b/libcr_ipc/tests/test_rwmutex.c
index 77e8c7c..e79e779 100644
--- a/libcr_ipc/tests/test_rwmutex.c
+++ b/libcr_ipc/tests/test_rwmutex.c
@@ -12,7 +12,7 @@
#include "test.h"
cr_rwmutex_t mu = {};
-char out[10] = {0};
+char out[10] = {};
size_t len = 0;
COROUTINE cr1_reader(void *_mu) {
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 1db645b..0000000
--- a/libcr_ipc/tests/test_select.c
+++ /dev/null
@@ -1,90 +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] = {0};
-intchan_t fch = {0};
-
-COROUTINE cr_consumer(void *) {
- cr_begin();
-
- struct cr_select_arg args[11];
-
- bool chdone[10] = {0};
- int arg2ch[10];
- for (;;) {
- int ret_ch;
- int i_arg = 0;
- for (int i_ch = 0; i_ch < 10; i_ch++) {
- if (!chdone[i_ch]) {
- args[i_arg] = CR_SELECT_RECV(&ch[i_ch], &ret_ch);
- arg2ch[i_arg] = i_ch;
- i_arg++;
- }
- }
- if (!i_arg)
- break;
- args[i_arg] = CR_SELECT_DEFAULT; /* check that default doesn't trigger */
- test_assert(i_arg <= 10);
- int ret_arg = cr_select_v(i_arg+1, args);
- test_assert(ret_arg < i_arg);
- test_assert(arg2ch[ret_arg] == ret_ch);
- chdone[ret_ch] = true;
- }
- int ret_ch, ret_arg;
- args[0] = CR_SELECT_RECV(&ch[0], &ret_ch);
- args[1] = CR_SELECT_DEFAULT;
- ret_arg = cr_select_v(2, args);
- test_assert(ret_arg == 1);
-
- int send = 567;
- args[0] = CR_SELECT_SEND(&fch, &send);
- args[1] = CR_SELECT_DEFAULT;
- ret_arg = cr_select_v(2, args);
- test_assert(ret_arg == 0);
-
- send = 890;
- args[0] = CR_SELECT_SEND(&fch, &send);
- args[1] = CR_SELECT_DEFAULT;
- ret_arg = cr_select_v(2, args);
- test_assert(ret_arg == 1);
-
- cr_end();
-}
-
-COROUTINE cr_producer(void *_n) {
- int n = *(int *)_n;
- cr_begin();
-
- intchan_send(&ch[n], n);
-
- cr_end();
-}
-
-COROUTINE cr_final(void *) {
- cr_begin();
-
- int ret = intchan_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", cr_producer, &i);
- coroutine_add("consumer", cr_consumer, NULL);
- coroutine_add("final", cr_final, NULL);
- coroutine_main();
- return 0;
-}
diff --git a/libcr_ipc/tests/test_sema.c b/libcr_ipc/tests/test_sema.c
index e5b22a5..435c01a 100644
--- a/libcr_ipc/tests/test_sema.c
+++ b/libcr_ipc/tests/test_sema.c
@@ -13,7 +13,7 @@
int counter = 0;
-COROUTINE cr_first(void *_sema) {
+COROUTINE first_cr(void *_sema) {
cr_sema_t *sema = _sema;
cr_begin();
@@ -24,7 +24,7 @@ COROUTINE cr_first(void *_sema) {
cr_exit();
}
-COROUTINE cr_second(void *_sema) {
+COROUTINE second_cr(void *_sema) {
cr_sema_t *sema = _sema;
cr_begin();
@@ -35,7 +35,7 @@ COROUTINE cr_second(void *_sema) {
cr_exit();
}
-COROUTINE cr_producer(void *_sema) {
+COROUTINE producer_cr(void *_sema) {
cr_sema_t *sema = _sema;
cr_begin();
@@ -45,7 +45,7 @@ COROUTINE cr_producer(void *_sema) {
cr_end();
}
-COROUTINE cr_consumer(void *_sema) {
+COROUTINE consumer_cr(void *_sema) {
cr_sema_t *sema = _sema;
cr_begin();
@@ -59,16 +59,16 @@ int main() {
cr_sema_t sema = {};
printf("== test 1 =========================================\n");
- coroutine_add("first", cr_first, &sema);
- coroutine_add("second", cr_second, &sema);
+ coroutine_add("first", first_cr, &sema);
+ coroutine_add("second", second_cr, &sema);
coroutine_main();
test_assert(sema.cnt == 0);
printf("== test 2 =========================================\n");
- coroutine_add("consumer", cr_consumer, &sema);
- coroutine_add("producer", cr_producer, &sema);
+ coroutine_add("consumer", consumer_cr, &sema);
+ coroutine_add("producer", producer_cr, &sema);
coroutine_main();
- coroutine_add("consumer", cr_consumer, &sema);
+ coroutine_add("consumer", consumer_cr, &sema);
coroutine_main();
test_assert(sema.cnt == 0);
diff --git a/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 8ec3647..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 *
\**********************************************************************/
@@ -297,7 +295,7 @@ static bool dhcp_client_send(struct dhcp_client *client, uint8_t msgtyp, const c
* Build the message *
\**********************************************************************/
- *scratch_msg = (struct dhcp_msg){0};
+ *scratch_msg = (struct dhcp_msg){};
size_t optlen = 0;
/* Base structure.
@@ -460,15 +458,15 @@ static bool dhcp_client_send(struct dhcp_client *client, uint8_t msgtyp, const c
/**********************************************************************\
* Send *
\**********************************************************************/
- debugf("state %s: sending DHCP %s", state_strs[client->state], 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) {
- debugf("error: sendto: %zd", r);
- return true;
+ log_debugln("state ", state_strs[client->state], ": sending DHCP ", dhcp_msgtyp_str(msgtyp));
+ 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);
- debugf("check_ip_conflict => %zd", 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) {
@@ -740,10 +726,10 @@ static void dhcp_client_take_lease(struct dhcp_client *client, struct dhcp_recv_
client->lease_time_ns_end = (dur_ns_end == DHCP_INFINITY * NS_PER_S) ? 0 : client->time_ns_init + dur_ns_end;
if (ifup) {
- infof("applying configuration to "PRI_net_eth_addr, ARG_net_eth_addr(client->self_eth_addr));
- infof(":: addr = "PRI_net_ip4_addr, ARG_net_ip4_addr(client->lease_client_addr));
- infof(":: gateway_addr = "PRI_net_ip4_addr, ARG_net_ip4_addr(client->lease_auxdata.gateway_addr));
- infof(":: subnet_mask = "PRI_net_ip4_addr, ARG_net_ip4_addr(client->lease_auxdata.subnet_mask));
+ log_infoln("applying configuration to ", (net_eth_addr, client->self_eth_addr));
+ log_infoln(":: addr = ", (net_ip4_addr, client->lease_client_addr));
+ log_infoln(":: gateway_addr = ", (net_ip4_addr, client->lease_auxdata.gateway_addr));
+ log_infoln(":: subnet_mask = ", (net_ip4_addr, client->lease_auxdata.subnet_mask));
LO_CALL(client->iface, ifup, (struct net_iface_config){
.addr = client->lease_client_addr,
.gateway_addr = client->lease_auxdata.gateway_addr,
@@ -755,19 +741,20 @@ 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 (;;) {
- debugf("loop: state=%s", state_strs[client->state]);
+ [[gnu::cleanup(error_cleanup)]] error err = {};
+ log_debugln("loop: state=", state_strs[client->state]);
switch (client->state) {
case STATE_INIT:
client->xid = rand_uint63n(UINT32_MAX);
@@ -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,26 +775,24 @@ 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);
- debugf("error: recvfrom: %d", 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)) {
- debugf("IP "PRI_net_ip4_addr" is already in use",
- ARG_net_ip4_addr(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 {
dhcp_client_take_lease(client, scratch_msg, true);
@@ -819,22 +804,20 @@ static void dhcp_client_setstate(struct dhcp_client *client,
}
break;
default:
- assert(r < 0);
- debugf("error: recvfrom: %d", 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);
- debugf("error: recvfrom: %d", r);
+ log_debugln("error: recvfrom: ", (error, err));
}
break;
case STATE_RENEWING:
@@ -842,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);
@@ -857,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);
- debugf("error: recvfrom: %d", 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);
@@ -883,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);
- debugf("error: recvfrom: %d", 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/libobj/tests/test.h b/libdhcp/tests/test.h
index 2fb1bd5..2fb1bd5 120000
--- a/libobj/tests/test.h
+++ b/libdhcp/tests/test.h
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/libfmt/CMakeLists.txt b/libfmt/CMakeLists.txt
deleted file mode 100644
index f65d462..0000000
--- a/libfmt/CMakeLists.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-# libfmt/CMakeLists.txt - Support for pico-fmt
-#
-# Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
-# SPDX-License-Identifier: AGPL-3.0-or-later
-
-add_library(libfmt INTERFACE)
-target_include_directories(libfmt PUBLIC INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
-target_sources(libfmt INTERFACE
- libmisc.c
- libobj.c
- quote.c
-)
-target_link_libraries(libfmt INTERFACE
- pico_fmt
- libmisc
- libobj
-)
diff --git a/libfmt/include/libfmt/fmt.h b/libfmt/include/libfmt/fmt.h
deleted file mode 100644
index 1b5bde1..0000000
--- a/libfmt/include/libfmt/fmt.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* libfmt/fmt.h - Support for pico-fmt
- *
- * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-#ifndef _LIBFMT_FMT_H_
-#define _LIBFMT_FMT_H_
-
-#include <pico/fmt_printf.h>
-#include <pico/fmt_install.h>
-
-#include <libobj/obj.h>
-
-/**
- * An object that implements fmt_formatter can be printed using
- * `printf("%v", boxed_obj)`.
- */
-#define fmt_formatter_LO_IFACE \
- LO_FUNC(void, format, struct fmt_state *)
-LO_INTERFACE(fmt_formatter);
-
-#endif /* _LIBFMT_FMT_H_ */
diff --git a/libfmt/libmisc.c b/libfmt/libmisc.c
deleted file mode 100644
index 803b281..0000000
--- a/libfmt/libmisc.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/* libfmt/libmisc.c - Integrate pico-fmt with libmisc
- *
- * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-#include <stdarg.h> /* for va_list, va_start(), va_end() */
-#include <stdio.h> /* for vprintf(), putchar(), fflush() */
-#if LIB_PICO_STDIO
-#include <pico/stdio.h> /* for stdio_putchar_raw() */
-#endif
-
-#include <libmisc/macro.h> /* for LM_UNUSED() */
-#include <libmisc/_intercept.h> /* for __lm_printf() and __lm_light_printf() */
-
-#include <libfmt/fmt.h> /* for fmt_vfctprintf() */
-
-#if LIB_PICO_STDIO
-static void libfmt_light_fct(char character, void *LM_UNUSED(arg)) {
- if (character == '\n')
- stdio_putchar_raw('\r');
- stdio_putchar_raw(character);
-}
-#else
-static void libfmt_libc_fct(char character, void *LM_UNUSED(arg)) {
- putchar(character);
-}
-#endif
-
-int __lm_printf(const char *format, ...) {
- va_list va;
- va_start(va, format);
-#if LIB_PICO_STDIO
- /* pico_stdio has already intercepted vprintf for us, and
- * their stdio_buffered_printer() is better than our
- * libfmt_libc_fct() because buffering. */
- int ret = vprintf(format, va);
-#else
- int ret = fmt_vfctprintf(libfmt_libc_fct, NULL, format, va);
- fflush(stdout);
-#endif
- va_end(va);
- return ret;
-}
-
-int __lm_light_printf(const char *format, ...) {
- va_list va;
- va_start(va, format);
-#if LIB_PICO_STDIO
- /* libfmt_light_fct() and stdio_buffered_printer() both use 68
- * bytes of stack; but the buffer lives on the stack of
- * stdio.c:__wrap_vprintf(); so that's where you'll see the
- * numbers be different if you're analyzing it. (Also, being
- * able to skip the stdio_stack_buffer_flush() call.) */
- int ret = fmt_vfctprintf(libfmt_light_fct, NULL, format, va);
- stdio_flush();
-#else
- int ret = fmt_vfctprintf(libfmt_libc_fct, NULL, format, va);
- fflush(stdout);
-#endif
- va_end(va);
- return ret;
-}
diff --git a/libfmt/libobj.c b/libfmt/libobj.c
deleted file mode 100644
index e4b833b..0000000
--- a/libfmt/libobj.c
+++ /dev/null
@@ -1,17 +0,0 @@
-/* libfmt/libobj.c - Integrate pico-fmt with libobj
- *
- * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-#include <libfmt/fmt.h>
-
-static void libfmt_conv_formatter(struct fmt_state *state) {
- lo_interface fmt_formatter obj = va_arg(*state->args, lo_interface fmt_formatter);
- LO_CALL(obj, format, state);
-}
-
-[[gnu::constructor]]
-static void libfmt_install_formatter(void) {
- fmt_install('v', libfmt_conv_formatter);
-}
diff --git a/libfmt/quote.c b/libfmt/quote.c
deleted file mode 100644
index c91e0b0..0000000
--- a/libfmt/quote.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/* libfmt/quote.c - C-string quoting for pico-fmt
- *
- * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-#include <string.h> /* for strnlen() */
-#include <stdint.h> /* for uint{n}_t() */
-
-#include <libfmt/fmt.h>
-
-enum quote {
- QUOTE_NONE, /* c */
- QUOTE_SIMPLE, /* \c */
- QUOTE_U4, /* \uABCD */
- QUOTE_U8, /* \UABCDABCD */
-};
-
-static inline enum quote needs_quote(uint32_t ch) {
- if (ch == '\a' ||
- ch == '\b' ||
- ch == '\f' ||
- ch == '\n' ||
- ch == '\r' ||
- ch == '\t' ||
- ch == '\v' ||
- ch == '\\' ||
- ch == '\'' ||
- ch == '"' ||
- ch == '?')
- return QUOTE_SIMPLE;
- else if (' ' <= ch && ch <= '~')
- return QUOTE_NONE;
- else if (ch < 0x10000)
- return QUOTE_U4;
- else
- return QUOTE_U8;
-}
-
-/**
- * Quote a string to ASCII-only C syntax. Valid UTF-8 is quoted as
- * short C-escape characters, \uABCD or \UABCDABCD; invalid UTF-8 is
- * quoted as \xAB.
- */
-static void libfmt_conv_quote(struct fmt_state *state) {
- uint32_t ch;
- uint8_t chlen;
-
- const char *in = va_arg(*state->args, char*);
- size_t in_len = strnlen(in, (state->flags & FMT_FLAG_PRECISION) ? state->precision : (size_t)-1);
-
- size_t out_len = 2;
- for (size_t pos = 0; pos < in_len;) {
- if ((in[pos] & 0b10000000) == 0b00000000) { ch = in[pos] & 0b01111111; chlen = 1; }
- else if ((in[pos] & 0b11100000) == 0b11000000) { ch = in[pos] & 0b00011111; chlen = 2; }
- else if ((in[pos] & 0b11110000) == 0b11100000) { ch = in[pos] & 0b00001111; chlen = 3; }
- else if ((in[pos] & 0b11111000) == 0b11110000) { ch = in[pos] & 0b00000111; chlen = 4; }
- else goto measure_invalid_utf8;
- if ((ch == 0 && chlen != 1) || pos + chlen > in_len) goto measure_invalid_utf8;
- for (uint8_t i = 1; i < chlen; i++) {
- if ((in[pos+i] & 0b11000000) != 0b10000000) goto measure_invalid_utf8;
- ch = (ch << 6) | (in[pos+i] & 0b00111111);
- }
- if (ch > 0x10FFFF) goto measure_invalid_utf8;
- pos += chlen;
-
- switch (needs_quote(ch)) {
- case QUOTE_NONE : out_len += 1; break;
- case QUOTE_SIMPLE : out_len += 2; break;
- case QUOTE_U4 : out_len += 6; break;
- case QUOTE_U8 : out_len += 10; break;
- }
- continue;
- measure_invalid_utf8:
- pos++;
- out_len += 4; /* \xAB */
- }
-
- if (!(state->flags & FMT_FLAG_LEFT)) {
- for (size_t i = 0; i + out_len < state->width; i++) {
- fmt_state_putchar(state, ' ');
- }
- }
-
- fmt_state_putchar(state, '"');
- for (size_t pos = 0; pos < in_len;) {
- if ((in[pos] & 0b10000000) == 0b00000000) { ch = in[pos] & 0b01111111; chlen = 1; }
- else if ((in[pos] & 0b11100000) == 0b11000000) { ch = in[pos] & 0b00011111; chlen = 2; }
- else if ((in[pos] & 0b11110000) == 0b11100000) { ch = in[pos] & 0b00001111; chlen = 3; }
- else if ((in[pos] & 0b11111000) == 0b11110000) { ch = in[pos] & 0b00000111; chlen = 4; }
- else goto output_invalid_utf8;
- if ((ch == 0 && chlen != 1) || pos + chlen > in_len) goto output_invalid_utf8;
- for (uint8_t i = 1; i < chlen; i++) {
- if ((in[pos+i] & 0b11000000) != 0b10000000) goto output_invalid_utf8;
- ch = (ch << 6) | (in[pos+i] & 0b00111111);
- }
- if (ch > 0x10FFFF) goto output_invalid_utf8;
- pos += chlen;
-
- switch (needs_quote(ch)) {
- case QUOTE_NONE:
- fmt_state_putchar(state, ch);
- break;
- case QUOTE_SIMPLE:
- fmt_state_putchar(state, '\\');
- switch (ch) {
- case '\a': fmt_state_putchar(state, 'a'); break;
- case '\b': fmt_state_putchar(state, 'b'); break;
- case '\f': fmt_state_putchar(state, 'f'); break;
- case '\n': fmt_state_putchar(state, 'n'); break;
- case '\r': fmt_state_putchar(state, 'r'); break;
- case '\t': fmt_state_putchar(state, 't'); break;
- case '\v': fmt_state_putchar(state, 'v'); break;
- case '\\': fmt_state_putchar(state, '\\'); break;
- case '\'': fmt_state_putchar(state, '\''); break;
- case '"': fmt_state_putchar(state, '"'); break;
- case '?': fmt_state_putchar(state, '?'); break;
- }
- break;
- case QUOTE_U4:
- fmt_state_putchar(state, '\\');
- fmt_state_putchar(state, 'u');
- fmt_state_putchar(state, (ch >> 12) & 0xF);
- fmt_state_putchar(state, (ch >> 8) & 0xF);
- fmt_state_putchar(state, (ch >> 4) & 0xF);
- fmt_state_putchar(state, (ch >> 0) & 0xF);
- break;
- case QUOTE_U8:
- fmt_state_putchar(state, '\\');
- fmt_state_putchar(state, 'U');
- fmt_state_putchar(state, (ch >> 28) & 0xF);
- fmt_state_putchar(state, (ch >> 24) & 0xF);
- fmt_state_putchar(state, (ch >> 20) & 0xF);
- fmt_state_putchar(state, (ch >> 16) & 0xF);
- fmt_state_putchar(state, (ch >> 12) & 0xF);
- fmt_state_putchar(state, (ch >> 8) & 0xF);
- fmt_state_putchar(state, (ch >> 4) & 0xF);
- fmt_state_putchar(state, (ch >> 0) & 0xF);
- break;
- }
- continue;
- output_invalid_utf8:
- fmt_state_putchar(state, '\\');
- fmt_state_putchar(state, 'x');
- fmt_state_putchar(state, (in[pos] >> 4) & 0xF);
- fmt_state_putchar(state, (in[pos] >> 0) & 0xF);
- pos++;
- }
- fmt_state_putchar(state, '"');
-
- for (size_t i = 0; i + out_len < state->width; i++) {
- fmt_state_putchar(state, ' ');
- }
-}
-
-[[gnu::constructor]]
-static void libfmt_install_quote(void) {
- fmt_install('q', libfmt_conv_quote);
-}
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 9eedec2..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);
}
@@ -49,18 +52,18 @@ static void hostclock_handle_sig_alarm(int LM_UNUSED(sig), siginfo_t *info, void
if (alarmclock->queue) {
struct itimerspec alarmspec = {
.it_value = ns_to_host_ns_time(alarmclock->queue->fire_at_ns),
- .it_interval = {0},
+ .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 = {0},
+ .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 0cb8d30..2ddb054 100644
--- a/libhw_cr/host_include/libhw/host_alarmclock.h
+++ b/libhw_cr/host_include/libhw/host_alarmclock.h
@@ -7,11 +7,10 @@
#ifndef _LIBHW_HOST_ALARMCLOCK_H_
#define _LIBHW_HOST_ALARMCLOCK_H_
-#include <stdbool.h> /* for bool */
-#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 6ed6e46..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 */
@@ -19,9 +21,10 @@
#include <signal.h> /* for siginfo_t, struct sigaction, enum sigval, sigaction(), SA_SIGINFO */
#include <libcr/coroutine.h>
+#include <libmisc/alloc.h>
#include <libmisc/assert.h>
#include <libmisc/macro.h>
-#include <libobj/obj.h>
+#include <libmisc/obj.h>
#include <libhw/generic/alarmclock.h>
@@ -30,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 *********************************************************************/
@@ -52,7 +55,7 @@ static void hostnet_handle_sig_io(int LM_UNUSED(sig), siginfo_t *info, void *LM_
}
static void hostnet_init(void) {
- struct sigaction action = {0};
+ struct sigaction action = {};
if (hostnet_sig_io)
return;
@@ -62,12 +65,12 @@ 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 { \
int r; \
- union sigval val = {0}; \
+ union sigval val = {}; \
val.sival_int = (int)((args)->cr_coroutine); \
do { \
r = pthread_sigqueue((args)->cr_thread, \
@@ -77,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);
}
}
@@ -127,7 +131,7 @@ void hostnet_tcp_listener_init(struct hostnet_tcp_listener *self, uint16_t port)
union {
struct sockaddr_in in;
struct sockaddr gen;
- } addr = { 0 };
+ } addr = {};
hostnet_init();
@@ -135,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;
}
@@ -157,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() *****************************************************************/
@@ -214,56 +222,74 @@ 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);
+ size_t count = 0;
+ for (int i = 0; i < iovcnt; i++)
+ 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){0};
+ 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() ****************************************************************/
@@ -276,14 +302,15 @@ 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) {
struct hostnet_pthread_writev_args *args = _args;
size_t count = 0;
- struct iovec *iov = alloca(sizeof(struct iovec)*args->iovcnt);
+ struct iovec *iov = stack_alloc(args->iovcnt, struct iovec);
for (int i = 0; i < args->iovcnt; i++) {
iov[i] = args->iov[i];
count += args->iov[i].iov_len;
@@ -294,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;
@@ -309,45 +336,59 @@ 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);
+ size_t count = 0;
+ for (int i = 0; i < iovcnt; 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() *****************************************************************/
@@ -358,7 +399,7 @@ void hostnet_udp_conn_init(struct hostnet_udp_conn *self, uint16_t port) {
struct sockaddr_in in;
struct sockaddr gen;
struct sockaddr_storage stor;
- } addr = { 0 };
+ } addr = {};
hostnet_init();
@@ -366,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;
@@ -386,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) {
@@ -395,27 +439,33 @@ static void *hostnet_pthread_sendto(void *_args) {
struct sockaddr_in in;
struct sockaddr gen;
struct sockaddr_storage stor;
- } addr = { 0 };
+ } addr = {};
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(),
@@ -426,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;
@@ -451,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;
};
@@ -463,42 +518,49 @@ static void *hostnet_pthread_recvfrom(void *_args) {
struct sockaddr_in in;
struct sockaddr gen;
struct sockaddr_storage stor;
- } addr = { 0 };
- socklen_t addr_size;
-
- *(args->ret_size) = setsockopt(args->connfd, SOL_SOCKET, SO_RCVTIMEO,
- &args->timeout, sizeof(args->timeout));
- if (*(args->ret_size) < 0)
+ } addr = {};
+ socklen_t addr_size = sizeof(addr);
+
+ 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(),
@@ -507,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){0};
+ 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 69116bf..8901f06 100644
--- a/libhw_cr/rp2040_dma.c
+++ b/libhw_cr/rp2040_dma.c
@@ -1,22 +1,38 @@
/* 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
*/
-#include <stdbool.h>
-
#include <hardware/irq.h> /* for irq_set_exclusive_handler() */
#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;
};
-struct dmairq_handler_entry dmairq_handlers[NUM_DMA_CHANNELS] = {0};
+struct dmairq_handler_entry dmairq_handlers[NUM_DMA_CHANNELS] = {};
-bool dmairq_initialized[NUM_DMA_IRQS] = {0};
+bool dmairq_initialized[NUM_DMA_IRQS] = {};
static void dmairq_handler(void) {
enum dmairq irq = __get_current_exception() - VTABLE_FIRST_IRQ;
diff --git a/libhw_cr/rp2040_dma.h b/libhw_cr/rp2040_dma.h
index c7f5a8f..5c1c7bb 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 ***************************************************************/
diff --git a/libhw_cr/rp2040_gpioirq.c b/libhw_cr/rp2040_gpioirq.c
index 1ae74f9..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>
@@ -15,7 +15,7 @@ struct gpioirq_handler_entry {
gpioirq_handler_t fn;
void *arg;
};
-struct gpioirq_handler_entry gpioirq_handlers[NUM_BANK0_GPIOS][4] = {0};
+struct gpioirq_handler_entry gpioirq_handlers[NUM_BANK0_GPIOS][4] = {};
int gpioirq_core = -1;
diff --git a/libhw_cr/rp2040_hwspi.c b/libhw_cr/rp2040_hwspi.c
index d181650..398cd68 100644
--- a/libhw_cr/rp2040_hwspi.c
+++ b/libhw_cr/rp2040_hwspi.c
@@ -4,14 +4,12 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-#include <alloca.h>
-#include <inttypes.h> /* for PRIu{n} */
-
#include <hardware/clocks.h> /* for clock_get_hz() and clk_peri */
#include <hardware/gpio.h>
#include <hardware/spi.h>
#include <libcr/coroutine.h>
+#include <libmisc/alloc.h>
#include <libmisc/assert.h>
#define LOG_NAME RP2040_SPI
@@ -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;
@@ -70,7 +68,7 @@ void _rp2040_hwspi_init(struct rp2040_hwspi *self,
assert(self);
assert(baudrate_hz);
uint32_t clk_peri_hz = clock_get_hz(clk_peri);
- debugf("clk_peri = %"PRIu32"Hz", clk_peri_hz);
+ log_debugln("clk_peri = ", clk_peri_hz, "Hz");
assert(baudrate_hz*2 <= clk_peri_hz);
assert_4distinct(pin_miso, pin_mosi, pin_clk, pin_cs);
assert_4distinct(dma1, dma2, dma3, dma4);
@@ -97,7 +95,7 @@ void _rp2040_hwspi_init(struct rp2040_hwspi *self,
}
actual_baudrate_hz = spi_init(inst, baudrate_hz);
- debugf("baudrate = %uHz", actual_baudrate_hz);
+ log_debugln("baudrate = ", actual_baudrate_hz, "Hz");
assert(actual_baudrate_hz == baudrate_hz);
spi_set_format(inst, 8,
(mode & 0b10) ? SPI_CPOL_1 : SPI_CPOL_0,
@@ -138,7 +136,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);
@@ -158,12 +156,14 @@ static void rp2040_hwspi_readwritev(struct rp2040_hwspi *self, const struct dupl
uint8_t bogus_rx_dst;
+ size_t count = 0;
int pruned_iovcnt = 0;
- for (int i = 0; i < iovcnt; i++)
+ for (int i = 0; i < iovcnt; i++) {
+ count += iov[i].iov_len;
if (iov[i].iov_len)
pruned_iovcnt++;
- if (!pruned_iovcnt)
- return;
+ }
+ assert(count);
/* It doesn't *really* matter which aliases we choose:
*
@@ -198,8 +198,8 @@ static void rp2040_hwspi_readwritev(struct rp2040_hwspi *self, const struct dupl
* happens, so the IRQ machinery doesn't need to be engaged
* at all.
*/
- struct dma_alias1 *tx_data_blocks = alloca(sizeof(struct dma_alias1)*(pruned_iovcnt+1));
- struct dma_alias0 *rx_data_blocks = alloca(sizeof(struct dma_alias0)*(pruned_iovcnt+1));
+ [[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));
@@ -230,8 +230,8 @@ static void rp2040_hwspi_readwritev(struct rp2040_hwspi *self, const struct dupl
};
j++;
}
- tx_data_blocks[pruned_iovcnt] = (typeof(tx_data_blocks[0])){0};
- rx_data_blocks[pruned_iovcnt] = (typeof(rx_data_blocks[0])){0};
+ tx_data_blocks[pruned_iovcnt] = (typeof(tx_data_blocks[0])){};
+ rx_data_blocks[pruned_iovcnt] = (typeof(rx_data_blocks[0])){};
/* If ctrl isn't the trigger then we need to make sure that
* DMA_CTRL_IRQ_QUIET isn't cleared before the trigger
* happens. */
@@ -268,4 +268,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/rp2040_hwspi.h b/libhw_cr/rp2040_include/libhw/rp2040_hwspi.h
index 4951136..8d4effa 100644
--- a/libhw_cr/rp2040_include/libhw/rp2040_hwspi.h
+++ b/libhw_cr/rp2040_include/libhw/rp2040_hwspi.h
@@ -99,7 +99,7 @@ LO_IMPLEMENTATION_H(spi, struct rp2040_hwspi, rp2040_hwspi);
min_delay_ns, bogus_data, \
pin_miso, pin_mosi, pin_clk, pin_cs, \
dma1, dma2, dma3, dma4); \
- } while(0)
+ } while (0)
void _rp2040_hwspi_init(struct rp2040_hwspi *self,
enum rp2040_hwspi_instance inst_num,
enum spi_mode mode,
diff --git a/libhw_cr/rp2040_include/libhw/w5500.h b/libhw_cr/rp2040_include/libhw/w5500.h
index 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 fa427d9..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,19 +68,19 @@
* 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() */
#include <libhw/generic/alarmclock.h> /* for sleep_*() */
#define LOG_NAME W5500
-#include <libmisc/log.h> /* for errorf(), debugf(), const_byte_str() */
+#include <libmisc/log.h>
#define IMPLEMENTATION_FOR_LIBHW_W5500_H YES
#include <libhw/w5500.h>
@@ -124,22 +125,22 @@ static const char *w5500_state_str(uint8_t state) {
}
}
-/* libobj *********************************************************************/
+/* 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 ********************************************************/
@@ -187,7 +188,7 @@ static COROUTINE w5500_irq_cr(void *_chip) {
bool had_intr = false;
uint8_t chipintr = w5500ll_read_common_reg(chip->spidev, chip_interrupt);
- n_debugf(W5500_LL, "w5500_irq_cr(): chipintr=%"PRIu8, chipintr);
+ log_n_debugln(W5500_LL, "w5500_irq_cr(): chipintr=", chipintr);
had_intr = had_intr || (chipintr != 0);
if (chipintr)
w5500ll_write_common_reg(chip->spidev, chip_interrupt, 0xFF);
@@ -196,7 +197,7 @@ static COROUTINE w5500_irq_cr(void *_chip) {
struct _w5500_socket *socket = &chip->sockets[socknum];
uint8_t sockintr = w5500ll_read_sock_reg(chip->spidev, socknum, interrupt);
- n_debugf(W5500_LL, "w5500_irq_cr(): sockintr[%"PRIu8"]=%"PRIu8, socknum, sockintr);
+ log_n_debugln(W5500_LL, "w5500_irq_cr(): sockintr[", socknum, "]=", sockintr);
had_intr = had_intr || (sockintr != 0);
switch (socket->mode) {
@@ -208,16 +209,16 @@ static COROUTINE w5500_irq_cr(void *_chip) {
recv_bits = sockintr & (SOCKINTR_RECV_DAT|SOCKINTR_RECV_FIN);
if (listen_bits) {
- debugf("w5500_irq_cr(): signal sock[%"PRIu8"]->listen_sema", socknum);
+ log_debugln("w5500_irq_cr(): signal sock[", socknum, "]->listen_sema");
cr_sema_signal(&socket->listen_sema);
}
if (recv_bits) {
- debugf("w5500_irq_cr(): signal sock[%"PRIu8"]->read_sema", socknum);
+ log_debugln("w5500_irq_cr(): signal sock[", socknum, "]->read_sema");
cr_sema_signal(&socket->read_sema);
}
if (send_bits) {
- debugf("w5500_irq_cr(): signal sock[%"PRIu8"]->write_ch", socknum);
- _w5500_sockintr_ch_send(&socket->write_ch, send_bits);
+ log_debugln("w5500_irq_cr(): signal sock[", socknum, "]->write_ch");
+ cr_chan_send(&socket->write_ch, send_bits);
}
break;
}
@@ -228,7 +229,7 @@ static COROUTINE w5500_irq_cr(void *_chip) {
cr_mutex_unlock(&chip->mu);
if (!had_intr && gpio_get(chip->pin_intr)) {
- debugf("w5500_irq_cr(): looks like all interrupts have been processed, sleeping...");
+ log_debugln("w5500_irq_cr(): looks like all interrupts have been processed, sleeping...");
cr_sema_wait(&chip->intr);
} else
cr_yield();
@@ -283,7 +284,7 @@ static inline void w5500_socket_close(struct _w5500_socket *socket) {
static void w5500_intrhandler(void *_chip, uint LM_UNUSED(gpio), enum gpio_irq_level LM_UNUSED(event)) {
struct w5500 *chip = _chip;
- debugf("w5500_intrhandler()");
+ log_debugln("w5500_intrhandler()");
cr_sema_signal_from_intrhandler(&chip->intr);
}
@@ -322,7 +323,7 @@ void _w5500_init(struct w5500 *chip,
w5500ll_write_sock_reg(chip->spidev, 0, mode, a);
uint8_t b = w5500ll_read_sock_reg(chip->spidev, 0, mode);
if (b != a) {
- errorf("SPI to W5500 does not appear to be functional: wrote:0x%02"PRIx16" != read:0x%02"PRIx8, a, b);
+ log_errorln("SPI to W5500 does not appear to be functional: wrote:", (base16_u8_, a), " != read:", (base16_u8_, b));
spi_ok = false;
}
}
@@ -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,28 +428,28 @@ 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) {
- debugf("if_up()");
- debugf(":: addr = "PRI_net_ip4_addr, ARG_net_ip4_addr(cfg.addr));
- debugf(":: gateway_addr = "PRI_net_ip4_addr, ARG_net_ip4_addr(cfg.gateway_addr));
- debugf(":: subnet_mask = "PRI_net_ip4_addr, ARG_net_ip4_addr(cfg.subnet_mask));
+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));
+ log_debugln(":: subnet_mask = ", (net_ip4_addr, cfg.subnet_mask));
_w5500_if_up(chip, cfg);
}
-static void w5500_if_ifdown(struct w5500 *chip) {
- debugf("if_down()");
- _w5500_if_up(chip, (struct net_iface_config){0});
+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);
if (!sock) {
- debugf("tcp_listen() => no sock");
+ log_debugln("tcp_listen() => no sock");
return LO_NULL(net_stream_listener);
}
- debugf("tcp_listen() => sock[%"PRIu8"]", sock->socknum);
+ log_debugln("tcp_listen() => sock[", sock->socknum, "]");
if (!local_port)
local_port = w5500_alloc_local_port(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));
@@ -470,11 +472,11 @@ static lo_interface net_stream_conn w5500_if_tcp_dial(struct w5500 *chip,
struct _w5500_socket *socket = w5500_alloc_socket(chip);
if (!socket) {
- debugf("tcp_dial() => no sock");
- return LO_NULL(net_stream_conn);
+ log_debugln("tcp_dial() => no sock");
+ return ERROR_NEW_ERR(net_stream_conn, error_new(E_POSIX_ENOTSOCK));
}
uint8_t socknum = socket->socknum;
- debugf("tcp_dial() => sock[%"PRIu8"]", socknum);
+ log_debugln("tcp_dial() => sock[", socknum, "]");
uint16_t local_port = w5500_alloc_local_port(chip);
@@ -502,29 +504,29 @@ static lo_interface net_stream_conn w5500_if_tcp_dial(struct w5500 *chip,
cr_mutex_unlock(&chip->mu);
for (;;) {
uint8_t state = w5500ll_read_sock_reg(chip->spidev, socknum, state);
- debugf("tcp_dial(): state=%s", w5500_state_str(state));
+ log_debugln("tcp_dial(): state=", w5500_state_str(state));
switch (state) {
case STATE_TCP_SYNSENT:
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);
if (!socket) {
- debugf("udp_conn() => no sock");
+ log_debugln("udp_conn() => no sock");
return LO_NULL(net_packet_conn);
}
uint8_t socknum = socket->socknum;
- debugf("udp_conn() => sock[%"PRIu8"]", socknum);
+ log_debugln("udp_conn() => sock[", socknum, "]");
if (!local_port)
local_port = w5500_alloc_local_port(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) {
- debugf("tcp_listener.accept() => already closed");
- return LO_NULL(net_stream_conn);
+ log_debugln("tcp_listener.accept() => already closed");
+ return ERROR_NEW_ERR(net_stream_conn, error_new(E_NET_ECLOSED));
}
cr_mutex_lock(&chip->mu);
@@ -573,7 +591,7 @@ static lo_interface net_stream_conn w5500_tcplist_accept(struct _w5500_socket *s
cr_mutex_unlock(&chip->mu);
for (;;) {
uint8_t state = w5500ll_read_sock_reg(chip->spidev, socknum, state);
- debugf("tcp_listener.accept() => state=%s", w5500_state_str(state));
+ log_debugln("tcp_listener.accept() => state=", w5500_state_str(state));
switch (state) {
case STATE_TCP_LISTEN:
case STATE_TCP_SYNRECV:
@@ -581,37 +599,36 @@ 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) {
- debugf("tcp_listener.close()");
+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;
for (int i = 0; i < iovcnt; i++)
count += iov[i].iov_len;
- debugf("tcp_conn.write(%zu)", count);
+ assert(count);
+ log_debugln("tcp_conn.write(", count, ")");
ASSERT_SELF(stream_conn, TCP);
- if (count == 0)
- return 0;
/* What we really want is to pause until we receive an ACK for
* some data we just queued, so that we can line up some new
@@ -636,15 +653,15 @@ static ssize_t w5500_tcp_writev(struct _w5500_socket *socket, const struct iovec
size_t done = 0;
while (done < count) {
if (!socket->write_open) {
- debugf(" => soft closed");
- return -NET_ECLOSED;
+ log_debugln(" => soft closed");
+ 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);
- debugf(" => hard closed");
- return -NET_ECLOSED;
+ log_debugln(" => hard closed");
+ 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));
@@ -666,26 +683,26 @@ static ssize_t w5500_tcp_writev(struct _w5500_socket *socket, const struct iovec
w5500_socket_cmd(socket, CMD_SEND);
cr_mutex_unlock(&chip->mu);
- switch (_w5500_sockintr_ch_recv(&socket->write_ch)) {
+ switch (cr_chan_recv(&socket->write_ch)) {
case SOCKINTR_SEND_OK:
- debugf(" => sent %zu", freesize);
+ log_debugln(" => sent ", freesize);
done += freesize;
break;
case SOCKINTR_SEND_TIMEOUT:
- debugf(" => ACK timeout");
- return -NET_EACK_TIMEOUT;
+ log_debugln(" => ACK 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:
assert_notreached("invalid write_ch bits");
}
}
- debugf(" => send finished");
- return done;
+ log_debugln(" => send finished");
+ return ERROR_AND(size_t, done, ERROR_NULL);
}
static void w5500_tcp_set_read_deadline(struct _w5500_socket *socket, uint64_t ns) {
- debugf("tcp_conn.set_read_deadline(%"PRIu64")", ns);
+ log_debugln("tcp_conn.set_read_deadline(", ns, ")");
ASSERT_SELF(stream_conn, TCP);
socket->read_deadline_ns = ns;
}
@@ -695,16 +712,15 @@ 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;
for (int i = 0; i < iovcnt; i++)
count += iov[i].iov_len;
- debugf("tcp_conn.read(%zu)", count);
+ assert(count);
+ log_debugln("tcp_conn.read(", count, ")");
ASSERT_SELF(stream_conn, TCP);
- if (count == 0)
- return 0;
struct alarmclock_trigger trigger = {};
if (socket->read_deadline_ns)
@@ -718,13 +734,13 @@ static ssize_t w5500_tcp_readv(struct _w5500_socket *socket, const struct iovec
for (;;) {
if (!socket->read_open) {
LO_CALL(bootclock, del_trigger, &trigger);
- debugf(" => soft closed");
- return -NET_ECLOSED;
+ log_debugln(" => soft closed");
+ 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);
- debugf(" => recv timeout");
- return -NET_ERECV_TIMEOUT;
+ log_debugln(" => recv 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);
@@ -736,8 +752,8 @@ static ssize_t w5500_tcp_readv(struct _w5500_socket *socket, const struct iovec
default:
LO_CALL(bootclock, del_trigger, &trigger);
cr_mutex_unlock(&chip->mu);
- debugf(" => hard closed");
- return -NET_ECLOSED;
+ log_debugln(" => hard closed");
+ return ERROR_NEW_ERR(size_t, error_new(E_NET_ECLOSED));
}
avail = uint16be_unmarshal(w5500ll_read_sock_reg(chip->spidev, socknum, rx_size));
@@ -747,15 +763,15 @@ static ssize_t w5500_tcp_readv(struct _w5500_socket *socket, const struct iovec
if (state == STATE_TCP_CLOSE_WAIT) {
LO_CALL(bootclock, del_trigger, &trigger);
cr_mutex_unlock(&chip->mu);
- debugf(" => EOF");
- return 0;
+ log_debugln(" => EOF");
+ return ERROR_NEW_ERR(size_t, error_new(E_EOF));
}
cr_mutex_unlock(&chip->mu);
cr_sema_wait(&socket->read_sema);
}
assert(avail);
- debugf(" => received %"PRIu16" bytes", avail);
+ log_debugln(" => received ", avail, " bytes");
uint16_t ptr = uint16be_unmarshal(w5500ll_read_sock_reg(chip->spidev, socknum, rx_read_pointer));
/* Read the data. */
if ((size_t)avail > count)
@@ -767,11 +783,11 @@ 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) {
- debugf("tcp_conn.close(rd=%s, wr=%s)", rd ? "true" : "false", wr ? "true" : "false");
+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);
if (rd)
@@ -798,26 +814,26 @@ 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) {
- debugf("udp_conn.sendto()");
+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);
assert(count);
uint16_t bufsize = ((uint16_t)w5500ll_read_sock_reg(chip->spidev, socknum, tx_buf_size))*1024;
if (count > bufsize) {
- debugf(" => msg too large");
- return -NET_EMSGSIZE;
+ log_debugln(" => msg too large");
+ return error_new(E_POSIX_EMSGSIZE);
}
for (;;) {
@@ -825,8 +841,8 @@ static ssize_t w5500_udp_sendto(struct _w5500_socket *socket, void *buf, size_t
uint8_t state = w5500ll_read_sock_reg(chip->spidev, socknum, state);
if (state != STATE_UDP) {
cr_mutex_unlock(&chip->mu);
- debugf(" => closed");
- return -NET_ECLOSED;
+ log_debugln(" => closed");
+ return error_new(E_NET_ECLOSED);
}
uint16_t freesize = uint16be_unmarshal(w5500ll_read_sock_reg(chip->spidev, socknum, tx_free_size));
@@ -844,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));
@@ -853,13 +869,13 @@ static ssize_t w5500_udp_sendto(struct _w5500_socket *socket, void *buf, size_t
w5500_socket_cmd(socket, CMD_SEND);
cr_mutex_unlock(&chip->mu);
- switch (_w5500_sockintr_ch_recv(&socket->write_ch)) {
+ switch (cr_chan_recv(&socket->write_ch)) {
case SOCKINTR_SEND_OK:
- debugf(" => sent");
- return count;
+ log_debugln(" => sent");
+ return ERROR_NULL;
case SOCKINTR_SEND_TIMEOUT:
- debugf(" => ARP timeout");
- return -NET_EARP_TIMEOUT;
+ log_debugln(" => ARP timeout");
+ return error_new(E_NET_EARP_TIMEOUT);
case SOCKINTR_SEND_OK|SOCKINTR_SEND_TIMEOUT:
assert_notreached("send both OK and timed out?");
default:
@@ -868,7 +884,7 @@ static ssize_t w5500_udp_sendto(struct _w5500_socket *socket, void *buf, size_t
}
static void w5500_udp_set_recv_deadline(struct _w5500_socket *socket, uint64_t ns) {
- debugf("udp_conn.set_recv_deadline(%"PRIu64")", ns);
+ log_debugln("udp_conn.set_recv_deadline(", ns, ")");
ASSERT_SELF(packet_conn, UDP);
socket->read_deadline_ns = ns;
}
@@ -878,9 +894,9 @@ 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) {
- debugf("udp_conn.recvfrom()");
+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);
assert(count);
@@ -897,15 +913,15 @@ static ssize_t w5500_udp_recvfrom(struct _w5500_socket *socket, void *buf, size_
for (;;) {
if (socket->read_deadline_ns && socket->read_deadline_ns <= LO_CALL(bootclock, get_time_ns)) {
LO_CALL(bootclock, del_trigger, &trigger);
- debugf(" => recv timeout");
- return -NET_ERECV_TIMEOUT;
+ log_debugln(" => recv 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);
- debugf(" => hard closed");
- return -NET_ECLOSED;
+ log_debugln(" => hard closed");
+ return ERROR_NEW_ERR(size_t, error_new(E_NET_ECLOSED));
}
avail = uint16be_unmarshal(w5500ll_read_sock_reg(chip->spidev, socknum, rx_size));
@@ -922,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) {
@@ -935,12 +951,12 @@ static ssize_t w5500_udp_recvfrom(struct _w5500_socket *socket, void *buf, size_
if (ret_port)
*ret_port = uint16be_decode(&hdr[4]);
uint16_t len = uint16be_decode(&hdr[6]);
- debugf(" => received %"PRIu16" bytes%s", len, len < avail-8 ? " (plus more messages)" : "");
+ log_debugln(" => received ", len, " bytes", len < avail-8 ? " (plus more messages)" : "");
/* 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. */
@@ -949,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) {
- debugf("udp_conn.close()");
+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..44eea32
--- /dev/null
+++ b/libhw_cr/w5500_ll.c
@@ -0,0 +1,115 @@
+/* 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 "w5500_ll.h"
+
+#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
+
+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 2506cd2..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>
@@ -10,17 +10,15 @@
#ifndef _LIBHW_CR_W5500_LL_H_
#define _LIBHW_CR_W5500_LL_H_
-#include <alloca.h> /* for alloca() */
#include <stdint.h> /* for uint{n}_t */
-#include <string.h> /* for memcmp() */
-#include <libmisc/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,93 +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 char *_ctl_block_part_strs[] = {
- "RES",
- "REG",
- "TX",
- "RX",
-};
-#define PRI_ctl_block "CTL_BLOCK_SOCK(%d, %s)"
-#define ARG_ctl_block(b) (((b)>>5) & 0b111), _ctl_block_part_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
- n_debugf(W5500_LL,
- "%s(): w5500ll_write(spidev, addr=%#04x, block="PRI_ctl_block", iov, iovcnt=%d)",
- func, addr, ARG_ctl_block(block), 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 = alloca(sizeof(struct duplex_iovec)*inner_cnt);
- 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
- n_debugf(W5500_LL,
- "%s(): w5500ll_read(spidev, addr=%#04x, block="PRI_ctl_block", iov, iovcnt=%d)",
- func, addr, ARG_ctl_block(block), 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 = alloca(sizeof(struct duplex_iovec)*inner_cnt);
- 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. ***********************************************/
@@ -378,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 603f30b..6f5fa34 100644
--- a/libhw_generic/CMakeLists.txt
+++ b/libhw_generic/CMakeLists.txt
@@ -3,11 +3,16 @@
# 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
- libobj
)
target_sources(libhw_generic INTERFACE
diff --git a/libhw_generic/alarmclock.c b/libhw_generic/alarmclock.c
index 31fbbaf..3579829 100644
--- a/libhw_generic/alarmclock.c
+++ b/libhw_generic/alarmclock.c
@@ -6,4 +6,20 @@
#include <libhw/generic/alarmclock.h>
-lo_interface alarmclock bootclock = {0};
+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 02789f5..e7e66a1 100644
--- a/libhw_generic/include/libhw/generic/alarmclock.h
+++ b/libhw_generic/include/libhw/generic/alarmclock.h
@@ -7,11 +7,10 @@
#ifndef _LIBHW_GENERIC_ALARMCLOCK_H_
#define _LIBHW_GENERIC_ALARMCLOCK_H_
-#include <stdbool.h> /* for bool */
-#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>
-#include <libobj/obj.h>
/* Useful constants ***********************************************************/
@@ -45,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) \
@@ -63,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 62ddbb3..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 <libobj/obj.h>
+#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,82 +50,171 @@ 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)
+
+/**
+ * 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 `count` on success, -errno on error; a short write *is* an
- * error.
+ * 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.
+ *
+ * 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_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)
+
+/* readwrite =======================================================*/
+
+/**
+ * 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(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(int, close)
+ LO_FUNC(error, close)
LO_INTERFACE(io_closer);
#define io_close(c) LO_CALL(c, close)
-/**
- * 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_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)
-/**
- * Return bytes-read and bytes-written on success, -errno on error; a
- * short read/write *is* an error.
- */
-#define io_duplex_readwriter_LO_IFACE \
- LO_FUNC(void, 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)
-
/* 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 4af574b..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 <stdbool.h> /* for bool */
#include <stddef.h> /* for size_t */
#include <stdint.h> /* for uint{n}_t} */
-#include <sys/types.h> /* for ssize_t */
#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 **************************************************************/
@@ -35,43 +21,16 @@ struct net_ip4_addr {
static const struct net_ip4_addr net_ip4_addr_broadcast = {{255, 255, 255, 255}};
static const struct net_ip4_addr net_ip4_addr_zero = {{0, 0, 0, 0}};
-
-#define PRI_net_ip4_addr "%"PRIu8".%"PRIu8".%"PRIu8".%"PRIu8
-#define ARG_net_ip4_addr(addr) (addr).octets[0], \
- (addr).octets[1], \
- (addr).octets[2], \
- (addr).octets[3]
+void fmt_print_net_ip4_addr(lo_interface fmt_dest, struct net_ip4_addr);
struct net_eth_addr {
unsigned char octets[6];
};
-#define PRI_net_eth_addr "%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8
-#define ARG_net_eth_addr(addr) (addr).octets[0], \
- (addr).octets[1], \
- (addr).octets[2], \
- (addr).octets[3], \
- (addr).octets[4], \
- (addr).octets[5]
+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) \
@@ -90,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) \
\
@@ -102,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) \
\
@@ -137,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/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 e2785ae..906e6e4 100644
--- a/libhw_generic/net.c
+++ b/libhw_generic/net.c
@@ -1,6 +1,6 @@
/* libhw_generic/net.c - Device-independent <libhw/generic/net.h> 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
*/
@@ -29,3 +29,21 @@ const char *net_strerror(int net_errno) {
assert_notreached("invalid net_errno");
}
}
+
+void fmt_print_net_ip4_addr(lo_interface fmt_dest w, struct net_ip4_addr addr) {
+ fmt_print(w,
+ addr.octets[0], ".",
+ addr.octets[1], ".",
+ addr.octets[2], ".",
+ addr.octets[3]);
+}
+
+void fmt_print_net_eth_addr(lo_interface fmt_dest w, struct net_eth_addr addr) {
+ fmt_print(w,
+ (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 fdbe949..7388a91 100644
--- a/libmisc/CMakeLists.txt
+++ b/libmisc/CMakeLists.txt
@@ -3,23 +3,40 @@
# 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
)
-target_compile_options(libmisc INTERFACE "$<$<COMPILE_LANGUAGE:C>:-fplan9-extensions>")
add_lib_test(libmisc test_assert)
add_lib_test(libmisc test_assert_min)
add_lib_test(libmisc test_endian)
+add_lib_test(libmisc test_fmt)
add_lib_test(libmisc test_hash)
add_lib_test(libmisc test_log)
add_lib_test(libmisc test_macro)
add_lib_test(libmisc test_map)
+add_lib_test(libmisc test_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 fdd8154..dc7f250 100644
--- a/libmisc/assert.c
+++ b/libmisc/assert.c
@@ -4,25 +4,21 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-#include <stdbool.h> /* for bool, true, false */
-
#define LOG_NAME ASSERT
-#include <libmisc/log.h> /* for errorf() */
+#include <libmisc/log.h> /* for log_errorln() */
#include <libmisc/assert.h>
#ifndef NDEBUG
-#define __lm_printf __lm_light_printf
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;
- errorf("%s:%u:%s(): assertion \"%s\" failed%s%s",
- file, line, func,
- expr,
- msg ? ": " : "", msg ?: "");
+ log_errorln(file, ":", line, ":", func, "(): ",
+ "assertion \"", (str, expr), "\" failed",
+ msg ? ": " : "", msg ?: "");
in_fail = false;
}
__lm_abort();
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
new file mode 100644
index 0000000..c78be8c
--- /dev/null
+++ b/libmisc/fmt.c
@@ -0,0 +1,266 @@
+/* libmisc/fmt.c - Write formatted text
+ *
+ * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#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);
+}
+
+void fmt_print_bool(lo_interface fmt_dest w, bool b) {
+ fmt_print_str(w, b ? "true" : "false");
+}
+
+void fmt_print_base16_u8_(lo_interface fmt_dest w, uint8_t x) {
+ fmt_print(w, "0x", (rjust, 2, '0', (base16, x)));
+}
+void fmt_print_base16_u16_(lo_interface fmt_dest w, uint16_t x) {
+ fmt_print(w, "0x", (rjust, 4, '0', (base16, x)));
+}
+void fmt_print_base16_u32_(lo_interface fmt_dest w, uint32_t x) {
+ fmt_print(w, "0x", (rjust, 8, '0', (base16, x)));
+}
+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, const void *ptr) {
+ LM_CAT3_(fmt_print_base16_u, __INTPTR_WIDTH__, _)(w, (uintptr_t)ptr);
+}
+
+/* quote **********************************************************************/
+
+/**
+ * Quote a byte to ASCII-only C syntax.
+ */
+void fmt_print_qbyte(lo_interface fmt_dest w, uint8_t 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, '\\');
+ fmt_print_byte(w, 'x');
+ fmt_print_byte(w, hexdig[(b >> 4) & 0xF]);
+ fmt_print_byte(w, hexdig[(b >> 0) & 0xF]);
+ }
+ fmt_print_byte(w, '\'');
+}
+
+/**
+ * Quote a region of memory to ASCII-only C string syntax. Valid
+ * UTF-8 is quoted as short C-escape characters, \uABCD, or
+ * \UABCDABCD; invalid UTF-8 is quoted as \xAB.
+ */
+void fmt_print_qmem(lo_interface fmt_dest w, const void *_str, size_t size) {
+ const uint8_t *str = _str;
+ fmt_print_byte(w, '"');
+ for (size_t pos = 0; pos < size;) {
+ uint32_t ch;
+ 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 == '\0' ||
+ ch == '\b' ||
+ ch == '\f' ||
+ ch == '\n' ||
+ ch == '\r' ||
+ ch == '\t' ||
+ ch == '\v' ||
+ ch == '\\' ||
+ ch == '\'' ||
+ ch == '"' ||
+ ch == '?') {
+ /* short C-escape */
+ fmt_print_byte(w, '\\');
+ switch (ch) {
+ 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 (' ' <= ch && ch <= '~') {
+ /* no escaping */
+ fmt_print_byte(w, ch);
+ } else if (ch < 0x10000) {
+ /* \uABCD */
+ fmt_print_byte(w, '\\');
+ fmt_print_byte(w, 'u');
+ fmt_print_byte(w, hexdig[(ch >> 12) & 0xF]);
+ fmt_print_byte(w, hexdig[(ch >> 8) & 0xF]);
+ fmt_print_byte(w, hexdig[(ch >> 4) & 0xF]);
+ fmt_print_byte(w, hexdig[(ch >> 0) & 0xF]);
+ } else {
+ /* \UABCDABCD */
+ fmt_print_byte(w, '\\');
+ fmt_print_byte(w, 'U');
+ fmt_print_byte(w, hexdig[(ch >> 28) & 0xF]);
+ fmt_print_byte(w, hexdig[(ch >> 24) & 0xF]);
+ fmt_print_byte(w, hexdig[(ch >> 20) & 0xF]);
+ fmt_print_byte(w, hexdig[(ch >> 16) & 0xF]);
+ fmt_print_byte(w, hexdig[(ch >> 12) & 0xF]);
+ fmt_print_byte(w, hexdig[(ch >> 8) & 0xF]);
+ fmt_print_byte(w, hexdig[(ch >> 4) & 0xF]);
+ fmt_print_byte(w, hexdig[(ch >> 0) & 0xF]);
+ }
+ pos += chlen;
+ }
+ fmt_print_byte(w, '"');
+}
+
+void fmt_print_qstr(lo_interface fmt_dest w, const char *str) {
+ fmt_print_qmem(w, str, strlen(str));
+}
+
+void fmt_print_qstrn(lo_interface fmt_dest w, const char *str, size_t n) {
+ fmt_print_qmem(w, str, strnlen(str, n));
+}
+
+/* int ************************************************************************/
+
+#define declare(BASE, BITS) \
+ void _fmt_print_base##BASE##_s##BITS(lo_interface fmt_dest w, \
+ int##BITS##_t val) { \
+ if (val < 0) { \
+ fmt_print_byte(w, '-'); \
+ val = -val; \
+ } \
+ _fmt_print_base##BASE##_u##BITS(w, (uint##BITS##_t)val); \
+ } \
+ \
+ void _fmt_print_base##BASE##_u##BITS(lo_interface fmt_dest w, \
+ uint##BITS##_t absval) { \
+ /* This digit-counting is O(log(absval)); there are \
+ * `__builtin_clz`-based O(1) ways to do this, but when I \
+ * tried them they bloated the code-size too much. And this \
+ * function as a whole is already O(log(absval)) anyway \
+ * because of actually printing the digits. */ \
+ unsigned ndigits = 1; \
+ uint##BITS##_t div = 1; \
+ while (absval / div >= BASE) { \
+ div *= BASE; \
+ ndigits++; \
+ } \
+ \
+ for (unsigned i = 0; i < ndigits; i++) { \
+ unsigned digit = (unsigned) (absval / div); \
+ absval %= div; \
+ div /= BASE; \
+ fmt_print_byte(w, hexdig[digit]); \
+ } \
+ } \
+ LM_FORCE_SEMICOLON
+
+declare(2, 8);
+declare(2, 16);
+declare(2, 32);
+declare(2, 64);
+
+declare(8, 8);
+declare(8, 16);
+declare(8, 32);
+declare(8, 64);
+
+declare(10, 8);
+declare(10, 16);
+declare(10, 32);
+declare(10, 64);
+
+declare(16, 8);
+declare(16, 16);
+declare(16, 32);
+declare(16, 64);
+
+#undef declare
+
+/* fmt_buf ********************************************************************/
+
+LO_IMPLEMENTATION_C(fmt_dest, struct fmt_buf, fmt_buf);
+
+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++;
+}
+
+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/_intercept.h b/libmisc/include/libmisc/_intercept.h
index a264144..fa327d6 100644
--- a/libmisc/include/libmisc/_intercept.h
+++ b/libmisc/include/libmisc/_intercept.h
@@ -7,21 +7,18 @@
#ifndef _LIBMISC__INTERCEPT_H_
#define _LIBMISC__INTERCEPT_H_
-/* pico-sdk/newlib define these to be [[gnu:weak]] already, but
+/* pico-sdk/newlib defines abort() to be [[gnu::weak]] already, but
* depending on optimization options glibc might not, and GCC might
- * assume it knows what they do and optimize them out. So define our
- * own `__lm_` wrappers that GCC/glibc won't interfere with.
+ * assume it knows what it does and optimize it out. So define our
+ * own `__lm_` wrapper that GCC/glibc won't interfere with.
*/
-[[gnu::format(printf, 1, 2)]]
-int __lm_printf(const char *format, ...);
-
[[noreturn]] void __lm_abort(void);
-/* __lm_light_printf is expected to have less stack use than regular
- * __lm_printf, if possible. */
+/* While newlib defines putchar() to be [[gnu::weak]], pico_stdio does
+ * not. Plus the above about optimizations.
+ */
-[[gnu::format(printf, 1, 2)]]
-int __lm_light_printf(const char *format, ...);
+void __lm_putchar(unsigned char c);
#endif /* _LIBMISC__INTERCEPT_H_ */
diff --git a/libmisc/include/libmisc/alloc.h b/libmisc/include/libmisc/alloc.h
new file mode 100644
index 0000000..d8bbc38
--- /dev/null
+++ b/libmisc/include/libmisc/alloc.h
@@ -0,0 +1,41 @@
+/* libmisc/alloc.h - Type-safe wrappers around alloca and malloc
+ *
+ * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#ifndef _LIBMISC_ALLOC_H_
+#define _LIBMISC_ALLOC_H_
+
+#include <alloca.h> /* for alloca() */
+#include <stdlib.h> /* for calloc(), free() */
+#include <string.h> /* for memset() */
+
+#include <libmisc/assert.h>
+
+#define stack_alloc(N, TYP) ({ \
+ size_t _size; \
+ TYP *_ret = NULL; \
+ if (!__builtin_mul_overflow(N, sizeof(TYP), &_size)) { \
+ _ret = alloca(_size); \
+ memset(_ret, 0, _size); \
+ } \
+ assert(_ret); \
+ _ret; \
+})
+
+#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 8cf0735..f726046 100644
--- a/libmisc/include/libmisc/assert.h
+++ b/libmisc/include/libmisc/assert.h
@@ -1,24 +1,36 @@
/* libmisc/assert.h - More assertions
*
- * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#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_msg_fail(expr_str, __FILE__, __LINE__, __func__, msg); } while (0)
+# define __assert_msg(expr, expr_str, msg) \
+ do { \
+ __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,
const char *file, unsigned int line, const char *func,
const char *msg);
#endif
-#define assert_msg(expr, msg) __assert_msg(expr, #expr, msg) /* libmisc */
-#define assert(expr) __assert_msg(expr, #expr, 0) /* C89, POSIX-2001 */
-#define assert_notreached(msg) do { __assert_msg(0, "notreached", msg); __builtin_unreachable(); } while (0) /* libmisc */
-#define static_assert _Static_assert /* C11 */
+#define assert_msg(expr, msg) __assert_msg(expr, #expr, msg) /* libmisc */
+#define assert(expr) __assert_msg(expr, #expr, 0) /* C89, POSIX-2001 */
+#define assert_notreached(msg) do { __assert_msg(0, "notreached", msg); __builtin_unreachable(); } while (0) /* libmisc */
+#define static_assert(...) __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
new file mode 100644
index 0000000..530fc63
--- /dev/null
+++ b/libmisc/include/libmisc/fmt.h
@@ -0,0 +1,163 @@
+/* libmisc/fmt.h - Write formatted text
+ *
+ * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#ifndef _LIBMISC_FMT_H_
+#define _LIBMISC_FMT_H_
+
+#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>
+
+/* destination interface ******************************************************/
+
+#define fmt_dest_LO_IFACE \
+ LO_FUNC(void , putb, uint8_t b) \
+ LO_FUNC(size_t, tell)
+LO_INTERFACE(fmt_dest);
+
+/* type-specific fmt_print_() functions ***************************************/
+
+/* Simple bytes. */
+void fmt_print_byte(lo_interface fmt_dest w, uint8_t b);
+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);
+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); \
+ void _fmt_print_base##base##_u16(lo_interface fmt_dest w, uint16_t val); \
+ void _fmt_print_base##base##_u32(lo_interface fmt_dest w, uint32_t val); \
+ void _fmt_print_base##base##_u64(lo_interface fmt_dest w, uint64_t val); \
+ void _fmt_print_base##base##_s8(lo_interface fmt_dest w, int8_t val); \
+ void _fmt_print_base##base##_s16(lo_interface fmt_dest w, int16_t val); \
+ void _fmt_print_base##base##_s32(lo_interface fmt_dest w, int32_t val); \
+ void _fmt_print_base##base##_s64(lo_interface fmt_dest w, int64_t val); \
+ LM_FORCE_SEMICOLON
+_fmt_declare_base(2);
+_fmt_declare_base(8);
+_fmt_declare_base(10);
+_fmt_declare_base(16);
+#undef _fmt_declare_base
+
+#define _fmt_intswitch(val, prefix) _Generic((val) , \
+ unsigned char : LM_CAT3_(prefix, u, __SCHAR_WIDTH__) , \
+ unsigned short : LM_CAT3_(prefix, u, __SHRT_WIDTH__) , \
+ unsigned int : LM_CAT3_(prefix, u, __INT_WIDTH__) , \
+ unsigned long : LM_CAT3_(prefix, u, __LONG_WIDTH__) , \
+ unsigned long long : LM_CAT3_(prefix, u, __LONG_LONG_WIDTH__) , \
+ signed char : LM_CAT3_(prefix, s, __SCHAR_WIDTH__) , \
+ signed short : LM_CAT3_(prefix, s, __SHRT_WIDTH__) , \
+ signed int : LM_CAT3_(prefix, s, __INT_WIDTH__) , \
+ signed long : LM_CAT3_(prefix, s, __LONG_WIDTH__) , \
+ signed long long : LM_CAT3_(prefix, s, __LONG_LONG_WIDTH__) )
+#define fmt_print_base2(w, val) (_fmt_intswitch((val), _fmt_print_base2_)((w), (val)))
+#define fmt_print_base8(w, val) (_fmt_intswitch((val), _fmt_print_base8_)((w), (val)))
+#define fmt_print_base10(w, val) (_fmt_intswitch((val), _fmt_print_base10_)((w), (val)))
+#define fmt_print_base16(w, val) (_fmt_intswitch((val), _fmt_print_base16_)((w), (val)))
+
+/* Booleans. */
+void fmt_print_bool(lo_interface fmt_dest w, bool b);
+
+/* The high-level fmt_print() interface ***************************************/
+
+#define fmt_print(w, ...) do { LM_FOREACH_PARAM_(_fmt_param, (w), __VA_ARGS__) } while (0)
+#define _fmt_param(w, arg) \
+ LM_IF(LM_IS_TUPLE(arg))( \
+ _fmt_param_tuple LM_EAT() (w, LM_EXPAND arg) \
+ )( \
+ _fmt_param_nontuple(w, arg) \
+ );
+#define _fmt_param_tuple(w, fn, ...) fmt_print_##fn(w __VA_OPT__(,) __VA_ARGS__)
+#define _fmt_param_nontuple(w, val) _Generic((val), \
+ unsigned char : LM_CAT2_(_fmt_print_base10_u, __SCHAR_WIDTH__) , \
+ unsigned short : LM_CAT2_(_fmt_print_base10_u, __SHRT_WIDTH__) , \
+ unsigned int : LM_CAT2_(_fmt_print_base10_u, __INT_WIDTH__) , \
+ unsigned long : LM_CAT2_(_fmt_print_base10_u, __LONG_WIDTH__) , \
+ unsigned long long : LM_CAT2_(_fmt_print_base10_u, __LONG_LONG_WIDTH__) , \
+ signed char : LM_CAT2_(_fmt_print_base10_s, __SCHAR_WIDTH__) , \
+ signed short : LM_CAT2_(_fmt_print_base10_s, __SHRT_WIDTH__) , \
+ signed int : LM_CAT2_(_fmt_print_base10_s, __INT_WIDTH__) , \
+ signed long : LM_CAT2_(_fmt_print_base10_s, __LONG_WIDTH__) , \
+ signed long long : LM_CAT2_(_fmt_print_base10_s, __LONG_LONG_WIDTH__) , \
+ char * : fmt_print_str , \
+ 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 {
+ void *dat;
+ size_t len, cap;
+};
+LO_IMPLEMENTATION_H(fmt_dest, struct fmt_buf, fmt_buf);
+
+#define fmt_snprint(buf, n, ...) ({ \
+ struct fmt_buf _w = { .dat = buf, .cap = n }; \
+ lo_interface fmt_dest w = lo_box_fmt_buf_as_fmt_dest(&_w); \
+ fmt_print(w, __VA_ARGS__); \
+ if (_w.len < _w.cap) \
+ ((char *)_w.dat)[_w.len] = '\0'; \
+ _w.len; \
+})
+
+#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; \
+})
+
+/* justify ********************************************************************/
+
+#define fmt_print_ljust(w, width, fillchar, ...) do { \
+ size_t beg = LO_CALL(w, tell); \
+ fmt_print2(w, __VA_ARGS__); \
+ while ((LO_CALL(w, tell) - beg) < width) \
+ fmt_print_byte(w, fillchar); \
+} while (0)
+
+#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__); \
+ while (_discard.len++ < width) \
+ fmt_print_byte(w, fillchar); \
+ 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, 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/linkedlist.h b/libmisc/include/libmisc/linkedlist.h
index 8adef66..b6ff688 100644
--- a/libmisc/include/libmisc/linkedlist.h
+++ b/libmisc/include/libmisc/linkedlist.h
@@ -7,40 +7,102 @@
#ifndef _LIBMISC_LINKEDLIST_H_
#define _LIBMISC_LINKEDLIST_H_
-#include <libmisc/assert.h>
-#include <libmisc/macro.h>
+/* low-level (intrusive) singly linked list ***********************************/
-/* singly linked list *********************************************************/
+struct _slist_node {
+ struct _slist_node *rear;
+};
-typedef struct _lm_sll_node {
- struct _lm_sll_node *rear;
-} lm_sll_node;
+struct _slist_root {
+ struct _slist_node *front, *rear;
+};
-typedef struct {
- lm_sll_node *front, *rear;
-} lm_sll_root;
+void _slist_push_to_rear(struct _slist_root *root, struct _slist_node *node);
+void _slist_pop_from_front(struct _slist_root *root);
-#define lm_sll_node_cast(node_typ, node_ptr) \
- LM_CAST_FIELD_TO_STRUCT(node_typ, lm_sll_node, node_ptr)
+/* low-level (intrusive) doubly linked list ***********************************/
-void lm_sll_push_to_rear(lm_sll_root *root, lm_sll_node *node);
-void lm_sll_pop_from_front(lm_sll_root *root);
+struct _dlist_node {
+ struct _dlist_node *front, *rear;
+};
-/* doubly linked list *********************************************************/
+struct _dlist_root {
+ struct _dlist_node *front, *rear;
+};
-typedef struct _lm_dll_node {
- struct _lm_dll_node *front, *rear;
-} lm_dll_node;
+void _dlist_push_to_rear(struct _dlist_root *root, struct _dlist_node *node);
+void _dlist_remove(struct _dlist_root *root, struct _dlist_node *node);
+void _dlist_pop_from_front(struct _dlist_root *root);
-typedef struct {
- lm_dll_node *front, *rear;
-} lm_dll_root;
+/* singly linked list (non-intrusive) *****************************************/
-#define lm_dll_node_cast(node_typ, node_ptr) \
- LM_CAST_FIELD_TO_STRUCT(node_typ, lm_dll_node, node_ptr)
+#define SLIST_DECLARE(NAME) \
+ struct NAME##_node; \
+ struct NAME { \
+ struct NAME##_node *front, *rear; \
+ struct NAME *_slist_root_typ[0]; \
+ }
-void lm_dll_push_to_rear(lm_dll_root *root, lm_dll_node *node);
-void lm_dll_remove(lm_dll_root *root, lm_dll_node *node);
-void lm_dll_pop_from_front(lm_dll_root *root);
+#define SLIST_DECLARE_NODE(NAME, VAL_T) \
+ struct NAME##_node { \
+ struct NAME##_node *rear; \
+ VAL_T val; \
+ }
+
+#define slist_push_to_rear(ROOT, NODE) { \
+ /* These temporary variables are to get the compiler to check \
+ * the types. */ \
+ typeof(*(ROOT)->_slist_root_typ[0]) *_rootp = ROOT; \
+ typeof(*_rootp->front) *_nodep = NODE; \
+ _slist_push_to_rear((struct _slist_root *)_rootp, \
+ (struct _slist_node *)_nodep); \
+} while (0)
+
+#define slist_pop_from_front(ROOT) { \
+ /* This temporary variables are to get the compiler to check \
+ * the type. */ \
+ typeof(*(ROOT)->_slist_root_typ[0]) *_rootp = ROOT; \
+ _slist_pop_from_front((struct _slist_root *)_rootp); \
+} while (0)
+
+/* doubly linked list (non-intrusive) *****************************************/
+
+#define DLIST_DECLARE(NAME) \
+ struct NAME##_node; \
+ struct NAME { \
+ struct NAME##_node *front, *rear; \
+ struct NAME *_dlist_root_typ[0]; \
+ }
+
+#define DLIST_DECLARE_NODE(NAME, VAL_T) \
+ struct NAME##_node { \
+ struct NAME##_node *front, *rear; \
+ VAL_T val; \
+ }
+
+#define dlist_push_to_rear(ROOT, NODE) { \
+ /* These temporary variables are to get the compiler to check \
+ * the types. */ \
+ typeof(*(ROOT)->_dlist_root_typ[0]) *_rootp = ROOT; \
+ typeof(*_rootp->front) *_nodep = NODE; \
+ _dlist_push_to_rear((struct _dlist_root *)_rootp, \
+ (struct _dlist_node *)_nodep); \
+} while (0)
+
+#define dlist_remove(ROOT, NODE) { \
+ /* These temporary variables are to get the compiler to check \
+ * the types. */ \
+ typeof(*(ROOT)->_dlist_root_typ[0]) *_rootp = ROOT; \
+ typeof(*_rootp->front) *_nodep = NODE; \
+ _dlist_remove((struct _dlist_root *)_rootp, \
+ (struct _dlist_node *)_nodep); \
+} while (0)
+
+#define dlist_pop_from_front(ROOT) { \
+ /* This temporary variables are to get the compiler to check \
+ * the type. */ \
+ typeof(*(ROOT)->_dlist_root_typ[0]) *_rootp = ROOT; \
+ _dlist_pop_from_front((struct _dlist_root *)_rootp); \
+} while (0)
#endif /* _LIBMISC_LINKEDLIST_H_ */
diff --git a/libmisc/include/libmisc/log.h b/libmisc/include/libmisc/log.h
index 79c0ab6..c40b642 100644
--- a/libmisc/include/libmisc/log.h
+++ b/libmisc/include/libmisc/log.h
@@ -9,8 +9,9 @@
#include <stdint.h> /* for uint8_t */
-#include <libmisc/macro.h>
#include <libmisc/_intercept.h>
+#include <libmisc/fmt.h>
+#include <libmisc/macro.h>
#ifdef NDEBUG
#define _LOG_NDEBUG 1
@@ -20,15 +21,17 @@
const char *const_byte_str(uint8_t b);
-#define n_errorf(nam, fmt, ...) do { __lm_printf("error: " LM_STR_(nam) ": " fmt "\n" __VA_OPT__(,) __VA_ARGS__); } while (0)
-#define n_infof(nam, fmt, ...) do { __lm_printf("info : " LM_STR_(nam) ": " fmt "\n" __VA_OPT__(,) __VA_ARGS__); } while (0)
-#define n_debugf(nam, fmt, ...) do { if (LM_CAT3_(CONFIG_, nam, _DEBUG) && !_LOG_NDEBUG) \
- __lm_printf("debug: " LM_STR_(nam) ": " fmt "\n" __VA_OPT__(,) __VA_ARGS__); } while (0)
+extern lo_interface fmt_dest _log_dest;
+
+#define log_n_errorln(nam, ...) fmt_print(_log_dest, "error: " LM_STR_(nam) ": ", __VA_ARGS__, "\n")
+#define log_n_infoln(nam, ...) fmt_print(_log_dest, "info : " LM_STR_(nam) ": ", __VA_ARGS__, "\n")
+#define log_n_debugln(nam, ...) do { if (LM_CAT3_(CONFIG_, nam, _DEBUG) && !_LOG_NDEBUG) \
+ fmt_print(_log_dest, "debug: " LM_STR_(nam) ": ", __VA_ARGS__, "\n"); } while (0)
#endif /* _LIBMISC_LOG_H_ */
-#if defined(LOG_NAME) && !defined(errorf)
-#define errorf(fmt, ...) n_errorf(LOG_NAME, fmt, __VA_ARGS__)
-#define infof(fmt, ...) n_infof(LOG_NAME, fmt, __VA_ARGS__)
-#define debugf(fmt, ...) n_debugf(LOG_NAME, fmt, __VA_ARGS__)
+#if defined(LOG_NAME) && !defined(log_errorln)
+#define log_errorln(...) log_n_errorln(LOG_NAME, __VA_ARGS__)
+#define log_infoln(...) log_n_infoln(LOG_NAME, __VA_ARGS__)
+#define log_debugln(...) log_n_debugln(LOG_NAME, __VA_ARGS__)
#endif
diff --git a/libmisc/include/libmisc/macro.h b/libmisc/include/libmisc/macro.h
index 6cb15fb..0f9fc3f 100644
--- a/libmisc/include/libmisc/macro.h
+++ b/libmisc/include/libmisc/macro.h
@@ -7,16 +7,30 @@
#ifndef _LIBMISC_MACRO_H_
#define _LIBMISC_MACRO_H_
-/* for function definitions */
+#include <libmisc/assert.h>
+
+/* C: syntax ******************************************************************/
+
+#define LM_FORCE_SEMICOLON _Static_assert(1, "force semicolon")
+
+#define LM_PARTIAL_SWITCH(VAL) \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Wswitch-enum\"") \
+ switch (VAL) \
+ _Pragma("GCC diagnostic pop") \
+
+/* 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 *******************************************************************/
-#define LM_ARRAY_LEN(ary) (sizeof(ary)/sizeof((ary)[0]))
+/* If it's a pointer instead of an array, then typeof(&ptr[0]) == typeof(ptr) */
+#define _LM_IS_ARRAY(ary) (!__builtin_types_compatible_p(typeof(&(ary)[0]), typeof(ary)))
+#define LM_ARRAY_LEN(ary) ( (sizeof(ary)/sizeof((ary)[0])) + static_assert_as_expr(_LM_IS_ARRAY(ary)) )
#define LM_CAST_FIELD_TO_STRUCT(STRUCT_TYP, FIELD_NAME, PTR_TO_FIELD) ({ \
/* The _fptr assignment is to get the compiler to do type checking. */ \
@@ -26,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` */
@@ -34,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
@@ -47,14 +61,18 @@
#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
+
+#define LM_FIRST_(...) LM_FIRST(__VA_ARGS__)
+#define LM_SECOND_(...) LM_SECOND(__VA_ARGS__)
+
#define LM_EAT(...)
#define LM_EXPAND(...) __VA_ARGS__
-/* conditionals */
+/* CPP: conditionals **********************************************************/
#define LM_T xxTxx
#define LM_F xxFxx
@@ -66,42 +84,104 @@
#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()
+#define LM_IS_TUPLE(x) LM_IS_SENTINEL(_LM_IS_TUPLE x)
+#define _LM_IS_TUPLE(...) LM_SENTINEL()
+/* For LM_IS_EMPTY_TUPLE:
+ *
+ * Given
+ *
+ * #define HELPER(...) B, __VA_OPT__(C,) D
+ *
+ * then evaluating the sequence of tokens `HELPER x , A` will give us a
+ * new sequence of tokens according to the following table:
+ *
+ * not a tuple : HELPER x , A
+ * tuple, nonempty: B , C , D , A
+ * tuple, empty : B , D , A
+ *
+ * Looking at this table, it is clear that we must look at the 2nd
+ * resulting comma-separated-value (argument), and set A=false,
+ * C=false, D=true (and B doesn't matter).
+ */
+#define LM_IS_EMPTY_TUPLE(x) LM_SECOND_(_LM_IS_EMPTY_TUPLE x, LM_F)
+#define _LM_IS_EMPTY_TUPLE(...) bogus, __VA_OPT__(LM_F,) LM_T
/* `tuples` is a sequence of `(tuple1)(tuple2)(tuple3)` */
-#define _LM_TUPLES_COMMA(tuple...) (tuple),
-#define LM_TUPLES_NONEMPTY(tuples) LM_IS_TUPLE(_LM_TUPLES_COMMA tuples)
+#define _LM_TUPLES_COMMA(...) (__VA_ARGS__),
+#define LM_TUPLES_IS_NONEMPTY(tuples) LM_IS_TUPLE(_LM_TUPLES_COMMA tuples)
#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
+ * power-of-2 for which the current code compiles. */
+#define _LM_EVAL _LM_EVAL__16
+#define _LM_EVAL__16(...) _LM_EVAL__8(_LM_EVAL__8(__VA_ARGS__))
+#define _LM_EVAL__8(...) _LM_EVAL__4(_LM_EVAL__4(__VA_ARGS__))
+#define _LM_EVAL__4(...) _LM_EVAL__2(_LM_EVAL__2(__VA_ARGS__))
+#define _LM_EVAL__2(...) _LM_EVAL__1(_LM_EVAL__1(__VA_ARGS__))
+#define _LM_EVAL__1(...) __VA_ARGS__
+
+#define _LM_DEFER2(macro) macro LM_EAT LM_EAT()()
-/* BUG: LM_FOREACH_TUPLE maxes out at 1024 tuples. */
+/**
+ * LM_FOREACH_PARAM(func, (fixedparams), params...) calls
+ * func(fixedparams..., param) for each param.
+ *
+ * BUG: LM_FOREACH_PARAM is limited to (16*2)-1=31 params.
+ */
+#define LM_FOREACH_PARAM(func, fixedparams, ...) _LM_EVAL(_LM_FOREACH_PARAM(func, fixedparams, __VA_ARGS__))
+#define _LM_FOREACH_PARAM(func, fixedparams, ...) _LM_FOREACH_PARAM_ITEM(func, fixedparams, __VA_ARGS__, ())
+#define _LM_FOREACH_PARAM_FIXEDPARAMS(fixedparams) _LM_FOREACH_PARAM_FIXEDPARAMS_inner fixedparams
+#define _LM_FOREACH_PARAM_FIXEDPARAMS_inner(...) __VA_ARGS__ __VA_OPT__(,)
+#define _LM_FOREACH_PARAM_ITEM(func, fixedparams, param, ...) \
+ LM_IF(LM_IS_EMPTY_TUPLE(param))()( \
+ _LM_DEFER2(func)(_LM_FOREACH_PARAM_FIXEDPARAMS(fixedparams) param) \
+ _LM_DEFER2(_LM_FOREACH_PARAM_ITEM_indirect)()(func, fixedparams, __VA_ARGS__) \
+ )
+#define _LM_FOREACH_PARAM_ITEM_indirect() _LM_FOREACH_PARAM_ITEM
+
+/** The same as LM_FOREACH_PARAM(), but callable from inside of LM_FOREACH_PARAM(). */
+#define LM_FOREACH_PARAM2(...) _LM_DEFER2(_LM_FOREACH_PARAM_ITEM_indirect)()(__VA_ARGS__, ())
+
+/** The same as above, but evaluates the arguments first. */
+#define LM_FOREACH_PARAM_(...) LM_FOREACH_PARAM(__VA_ARGS__)
+#define LM_FOREACH_PARAM2_(...) LM_FOREACH_PARAM2(__VA_ARGS__)
+
+/**
+ * LM_FOREACH_TUPLE( (tup1) (tup2) (tup3), func, args...) calls
+ * func(args..., tup...) for each tuple.
+ *
+ * BUG: LM_FOREACH_TUPLE is limited to (16*2)-1=31 tuples.
+ */
#define LM_FOREACH_TUPLE(tuples, func, ...) \
_LM_EVAL(_LM_FOREACH_TUPLE(tuples, func, __VA_ARGS__))
#define _LM_FOREACH_TUPLE(tuples, func, ...) \
- LM_IF(LM_TUPLES_NONEMPTY(tuples))( \
+ LM_IF(LM_TUPLES_IS_NONEMPTY(tuples))( \
_LM_DEFER2(func)(__VA_ARGS__ __VA_OPT__(,) LM_EXPAND LM_TUPLES_HEAD(tuples)) \
_LM_DEFER2(_LM_FOREACH_TUPLE_indirect)()(LM_TUPLES_TAIL(tuples), func, __VA_ARGS__) \
)()
#define _LM_FOREACH_TUPLE_indirect() _LM_FOREACH_TUPLE
-#define _LM_DEFER2(macro) macro LM_EAT LM_EAT()()
+/** 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__)
-#define _LM_EVAL(...) _LM_EVAL__1024(__VA_ARGS__) /* 1024 iterations aught to be enough for anybody */
-#define _LM_EVAL__1024(...) _LM_EVAL__512(_LM_EVAL__512(__VA_ARGS__))
-#define _LM_EVAL__512(...) _LM_EVAL__256(_LM_EVAL__256(__VA_ARGS__))
-#define _LM_EVAL__256(...) _LM_EVAL__128(_LM_EVAL__128(__VA_ARGS__))
-#define _LM_EVAL__128(...) _LM_EVAL__64(_LM_EVAL__64(__VA_ARGS__))
-#define _LM_EVAL__64(...) _LM_EVAL__32(_LM_EVAL__32(__VA_ARGS__))
-#define _LM_EVAL__32(...) _LM_EVAL__16(_LM_EVAL__16(__VA_ARGS__))
-#define _LM_EVAL__16(...) _LM_EVAL__8(_LM_EVAL__8(__VA_ARGS__))
-#define _LM_EVAL__8(...) _LM_EVAL__4(_LM_EVAL__4(__VA_ARGS__))
-#define _LM_EVAL__4(...) _LM_EVAL__2(_LM_EVAL__2(__VA_ARGS__))
-#define _LM_EVAL__2(...) _LM_EVAL__1(_LM_EVAL__1(__VA_ARGS__))
-#define _LM_EVAL__1(...) __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 f846f57..65a71bc 100644
--- a/libmisc/include/libmisc/map.h
+++ b/libmisc/include/libmisc/map.h
@@ -7,7 +7,6 @@
#ifndef _LIBMISC_MAP_H_
#define _LIBMISC_MAP_H_
-#include <stdbool.h>
#include <stddef.h> /* for size_t */
#include <stdint.h> /* for uint8_t */
@@ -15,12 +14,14 @@
/* Type ***********************************************************************/
+DLIST_DECLARE(_map_kv_list);
+
struct _map {
- size_t len;
- size_t nbuckets;
- lm_dll_root *buckets;
+ size_t len;
+ size_t nbuckets;
+ struct _map_kv_list *buckets;
- unsigned iterating;
+ unsigned int iterating;
size_t sizeof_kv;
size_t offsetof_k, sizeof_k;
@@ -30,26 +31,27 @@ struct _map {
/**
* MAP_DECLARE(MAPNAME, KEY_T, VAL_T) declares `struct MAPNAME`.
*/
-#define MAP_DECLARE(MAPNAME, KEY_T, VAL_T) \
- struct MAPNAME { \
- struct _map core; \
- struct { \
- lm_dll_node; \
- uint8_t flags; \
- KEY_T key; \
- VAL_T val; \
- } kv_typ[0]; \
+#define MAP_DECLARE(MAPNAME, KEY_T, VAL_T) \
+ struct _##MAPNAME##_kv { \
+ uint8_t flags; \
+ KEY_T key; \
+ VAL_T val; \
+ }; \
+ DLIST_DECLARE_NODE(_##MAPNAME##_kv_list, struct _##MAPNAME##_kv); \
+ struct MAPNAME { \
+ struct _map core; \
+ struct _##MAPNAME##_kv_list_node kv_typ[0]; \
}
-#define _map_init(M) do { \
- if (!(M)->core.sizeof_kv) { \
- (M)->core.sizeof_kv = sizeof((M)->kv_typ[0]); \
- (M)->core.sizeof_k = sizeof((M)->kv_typ[0].key); \
- (M)->core.sizeof_v = sizeof((M)->kv_typ[0].val); \
- (M)->core.offsetof_k = offsetof(typeof((M)->kv_typ[0]), key); \
- (M)->core.offsetof_v = offsetof(typeof((M)->kv_typ[0]), val); \
- } \
-} while(0)
+#define _map_init(M) do { \
+ if (!(M)->core.sizeof_kv) { \
+ (M)->core.sizeof_kv = sizeof((M)->kv_typ[0]); \
+ (M)->core.sizeof_k = sizeof((M)->kv_typ[0].val.key); \
+ (M)->core.sizeof_v = sizeof((M)->kv_typ[0].val.val); \
+ (M)->core.offsetof_k = offsetof(typeof((M)->kv_typ[0]), val.key); \
+ (M)->core.offsetof_v = offsetof(typeof((M)->kv_typ[0]), val.val); \
+ } \
+} while (0)
/* Methods ********************************************************************/
@@ -62,10 +64,10 @@ 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].key) _k = K; \
- (typeof((M)->kv_typ[0].val)*)_map_load(&(M)->core, &_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);
@@ -73,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].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);
@@ -84,11 +86,11 @@ bool _map_del(struct _map *m, void *kp);
* map_store(map, key, val) sets a value in the map. Returns a
* pointer to the map's copy of `val`.
*/
-#define map_store(M, K, ...) ({ \
- _map_init(M); \
- typeof((M)->kv_typ[0].key) _k = K; \
- typeof((M)->kv_typ[0].val) _v = __VA_ARGS__; \
- (typeof((M)->kv_typ[0].val)*)_map_store(&(M)->core, &_k, &_v); \
+#define map_store(M, K, ...) ({ \
+ _map_init(M); \
+ typeof((M)->kv_typ[0].val.key) _k = (K); \
+ typeof((M)->kv_typ[0].val.val) _v = (__VA_ARGS__); \
+ (typeof((M)->kv_typ[0].val.val)*)_map_store(&(M)->core, &_k, &_v); \
})
void *_map_store(struct _map *m, void *kp, void *vp);
@@ -100,18 +102,13 @@ void _map_free(struct _map *m);
/* Iteration ******************************************************************/
-struct _map_kv {
- lm_dll_node;
- uint8_t flags;
-};
-
struct _map_iter {
- struct _map *m;
- void *keyp;
- void **valpp;
+ struct _map *m;
+ void *keyp;
+ void **valpp;
- size_t i;
- struct _map_kv *kv;
+ size_t i;
+ struct _map_kv_list_node *kv;
};
/**
@@ -121,15 +118,15 @@ 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.
*/
#define MAP_FOREACH(M, KNAME, VNAME) _MAP_FOREACH(__COUNTER__, M, KNAME, VNAME)
#define _MAP_FOREACH(CNT, M, KNAME, VNAME) \
for (bool _once_##CNT = true; _once_##CNT;) \
- for (typeof((M)->kv_typ[0].key) KNAME; _once_##CNT;) \
- for (typeof((M)->kv_typ[0].val) *VNAME; _once_##CNT;) \
+ for (typeof((M)->kv_typ[0].val.key) KNAME; _once_##CNT;) \
+ for (typeof((M)->kv_typ[0].val.val) *VNAME; _once_##CNT;) \
for ( \
struct _map_iter _iter_##CNT = ({ \
_map_init(M); \
diff --git a/libmisc/include/libmisc/obj.h b/libmisc/include/libmisc/obj.h
new file mode 100644
index 0000000..c00e512
--- /dev/null
+++ b/libmisc/include/libmisc/obj.h
@@ -0,0 +1,184 @@
+/* libmisc/obj.h - A simple Go-ish object system
+ *
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#ifndef _LIBMISC_OBJ_H_
+#define _LIBMISC_OBJ_H_
+
+#include <libmisc/macro.h>
+
+/**
+ * Use `lo_interface` similarly to how you would use
+ * `struct`/`enum`/`union` when writing the type of an interface
+ * value.
+ */
+#define lo_interface struct
+
+/**
+ * Use `LO_INTERFACE` in a .h file to define an interface.
+ *
+ * First define a macro named `{iface_name}_LO_IFACE` consisting of a
+ * series of calls to LO_NEST and/or LO_FUNC, then call
+ * `LO_INTERFACE({iface_name})`:
+ *
+ * #define myiface_LO_IFACE \
+ * LO_NEST(wrapped_iface_name) \
+ * LO_FUNC(ret_type, func_name, args...)
+ * LO_INTERFACE(myiface)
+ *
+ * Use `lo_interface {iface_name}` as the type of this interface; it
+ * should not be a pointer type.
+ *
+ * If there are any LO_NEST interfaces, this will define a
+ * `lo_box_{iface_name}_as_{wrapped_iface_name}(obj)` function for
+ * each.
+ */
+#define LO_NEST(_ARG_child_iface_name) \
+ (lo_nest, _ARG_child_iface_name)
+#define LO_FUNC(_ARG_ret_type, _ARG_func_name, ...) \
+ (lo_func, _ARG_ret_type, _ARG_func_name __VA_OPT__(,) __VA_ARGS__)
+#define LO_INTERFACE(_ARG_iface_name) \
+ struct _lo_##_ARG_iface_name##_vtable { \
+ LM_FOREACH_TUPLE(_ARG_iface_name##_LO_IFACE, \
+ _LO_IFACE_VTABLE) \
+ }; \
+ struct _ARG_iface_name { \
+ void *self; \
+ const struct _lo_##_ARG_iface_name##_vtable *vtable; \
+ }; \
+ LM_FOREACH_TUPLE(_ARG_iface_name##_LO_IFACE, \
+ _LO_IFACE_PROTO, _ARG_iface_name) \
+ 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_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_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){})
+
+/**
+ * `LO_IS_NULL(iface_val)` returns whether `iface_val` is LO_NULL.
+ */
+#define LO_IS_NULL(_ARG_iface_val) ((_ARG_iface_val).vtable == NULL)
+
+/**
+ * `LO_IFACE_EQ(a, b)` returns whether the interface values `a` and
+ * `b` are the same object.
+ */
+#define LO_EQ(_ARG_iface_val_a, _ARG_iface_val_b) \
+ ((_ARG_iface_val_a).self == (_ARG_iface_val_b).self)
+
+/**
+ * Use LO_CALL(obj, method_name, args...) to call a method on an `lo_interface`.
+ */
+#define LO_CALL(_ARG_obj, _ARG_meth, ...) \
+ (_ARG_obj).vtable->_ARG_meth((_ARG_obj).self __VA_OPT__(,) __VA_ARGS__)
+
+/**
+ * `LO_IMPLEMENTATION_{H,C,STATIC}` declare that `{impl_type}`
+ * implements the `{iface_name}` interface with functions named
+ * `{impl_name}_{method_name}`.
+ *
+ * Either use _H and _C in the .h file and .c file respectively, or
+ * use _STATIC in just a .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( 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
+
+#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,
+
+#define _LO_IMPL_VTABLE_indirect() _LO_IMPL_VTABLE
+#define _LO_IMPL_VTABLE2(...) _LM_DEFER2(_LO_IMPL_VTABLE_indirect)()(__VA_ARGS__)
+
+#endif /* _LIBMISC_OBJ_H_ */
diff --git a/libmisc/include/libmisc/private.h b/libmisc/include/libmisc/private.h
index 5518d1f..5a8777c 100644
--- a/libmisc/include/libmisc/private.h
+++ b/libmisc/include/libmisc/private.h
@@ -11,7 +11,7 @@
#define YES LM_SENTINEL()
#define IS_IMPLEMENTATION_FOR(name) LM_IS_SENTINEL(IMPLEMENTATION_FOR_##name)
-#define BEGIN_PRIVATE(name) LM_IF(IS_IMPLEMENTATION_FOR(name))()(struct {) struct {} LM_CAT2_(_PRIVATE_FORCE_SEMICOLON_, __COUNTER__)
-#define END_PRIVATE(name) LM_IF(IS_IMPLEMENTATION_FOR(name))(struct {} LM_CAT2_(_PRIVATE_FORCE_SEMICOLON_, __COUNTER__))(} LM_CAT2_(_PRIVATE_, __COUNTER__))
+#define BEGIN_PRIVATE(name) LM_IF(IS_IMPLEMENTATION_FOR(name))()(struct {) LM_FORCE_SEMICOLON
+#define END_PRIVATE(name) LM_IF(IS_IMPLEMENTATION_FOR(name))(LM_FORCE_SEMICOLON)(} LM_CAT2_(_PRIVATE_, __COUNTER__))
#endif /* _LIBMISC_PRIVATE_H_ */
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 85a3801..d0e3602 100644
--- a/libmisc/intercept.c
+++ b/libmisc/intercept.c
@@ -4,28 +4,14 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-#include <stdarg.h> /* for va_list, va_start(), va_end() */
-#include <stdio.h> /* for vprintf() */
+#include <stdio.h> /* for putchar() */
#include <stdlib.h> /* for abort() */
#include <libmisc/_intercept.h>
[[gnu::weak]]
-int __lm_printf(const char *format, ...) {
- va_list va;
- va_start(va, format);
- int ret = vprintf(format, va);
- va_end(va);
- return ret;
-}
-
-[[gnu::weak]]
-int __lm_light_printf(const char *format, ...) {
- va_list va;
- va_start(va, format);
- int ret = vprintf(format, va);
- va_end(va);
- return ret;
+void __lm_putchar(unsigned char c) {
+ (void)putchar(c);
}
[[gnu::weak]]
diff --git a/libmisc/linkedlist.c b/libmisc/linkedlist.c
index 5fe0977..71a0aa9 100644
--- a/libmisc/linkedlist.c
+++ b/libmisc/linkedlist.c
@@ -6,11 +6,13 @@
#include <stddef.h> /* for NULL */
+#include <libmisc/assert.h>
+
#include <libmisc/linkedlist.h>
/* singly linked list *********************************************************/
-void lm_sll_push_to_rear(lm_sll_root *root, lm_sll_node *node) {
+void _slist_push_to_rear(struct _slist_root *root, struct _slist_node *node) {
assert(root);
node->rear = NULL;
if (root->rear)
@@ -20,7 +22,7 @@ void lm_sll_push_to_rear(lm_sll_root *root, lm_sll_node *node) {
root->rear = node;
}
-void lm_sll_pop_from_front(lm_sll_root *root) {
+void _slist_pop_from_front(struct _slist_root *root) {
assert(root);
assert(root->front);
root->front = root->front->rear;
@@ -30,7 +32,7 @@ void lm_sll_pop_from_front(lm_sll_root *root) {
/* doubly linked list *********************************************************/
-void lm_dll_push_to_rear(lm_dll_root *root, lm_dll_node *node) {
+void _dlist_push_to_rear(struct _dlist_root *root, struct _dlist_node *node) {
assert(root);
assert(node);
node->front = root->rear;
@@ -42,7 +44,7 @@ void lm_dll_push_to_rear(lm_dll_root *root, lm_dll_node *node) {
root->rear = node;
}
-void lm_dll_remove(lm_dll_root *root, lm_dll_node *node) {
+void _dlist_remove(struct _dlist_root *root, struct _dlist_node *node) {
assert(root);
assert(node);
if (node->front)
@@ -55,8 +57,8 @@ void lm_dll_remove(lm_dll_root *root, lm_dll_node *node) {
root->rear = node->front;
}
-void lm_dll_pop_from_front(lm_dll_root *root) {
+void _dlist_pop_from_front(struct _dlist_root *root) {
assert(root);
assert(root->front);
- lm_dll_remove(root, root->front);
+ _dlist_remove(root, root->front);
}
diff --git a/libmisc/log.c b/libmisc/log.c
index be87de6..96e9ca4 100644
--- a/libmisc/log.c
+++ b/libmisc/log.c
@@ -8,6 +8,25 @@
#include <libmisc/assert.h> /* for static_assert() */
+#include <libmisc/_intercept.h>
+#include <libmisc/log.h>
+
+struct log_stdout {};
+LO_IMPLEMENTATION_STATIC(fmt_dest, struct log_stdout, log_stdout);
+
+static size_t log_bytes = 0;
+
+static void log_stdout_putb(struct log_stdout *, uint8_t b) {
+ __lm_putchar(b);
+ log_bytes++;
+}
+
+static size_t log_stdout_tell(struct log_stdout *) {
+ return log_bytes;
+}
+
+lo_interface fmt_dest _log_dest = { .vtable = &_lo_log_stdout_fmt_dest_vtable };
+
static const char *byte_strs[] = {
"0x00",
"0x01",
diff --git a/libmisc/map.c b/libmisc/map.c
index bb8a2d2..d1b2a57 100644
--- a/libmisc/map.c
+++ b/libmisc/map.c
@@ -7,8 +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)
@@ -16,14 +17,19 @@
/* Internal utilities *********************************************************/
-#define cast(n) lm_dll_node_cast(struct _map_kv, n)
+struct _map_kv {
+ uint8_t flags;
+ /* opaque key; */
+ /* opaque val; */
+};
+DLIST_DECLARE_NODE(_map_kv_list, struct _map_kv);
-static inline void *_map_kv_keyp(struct _map *m, struct _map_kv *kv) {
+static inline void *_map_kv_keyp(struct _map *m, struct _map_kv_list_node *kv) {
assert(m);
assert(kv);
return ((void*)kv)+m->offsetof_k;
}
-static inline void *_map_kv_valp(struct _map *m, struct _map_kv *kv) {
+static inline void *_map_kv_valp(struct _map *m, struct _map_kv_list_node *kv) {
assert(m);
assert(kv);
return ((void*)kv)+m->offsetof_v;
@@ -31,8 +37,8 @@ static inline void *_map_kv_valp(struct _map *m, struct _map_kv *kv) {
static inline void _map_lookup(struct _map *m, void *keyp,
hash_t *ret_hash,
- lm_dll_root **ret_bucket,
- struct _map_kv **ret_kv) {
+ struct _map_kv_list **ret_bucket,
+ struct _map_kv_list_node **ret_kv) {
assert(m);
assert(keyp);
assert(ret_hash);
@@ -45,8 +51,8 @@ static inline void _map_lookup(struct _map *m, void *keyp,
return;
}
*ret_bucket = &m->buckets[*ret_hash % m->nbuckets];
- for (struct _map_kv *kv = cast((*ret_bucket)->front); kv; kv = cast(kv->rear)) {
- if (!(kv->flags & FLAG_DEL) &&
+ for (struct _map_kv_list_node *kv = (*ret_bucket)->front; kv; kv = kv->rear) {
+ if (!(kv->val.flags & FLAG_DEL) &&
memcmp(_map_kv_keyp(m, kv), keyp, m->sizeof_k) == 0) {
*ret_kv = kv;
return;
@@ -58,13 +64,13 @@ static inline void _map_lookup(struct _map *m, void *keyp,
static inline void _map_resize(struct _map *m, size_t new_nbuckets) {
assert(m);
assert(new_nbuckets);
- lm_dll_root *new_buckets = calloc(new_nbuckets, sizeof(lm_dll_root));
+ struct _map_kv_list *new_buckets = heap_alloc(new_nbuckets, struct _map_kv_list);
for (size_t i = 0; i < m->nbuckets; i++) {
while (m->buckets[i].front) {
- struct _map_kv *kv = cast(m->buckets[i].front);
- lm_dll_pop_from_front(&m->buckets[i]);
+ struct _map_kv_list_node *kv = m->buckets[i].front;
+ dlist_pop_from_front(&m->buckets[i]);
hash_t h = hash(_map_kv_keyp(m, kv), m->sizeof_k);
- lm_dll_push_to_rear(&new_buckets[h % new_nbuckets], kv);
+ dlist_push_to_rear(&new_buckets[h % new_nbuckets], kv);
}
}
m->nbuckets = new_nbuckets;
@@ -91,8 +97,8 @@ void *_map_load(struct _map *m, void *keyp) {
assert(keyp);
hash_t h;
- lm_dll_root *bucket;
- struct _map_kv *kv;
+ struct _map_kv_list *bucket;
+ struct _map_kv_list_node *kv;
_map_lookup(m, keyp, &h, &bucket, &kv);
if (!kv)
@@ -105,16 +111,16 @@ bool _map_del(struct _map *m, void *keyp) {
assert(keyp);
hash_t h;
- lm_dll_root *bucket;
- struct _map_kv *kv;
+ struct _map_kv_list *bucket;
+ struct _map_kv_list_node *kv;
_map_lookup(m, keyp, &h, &bucket, &kv);
if (!kv)
return false;
- if (kv->flags & FLAG_ITER) {
- kv->flags |= FLAG_DEL;
+ if (kv->val.flags & FLAG_ITER) {
+ kv->val.flags |= FLAG_DEL;
} else {
- lm_dll_remove(bucket, kv);
+ dlist_remove(bucket, kv);
free(kv);
}
m->len--;
@@ -127,12 +133,12 @@ void *_map_store(struct _map *m, void *keyp, void *valp) {
assert(valp);
hash_t h;
- lm_dll_root *bucket;
- struct _map_kv *old;
+ struct _map_kv_list *bucket;
+ struct _map_kv_list_node *old;
_map_lookup(m, keyp, &h, &bucket, &old);
if (old) {
- lm_dll_remove(bucket, old);
+ dlist_remove(bucket, old);
free(old);
m->len--;
}
@@ -141,10 +147,10 @@ void *_map_store(struct _map *m, void *keyp, void *valp) {
h = hash(keyp, m->sizeof_k);
bucket = &m->buckets[h % m->nbuckets];
}
- struct _map_kv *kv = calloc(1, m->sizeof_kv);
+ struct _map_kv_list_node *kv = calloc(1, m->sizeof_kv);
memcpy(_map_kv_keyp(m, kv), keyp, m->sizeof_k);
memcpy(_map_kv_valp(m, kv), valp, m->sizeof_v);
- lm_dll_push_to_rear(bucket, kv);
+ dlist_push_to_rear(bucket, kv);
return _map_kv_valp(m, kv);
}
@@ -153,8 +159,8 @@ void _map_free(struct _map *m) {
for (size_t i = 0; i < m->nbuckets; i++) {
while (m->buckets[i].front) {
- struct _map_kv *kv = cast(m->buckets[i].front);
- lm_dll_pop_from_front(&m->buckets[i]);
+ struct _map_kv_list_node *kv = m->buckets[i].front;
+ dlist_pop_from_front(&m->buckets[i]);
free(kv);
}
}
@@ -199,14 +205,14 @@ bool _map_iter_next(struct _map_iter *state) {
return false;
while (!state->m->buckets[state->i].front)
state->i++;
- state->kv = cast(state->m->buckets[state->i].front);
+ state->kv = state->m->buckets[state->i].front;
} else {
- struct _map_kv *old_kv = state->kv;
- state->kv = cast(old_kv->rear);
+ struct _map_kv_list_node *old_kv = state->kv;
+ state->kv = old_kv->rear;
- old_kv->flags &= ~FLAG_ITER;
- if (old_kv->flags & FLAG_DEL) {
- lm_dll_remove(&state->m->buckets[state->i], old_kv);
+ old_kv->val.flags &= ~FLAG_ITER;
+ if (old_kv->val.flags & FLAG_DEL) {
+ dlist_remove(&state->m->buckets[state->i], old_kv);
free(old_kv);
}
@@ -214,10 +220,10 @@ bool _map_iter_next(struct _map_iter *state) {
state->i++;
if (state->i == state->m->nbuckets)
return false;
- state->kv = cast(state->m->buckets[state->i].front);
+ state->kv = state->m->buckets[state->i].front;
}
}
- state->kv->flags |= FLAG_ITER;
+ state->kv->val.flags |= FLAG_ITER;
memcpy(state->keyp, _map_kv_keyp(state->m, state->kv), state->m->sizeof_k);
*(state->valpp) = _map_kv_valp(state->m, state->kv);
return true;
diff --git a/libmisc/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 15f9446..84b4d36 100644
--- a/libmisc/tests/test_assert.c
+++ b/libmisc/tests/test_assert.c
@@ -5,28 +5,25 @@
*/
#include <setjmp.h>
-#include <stdarg.h> /* for va_list, va_start(), va_end() */
-#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
-#include <libmisc/macro.h>
-#include <libmisc/assert.h>
#include <libmisc/_intercept.h>
+#include <libmisc/assert.h>
+#include <libmisc/fmt.h>
+#include <libmisc/macro.h>
#include "test.h"
/* Intercept failures and logging *********************************************/
-bool global_failed;
-char *global_log;
-jmp_buf global_env;
+static bool global_failed;
+static struct fmt_buf global_log;
+static jmp_buf global_env;
#define with_intercept() ({ \
global_failed = false; \
- if (global_log) \
- free(global_log); \
- global_log = NULL; \
+ global_log_clear(); \
setjmp(global_env) == 0; \
})
@@ -35,12 +32,19 @@ void __lm_abort(void) {
longjmp(global_env, 1);
}
-int __lm_light_printf(const char *format, ...) {
- va_list va;
- va_start(va, format);
- int ret = vasprintf(&global_log, format, va);
- va_end(va);
- return ret;
+void __lm_putchar(unsigned char c) {
+ if (global_log.len+1 >= global_log.cap) {
+ global_log.cap += 16;
+ global_log.dat = realloc(global_log.dat, global_log.cap);
+ memset(global_log.dat + global_log.len, 0, global_log.cap - global_log.len);
+ }
+ ((uint8_t *)global_log.dat)[global_log.len++] = (uint8_t)c;
+}
+
+static void global_log_clear(void) {
+ if (global_log.dat)
+ memset(global_log.dat, 0, global_log.cap);
+ global_log.len = 0;
}
#define __builtin_unreachable() test_assert(0)
@@ -52,21 +56,21 @@ int __lm_light_printf(const char *format, ...) {
test; \
} \
test_assert(global_failed == false); \
- test_assert(global_log == NULL); \
+ test_assert(global_log.len == 0); \
} while (0)
-#define test_should_fail(test, exp_log) do { \
- if (with_intercept()) { \
- test; \
- } \
- test_assert(global_failed == true); \
- if (!(global_log != NULL && \
- strcmp(global_log, exp_log) == 0)) { \
- printf("exp = \"%s\"\n" \
- "act = \"%s\"\n", \
- exp_log, global_log); \
- test_assert(0); \
- } \
+#define test_should_fail(test, exp_log) do { \
+ if (with_intercept()) { \
+ test; \
+ } \
+ test_assert(global_failed == true); \
+ if (!(global_log.len != 0 && \
+ strcmp(global_log.dat, exp_log) == 0)) { \
+ printf("exp = \"%s\"\n" \
+ "act = \"%s\"\n", \
+ exp_log, (char *)global_log.dat); \
+ test_assert(0); \
+ } \
} while (0)
/* Actual tests ***************************************************************/
@@ -74,6 +78,10 @@ int __lm_light_printf(const char *format, ...) {
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");
@@ -84,11 +92,13 @@ int main() {
test_should_fail(assert_msg(false, NULL), "error: ASSERT: "__FILE__":"LM_STR_(__LINE__)":main(): assertion \"false\" failed\n");
test_should_fail(assert_notreached("xxx"), "error: ASSERT: "__FILE__":"LM_STR_(__LINE__)":main(): assertion \"notreached\" failed: xxx\n");
+#endif
- if (global_log) {
- free(global_log);
- global_log = NULL;
+ if (global_log.dat) {
+ global_log_clear();
+ free(global_log.dat);
+ global_log.dat = NULL;
+ global_log.cap = 0;
}
-#endif
return 0;
}
diff --git a/libmisc/tests/test_endian.c b/libmisc/tests/test_endian.c
index dcb3cc2..8c48727 100644
--- a/libmisc/tests/test_endian.c
+++ b/libmisc/tests/test_endian.c
@@ -11,7 +11,7 @@
#include "test.h"
int main() {
- uint8_t act[(2+4+8)*2] = {0};
+ uint8_t act[(2+4+8)*2] = {};
size_t pos = 0;
pos += uint16be_encode(&act[pos], UINT16_C(0x1234));
pos += uint32be_encode(&act[pos], UINT32_C(0x56789ABC));
diff --git a/libmisc/tests/test_fmt.c b/libmisc/tests/test_fmt.c
new file mode 100644
index 0000000..64b3b8a
--- /dev/null
+++ b/libmisc/tests/test_fmt.c
@@ -0,0 +1,243 @@
+/* libmisc/tests/test_fmt.c - Tests for <libmisc/fmt.h>
+ *
+ * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <stdlib.h> /* for free() */
+#include <string.h> /* for strcmp(), memcmp(), memset() */
+
+#include <libmisc/fmt.h>
+
+#include "test.h"
+
+int main() {
+ char str[128] = {};
+#define do_print(...) fmt_snprint(str, sizeof(str), __VA_ARGS__)
+
+ do_print("hello ", 9, " world!\n");
+ test_assert(strcmp(str, "hello 9 world!\n") == 0);
+ memset(str, 0, sizeof(str));
+
+ do_print("hello ", (base8, 9), " world!\n");
+ test_assert(strcmp(str, "hello 11 world!\n") == 0);
+ memset(str, 0, sizeof(str));
+
+ do_print("hello ", (base2, 9), (qstr, " world!\n"));
+ test_assert(strcmp(str, "hello 1001\" world!\\n\"") == 0);
+ memset(str, 0, sizeof(str));
+
+ do_print("hello ", (base16, 17), " world!\n");
+ test_assert(strcmp(str, "hello 11 world!\n") == 0);
+ memset(str, 0, sizeof(str));
+
+ do_print((strn, "hello ", 4));
+ test_assert(strcmp(str, "hell") == 0);
+ memset(str, 0, sizeof(str));
+
+ do_print((strn, "h\0ello ", 4));
+ test_assert(memcmp(str, "h\0\0", 3) == 0);
+ memset(str, 0, sizeof(str));
+
+ do_print((mem, "hello ", 4));
+ test_assert(strcmp(str, "hell") == 0);
+ memset(str, 0, sizeof(str));
+
+ do_print((mem, "hello\0world", strlen("hello world")+1));
+ test_assert(memcmp(str, "hello\0world", strlen("hello world")+1) == 0);
+ memset(str, 0, sizeof(str));
+
+ do_print((qmem, "hello\0world", strlen("hello world")+1));
+ test_assert(strcmp(str, "\"hello\\0world\\0\"") == 0);
+ memset(str, 0, sizeof(str));
+
+ do_print((qstr, "hello\0world"));
+ test_assert(strcmp(str, "\"hello\"") == 0);
+ memset(str, 0, sizeof(str));
+
+ do_print((qstrn, "hello\0world", strlen("hello world")+1));
+ test_assert(strcmp(str, "\"hello\"") == 0);
+ memset(str, 0, sizeof(str));
+
+ do_print((qstrn, "hello\0world", 4));
+ 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));
+
+ do_print((qbyte, 'h'), (qbyte, 'w'));
+ 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));
+
+ const char *const_str = "hello";
+ do_print(const_str);
+ test_assert(strcmp(str, "hello") == 0);
+ memset(str, 0, sizeof(str));
+
+ bool t = true;
+ do_print(t);
+ test_assert(strcmp(str, "true") == 0);
+ memset(str, 0, sizeof(str));
+
+ bool f = false;
+ do_print(f);
+ test_assert(strcmp(str, "false") == 0);
+ memset(str, 0, sizeof(str));
+
+ /* Check that it accepts all primitive types of integer, not
+ * just all sizes of integer (e.g., on x86-64,
+ * sizeof(long)==sizeof(int), but they're different primitive
+ * types). */
+ {
+ signed char x = 42;
+ do_print("schar ", x);
+ test_assert(strcmp(str, "schar 42") == 0);
+ memset(str, 0, sizeof(str));
+ }
+ {
+ unsigned char x = 43;
+ do_print("uchar ", x);
+ test_assert(strcmp(str, "uchar 43") == 0);
+ memset(str, 0, sizeof(str));
+ }
+
+ {
+ short x = 44;
+ do_print("short ", x);
+ test_assert(strcmp(str, "short 44") == 0);
+ memset(str, 0, sizeof(str));
+ }
+ {
+ unsigned short x = 45;
+ do_print("ushort ", x);
+ test_assert(strcmp(str, "ushort 45") == 0);
+ memset(str, 0, sizeof(str));
+ }
+
+ {
+ int x = 46;
+ do_print("int ", x);
+ test_assert(strcmp(str, "int 46") == 0);
+ memset(str, 0, sizeof(str));
+ }
+ {
+ unsigned int x = 47;
+ do_print("uint ", x);
+ test_assert(strcmp(str, "uint 47") == 0);
+ memset(str, 0, sizeof(str));
+ }
+
+ {
+ long x = 48;
+ do_print("long ", x);
+ test_assert(strcmp(str, "long 48") == 0);
+ memset(str, 0, sizeof(str));
+ }
+ {
+ unsigned long x = 49;
+ do_print("ulong ", x);
+ test_assert(strcmp(str, "ulong 49") == 0);
+ memset(str, 0, sizeof(str));
+ }
+
+ {
+ long long x = 50;
+ do_print("long long ", x);
+ test_assert(strcmp(str, "long long 50") == 0);
+ memset(str, 0, sizeof(str));
+ }
+ {
+ unsigned long long x = 51;
+ do_print("ulong long ", x);
+ test_assert(strcmp(str, "ulong long 51") == 0);
+ memset(str, 0, sizeof(str));
+ }
+
+ do_print((ljust, 10, ' ', (base10, 1), "x"));
+ test_assert(strcmp(str, "1x ") == 0);
+ memset(str, 0, sizeof(str));
+
+ do_print((rjust, 10, ' ', (base10, 1), "x"));
+ 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 49a76ca..6e7cdfd 100644
--- a/libmisc/tests/test_log.c
+++ b/libmisc/tests/test_log.c
@@ -1,14 +1,12 @@
/* libmisc/tests/test_log.c - Tests for <libmisc/log.h>
*
- * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-#define _GNU_SOURCE /* for vasprintf() */
-#include <stdarg.h> /* for va_list */
-#include <stdio.h> /* for vasprintf() */
-#include <stdlib.h> /* for free() */
-#include <string.h> /* for strcmp() */
+#include <stdio.h> /* for vsnprintf() */
+#include <stdlib.h> /* for realloc(), free() */
+#include <string.h> /* for strlen(), strcmp() */
#define LOG_NAME FROBNICATE
#include <libmisc/log.h>
@@ -19,52 +17,64 @@
/* Intercept output ***********************************************************/
-static char *log_output = NULL;
+static struct fmt_buf log_output = {};
-int __lm_printf(const char *format, ...) {
- va_list va;
- va_start(va, format);
- int ret = vasprintf(&log_output, format, va);
- va_end(va);
- return ret;
+void __lm_putchar(unsigned char c) {
+ if (log_output.len+1 >= log_output.cap) {
+ log_output.cap += 16;
+ log_output.dat = realloc(log_output.dat, log_output.cap);
+ memset(log_output.dat + log_output.len, 0, log_output.cap - log_output.len);
+ }
+ ((uint8_t *)log_output.dat)[log_output.len++] = (uint8_t)c;
+}
+
+static void log_output_clear(void) {
+ if (log_output.dat)
+ memset(log_output.dat, 0, log_output.cap);
+ log_output.len = 0;
}
/* Actual tests ***************************************************************/
-#define should_print(_exp, cmd) do { \
- char *exp = _exp; \
- test_assert(!log_output); \
- cmd; \
- if (!exp) \
- test_assert(!log_output); \
- else { \
- test_assert(log_output); \
- if (strcmp(log_output, exp)) { \
- printf("exp = \"%s\"\n" \
- "act = \"%s\"\n", \
- exp, log_output); \
- test_assert(0); \
- } \
- } \
- if (log_output) { \
- free(log_output); \
- log_output = NULL; \
- } \
+#define should_print(_exp, cmd) do { \
+ char *exp = _exp; \
+ test_assert(log_output.len == 0); \
+ cmd; \
+ if (!exp) \
+ test_assert(log_output.len == 0); \
+ else { \
+ test_assert(log_output.dat); \
+ test_assert(strlen(log_output.dat) == log_output.len); \
+ if (strcmp(log_output.dat, exp)) { \
+ printf("exp = \"%s\"\n" \
+ "act = \"%s\"\n", \
+ exp, (char *)log_output.dat); \
+ test_assert(0); \
+ } \
+ } \
+ log_output_clear(); \
} while (0)
int main() {
should_print("error: FROBNICATE: val=42\n",
- errorf("val=%d", 42));
+ log_errorln("val=", 42));
should_print("info : FROBNICATE: val=0\n",
- infof("val=%d", 0));
+ log_infoln("val=", 0));
#ifndef NDEBUG
#define CONFIG_FROBNICATE_DEBUG 1
should_print("debug: FROBNICATE: val=-2\n",
- debugf("val=%d", -2));
+ log_debugln("val=", -2));
#undef CONFIG_FROBNICATE_DEBUG
#define CONFIG_FROBNICATE_DEBUG 0
should_print(NULL,
- debugf("val=%d", -2));
+ log_debugln("val=", -2));
+#undef CONFIG_FROBNICATE_DEBUG
#endif
+
+ if (log_output.dat) {
+ free(log_output.dat);
+ log_output.dat = NULL;
+ log_output.cap = 0;
+ }
return 0;
}
diff --git a/libmisc/tests/test_macro.c b/libmisc/tests/test_macro.c
index 1320eb3..6810005 100644
--- a/libmisc/tests/test_macro.c
+++ b/libmisc/tests/test_macro.c
@@ -4,10 +4,34 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
+#include <stdlib.h> /* for free() */
+#include <string.h> /* for strcmp(), strlen(), memcmp(), strdup() */
+
#include <libmisc/macro.h>
#include "test.h"
+/** Given `N` from `#define _LM_EVAL _LM_EVAL__{N}`, UNDER is `(N*2)-2`. (16*2)-2=30. */
+#define UNDER 30
+/** Given `N` from `#define _LM_EVAL _LM_EVAL__{N}`, OVER is `(N*2)-1`. (16*2)-1=31. */
+#define OVER 31
+
+/** XUNDER is 0 through `UNDER` inclusive. */
+#define XUNDER \
+ X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) \
+ X(16) X(17) X(18) X(19) X(20) X(21) X(22) X(23) X(24) X(25) X(26) X(27) X(28) X(29) X(30)
+/** XUNDER is 0 through `OVER` inclusive. */
+#define XOVER XUNDER X(OVER)
+
+static char *without_spaces(const char *in) {
+ char *out = strdup(in);
+ for (size_t i = 0; out[i]; i++)
+ while (out[i] == ' ')
+ for (size_t j = i; out[j]; j++)
+ out[j] = out[j+1];
+ return out;
+}
+
int main() {
printf("== LM_NEXT_POWER_OF_2 =====================================\n");
/* valid down to 0. */
@@ -50,5 +74,118 @@ int main() {
/* ... */
test_assert(LM_FLOORLOG2(0xFFFFFFFFFFFFFFFF) == 63);
+ printf("== LM_TUPLE ===============================================\n");
+ test_assert(LM_IF(LM_IS_TUPLE( 9 ))(0)(1));
+ test_assert(LM_IF(LM_IS_TUPLE( a ))(0)(1));
+ test_assert(LM_IF(LM_IS_TUPLE( () ))(1)(0));
+ test_assert(LM_IF(LM_IS_TUPLE( (9) ))(1)(0));
+ test_assert(LM_IF(LM_IS_TUPLE( (a) ))(1)(0));
+ test_assert(LM_IF(LM_IS_TUPLE( (a, b) ))(1)(0));
+
+ test_assert(LM_IF(LM_IS_EMPTY_TUPLE( () ))(1)(0));
+ test_assert(LM_IF(LM_IS_EMPTY_TUPLE( 9 ))(0)(1));
+ test_assert(LM_IF(LM_IS_EMPTY_TUPLE( a ))(0)(1));
+ test_assert(LM_IF(LM_IS_EMPTY_TUPLE( (9) ))(0)(1));
+ test_assert(LM_IF(LM_IS_EMPTY_TUPLE( (a) ))(0)(1));
+ test_assert(LM_IF(LM_IS_EMPTY_TUPLE( (a, b) ))(0)(1));
+
+ printf("== LM_TUPLES ==============================================\n");
+ test_assert(LM_IF(LM_TUPLES_IS_NONEMPTY( ))(0)(1));
+ test_assert(LM_IF(LM_TUPLES_IS_NONEMPTY( () ))(1)(0));
+ test_assert(LM_IF(LM_TUPLES_IS_NONEMPTY( (a) ))(1)(0));
+ test_assert(LM_IF(LM_TUPLES_IS_NONEMPTY( (a)(b) ))(1)(0));
+ test_assert(LM_IF(LM_TUPLES_IS_NONEMPTY( (a)(b)(c) ))(1)(0));
+
+ printf("== LM_FOREACH_PARAM =======================================\n");
+ /* Basic test. */
+ {
+ #define FN(A, B) A "-" #B
+ const char *str = LM_FOREACH_PARAM(FN, (" "), a, (b), c);
+ #undef FN
+ test_assert(strcmp(str, " -a -(b) -c") == 0);
+ }
+
+ /* Test that it works with the documented limit of params. */
+ {
+ #define X(n) , n
+ #define FN(n) #n "\n"
+ const char *str = LM_FOREACH_PARAM_(FN, () XUNDER);
+ #undef FN
+ #undef X
+ #define X(n) #n "\n"
+ test_assert(strcmp(str, XUNDER) == 0);
+ #undef X
+ }
+
+ /* Test that it breaks at documented_limit+1 tuples. */
+ {
+ #define X(n) , n
+ #define FN(n) n
+ const char *str = LM_STR_(LM_FOREACH_PARAM_(FN, () XOVER));
+ #undef FN
+ #undef X
+ /* This comparison is a little extra complicated in
+ * order to not be sensitive to whitespace in the
+ * suffix. */
+ #define X(n) #n " "
+ const char *exp_prefix = XUNDER;
+ #undef X
+ const char *exp_suffix = "FN(" LM_STR_(OVER) ")_LM_FOREACH_PARAM_ITEM_indirect()(FN,(),())";
+ test_assert(strlen(exp_prefix) < strlen(str) && memcmp(exp_prefix, str, strlen(exp_prefix)) == 0);
+ char *act_suffix = without_spaces(&str[strlen(exp_prefix)]);
+ test_assert(strcmp(act_suffix, exp_suffix) == 0);
+ free(act_suffix);
+ }
+
+ printf("== LM_FOREACH_TUPLE =======================================\n");
+ /* Basic test. */
+ {
+ #define FN(a, b) a "-" b
+ const char *str = LM_FOREACH_TUPLE( ("a") ("b") ("c"), FN, " ");
+ #undef FN
+ test_assert(strcmp(str, " -a -b -c") == 0);
+ }
+
+ /* Test that it works with the documented limit of tuples. */
+ {
+ #define X(n) (n)
+ #define FN(n) #n "\n"
+ const char *str = LM_FOREACH_TUPLE(XUNDER, FN);
+ #undef FN
+ #undef X
+ #define X(n) #n "\n"
+ test_assert(strcmp(str, XUNDER) == 0);
+ #undef X
+ }
+
+ /* Test that it breaks at documented_limit+1 tuples. */
+ {
+ #define X(n) (n)
+ #define FN(n) n
+ const char *str = LM_STR_(LM_FOREACH_TUPLE(XOVER, FN));
+ #undef FN
+ #undef X
+ /* This comparison is a little extra complicated in
+ * order to not be sensitive to whitespace in the
+ * suffix. */
+ #define X(n) #n " "
+ const char *exp_prefix = XUNDER;
+ #undef X
+ const char *exp_suffix = "FN(" LM_STR_(OVER) ")_LM_FOREACH_TUPLE_indirect()(,FN,)";
+ test_assert(strlen(exp_prefix) < strlen(str) && memcmp(exp_prefix, str, strlen(exp_prefix)) == 0);
+ char *act_suffix = without_spaces(&str[strlen(exp_prefix)]);
+ test_assert(strcmp(act_suffix, exp_suffix) == 0);
+ 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/libobj/tests/test_obj.c b/libmisc/tests/test_obj.c
index d6861dc..c3c6786 100644
--- a/libobj/tests/test_obj.c
+++ b/libmisc/tests/test_obj.c
@@ -1,10 +1,10 @@
-/* libobj/tests/test_obj.c - Tests for <libobj/obj.h>
+/* libmisc/tests/test_obj.c - Tests for <libmisc/obj.h>
*
* Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-#include <libobj/obj.h>
+#include <libmisc/obj.h>
#include "test.h"
@@ -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/libobj/tests/test_nest.c b/libmisc/tests/test_obj_nest.c
index f18b018..b52cd7b 100644
--- a/libobj/tests/test_nest.c
+++ b/libmisc/tests/test_obj_nest.c
@@ -1,4 +1,4 @@
-/* libobj/tests/test_nest.c - Tests for <libobj/obj.h>
+/* 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
@@ -6,18 +6,18 @@
#include <string.h> /* for memcpy() */
-#include <libobj/obj.h>
+#include <libmisc/obj.h>
#include "test.h"
/* 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);
@@ -63,11 +57,20 @@ static ssize_t myclass_write(struct myclass *self, void *buf, size_t count) {
/* main test body *************************************************************/
int main() {
- struct myclass _obj = {0};
+ struct myclass _obj = {};
lo_interface read_writer obj = lo_box_myclass_as_read_writer(&_obj);
test_assert(LO_CALL(obj, write, "Hello", 6) == 6);
- char buf[6] = {0};
+ 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 8076155..1cfbd65 100644
--- a/libmisc/tests/test_rand.c
+++ b/libmisc/tests/test_rand.c
@@ -1,14 +1,13 @@
/* libmisc/tests/test_rand.c - Tests for <libmisc/rand.h>
*
- * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-#include <stdbool.h>
#include <setjmp.h>
-#include <libmisc/rand.h>
#include <libmisc/_intercept.h>
+#include <libmisc/rand.h>
#include "test.h"
@@ -51,7 +50,7 @@ static void test_n(uint64_t cnt) {
#endif
} else {
double sum = 0;
- bool seen[MAX_SEE_ALL] = {0};
+ bool seen[MAX_SEE_ALL] = {};
for (int i = 0; i < ROUNDS; i++) {
uint64_t val = rand_uint63n(cnt);
sum += val;
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/libobj/CMakeLists.txt b/libobj/CMakeLists.txt
deleted file mode 100644
index e4d8095..0000000
--- a/libobj/CMakeLists.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-# libobj/CMakeLists.txt - A simple Go-ish object system built on GCC -fplan9-extensions
-#
-# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
-# SPDX-License-Identifier: AGPL-3.0-or-later
-
-add_library(libobj INTERFACE)
-target_include_directories(libobj PUBLIC INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
-target_link_libraries(libobj INTERFACE
- libmisc
-)
-target_compile_options(libobj INTERFACE "$<$<COMPILE_LANGUAGE:C>:-fplan9-extensions>")
-
-add_lib_test(libobj test_obj)
-add_lib_test(libobj test_nest)
diff --git a/libobj/include/libobj/obj.h b/libobj/include/libobj/obj.h
deleted file mode 100644
index 7a9041e..0000000
--- a/libobj/include/libobj/obj.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/* libobj/obj.h - A simple Go-ish object system
- *
- * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-#ifndef _LIBOBJ_OBJ_H_
-#define _LIBOBJ_OBJ_H_
-
-#include <libmisc/macro.h>
-
-/**
- * Use `lo_interface` similarly to how you would use
- * `struct`/`enum`/`union` when writing the type of an interface
- * value.
- */
-#define lo_interface struct
-
-/**
- * Use `LO_INTERFACE` in a .h file to define an interface.
- *
- * First define a macro named `{iface_name}_LO_IFACE` consisting of a
- * series of calls to LO_NEST and/or LO_FUNC, then call
- * `LO_INTERFACE({iface_name})`:
- *
- * #define myiface_LO_IFACE \
- * LO_NEST(wrapped_iface_name) \
- * LO_FUNC(ret_type, func_name, args...)
- * LO_INTERFACE(myiface)
- *
- * Use `lo_interface {iface_name}` as the type of this interface; it
- * should not be a pointer type.
- *
- * If there are any LO_NEST interfaces, this will define a
- * `lo_box_{iface_name}_as_{wrapped_iface_name}(obj)` function for
- * each.
- */
-#define LO_NEST(_ARG_child_iface_name) \
- (lo_nest, _ARG_child_iface_name)
-#define LO_FUNC(_ARG_ret_type, _ARG_func_name, ...) \
- (lo_func, _ARG_ret_type, _ARG_func_name __VA_OPT__(,) __VA_ARGS__)
-#define LO_INTERFACE(_ARG_iface_name) \
- typedef struct { \
- LM_FOREACH_TUPLE(_ARG_iface_name##_LO_IFACE, \
- _LO_IFACE_VTABLE) \
- } _lo_##_ARG_iface_name##_vtable; \
- struct _ARG_iface_name { \
- void *self; \
- const _lo_##_ARG_iface_name##_vtable *vtable; \
- }; \
- LM_FOREACH_TUPLE(_ARG_iface_name##_LO_IFACE, \
- _LO_IFACE_PROTO, _ARG_iface_name) \
- extern int LM_CAT2_(_HIDDEN_BOGUS_, __COUNTER__)
-#define _LO_IFACE_VTABLE(_tuple_typ, ...) \
- _LO_IFACE_VTABLE_##_tuple_typ(__VA_ARGS__)
-#define _LO_IFACE_VTABLE_lo_nest(_ARG_child_iface_name) \
- _lo_##_ARG_child_iface_name##_vtable;
-#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_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_lo_func(_ARG_iface_name, _ARG_ret_type, _ARG_func_name, ...) \
- /* empty */
-
-/**
- * `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){0})
-
-/**
- * `LO_IS_NULL(iface_val)` returns whether `iface_val` is LO_NULL.
- */
-#define LO_IS_NULL(_ARG_iface_val) ((_ARG_iface_val).vtable == NULL)
-
-/**
- * `LO_IFACE_EQ(a, b)` returns whether the interface values `a` and
- * `b` are the same object.
- */
-#define LO_EQ(_ARG_iface_val_a, _ARG_iface_val_b) \
- ((_ARG_iface_val_a).self == (_ARG_iface_val_b).self)
-
-/**
- * Use LO_CALL(obj, method_name, args...) to call a method on an `lo_interface`.
- */
-#define LO_CALL(_ARG_obj, _ARG_meth, ...) \
- (_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}`.
- *
- * This will also define a `lo_box_{impl_name}_as_{iface_name}(obj)`
- * function.
- *
- * You must also call the LO_IMPLEMENTATION_C in a single .c file.
- */
-#define LO_IMPLEMENTATION_H(_ARG_iface_name, _ARG_impl_type, _ARG_impl_name) \
- /* Vtable. */ \
- extern const _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, \
- }; \
- } \
- extern int LM_CAT2_(_LO_FORCE_SEMICOLON_, __COUNTER__)
-
-/**
- * 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 _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_lo_nest(_ARG_impl_name, _ARG_child_iface_name) \
- ._lo_##_ARG_child_iface_name##_vtable = _lo_##_ARG_impl_name##_##_ARG_child_iface_name##_vtable,
-#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,
-
-#endif /* _LIBOBJ_OBJ_H_ */
diff --git a/libusb/usb_common.c b/libusb/usb_common.c
index 29dec42..4fe7dd4 100644
--- a/libusb/usb_common.c
+++ b/libusb/usb_common.c
@@ -1,15 +1,15 @@
/* libusb/usb_common.c - Common framework for implementing multiple USB devices at once
*
- * 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
*/
-#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>
@@ -30,7 +30,7 @@ static struct {
uint8_t **configv;
uint16_t *serial;
uint8_t serial_bytelen;
-} globals = {0};
+} globals = {};
/* Strings ********************************************************************/
@@ -68,12 +68,12 @@ uint16_t const *tud_descriptor_string_cb(uint8_t strid, uint16_t langid) {
memcpy(desc.bString, globals.serial, bytelen);
break;
default:
- debugf("GET STRING: unknown string id=%"PRIu8, strid);
+ log_debugln("GET STRING: unknown string id=", strid);
return NULL;
}
break;
default:
- debugf("GET STRING: unknown LANGID=%"PRIx16, langid);
+ log_debugln("GET STRING: unknown LANGID=", (base16_u16_, langid));
return NULL;
}
}
@@ -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/