aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmake/wnix_program.cmake19
-rw-r--r--programs/initd/initd.c17
-rw-r--r--programs/libc/CMakeLists.txt (renamed from programs/wnix/CMakeLists.txt)17
-rw-r--r--programs/libc/fcntl/CMakeLists.txt19
-rw-r--r--programs/libc/fcntl/open.c41
-rw-r--r--programs/libc/malloc_init.c29
-rw-r--r--programs/libc/start.c (renamed from programs/wnix/start.c)12
-rw-r--r--programs/libc/sys/CMakeLists.txt18
-rw-r--r--programs/libc/sys/mount/CMakeLists.txt19
-rw-r--r--programs/libc/sys/mount/mount.c (renamed from programs/wnix/mount.c)0
-rw-r--r--programs/libc/sys/stat/CMakeLists.txt20
-rw-r--r--programs/libc/sys/stat/mkdir.c (renamed from programs/wnix/mkdir.c)0
-rw-r--r--programs/libc/sys/stat/umask.c29
-rw-r--r--programs/libc/unistd/CMakeLists.txt21
-rw-r--r--programs/libc/unistd/close.c30
-rw-r--r--programs/libc/unistd/sbrk.c (renamed from programs/wnix/sbrk.c)0
-rw-r--r--programs/libc/unistd/write.c32
-rw-r--r--programs/wasm-clang-toolchain.cmake1
-rw-r--r--programs/yes/CMakeLists.txt13
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/aio/src/mkdir.c6
-rw-r--r--src/bin/include/bin.h4
-rw-r--r--src/bin/private_include/bin/proc.h2
-rw-r--r--src/bin/private_include/bin/types.h16
-rw-r--r--src/bin/private_include/bin/wasi/errno.h105
-rw-r--r--src/bin/private_include/bin/wnix.h8
-rw-r--r--src/bin/private_include/bin/wnix/routines.h19
-rw-r--r--src/bin/src/exec.c9
-rw-r--r--src/bin/src/mod/cfg.c44
-rw-r--r--src/bin/src/proc/CMakeLists.txt2
-rw-r--r--src/bin/src/proc/fd_alloc.c54
-rw-r--r--src/bin/src/proc/fd_find.c38
-rw-r--r--src/bin/src/proc/free.c3
-rw-r--r--src/bin/src/proc/pc.c19
-rw-r--r--src/bin/src/update.c6
-rw-r--r--src/bin/src/wnix/CMakeLists.txt7
-rw-r--r--src/bin/src/wnix/argcopy.c14
-rw-r--r--src/bin/src/wnix/close.c32
-rw-r--r--src/bin/src/wnix/mkdir.c207
-rw-r--r--src/bin/src/wnix/mount.c75
-rw-r--r--src/bin/src/wnix/open.c222
-rw-r--r--src/bin/src/wnix/routines/CMakeLists.txt20
-rw-r--r--src/bin/src/wnix/routines/readstr.c129
-rw-r--r--src/bin/src/wnix/routines/set_errno.c (renamed from src/bin/src/wnix/set_errno.c)41
-rw-r--r--src/bin/src/wnix/umask.c35
-rw-r--r--src/bin/src/wnix/write.c251
-rw-r--r--src/drv/CMakeLists.txt14
-rw-r--r--src/drv/event/include/drv/event.h14
-rw-r--r--src/drv/null/CMakeLists.txt20
-rw-r--r--src/drv/null/include/drv/null.h28
-rw-r--r--src/drv/null/private_include/drv/null/ops.h31
-rw-r--r--src/drv/null/private_include/drv/null/types.h32
-rw-r--r--src/drv/null/src/CMakeLists.txt23
-rw-r--r--src/drv/null/src/free.c32
-rw-r--r--src/drv/null/src/init.c35
-rw-r--r--src/drv/null/src/read.c30
-rw-r--r--src/drv/null/src/update.c48
-rw-r--r--src/drv/null/src/write.c29
-rw-r--r--src/drv/ps1/cd/private_include/drv/ps1/cd/routines.h8
-rw-r--r--src/drv/ps1/cd/src/read.c4
-rw-r--r--src/drv/ps1/cd/src/write.c4
-rw-r--r--src/drv/ps1/sio/private_include/drv/ps1/sio/ops.h10
-rw-r--r--src/drv/ps1/sio/src/read.c4
-rw-r--r--src/drv/ps1/sio/src/read_nb.c3
-rw-r--r--src/drv/ps1/sio/src/write.c4
-rw-r--r--src/drv/src/tree.c22
-rw-r--r--src/drv/stderr/CMakeLists.txt20
-rw-r--r--src/drv/stderr/include/drv/stderr.h28
-rw-r--r--src/drv/stderr/private_include/drv/stderr/ops.h29
-rw-r--r--src/drv/stderr/private_include/drv/stderr/types.h32
-rw-r--r--src/drv/stderr/src/CMakeLists.txt22
-rw-r--r--src/drv/stderr/src/free.c32
-rw-r--r--src/drv/stderr/src/init.c35
-rw-r--r--src/drv/stderr/src/update.c47
-rw-r--r--src/drv/stderr/src/write.c29
-rw-r--r--src/drv/stdin/CMakeLists.txt20
-rw-r--r--src/drv/stdin/include/drv/stdin.h28
-rw-r--r--src/drv/stdin/private_include/drv/stdin/ops.h29
-rw-r--r--src/drv/stdin/private_include/drv/stdin/types.h32
-rw-r--r--src/drv/stdin/src/CMakeLists.txt22
-rw-r--r--src/drv/stdin/src/free.c32
-rw-r--r--src/drv/stdin/src/init.c35
-rw-r--r--src/drv/stdin/src/read.c30
-rw-r--r--src/drv/stdin/src/update.c47
-rw-r--r--src/drv/stdout/CMakeLists.txt20
-rw-r--r--src/drv/stdout/include/drv/stdout.h28
-rw-r--r--src/drv/stdout/private_include/drv/stdout/ops.h29
-rw-r--r--src/drv/stdout/private_include/drv/stdout/types.h32
-rw-r--r--src/drv/stdout/src/CMakeLists.txt22
-rw-r--r--src/drv/stdout/src/free.c32
-rw-r--r--src/drv/stdout/src/init.c35
-rw-r--r--src/drv/stdout/src/update.c47
-rw-r--r--src/drv/stdout/src/write.c29
-rw-r--r--src/drv/tty/private_include/drv/tty/ops.h4
-rw-r--r--src/drv/tty/src/update.backup.c2
-rw-r--r--src/drv/tty/src/update.c2
-rw-r--r--src/drv/tty/src/write.c6
-rw-r--r--src/fs/devfs/src/open.c27
-rw-r--r--src/fs/devfs/src/read.c2
-rw-r--r--src/fs/devfs/src/read_nb.c2
-rw-r--r--src/fs/devfs/src/write.c2
-rw-r--r--src/fs/include/fs/fs.h40
-rw-r--r--src/fs/include/fs/inode.h1
-rw-r--r--src/fs/iso9660/src/eof.c4
-rw-r--r--src/fs/iso9660/src/open.c5
-rw-r--r--src/fs/ramfs/src/search.c4
-rw-r--r--src/init/private_include/init/types.h1
-rw-r--r--src/init/ps1/private_include/init/ps1/types.h3
-rw-r--r--src/init/ps1/src/boot.c166
-rw-r--r--src/init/src/boot.c35
-rw-r--r--src/libc/include/fcntl.h13
-rw-r--r--src/libc/include/stdio.h17
-rw-r--r--src/libc/include/stdlib.h38
-rw-r--r--src/libc/include/sys/stat.h32
-rw-r--r--src/libc/include/sys/types.h1
-rw-r--r--src/libc/include/unistd.h14
-rw-r--r--src/libc/private_include/libc/file.h29
-rw-r--r--src/libc/src/CMakeLists.txt2
-rw-r--r--src/libc/src/_putchar.c24
-rw-r--r--src/libc/src/malloc_init.c29
-rw-r--r--src/libc/src/ps1/CMakeLists.txt1
-rw-r--r--src/libc/src/stdio/CMakeLists.txt6
-rw-r--r--src/libc/src/stdio/fopen.c95
-rw-r--r--src/libc/src/stdio/fputc.c40
-rw-r--r--src/libc/src/stdio/fwrite.c50
-rw-r--r--src/libc/src/stdio/putc.c25
-rw-r--r--src/libc/src/stdio/putchar.c (renamed from src/libc/src/ps1/putchar.c)7
-rw-r--r--src/libc/src/stdio/streams.c24
-rw-r--r--src/libc/src/stdlib/malloc.c6
-rw-r--r--src/libc/src/unistd/sbrk.c3
m---------src/libc/tinyalloc0
-rw-r--r--src/loop/src/run.c7
m---------src/nanowasm0
m---------tools/nwc0
134 files changed, 3292 insertions, 402 deletions
diff --git a/cmake/wnix_program.cmake b/cmake/wnix_program.cmake
new file mode 100644
index 0000000..65efc50
--- /dev/null
+++ b/cmake/wnix_program.cmake
@@ -0,0 +1,19 @@
+function(wnix_program)
+ add_compile_options(-g)
+
+ if(CMAKE_BUILD_TYPE STREQUAL "Debug")
+ add_compile_options(-Og)
+ endif()
+
+ add_subdirectory(../libc ${CMAKE_CURRENT_BINARY_DIR}/libc)
+ target_link_libraries(${PROJECT_NAME} PRIVATE c)
+ # TODO: Debugging symbols could still be there, but nwc still has issues.
+ add_custom_target(${PROJECT_NAME}_strip ALL
+ ${CMAKE_STRIP} ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}
+ BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}
+ )
+ add_dependencies(${PROJECT_NAME}_strip ${PROJECT_NAME})
+ install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
+endfunction()
diff --git a/programs/initd/initd.c b/programs/initd/initd.c
index 5e200b3..3ca3f6e 100644
--- a/programs/initd/initd.c
+++ b/programs/initd/initd.c
@@ -16,9 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-#if 1
#include <sys/mount.h>
-#endif
#include <sys/stat.h>
#include <errno.h>
#include <stddef.h>
@@ -27,17 +25,14 @@
int main(int argc, char *argv[])
{
+ puts("Starting second-stage bootloader from WebAssembly!");
+
#if 0
- puts("hi from wasm!");
-#endif
-#if 1
- if (mkdir("/home", 0755))
- return errno;
-#endif
-#if 1
- if (mount("/dev/mc0", "/home", NULL, 0, NULL))
+ if (mkdir("/home", 0755)
+ || mkdir("/home/wnix", 0755)
+ || mount("/dev/mc0", "/home/wnix", "ps1mcfs", 0, NULL))
return errno;
#endif
- return 1;
+ return EXIT_SUCCESS;
}
diff --git a/programs/wnix/CMakeLists.txt b/programs/libc/CMakeLists.txt
index a118bd0..a0c6d97 100644
--- a/programs/wnix/CMakeLists.txt
+++ b/programs/libc/CMakeLists.txt
@@ -14,13 +14,14 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
-add_library(wnix
- mkdir.c
- mount.c
- sbrk.c
- start.c
-)
set(LIBC_FREESTANDING ON)
-add_subdirectory(../../src/libc ${CMAKE_CURRENT_BINARY_DIR}/libc)
+set(libc_dir ${CMAKE_CURRENT_LIST_DIR}/../../src/libc)
+add_subdirectory(${libc_dir} ${CMAKE_CURRENT_BINARY_DIR}/libc)
+add_subdirectory(fcntl)
+add_subdirectory(sys)
+add_subdirectory(unistd)
target_compile_definitions(c PRIVATE PRINTF_DISABLE_SUPPORT_FLOAT)
-target_link_libraries(wnix PUBLIC c)
+target_sources(c PRIVATE
+ malloc_init.c
+ start.c
+)
diff --git a/programs/libc/fcntl/CMakeLists.txt b/programs/libc/fcntl/CMakeLists.txt
new file mode 100644
index 0000000..c0ca1d1
--- /dev/null
+++ b/programs/libc/fcntl/CMakeLists.txt
@@ -0,0 +1,19 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(c PRIVATE
+ open.c
+)
diff --git a/programs/libc/fcntl/open.c b/programs/libc/fcntl/open.c
new file mode 100644
index 0000000..71511a7
--- /dev/null
+++ b/programs/libc/fcntl/open.c
@@ -0,0 +1,41 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <stdarg.h>
+
+int open(const char *const path, const int flags, ...)
+{
+ int __wnix_open(const char *, int, mode_t, int *) __attribute__((
+ __import_module__("wnix"),
+ __import_name__("open")
+ ));
+
+ mode_t mode = 0;
+ va_list ap;
+
+ va_start(ap, flags);
+
+ if (flags & O_CREAT)
+ mode = va_arg(ap, mode_t);
+
+ va_end(ap);
+ return __wnix_open(path, flags, mode, &errno);
+}
diff --git a/programs/libc/malloc_init.c b/programs/libc/malloc_init.c
new file mode 100644
index 0000000..969f523
--- /dev/null
+++ b/programs/libc/malloc_init.c
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <libc/malloc.h>
+#include <tinyalloc.h>
+#include <stdint.h>
+
+void __malloc_init(void)
+{
+ /* README.md states 16 is a "good default value". */
+ if (!ta_init(64, 16, sizeof (intmax_t)))
+ abort();
+}
diff --git a/programs/wnix/start.c b/programs/libc/start.c
index 06dc4d5..5e56239 100644
--- a/programs/wnix/start.c
+++ b/programs/libc/start.c
@@ -19,10 +19,13 @@
#include <errno.h>
#include <stddef.h>
#include <stdlib.h>
+#include <stdio.h>
void _start(void)
{
- int main(int, char *[]);
+ /* clang mangles main if argc/argv are present:
+ * https://reviews.llvm.org/D127888 */
+ int __main_argc_argv(int, char *[]);
int __wnix_argc(void) __attribute__((
__import_module__("wnix"),
__import_name__("argc")
@@ -32,6 +35,11 @@ void _start(void)
__import_name__("exit")
));
+ if (!(__stdin = fopen("/dev/stdin", "rb"))
+ || !(__stdout = fopen("/dev/stdout", "wb"))
+ || !(__stderr = fopen("/dev/stderr", "wb")))
+ __wnix_exit(EXIT_FAILURE);
+
const int argc = __wnix_argc();
char **argv = malloc((argc + 1) * sizeof *argv);
@@ -60,5 +68,5 @@ void _start(void)
}
argv[argc] = NULL;
- __wnix_exit(main(argc, argv));
+ __wnix_exit(__main_argc_argv(argc, argv));
}
diff --git a/programs/libc/sys/CMakeLists.txt b/programs/libc/sys/CMakeLists.txt
new file mode 100644
index 0000000..ea57403
--- /dev/null
+++ b/programs/libc/sys/CMakeLists.txt
@@ -0,0 +1,18 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_subdirectory(mount)
+add_subdirectory(stat)
diff --git a/programs/libc/sys/mount/CMakeLists.txt b/programs/libc/sys/mount/CMakeLists.txt
new file mode 100644
index 0000000..222e506
--- /dev/null
+++ b/programs/libc/sys/mount/CMakeLists.txt
@@ -0,0 +1,19 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(c PRIVATE
+ mount.c
+)
diff --git a/programs/wnix/mount.c b/programs/libc/sys/mount/mount.c
index 2512f73..2512f73 100644
--- a/programs/wnix/mount.c
+++ b/programs/libc/sys/mount/mount.c
diff --git a/programs/libc/sys/stat/CMakeLists.txt b/programs/libc/sys/stat/CMakeLists.txt
new file mode 100644
index 0000000..60a8d6c
--- /dev/null
+++ b/programs/libc/sys/stat/CMakeLists.txt
@@ -0,0 +1,20 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(c PRIVATE
+ mkdir.c
+ umask.c
+)
diff --git a/programs/wnix/mkdir.c b/programs/libc/sys/stat/mkdir.c
index 5547616..5547616 100644
--- a/programs/wnix/mkdir.c
+++ b/programs/libc/sys/stat/mkdir.c
diff --git a/programs/libc/sys/stat/umask.c b/programs/libc/sys/stat/umask.c
new file mode 100644
index 0000000..f42a6e5
--- /dev/null
+++ b/programs/libc/sys/stat/umask.c
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <sys/stat.h>
+
+mode_t umask(const mode_t mask)
+{
+ int __wnix_umask(mode_t) __attribute__((
+ __import_module__("wnix"),
+ __import_name__("umask")
+ ));
+
+ return __wnix_umask(mask);
+}
diff --git a/programs/libc/unistd/CMakeLists.txt b/programs/libc/unistd/CMakeLists.txt
new file mode 100644
index 0000000..e3481bc
--- /dev/null
+++ b/programs/libc/unistd/CMakeLists.txt
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(c PRIVATE
+ close.c
+ sbrk.c
+ write.c
+)
diff --git a/programs/libc/unistd/close.c b/programs/libc/unistd/close.c
new file mode 100644
index 0000000..94ca6fc
--- /dev/null
+++ b/programs/libc/unistd/close.c
@@ -0,0 +1,30 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <unistd.h>
+#include <errno.h>
+
+int close(const int fd)
+{
+ int __wnix_close(int, int *) __attribute__((
+ __import_module__("wnix"),
+ __import_name__("close")
+ ));
+
+ return __wnix_close(fd, &errno);
+}
diff --git a/programs/wnix/sbrk.c b/programs/libc/unistd/sbrk.c
index 7e32118..7e32118 100644
--- a/programs/wnix/sbrk.c
+++ b/programs/libc/unistd/sbrk.c
diff --git a/programs/libc/unistd/write.c b/programs/libc/unistd/write.c
new file mode 100644
index 0000000..9151e61
--- /dev/null
+++ b/programs/libc/unistd/write.c
@@ -0,0 +1,32 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <stddef.h>
+
+ssize_t write(const int fd, const void *const p, const size_t sz)
+{
+ int __wnix_write(int, const void *, size_t, int *) __attribute__((
+ __import_module__("wnix"),
+ __import_name__("write")
+ ));
+
+ return __wnix_write(fd, p, sz, &errno);
+}
diff --git a/programs/wasm-clang-toolchain.cmake b/programs/wasm-clang-toolchain.cmake
index a6890f8..746392c 100644
--- a/programs/wasm-clang-toolchain.cmake
+++ b/programs/wasm-clang-toolchain.cmake
@@ -23,6 +23,7 @@ set(CMAKE_C_COMPILER_WORKS 1)
set(CMAKE_C_FLAGS " \
${CMAKE_C_FLAGS} \
--target=wasm32-unknown-unknown-wasm \
+ -mcpu=mvp \
-fno-exceptions \
-nostdinc \
-nostdlib \
diff --git a/programs/yes/CMakeLists.txt b/programs/yes/CMakeLists.txt
index 59abf8f..cebd1c4 100644
--- a/programs/yes/CMakeLists.txt
+++ b/programs/yes/CMakeLists.txt
@@ -18,14 +18,5 @@ cmake_minimum_required(VERSION 3.13)
include(GNUInstallDirs)
project(yes C)
add_executable(${PROJECT_NAME} yes.c)
-add_subdirectory(../wnix ${CMAKE_CURRENT_BINARY_DIR}/wnix)
-target_link_libraries(${PROJECT_NAME} PRIVATE wnix)
-# TODO: Debugging symbols could still be there, but nwc still has issues.
-add_custom_target(${PROJECT_NAME}_strip ALL
- ${CMAKE_STRIP} ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
- DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}
- BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}
-)
-add_dependencies(${PROJECT_NAME}_strip ${PROJECT_NAME})
-install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
+include(wnix_program)
+wnix_program()
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 9fb2cb4..d61582f 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -21,7 +21,7 @@ add_subdirectory(wip)
add_subdirectory(dynstr)
# Avoid C11 since it is not supported by the i386-mingw32 toolchain.
-set(cflags ${cflags} -Wall -pedantic)
+set(cflags ${cflags} -Wall)
set(components
aio
diff --git a/src/aio/src/mkdir.c b/src/aio/src/mkdir.c
index 40b09b6..44cc43d 100644
--- a/src/aio/src/mkdir.c
+++ b/src/aio/src/mkdir.c
@@ -121,10 +121,10 @@ struct aio *aio_mkdir(const struct fs_mkdir *const m,
.args = mk
};
- if (d)
- mk->done = *d;
- else if (inode_search(&s, &aio->r))
+ if (inode_search(&s, &aio->r))
goto failure;
+ else if (d)
+ mk->done = *d;
return aio;
diff --git a/src/bin/include/bin.h b/src/bin/include/bin.h
index a5528c5..34558f9 100644
--- a/src/bin/include/bin.h
+++ b/src/bin/include/bin.h
@@ -20,8 +20,10 @@
#define BIN_H
#include <sys/types.h>
+#include <fs/fs.h>
-int bin_exec(const char *path, const char *const *argv, uid_t uid, gid_t gid);
+int bin_exec(const char *path, const char *const *argv,
+ const struct fs_stdstreams *ss, pid_t parent, uid_t uid, gid_t gid);
int bin_update(void);
#endif
diff --git a/src/bin/private_include/bin/proc.h b/src/bin/private_include/bin/proc.h
index cf0c04e..92f1566 100644
--- a/src/bin/private_include/bin/proc.h
+++ b/src/bin/private_include/bin/proc.h
@@ -43,6 +43,8 @@ int bin_proc_s_pop(void *dst, size_t n, void *user);
int bin_proc_s_read(size_t offset, void *dst, size_t n, void *user);
int bin_proc_s_write(size_t offset, const void *dst, size_t n, void *user);
size_t bin_proc_s_ptr(void *user);
+struct bin_proc_fd *bin_proc_fd_find(const struct bin_proc *p, int fd);
+int bin_proc_fd_alloc(struct bin_proc *p, const struct fs_fd *fd, int flags);
extern const struct nw_inst_cfg bin_proc_cfg;
diff --git a/src/bin/private_include/bin/types.h b/src/bin/private_include/bin/types.h
index 2a498ed..6f231ae 100644
--- a/src/bin/private_include/bin/types.h
+++ b/src/bin/private_include/bin/types.h
@@ -28,7 +28,7 @@
#include <sys/types.h>
#include <stdbool.h>
-enum {BIN_IMPORTS = 9};
+enum {BIN_IMPORTS = 10};
struct bin_dbg
{
@@ -54,18 +54,25 @@ struct bin_global
size_t sz;
};
+struct bin_proc_fd
+{
+ int fd, flags;
+ struct fs_fd fs_fd;
+};
+
struct bin_proc
{
const struct bin_mod *mod;
struct nw_inst instance;
- union nw_value args[7];
+ union nw_value args[6];
struct bin_dbg dbg;
struct caio *caio;
char *path, **argv;
size_t argc;
- pid_t pid;
+ pid_t pid, parent;
uid_t uid;
gid_t gid;
+ mode_t umask;
char header[sizeof "asm"];
size_t i;
long retval;
@@ -73,7 +80,8 @@ struct bin_proc
struct bin_global global;
void *import;
struct page *linear;
- int *fds;
+ struct fs_stdstreams ss;
+ struct bin_proc_fd *fds;
size_t n_fds;
struct bin_proc *prev, *next;
};
diff --git a/src/bin/private_include/bin/wasi/errno.h b/src/bin/private_include/bin/wasi/errno.h
deleted file mode 100644
index 442e877..0000000
--- a/src/bin/private_include/bin/wasi/errno.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * wnix, a Unix-like operating system for WebAssembly applications.
- * Copyright (C) 2025 Xavier Del Campo Romero
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
-
-#ifndef WASI_ERRNO_H
-#define WASI_ERRNO_H
-
-enum wasi_errno
-{
- WASI_SUCCESS,
- WASI_2BIG,
- WASI_ACCES,
- WASI_ADDRINUSE,
- WASI_ADDRNOTAVAIL,
- WASI_AFNOSUPPORT,
- WASI_AGAIN,
- WASI_ALREADY,
- WASI_BADF,
- WASI_BADMSG,
- WASI_BUSY,
- WASI_CANCELED,
- WASI_CHILD,
- WASI_CONNABORTED,
- WASI_CONNREFUSED,
- WASI_CONNRESET,
- WASI_DEADLK,
- WASI_DESTADDRREQ,
- WASI_DOM,
- WASI_DQUOT,
- WASI_EXIST,
- WASI_FAULT,
- WASI_FBIG,
- WASI_HOSTUNREACH,
- WASI_IDRM,
- WASI_ILSEQ,
- WASI_INPROGRESS,
- WASI_INTR,
- WASI_INVAL,
- WASI_IO,
- WASI_ISCONN,
- WASI_ISDIR,
- WASI_LOOP,
- WASI_MFILE,
- WASI_MLINK,
- WASI_MSGSIZE,
- WASI_MULTIHOP,
- WASI_NAMETOOLONG,
- WASI_NETDOWN,
- WASI_NETRESET,
- WASI_NETUNREACH,
- WASI_NFILE,
- WASI_NOBUFS,
- WASI_NODEV,
- WASI_NOENT,
- WASI_NOEXEC,
- WASI_NOLCK,
- WASI_NOLINK,
- WASI_NOMEM,
- WASI_NOMSG,
- WASI_NOPROTOOPT,
- WASI_NOSPC,
- WASI_NOSYS,
- WASI_NOTCONN,
- WASI_NOTDIR,
- WASI_NOTEMPTY,
- WASI_NOTRECOVERABLE,
- WASI_NOTSOCK,
- WASI_NOTSUP,
- WASI_NOTTY,
- WASI_NXIO,
- WASI_OVERFLOW,
- WASI_OWNERDEAD,
- WASI_PERM,
- WASI_PIPE,
- WASI_PROTO,
- WASI_PROTONOSUPPORT,
- WASI_PROTOTYPE,
- WASI_RANGE,
- WASI_ROFS,
- WASI_SPIPE,
- WASI_SRCH,
- WASI_STALE,
- WASI_TIMEDOUT,
- WASI_TXTBSY,
- WASI_XDEV,
- WASI_NOTCAPABLE
-};
-
-int wasi_errno(int error, enum wasi_errno *out);
-
-#endif
diff --git a/src/bin/private_include/bin/wnix.h b/src/bin/private_include/bin/wnix.h
index 07e7131..f3844c5 100644
--- a/src/bin/private_include/bin/wnix.h
+++ b/src/bin/private_include/bin/wnix.h
@@ -33,5 +33,13 @@ enum nw_state bin_wnix_mkdir(const union nw_value *params,
union nw_value *ret, void *user, struct nw_next *next);
enum nw_state bin_wnix_mount(const union nw_value *params,
union nw_value *ret, void *user, struct nw_next *next);
+enum nw_state bin_wnix_write(const union nw_value *params,
+ union nw_value *ret, void *user, struct nw_next *next);
+enum nw_state bin_wnix_umask(const union nw_value *params,
+ union nw_value *ret, void *user, struct nw_next *next);
+enum nw_state bin_wnix_open(const union nw_value *params,
+ union nw_value *ret, void *user, struct nw_next *next);
+enum nw_state bin_wnix_close(const union nw_value *params,
+ union nw_value *ret, void *user, struct nw_next *next);
#endif
diff --git a/src/bin/private_include/bin/wnix/routines.h b/src/bin/private_include/bin/wnix/routines.h
index aa488fb..3ba5118 100644
--- a/src/bin/private_include/bin/wnix/routines.h
+++ b/src/bin/private_include/bin/wnix/routines.h
@@ -23,7 +23,22 @@
#include <bin/types.h>
#include <nanowasm/nw.h>
-int bin_wnix_set_errno(struct bin_proc *p, int error, unsigned long addr,
- struct nw_next *next);
+struct bin_readstr
+{
+ unsigned long addr;
+ struct bin_proc *p;
+ char **str;
+ int (*error)(struct bin_proc *, int, struct nw_next *);
+};
+
+struct bin_set_errno
+{
+ int error;
+ unsigned long addr;
+ struct bin_proc *p;
+};
+
+int bin_wnix_readstr(const struct bin_readstr *cfg, struct nw_next *next);
+int bin_wnix_set_errno(const struct bin_set_errno *cfg, struct nw_next *next);
#endif
diff --git a/src/bin/src/exec.c b/src/bin/src/exec.c
index 83c0e5f..1796af9 100644
--- a/src/bin/src/exec.c
+++ b/src/bin/src/exec.c
@@ -30,6 +30,7 @@
#include <nanowasm/nw.h>
#include <nanowasm/dbg.h>
#include <fcntl.h>
+#include <sys/stat.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
@@ -318,7 +319,8 @@ failure:
}
int bin_exec(const char *const path, const char *const *const argv,
- const uid_t uid, const gid_t gid)
+ const struct fs_stdstreams *const ss, const pid_t parent, const uid_t uid,
+ const gid_t gid)
{
const pid_t pid = bin_pid();
char *pathdup = NULL;
@@ -353,9 +355,12 @@ int bin_exec(const char *const path, const char *const *const argv,
{
.path = pathdup,
.dbg.aio = serial,
+ .parent = parent,
.pid = pid,
.uid = uid,
- .gid = gid
+ .gid = gid,
+ .ss = *ss,
+ .umask = S_IWGRP | S_IWOTH
};
if (copy_args(p, path, argv)
diff --git a/src/bin/src/mod/cfg.c b/src/bin/src/mod/cfg.c
index 8c78a32..1be26ca 100644
--- a/src/bin/src/mod/cfg.c
+++ b/src/bin/src/mod/cfg.c
@@ -88,6 +88,50 @@ static const struct nw_import imports[BIN_IMPORTS] =
.fn = bin_wnix_mount,
.signature = "i(iiiiii)"
}
+ },
+
+ {
+ .kind = NW_KIND_FUNCTION,
+ .module = "wnix",
+ .field = "write",
+ .u.function =
+ {
+ .fn = bin_wnix_write,
+ .signature = "i(iiii)"
+ }
+ },
+
+ {
+ .kind = NW_KIND_FUNCTION,
+ .module = "wnix",
+ .field = "umask",
+ .u.function =
+ {
+ .fn = bin_wnix_umask,
+ .signature = "i(i)"
+ }
+ },
+
+ {
+ .kind = NW_KIND_FUNCTION,
+ .module = "wnix",
+ .field = "open",
+ .u.function =
+ {
+ .fn = bin_wnix_open,
+ .signature = "i(iiii)"
+ }
+ },
+
+ {
+ .kind = NW_KIND_FUNCTION,
+ .module = "wnix",
+ .field = "close",
+ .u.function =
+ {
+ .fn = bin_wnix_close,
+ .signature = "i(ii)"
+ }
}
};
diff --git a/src/bin/src/proc/CMakeLists.txt b/src/bin/src/proc/CMakeLists.txt
index 47df502..e9a1d1c 100644
--- a/src/bin/src/proc/CMakeLists.txt
+++ b/src/bin/src/proc/CMakeLists.txt
@@ -17,6 +17,8 @@
target_sources(bin PRIVATE
cfg.c
eof.c
+ fd_alloc.c
+ fd_find.c
free.c
init.c
lock.c
diff --git a/src/bin/src/proc/fd_alloc.c b/src/bin/src/proc/fd_alloc.c
new file mode 100644
index 0000000..3db5e17
--- /dev/null
+++ b/src/bin/src/proc/fd_alloc.c
@@ -0,0 +1,54 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin/proc.h>
+#include <bin/types.h>
+#include <fs/fs.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+int bin_proc_fd_alloc(struct bin_proc *const p, const struct fs_fd *const fs_fd,
+ const int flags)
+{
+ int fd = 0;
+
+ for (size_t i = 0; i < p->n_fds;)
+ if (fd == p->fds[i].fd)
+ {
+ fd++;
+ i = 0;
+ }
+ else
+ i++;
+
+ const size_t n = p->n_fds + 1;
+ struct bin_proc_fd *const fds = realloc(p->fds, n * sizeof *fds);
+
+ if (!fds)
+ return -1;
+
+ fds[p->n_fds++] = (const struct bin_proc_fd)
+ {
+ .fd = fd,
+ .flags = flags,
+ .fs_fd = *fs_fd
+ };
+
+ p->fds = fds;
+ return fd;
+}
diff --git a/src/bin/src/proc/fd_find.c b/src/bin/src/proc/fd_find.c
new file mode 100644
index 0000000..b729e26
--- /dev/null
+++ b/src/bin/src/proc/fd_find.c
@@ -0,0 +1,38 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin/proc.h>
+#include <bin/types.h>
+#include <fcntl.h>
+#include <stddef.h>
+
+struct bin_proc_fd *bin_proc_fd_find(const struct bin_proc *const p, const int fd)
+{
+ if (fd < 0)
+ return NULL;
+
+ for (size_t i = 0; i < p->n_fds; i++)
+ {
+ struct bin_proc_fd *const pfd = &p->fds[i];
+
+ if (pfd->fd == fd && pfd->flags & O_WRONLY)
+ return pfd;
+ }
+
+ return NULL;
+}
diff --git a/src/bin/src/proc/free.c b/src/bin/src/proc/free.c
index a5bdea1..6876749 100644
--- a/src/bin/src/proc/free.c
+++ b/src/bin/src/proc/free.c
@@ -30,6 +30,9 @@ void bin_proc_free(struct bin_proc *const p)
struct bin_dbg *const d = &p->dbg;
+ for (char **arg = p->argv; *arg; arg++)
+ free(*arg);
+
dynstr_free(&d->dstr);
free(d->bkpt);
aio_free(d->aio);
diff --git a/src/bin/src/proc/pc.c b/src/bin/src/proc/pc.c
index 28b2f44..29bdd7f 100644
--- a/src/bin/src/proc/pc.c
+++ b/src/bin/src/proc/pc.c
@@ -643,6 +643,7 @@ enum nw_state bin_proc_pc(const long offset, struct nw_next *const next,
return NW_AGAIN;
}
else
+ {
for (size_t i = 0; i < d->n_bkpt; i++)
if (offset == d->bkpt[i])
{
@@ -653,5 +654,23 @@ enum nw_state bin_proc_pc(const long offset, struct nw_next *const next,
return NW_AGAIN;
}
+ const struct fs_read r =
+ {
+ .fd = &d->fd,
+ .buf = &d->b,
+ .n = sizeof d->b
+ };
+
+ const int n = aio_read_nb(&r);
+
+ if (n < 0)
+ {
+ kprintf("%s: aio_read_nb failed\n", __func__);
+ return NW_FATAL;
+ }
+ else if (n && d->b == -1)
+ d->running = false;
+ }
+
return NW_OK;
}
diff --git a/src/bin/src/update.c b/src/bin/src/update.c
index 3f03ae7..f5ce1c6 100644
--- a/src/bin/src/update.c
+++ b/src/bin/src/update.c
@@ -35,10 +35,10 @@ static int load(void)
switch (nw_load(&m->mod, &m->mod_out))
{
- case STATE_AGAIN:
+ case NW_AGAIN:
break;
- case STATE_FATAL:
+ case NW_FATAL:
/* TODO: call nw_loadexc. */
kprintf("Module %s failed to load\n", m->path);
@@ -48,7 +48,7 @@ static int load(void)
bin_mod_free(m);
break;
- case STATE_OK:
+ case NW_OK:
kprintf("Module %s loaded successfully\n", m->path);
if (bin_start(m))
diff --git a/src/bin/src/wnix/CMakeLists.txt b/src/bin/src/wnix/CMakeLists.txt
index b4868f2..5a92246 100644
--- a/src/bin/src/wnix/CMakeLists.txt
+++ b/src/bin/src/wnix/CMakeLists.txt
@@ -18,8 +18,13 @@ target_sources(bin PRIVATE
argc.c
argcopy.c
arglen.c
+ close.c
exit.c
mkdir.c
mount.c
- set_errno.c
+ open.c
+ umask.c
+ write.c
)
+
+add_subdirectory(routines)
diff --git a/src/bin/src/wnix/argcopy.c b/src/bin/src/wnix/argcopy.c
index cedb26e..f712016 100644
--- a/src/bin/src/wnix/argcopy.c
+++ b/src/bin/src/wnix/argcopy.c
@@ -21,7 +21,6 @@
#include <bin/wnix/routines.h>
#include <bin/proc.h>
#include <bin/types.h>
-#include <endian.h>
#include <nanowasm/nw.h>
#include <nanowasm/linear.h>
#include <errno.h>
@@ -66,7 +65,14 @@ static int set_errno(struct bin_proc *const p, const int error,
.user = p
};
- return bin_wnix_set_errno(p, error, c->errno_addr, next);
+ const struct bin_set_errno cfg =
+ {
+ .addr = c->errno_addr,
+ .error = error,
+ .p = p
+ };
+
+ return bin_wnix_set_errno(&cfg, next);
}
static enum nw_state read_arg(void *const user, struct nw_next *const next)
@@ -112,6 +118,8 @@ static enum nw_state check(void *const user, struct nw_next *const next)
else
*next = (const struct nw_next){.fn = read_arg, .user = user};
+ return NW_AGAIN;
+
failure:
free_argcopy(c);
return NW_FATAL;
@@ -137,7 +145,7 @@ enum nw_state bin_wnix_argcopy(const union nw_value *const params,
struct bin_proc *const p = user;
- *next = (const struct nw_next){.fn = check, .user = user};
p->import = c;
+ *next = (const struct nw_next){.fn = check, .user = user};
return NW_AGAIN;
}
diff --git a/src/bin/src/wnix/close.c b/src/bin/src/wnix/close.c
new file mode 100644
index 0000000..7e1754f
--- /dev/null
+++ b/src/bin/src/wnix/close.c
@@ -0,0 +1,32 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/wnix.h>
+#include <bin/proc.h>
+#include <bin/types.h>
+#include <nanowasm/nw.h>
+
+enum nw_state bin_wnix_close(const union nw_value *const params,
+ union nw_value *const ret, void *const user,
+ struct nw_next *const next)
+{
+ /* TODO */
+ ret->i32 = -1;
+ return NW_OK;
+}
diff --git a/src/bin/src/wnix/mkdir.c b/src/bin/src/wnix/mkdir.c
index 30a274a..8b26a2c 100644
--- a/src/bin/src/wnix/mkdir.c
+++ b/src/bin/src/wnix/mkdir.c
@@ -21,18 +21,215 @@
#include <bin/wnix/routines.h>
#include <bin/proc.h>
#include <bin/types.h>
-#include <endian.h>
+#include <aio.h>
+#include <fs/fs.h>
+#include <loop.h>
#include <nanowasm/nw.h>
#include <nanowasm/linear.h>
#include <errno.h>
#include <stdlib.h>
-#include <string.h>
+
+struct mkdir
+{
+ char *path;
+ unsigned long path_addr, errno_addr, mode;
+ union nw_value *ret;
+ struct aio *aio;
+ int error;
+};
+
+static void free_mkdir(struct mkdir *const m)
+{
+ if (!m)
+ return;
+
+ aio_free(m->aio);
+ free(m->path);
+ free(m);
+}
+
+static enum nw_state fail(void *const user, struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+ struct mkdir *const m = p->import;
+
+ m->ret->i32 = -1;
+ free_mkdir(m);
+ return NW_OK;
+}
+
+static int set_errno(struct bin_proc *const p, const int error,
+ struct nw_next *const next)
+{
+ struct mkdir *const m = p->import;
+
+ if (m->errno_addr)
+ {
+ const struct bin_set_errno cfg =
+ {
+ .addr = m->errno_addr,
+ .error = error,
+ .p = p
+ };
+
+ *next = (const struct nw_next)
+ {
+ .fn = fail,
+ .user = p
+ };
+
+ if (bin_wnix_set_errno(&cfg, next))
+ {
+ free_mkdir(m);
+ return -1;
+ }
+ }
+ else
+ return fail(p, next);
+
+ return 0;
+}
+
+static enum nw_state check_mkdir(void *const user, struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+ struct mkdir *const m = p->import;
+ enum nw_state ret = NW_OK;
+
+ if (m->error)
+ {
+ if (set_errno(p, m->error, next))
+ ret = NW_FATAL;
+ else
+ return NW_AGAIN;
+ }
+
+ free_mkdir(m);
+ return ret;
+}
+
+static int mkdir_done(const enum state state, void *const args)
+{
+ struct bin_proc *const p = args;
+ struct mkdir *const m = p->import;
+
+ m->error = state ? errno : 0;
+
+ if (bin_proc_unlock(p) || loop_rm_aio(m->aio))
+ {
+ free_mkdir(m);
+ return -1;
+ }
+
+ aio_free(m->aio);
+ m->aio = NULL;
+ return 0;
+}
+
+static enum nw_state do_mkdir(void *const user, struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+ struct mkdir *const m = p->import;
+ const struct aio_done d =
+ {
+ .f = mkdir_done,
+ .args = p
+ };
+
+ const struct fs_mkdir mk =
+ {
+ .mode = m->mode,
+ .path = m->path,
+ .uid = p->uid,
+ .gid = p->gid
+ };
+
+ struct aio *const aio = aio_mkdir(&mk, &d);
+
+ if (!aio || bin_proc_lock(p) || loop_add_aio(aio))
+ {
+ aio_free(aio);
+ free_mkdir(m);
+ return NW_FATAL;
+ }
+
+ m->aio = aio;
+ *next = (const struct nw_next){.fn = check_mkdir, .user = user};
+ return NW_AGAIN;
+}
+
+static enum nw_state read_path(void *const user, struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+ struct mkdir *const m = p->import;
+ const struct bin_readstr cfg =
+ {
+ .error = set_errno,
+ .addr = m->path_addr,
+ .str = &m->path,
+ .p = p
+ };
+
+ *next = (const struct nw_next){.fn = do_mkdir, .user = user};
+
+ if (bin_wnix_readstr(&cfg, next))
+ {
+ free_mkdir(m);
+ return NW_FATAL;
+ }
+
+ return NW_AGAIN;
+}
+
+static enum nw_state check(void *const user, struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+ struct mkdir *const m = p->import;
+
+ if (!m->path_addr || !m->errno_addr)
+ {
+ if (m->errno_addr)
+ {
+ if (set_errno(p, EINVAL, next))
+ goto failure;
+ }
+ else
+ {
+ m->ret->i32 = -1;
+ return NW_OK;
+ }
+ }
+ else
+ *next = (const struct nw_next){.fn = read_path, .user = user};
+
+ return NW_AGAIN;
+
+failure:
+ free_mkdir(m);
+ return NW_FATAL;
+}
enum nw_state bin_wnix_mkdir(const union nw_value *const params,
union nw_value *const ret, void *const user,
struct nw_next *const next)
{
- /* TODO */
- ret->i32 = -1;
- return NW_OK;
+ enum {PATH, MODE, ERRNO};
+ struct mkdir *const m = malloc(sizeof *m);
+
+ if (!m)
+ return NW_FATAL;
+
+ *m = (const struct mkdir)
+ {
+ .path_addr = params[PATH].i32,
+ .mode = params[MODE].i32,
+ .errno_addr = params[ERRNO].i32,
+ .ret = ret
+ };
+
+ struct bin_proc *const p = user;
+
+ *next = (const struct nw_next){.fn = check, .user = user};
+ p->import = m;
+ return NW_AGAIN;
}
diff --git a/src/bin/src/wnix/mount.c b/src/bin/src/wnix/mount.c
index 562f7d9..f3acea6 100644
--- a/src/bin/src/wnix/mount.c
+++ b/src/bin/src/wnix/mount.c
@@ -78,7 +78,14 @@ static int set_errno(struct bin_proc *const p, const int error,
.user = p
};
- return bin_wnix_set_errno(p, error, m->errno_addr, next);
+ const struct bin_set_errno cfg =
+ {
+ .addr = m->errno_addr,
+ .error = error,
+ .p = p
+ };
+
+ return bin_wnix_set_errno(&cfg, next);
}
static enum nw_state mounted(void *const user, struct nw_next *const next)
@@ -160,55 +167,23 @@ failure:
return NW_FATAL;
}
-static enum nw_state read_str(struct bin_proc *const p,
- struct mountstr *const ms)
+static enum nw_state read_string(struct bin_proc *const p,
+ struct mountstr *const ms, struct nw_next *const next)
{
- char b;
struct mount *const m = p->import;
- struct nw_sm_io io = {.buf = &b, .n = sizeof b};
- const enum nw_state n = nw_linear_load(&p->instance, &io, ms->addr + m->i);
-
- if (n)
- return n;
-
- char *const s = realloc(ms->str, m->i + 1);
- if (!s)
- return NW_FATAL;
-
- s[m->i++] = b;
- ms->str = s;
- return b ? NW_AGAIN : NW_OK;
-}
-
-static enum nw_state check_read_str(struct bin_proc *const p,
- struct mountstr *const ms, const struct nw_next *const innext,
- struct nw_next *const outnext)
-{
- struct mount *const m = p->import;
- enum {PATHMAX = 128};
-
- if (m->i >= PATHMAX)
+ const struct bin_readstr cfg =
{
- free_mount(m);
- /* TODO: assign errno. */
- m->ret->i32 = -1;
- return NW_OK;
- }
+ .error = set_errno,
+ .addr = ms->addr,
+ .str = &ms->str,
+ .p = p
+ };
- switch (read_str(p, ms))
+ if (bin_wnix_readstr(&cfg, next))
{
- case NW_FATAL:
- free_mount(m);
- return NW_FATAL;
-
- case NW_OK:
- m->i = 0;
- *outnext = *innext;
- break;
-
- case NW_AGAIN:
- break;
+ free_mount(m);
+ return NW_FATAL;
}
return NW_AGAIN;
@@ -218,27 +193,27 @@ static enum nw_state read_type(void *const user, struct nw_next *const next)
{
struct bin_proc *const p = user;
struct mount *const m = p->import;
- const struct nw_next rnext = {.fn = do_mount, .user = p};
- return check_read_str(p, &m->type, &rnext, next);
+ *next = (const struct nw_next){.fn = do_mount, .user = user};
+ return read_string(p, &m->type, next);
}
static enum nw_state read_tgt(void *const user, struct nw_next *const next)
{
struct bin_proc *const p = user;
struct mount *const m = p->import;
- const struct nw_next rnext = {.fn = read_type, .user = p};
- return check_read_str(p, &m->tgt, &rnext, next);
+ *next = (const struct nw_next){.fn = read_type, .user = user};
+ return read_string(p, &m->tgt, next);
}
static enum nw_state read_src(void *const user, struct nw_next *const next)
{
struct bin_proc *const p = user;
struct mount *const m = p->import;
- const struct nw_next rnext = {.fn = read_tgt, .user = p};
- return check_read_str(p, &m->src, &rnext, next);
+ *next = (const struct nw_next){.fn = read_tgt, .user = user};
+ return read_string(p, &m->src, next);
}
static enum nw_state check(void *const user, struct nw_next *const next)
diff --git a/src/bin/src/wnix/open.c b/src/bin/src/wnix/open.c
new file mode 100644
index 0000000..fdab80a
--- /dev/null
+++ b/src/bin/src/wnix/open.c
@@ -0,0 +1,222 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/wnix.h>
+#include <bin/wnix/routines.h>
+#include <bin/proc.h>
+#include <bin/types.h>
+#include <aio.h>
+#include <loop.h>
+#include <nanowasm/nw.h>
+#include <errno.h>
+#include <stdlib.h>
+
+struct open
+{
+ char *path;
+ struct fs_fd fd;
+ unsigned long path_addr, errno_addr;
+ long flags, mode;
+ union nw_value *ret;
+ struct aio *aio;
+ int error;
+};
+
+static void free_open(struct open *const op)
+{
+ if (!op)
+ return;
+
+ aio_free(op->aio);
+ free(op->path);
+ free(op);
+}
+
+static enum nw_state fail(void *const user, struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+ struct open *const op = p->import;
+
+ op->ret->i32 = -1;
+ free_open(op);
+ return NW_OK;
+}
+
+static int set_errno(struct bin_proc *const p, const int error,
+ struct nw_next *const next)
+{
+ struct open *const op = p->import;
+
+ if (op->errno_addr)
+ {
+ const struct bin_set_errno cfg =
+ {
+ .addr = op->errno_addr,
+ .error = error,
+ .p = p
+ };
+
+ *next = (const struct nw_next)
+ {
+ .fn = fail,
+ .user = p
+ };
+
+ if (bin_wnix_set_errno(&cfg, next))
+ {
+ free_open(op);
+ return -1;
+ }
+ }
+ else
+ return fail(p, next);
+
+ return 0;
+}
+
+static enum nw_state check_open(void *const user, struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+ struct open *const op = p->import;
+ int fd;
+
+ if (op->error)
+ return set_errno(p, op->error, next);
+ else if ((fd = bin_proc_fd_alloc(p, &op->fd, op->flags)) < 0)
+ return set_errno(p, errno, next);
+
+ op->ret->i32 = fd;
+ free_open(op);
+ return NW_OK;
+}
+
+static int opened(const enum state state, void *const args)
+{
+ struct bin_proc *const p = args;
+ struct open *const op = p->import;
+
+ op->error = state ? errno : 0;
+
+ if (bin_proc_unlock(p) || loop_rm_aio(op->aio))
+ {
+ free_open(op);
+ return -1;
+ }
+
+ aio_free(op->aio);
+ op->aio = NULL;
+ return 0;
+}
+
+static enum nw_state do_open(void *const user, struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+ struct open *const op = p->import;
+ const struct aio_done d =
+ {
+ .f = opened,
+ .args = p
+ };
+
+ const struct fs_open fo =
+ {
+ .flags = op->flags,
+ .mode = op->mode,
+ .path = op->path,
+ .fd = &op->fd,
+ .uid = p->uid,
+ .gid = p->gid,
+ .ss = p->ss
+ };
+
+ struct aio *const aio = aio_open(&fo, &d);
+
+ if (!aio || bin_proc_lock(p) || loop_add_aio(aio))
+ {
+ aio_free(aio);
+ free_open(op);
+ return NW_FATAL;
+ }
+
+ op->aio = aio;
+ *next = (const struct nw_next){.fn = check_open, .user = user};
+ return NW_AGAIN;
+}
+
+static enum nw_state read_path(void *const user, struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+ struct open *const op = p->import;
+ const struct bin_readstr cfg =
+ {
+ .error = set_errno,
+ .addr = op->path_addr,
+ .str = &op->path,
+ .p = p
+ };
+
+ *next = (const struct nw_next){.fn = do_open, .user = user};
+
+ if (bin_wnix_readstr(&cfg, next))
+ {
+ free_open(op);
+ return NW_FATAL;
+ }
+
+ return NW_AGAIN;
+}
+
+static enum nw_state check(void *const user, struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+ struct open *const op = p->import;
+
+ if (!op->path_addr || !op->errno_addr)
+ return set_errno(p, EINVAL, next);
+ else
+ *next = (const struct nw_next){.fn = read_path, .user = user};
+
+ return NW_AGAIN;
+}
+
+enum nw_state bin_wnix_open(const union nw_value *const params,
+ union nw_value *const ret, void *const user,
+ struct nw_next *const next)
+{
+ enum {PATH, FLAGS, MODE, ERRNO};
+ struct open *const op = malloc(sizeof *op);
+
+ if (!op)
+ return NW_FATAL;
+
+ *op = (const struct open)
+ {
+ .path_addr = params[PATH].i32,
+ .flags = params[FLAGS].i32,
+ .mode = params[MODE].i32,
+ .errno_addr = params[ERRNO].i32,
+ .ret = ret
+ };
+
+ struct bin_proc *const p = user;
+
+ *next = (const struct nw_next){.fn = check, .user = user};
+ p->import = op;
+ return NW_AGAIN;
+}
diff --git a/src/bin/src/wnix/routines/CMakeLists.txt b/src/bin/src/wnix/routines/CMakeLists.txt
new file mode 100644
index 0000000..784acf4
--- /dev/null
+++ b/src/bin/src/wnix/routines/CMakeLists.txt
@@ -0,0 +1,20 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(bin PRIVATE
+ readstr.c
+ set_errno.c
+)
diff --git a/src/bin/src/wnix/routines/readstr.c b/src/bin/src/wnix/routines/readstr.c
new file mode 100644
index 0000000..06f6fde
--- /dev/null
+++ b/src/bin/src/wnix/routines/readstr.c
@@ -0,0 +1,129 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/types.h>
+#include <bin/wnix/routines.h>
+#include <endian.h>
+#include <nanowasm/nw.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct readstr
+{
+ char *s;
+ size_t i;
+ struct bin_readstr cfg;
+ struct nw_next next;
+};
+
+static void free_readstr(struct readstr *const rs)
+{
+ if (!rs)
+ return ;
+
+ free(rs->s);
+ free(rs);
+}
+
+static enum nw_state read_str(struct readstr *const rs)
+{
+ char b;
+ struct nw_sm_io io = {.buf = &b, .n = sizeof b};
+ const struct bin_readstr *const cfg = &rs->cfg;
+ struct bin_proc *const p = cfg->p;
+ const enum nw_state n = nw_linear_load(&p->instance, &io, cfg->addr + rs->i);
+
+ if (n)
+ return n;
+
+ char *const s = realloc(rs->s, rs->i + 1);
+
+ if (!s)
+ return NW_FATAL;
+
+ s[rs->i++] = b;
+ rs->s = s;
+ return b ? NW_AGAIN : NW_OK;
+}
+
+static enum nw_state check_read_str(void *const user,
+ struct nw_next *const next)
+{
+ struct readstr *const rs = user;
+ const struct bin_readstr *const cfg = &rs->cfg;
+ struct bin_proc *const p = cfg->p;
+ enum nw_state ret = NW_AGAIN;
+ enum {PATHMAX = 128};
+
+ if (rs->i >= PATHMAX)
+ {
+ if (rs->cfg.error(p, ENAMETOOLONG, next))
+ ret = NW_FATAL;
+ }
+ else
+ {
+ switch (read_str(rs))
+ {
+ case NW_FATAL:
+ if (rs->cfg.error(p, errno, next))
+ ret = NW_FATAL;
+
+ break;
+
+ case NW_OK:
+ {
+ char *const s = strdup(rs->s);
+
+ if (!s)
+ ret = NW_FATAL;
+ else
+ {
+ *cfg->str = s;
+ *next = rs->next;
+ }
+ }
+ break;
+
+ case NW_AGAIN:
+ return NW_AGAIN;
+ }
+ }
+
+ free_readstr(rs);
+ return ret;
+}
+
+int bin_wnix_readstr(const struct bin_readstr *const cfg,
+ struct nw_next *const next)
+{
+ struct readstr *const rs = malloc(sizeof *rs);
+
+ if (!rs)
+ return -1;
+
+ *rs = (const struct readstr)
+ {
+ .cfg = *cfg,
+ .next = *next
+ };
+
+ *next = (const struct nw_next){.fn = check_read_str, .user = rs};
+ return 0;
+}
diff --git a/src/bin/src/wnix/set_errno.c b/src/bin/src/wnix/routines/set_errno.c
index cc04420..0db98af 100644
--- a/src/bin/src/wnix/set_errno.c
+++ b/src/bin/src/wnix/routines/set_errno.c
@@ -25,30 +25,38 @@
struct set_errno
{
- struct bin_proc *p;
- struct nw_next next;
- struct nw_sm_io io;
struct endian_le32 error;
- unsigned long addr;
+ struct nw_sm_io io;
+ struct bin_set_errno cfg;
+ struct nw_next next;
};
-static enum nw_state store_errno(void *const user,
- struct nw_next *const next)
+static enum nw_state store_errno(void *const user, struct nw_next *const next)
{
struct set_errno *const e = user;
- struct bin_proc *const p = e->p;
- const enum nw_state n = nw_linear_store(&p->instance, &e->io, e->addr);
+ const struct bin_set_errno *const cfg = &e->cfg;
+ struct bin_proc *const p = cfg->p;
+ const enum nw_state n = nw_linear_store(&p->instance, &e->io, cfg->addr);
+
+ switch (n)
+ {
+ case NW_FATAL:
+ free(e);
+ /* Fall through.*/
+ case NW_AGAIN:
+ return n;
- if (n)
- return n;
+ case NW_OK:
+ *next = e->next;
+ free(e);
+ break;
+ }
- *next = e->next;
- free(e);
return NW_AGAIN;
}
-int bin_wnix_set_errno(struct bin_proc *const p, const int error,
- const unsigned long addr, struct nw_next *const next)
+int bin_wnix_set_errno(const struct bin_set_errno *const cfg,
+ struct nw_next *const next)
{
struct set_errno *const e = malloc(sizeof *e);
@@ -57,10 +65,9 @@ int bin_wnix_set_errno(struct bin_proc *const p, const int error,
*e = (const struct set_errno)
{
- .error = endian_to_le32(error),
+ .error = endian_to_le32(cfg->error),
+ .cfg = *cfg,
.next = *next,
- .addr = addr,
- .p = p,
.io =
{
.buf = &e->error,
diff --git a/src/bin/src/wnix/umask.c b/src/bin/src/wnix/umask.c
new file mode 100644
index 0000000..f4fd701
--- /dev/null
+++ b/src/bin/src/wnix/umask.c
@@ -0,0 +1,35 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/wnix.h>
+#include <bin/proc.h>
+#include <bin/types.h>
+#include <nanowasm/nw.h>
+
+enum nw_state bin_wnix_umask(const union nw_value *const params,
+ union nw_value *const ret, void *const user,
+ struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+ const mode_t mask = params->i32, oldmask = p->umask;
+
+ p->umask = mask;
+ ret->i32 = oldmask;
+ return NW_OK;
+}
diff --git a/src/bin/src/wnix/write.c b/src/bin/src/wnix/write.c
new file mode 100644
index 0000000..3a4b8d5
--- /dev/null
+++ b/src/bin/src/wnix/write.c
@@ -0,0 +1,251 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/wnix.h>
+#include <bin/proc.h>
+#include <bin/routines.h>
+#include <bin/types.h>
+#include <bin/wnix/routines.h>
+#include <aio.h>
+#include <fs/fs.h>
+#include <loop.h>
+#include <nanowasm/nw.h>
+#include <nanowasm/linear.h>
+#include <errno.h>
+#include <stdlib.h>
+
+struct write
+{
+ long fd;
+ int error;
+ unsigned long addr, count, errno_addr;
+ char buf[64];
+ size_t i;
+ union nw_value *ret;
+ struct aio *aio;
+ struct bin_proc_fd *pfd;
+ struct nw_sm_io io;
+};
+
+static enum nw_state read_chunk(void *, struct nw_next *);
+
+static void free_write(struct write *const w)
+{
+ if (!w)
+ return;
+
+ aio_free(w->aio);
+ free(w);
+}
+
+static enum nw_state fail(void *const user, struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+ struct write *const w = p->import;
+
+ w->ret->i32 = -1;
+ free_write(w);
+ return NW_OK;
+}
+
+static enum nw_state set_errno(struct bin_proc *const p, const int error,
+ struct nw_next *const next)
+{
+ struct write *const w = p->import;
+
+ if (w->errno_addr)
+ {
+ const struct bin_set_errno cfg =
+ {
+ .addr = w->errno_addr,
+ .error = error,
+ .p = p
+ };
+
+ *next = (const struct nw_next)
+ {
+ .fn = fail,
+ .user = p
+ };
+
+ if (bin_wnix_set_errno(&cfg, next))
+ {
+ free_write(w);
+ return NW_FATAL;
+ }
+ }
+ else
+ return fail(p, next);
+
+ return NW_AGAIN;
+}
+
+static void setup_buf(struct bin_proc *const p, struct nw_next *const next)
+{
+ struct write *const w = p->import;
+ const size_t rem = w->count - w->i,
+ n = rem > sizeof w->buf ? sizeof w->buf : rem;
+
+ w->io = (const struct nw_sm_io)
+ {
+ .buf = w->buf,
+ .n = n
+ };
+
+ *next = (const struct nw_next){.fn = read_chunk, .user = p};
+}
+
+static enum nw_state check_write(void *const user, struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+ struct write *const w = p->import;
+
+ if (w->error)
+ {
+ if (set_errno(p, w->error, next))
+ {
+ free_write(w);
+ return NW_FATAL;
+ }
+ }
+ else if ((w->i += w->io.n) >= w->count)
+ {
+ w->ret->i32 = w->count;
+ free_write(w);
+ return NW_OK;
+ }
+ else
+ setup_buf(p, next);
+
+ return NW_AGAIN;
+}
+
+static int write_done(const enum state state, void *const args)
+{
+ struct bin_proc *const p = args;
+ struct write *const w = p->import;
+
+ w->error = state ? errno : 0;
+
+ if (bin_proc_unlock(p) || loop_rm_aio(w->aio))
+ {
+ free_write(w);
+ return -1;
+ }
+
+ aio_free(w->aio);
+ w->aio = NULL;
+ return 0;
+}
+
+static enum nw_state do_write(void *const user, struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+ struct write *const w = p->import;
+ const struct aio_done d =
+ {
+ .f = write_done,
+ .args = user
+ };
+
+ const struct fs_write fw =
+ {
+ .fd = &w->pfd->fs_fd,
+ .buf = w->buf,
+ .n = w->io.n
+ };
+
+ struct aio *const aio = aio_write(&fw, &d);
+
+ if (!aio || bin_proc_lock(p) || loop_add_aio(aio))
+ {
+ aio_free(aio);
+ free_write(w);
+ return NW_FATAL;
+ }
+
+ w->aio = aio;
+ *next = (const struct nw_next){.fn = check_write, .user = user};
+ return NW_AGAIN;
+}
+
+static enum nw_state read_chunk(void *const user, struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+ struct write *const w = p->import;
+ const unsigned long offset = w->addr + w->i;
+ const enum nw_state n = nw_linear_load(&p->instance, &w->io, offset);
+
+ switch (n)
+ {
+ case NW_OK:
+ *next = (const struct nw_next){.fn = do_write, .user = user};
+ break;
+
+ case NW_FATAL:
+ free_write(w);
+ return n;
+
+ case NW_AGAIN:
+ break;
+ }
+
+ return NW_AGAIN;
+}
+
+static enum nw_state check(void *const user, struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+ struct write *const w = p->import;
+
+ if (!(w->pfd = bin_proc_fd_find(p, w->fd)))
+ return set_errno(p, EBADF, next);
+ else if (!w->addr || !w->errno_addr)
+ return set_errno(p, EINVAL, next);
+ else
+ setup_buf(p, next);
+
+ return NW_AGAIN;
+}
+
+enum nw_state bin_wnix_write(const union nw_value *const params,
+ union nw_value *const ret, void *const user,
+ struct nw_next *const next)
+{
+ enum {FD, ADDR, COUNT, ERRNO};
+ struct write *const w = malloc(sizeof *w);
+
+ if (!w)
+ return NW_FATAL;
+
+ *w = (const struct write)
+ {
+ .fd = params[FD].i32,
+ .addr = params[ADDR].i32,
+ .count = params[COUNT].i32,
+ .errno_addr = params[ERRNO].i32,
+ .ret = ret
+ };
+
+ struct bin_proc *const p = user;
+
+ *next = (const struct nw_next){.fn = check, .user = user};
+ p->import = w;
+ return NW_AGAIN;
+}
diff --git a/src/drv/CMakeLists.txt b/src/drv/CMakeLists.txt
index 3306d93..aa21753 100644
--- a/src/drv/CMakeLists.txt
+++ b/src/drv/CMakeLists.txt
@@ -16,10 +16,20 @@
add_library(drv)
add_subdirectory(event)
-add_subdirectory(tty)
+add_subdirectory(null)
add_subdirectory(src)
+add_subdirectory(stderr)
+add_subdirectory(stdin)
+add_subdirectory(stdout)
+add_subdirectory(tty)
target_include_directories(drv PUBLIC include PRIVATE private_include)
-target_link_libraries(drv PUBLIC drv_event PRIVATE drv_tty)
+target_link_libraries(drv PUBLIC drv_event PRIVATE
+ drv_null
+ drv_stderr
+ drv_stdin
+ drv_stdout
+ drv_tty
+)
if(PS1_BUILD)
add_subdirectory(ps1)
diff --git a/src/drv/event/include/drv/event.h b/src/drv/event/include/drv/event.h
index 5707242..acd3659 100644
--- a/src/drv/event/include/drv/event.h
+++ b/src/drv/event/include/drv/event.h
@@ -23,6 +23,8 @@
#include <stdbool.h>
#include <stddef.h>
+struct drv_port;
+
struct drv_event_done
{
int (*f)(int error, void *args);
@@ -31,12 +33,12 @@ struct drv_event_done
struct drv_event_ops
{
- int (*read)(void *buf, size_t n, off_t offset,
- const struct drv_event_done *done, void *args);
- int (*read_nb)(void *buf, size_t n, void *args);
- int (*write)(const void *buf, size_t n, const struct drv_event_done *done,
- void *args);
- void *args;
+ int (*read)(struct drv_port *p, void *buf, size_t n, off_t offset,
+ const struct drv_event_done *done);
+ int (*read_nb)(struct drv_port *p, void *buf, size_t n);
+ int (*write)(struct drv_port *p, const void *buf, size_t n,
+ const struct drv_event_done *done);
+ struct drv_port *p;
};
struct drv_event
diff --git a/src/drv/null/CMakeLists.txt b/src/drv/null/CMakeLists.txt
new file mode 100644
index 0000000..ab09fc2
--- /dev/null
+++ b/src/drv/null/CMakeLists.txt
@@ -0,0 +1,20 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_null)
+add_subdirectory(src)
+target_include_directories(drv_null PUBLIC include PRIVATE private_include)
+target_link_libraries(drv_null PUBLIC c PRIVATE drv_event)
diff --git a/src/drv/null/include/drv/null.h b/src/drv/null/include/drv/null.h
new file mode 100644
index 0000000..52ff26f
--- /dev/null
+++ b/src/drv/null/include/drv/null.h
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_NULL_H
+#define DRV_NULL_H
+
+#include <drv/event.h>
+
+struct drv_port *drv_null_init(const struct drv_event *ev);
+int drv_null_update(struct drv_port *p);
+void drv_null_free(struct drv_port *p);
+
+#endif
diff --git a/src/drv/null/private_include/drv/null/ops.h b/src/drv/null/private_include/drv/null/ops.h
new file mode 100644
index 0000000..cf9d8f2
--- /dev/null
+++ b/src/drv/null/private_include/drv/null/ops.h
@@ -0,0 +1,31 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_NULL_OPS_H
+#define DRV_NULL_OPS_H
+
+#include <drv/event.h>
+#include <drv/null/types.h>
+#include <stddef.h>
+
+int drv_null_read(struct drv_port *p, void *buf, size_t n, off_t offset,
+ const struct drv_event_done *done);
+int drv_null_write(struct drv_port *p, const void *buf, size_t n,
+ const struct drv_event_done *done);
+
+#endif
diff --git a/src/drv/null/private_include/drv/null/types.h b/src/drv/null/private_include/drv/null/types.h
new file mode 100644
index 0000000..1c9266d
--- /dev/null
+++ b/src/drv/null/private_include/drv/null/types.h
@@ -0,0 +1,32 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_NULL_TYPES_H
+#define DRV_NULL_TYPES_H
+
+#include <drv/event.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+struct drv_port
+{
+ bool init;
+ struct drv_event ev;
+};
+
+#endif
diff --git a/src/drv/null/src/CMakeLists.txt b/src/drv/null/src/CMakeLists.txt
new file mode 100644
index 0000000..899cada
--- /dev/null
+++ b/src/drv/null/src/CMakeLists.txt
@@ -0,0 +1,23 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv_null PRIVATE
+ free.c
+ init.c
+ read.c
+ update.c
+ write.c
+)
diff --git a/src/drv/null/src/free.c b/src/drv/null/src/free.c
new file mode 100644
index 0000000..1251580
--- /dev/null
+++ b/src/drv/null/src/free.c
@@ -0,0 +1,32 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/event.h>
+#include <drv/null.h>
+#include <drv/null/ops.h>
+#include <drv/null/types.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+void drv_null_free(struct drv_port *const p)
+{
+ if (!p)
+ return;
+
+ free(p);
+}
diff --git a/src/drv/null/src/init.c b/src/drv/null/src/init.c
new file mode 100644
index 0000000..4ed6c39
--- /dev/null
+++ b/src/drv/null/src/init.c
@@ -0,0 +1,35 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/event.h>
+#include <drv/null.h>
+#include <drv/null/ops.h>
+#include <drv/null/types.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+struct drv_port *drv_null_init(const struct drv_event *const ev)
+{
+ struct drv_port *ret = NULL;
+
+ if (!(ret = malloc(sizeof *ret)))
+ return NULL;
+
+ *ret = (const struct drv_port){.ev = *ev};
+ return ret;
+}
diff --git a/src/drv/null/src/read.c b/src/drv/null/src/read.c
new file mode 100644
index 0000000..7dd9820
--- /dev/null
+++ b/src/drv/null/src/read.c
@@ -0,0 +1,30 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/event.h>
+#include <drv/null.h>
+#include <drv/null/types.h>
+#include <drv/null/ops.h>
+#include <stddef.h>
+
+int drv_null_read(struct drv_port *const p, void *const buf, const size_t n,
+ const off_t offset, const struct drv_event_done *const d)
+{
+ /* TODO: how to set EOF? */
+ return 0;
+}
diff --git a/src/drv/null/src/update.c b/src/drv/null/src/update.c
new file mode 100644
index 0000000..cc0b456
--- /dev/null
+++ b/src/drv/null/src/update.c
@@ -0,0 +1,48 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/event.h>
+#include <drv/null.h>
+#include <drv/null/ops.h>
+#include <drv/null/types.h>
+#include <stdbool.h>
+
+static int init(struct drv_port *const p)
+{
+ if (p->init)
+ return 0;
+
+ const struct drv_event *const ev = &p->ev;
+ const struct drv_event_ops ops =
+ {
+ .read = drv_null_read,
+ .write = drv_null_write,
+ .p = p
+ };
+
+ if (ev->status("null", &ops, true, 0666, ev->args))
+ return -1;
+
+ p->init = true;
+ return 0;
+}
+
+int drv_null_update(struct drv_port *const p)
+{
+ return init(p);
+}
diff --git a/src/drv/null/src/write.c b/src/drv/null/src/write.c
new file mode 100644
index 0000000..9ca8b53
--- /dev/null
+++ b/src/drv/null/src/write.c
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/event.h>
+#include <drv/null.h>
+#include <drv/null/types.h>
+#include <drv/null/ops.h>
+#include <stddef.h>
+
+int drv_null_write(struct drv_port *const p, const void *const buf,
+ const size_t n, const struct drv_event_done *const d)
+{
+ return n;
+}
diff --git a/src/drv/ps1/cd/private_include/drv/ps1/cd/routines.h b/src/drv/ps1/cd/private_include/drv/ps1/cd/routines.h
index 0b756de..9870445 100644
--- a/src/drv/ps1/cd/private_include/drv/ps1/cd/routines.h
+++ b/src/drv/ps1/cd/private_include/drv/ps1/cd/routines.h
@@ -27,10 +27,10 @@
int drv_ps1_cd_send(const struct cmd *cmd);
int drv_ps1_cd_getstat(void);
-int drv_ps1_cd_read(void *buf, size_t n, off_t offset,
- const struct drv_event_done *done, void *args);
-int drv_ps1_cd_write(const void *buf, size_t n,
- const struct drv_event_done *done, void *args);
+int drv_ps1_cd_read(struct drv_port *p, void *buf, size_t n, off_t offset,
+ const struct drv_event_done *done);
+int drv_ps1_cd_write(struct drv_port *p, const void *buf, size_t n,
+ const struct drv_event_done *done);
int drv_ps1_cd_next(void);
struct CdAsyncSeekL drv_ps1_cd_toseekl(unsigned i);
diff --git a/src/drv/ps1/cd/src/read.c b/src/drv/ps1/cd/src/read.c
index d21cbae..f8db3a0 100644
--- a/src/drv/ps1/cd/src/read.c
+++ b/src/drv/ps1/cd/src/read.c
@@ -208,8 +208,8 @@ static int start(void)
return cached_read(p);
}
-int drv_ps1_cd_read(void *const buf, const size_t n, const off_t offset,
- const struct drv_event_done *const done, void *const args)
+int drv_ps1_cd_read(struct drv_port *const pt, void *const buf, const size_t n,
+ const off_t offset, const struct drv_event_done *const done)
{
struct cd_prv *const p = &drv_ps1_cd_prv;
struct cd_req *const r = malloc(sizeof *r);
diff --git a/src/drv/ps1/cd/src/write.c b/src/drv/ps1/cd/src/write.c
index ba47993..a314862 100644
--- a/src/drv/ps1/cd/src/write.c
+++ b/src/drv/ps1/cd/src/write.c
@@ -22,8 +22,8 @@
#include <drv/event.h>
#include <errno.h>
-int drv_ps1_cd_write(const void *const buf, const size_t n,
- const struct drv_event_done *const done, void *const args)
+int drv_ps1_cd_write(struct drv_port *const p, const void *const buf,
+ const size_t n, const struct drv_event_done *const done)
{
/* TODO: write event callback returning EROFS */
errno = EROFS;
diff --git a/src/drv/ps1/sio/private_include/drv/ps1/sio/ops.h b/src/drv/ps1/sio/private_include/drv/ps1/sio/ops.h
index a481fa9..a7e19dd 100644
--- a/src/drv/ps1/sio/private_include/drv/ps1/sio/ops.h
+++ b/src/drv/ps1/sio/private_include/drv/ps1/sio/ops.h
@@ -22,10 +22,10 @@
#include <drv/event.h>
#include <sys/types.h>
-int drv_ps1_sio_read(void *buf, size_t n, off_t offset,
- const struct drv_event_done *done, void *args);
-int drv_ps1_sio_read_nb(void *buf, size_t n, void *args);
-int drv_ps1_sio_write(const void *buf, size_t n,
- const struct drv_event_done *done, void *args);
+int drv_ps1_sio_read(struct drv_port *p, void *buf, size_t n, off_t offset,
+ const struct drv_event_done *done);
+int drv_ps1_sio_read_nb(struct drv_port *p, void *buf, size_t n);
+int drv_ps1_sio_write(struct drv_port *p, const void *buf, size_t n,
+ const struct drv_event_done *done);
#endif
diff --git a/src/drv/ps1/sio/src/read.c b/src/drv/ps1/sio/src/read.c
index e13ad29..63bd29f 100644
--- a/src/drv/ps1/sio/src/read.c
+++ b/src/drv/ps1/sio/src/read.c
@@ -94,8 +94,8 @@ static int load(void)
return 0;
}
-int drv_ps1_sio_read(void *const buf, const size_t n, const off_t offset,
- const struct drv_event_done *const done, void *const args)
+int drv_ps1_sio_read(struct drv_port *const p, void *const buf, const size_t n,
+ const off_t offset, const struct drv_event_done *const done)
{
struct drv_ps1_sio *const s = &drv_ps1_sio;
struct sio_fifo *const f = &s->rx;
diff --git a/src/drv/ps1/sio/src/read_nb.c b/src/drv/ps1/sio/src/read_nb.c
index 755c5cf..9b9c3bf 100644
--- a/src/drv/ps1/sio/src/read_nb.c
+++ b/src/drv/ps1/sio/src/read_nb.c
@@ -55,7 +55,8 @@ static int read_fifo(char *buf, size_t n)
return ret;
}
-int drv_ps1_sio_read_nb(void *const buf, const size_t n, void *const args)
+int drv_ps1_sio_read_nb(struct drv_port *const p, void *const buf,
+ const size_t n)
{
return read_fifo(buf, n);
}
diff --git a/src/drv/ps1/sio/src/write.c b/src/drv/ps1/sio/src/write.c
index 942456f..4f5a702 100644
--- a/src/drv/ps1/sio/src/write.c
+++ b/src/drv/ps1/sio/src/write.c
@@ -86,8 +86,8 @@ static int store(void)
return 0;
}
-int drv_ps1_sio_write(const void *const buf, const size_t n,
- const struct drv_event_done *const done, void *const args)
+int drv_ps1_sio_write(struct drv_port *const p, const void *const buf,
+ const size_t n, const struct drv_event_done *const done)
{
struct drv_ps1_sio *const s = &drv_ps1_sio;
struct sio_fifo *const f = &s->tx;
diff --git a/src/drv/src/tree.c b/src/drv/src/tree.c
index d52df3d..087c38b 100644
--- a/src/drv/src/tree.c
+++ b/src/drv/src/tree.c
@@ -18,6 +18,10 @@
#include <drv/drv.h>
#include <drv/tree.h>
+#include <drv/null.h>
+#include <drv/stderr.h>
+#include <drv/stdin.h>
+#include <drv/stdout.h>
#include <drv/tty.h>
#include <drv/port.h>
#include <stddef.h>
@@ -27,7 +31,11 @@ struct drv_port *(*const drv_tree_init[])(const struct drv_event *) =
#if DRV_PS1
drv_ps1_init,
#endif
- drv_tty_init
+ drv_tty_init,
+ drv_null_init,
+ drv_stderr_init,
+ drv_stdin_init,
+ drv_stdout_init
};
enum {N = sizeof drv_tree_init / sizeof *drv_tree_init};
@@ -37,7 +45,11 @@ int (*const drv_tree_update[N])(struct drv_port *) =
#if DRV_PS1
drv_ps1_update,
#endif
- drv_tty_update
+ drv_tty_update,
+ drv_null_update,
+ drv_stderr_update,
+ drv_stdin_update,
+ drv_stdout_update
};
void (*const drv_tree_free[N])(struct drv_port *) =
@@ -45,7 +57,11 @@ void (*const drv_tree_free[N])(struct drv_port *) =
#if DRV_PS1
drv_ps1_free,
#endif
- drv_tty_free
+ drv_tty_free,
+ drv_null_free,
+ drv_stderr_free,
+ drv_stdin_free,
+ drv_stdout_free
};
const size_t drv_tree_n = N;
diff --git a/src/drv/stderr/CMakeLists.txt b/src/drv/stderr/CMakeLists.txt
new file mode 100644
index 0000000..cb9a07a
--- /dev/null
+++ b/src/drv/stderr/CMakeLists.txt
@@ -0,0 +1,20 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_stderr)
+add_subdirectory(src)
+target_include_directories(drv_stderr PUBLIC include PRIVATE private_include)
+target_link_libraries(drv_stderr PUBLIC c PRIVATE drv_event)
diff --git a/src/drv/stderr/include/drv/stderr.h b/src/drv/stderr/include/drv/stderr.h
new file mode 100644
index 0000000..eceff6a
--- /dev/null
+++ b/src/drv/stderr/include/drv/stderr.h
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_STDERR_H
+#define DRV_STDERR_H
+
+#include <drv/event.h>
+
+struct drv_port *drv_stderr_init(const struct drv_event *ev);
+int drv_stderr_update(struct drv_port *p);
+void drv_stderr_free(struct drv_port *p);
+
+#endif
diff --git a/src/drv/stderr/private_include/drv/stderr/ops.h b/src/drv/stderr/private_include/drv/stderr/ops.h
new file mode 100644
index 0000000..a265b15
--- /dev/null
+++ b/src/drv/stderr/private_include/drv/stderr/ops.h
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_STDERR_OPS_H
+#define DRV_STDERR_OPS_H
+
+#include <drv/event.h>
+#include <drv/stderr/types.h>
+#include <stddef.h>
+
+int drv_stderr_write(struct drv_port *p, const void *buf, size_t n,
+ const struct drv_event_done *done);
+
+#endif
diff --git a/src/drv/stderr/private_include/drv/stderr/types.h b/src/drv/stderr/private_include/drv/stderr/types.h
new file mode 100644
index 0000000..196568c
--- /dev/null
+++ b/src/drv/stderr/private_include/drv/stderr/types.h
@@ -0,0 +1,32 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_STDERR_TYPES_H
+#define DRV_STDERR_TYPES_H
+
+#include <drv/event.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+struct drv_port
+{
+ bool init;
+ struct drv_event ev;
+};
+
+#endif
diff --git a/src/drv/stderr/src/CMakeLists.txt b/src/drv/stderr/src/CMakeLists.txt
new file mode 100644
index 0000000..fd685c8
--- /dev/null
+++ b/src/drv/stderr/src/CMakeLists.txt
@@ -0,0 +1,22 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv_stderr PRIVATE
+ free.c
+ init.c
+ update.c
+ write.c
+)
diff --git a/src/drv/stderr/src/free.c b/src/drv/stderr/src/free.c
new file mode 100644
index 0000000..1793540
--- /dev/null
+++ b/src/drv/stderr/src/free.c
@@ -0,0 +1,32 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/event.h>
+#include <drv/stderr.h>
+#include <drv/stderr/ops.h>
+#include <drv/stderr/types.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+void drv_stderr_free(struct drv_port *const p)
+{
+ if (!p)
+ return;
+
+ free(p);
+}
diff --git a/src/drv/stderr/src/init.c b/src/drv/stderr/src/init.c
new file mode 100644
index 0000000..95797d7
--- /dev/null
+++ b/src/drv/stderr/src/init.c
@@ -0,0 +1,35 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/event.h>
+#include <drv/stderr.h>
+#include <drv/stderr/ops.h>
+#include <drv/stderr/types.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+struct drv_port *drv_stderr_init(const struct drv_event *const ev)
+{
+ struct drv_port *ret = NULL;
+
+ if (!(ret = malloc(sizeof *ret)))
+ return NULL;
+
+ *ret = (const struct drv_port){.ev = *ev};
+ return ret;
+}
diff --git a/src/drv/stderr/src/update.c b/src/drv/stderr/src/update.c
new file mode 100644
index 0000000..24e0cf4
--- /dev/null
+++ b/src/drv/stderr/src/update.c
@@ -0,0 +1,47 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/event.h>
+#include <drv/stderr.h>
+#include <drv/stderr/ops.h>
+#include <drv/stderr/types.h>
+#include <stdbool.h>
+
+static int init(struct drv_port *const p)
+{
+ if (p->init)
+ return 0;
+
+ const struct drv_event *const ev = &p->ev;
+ const struct drv_event_ops ops =
+ {
+ .write = drv_stderr_write,
+ .p = p
+ };
+
+ if (ev->status("stderr", &ops, true, 0666, ev->args))
+ return -1;
+
+ p->init = true;
+ return 0;
+}
+
+int drv_stderr_update(struct drv_port *const p)
+{
+ return init(p);
+}
diff --git a/src/drv/stderr/src/write.c b/src/drv/stderr/src/write.c
new file mode 100644
index 0000000..2f5ccf8
--- /dev/null
+++ b/src/drv/stderr/src/write.c
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/event.h>
+#include <drv/stderr.h>
+#include <drv/stderr/types.h>
+#include <drv/stderr/ops.h>
+#include <stddef.h>
+
+int drv_stderr_write(struct drv_port *const p, const void *const buf,
+ const size_t n, const struct drv_event_done *const d)
+{
+ return n;
+}
diff --git a/src/drv/stdin/CMakeLists.txt b/src/drv/stdin/CMakeLists.txt
new file mode 100644
index 0000000..8c788a0
--- /dev/null
+++ b/src/drv/stdin/CMakeLists.txt
@@ -0,0 +1,20 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_stdin)
+add_subdirectory(src)
+target_include_directories(drv_stdin PUBLIC include PRIVATE private_include)
+target_link_libraries(drv_stdin PUBLIC c PRIVATE drv_event)
diff --git a/src/drv/stdin/include/drv/stdin.h b/src/drv/stdin/include/drv/stdin.h
new file mode 100644
index 0000000..70ec64a
--- /dev/null
+++ b/src/drv/stdin/include/drv/stdin.h
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_STDIN_H
+#define DRV_STDIN_H
+
+#include <drv/event.h>
+
+struct drv_port *drv_stdin_init(const struct drv_event *ev);
+int drv_stdin_update(struct drv_port *p);
+void drv_stdin_free(struct drv_port *p);
+
+#endif
diff --git a/src/drv/stdin/private_include/drv/stdin/ops.h b/src/drv/stdin/private_include/drv/stdin/ops.h
new file mode 100644
index 0000000..0514172
--- /dev/null
+++ b/src/drv/stdin/private_include/drv/stdin/ops.h
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_STDIN_OPS_H
+#define DRV_STDIN_OPS_H
+
+#include <drv/event.h>
+#include <drv/stdin/types.h>
+#include <stddef.h>
+
+int drv_stdin_read(struct drv_port *p, void *buf, size_t n, off_t offset,
+ const struct drv_event_done *done);
+
+#endif
diff --git a/src/drv/stdin/private_include/drv/stdin/types.h b/src/drv/stdin/private_include/drv/stdin/types.h
new file mode 100644
index 0000000..62d1c41
--- /dev/null
+++ b/src/drv/stdin/private_include/drv/stdin/types.h
@@ -0,0 +1,32 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_STDIN_TYPES_H
+#define DRV_STDIN_TYPES_H
+
+#include <drv/event.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+struct drv_port
+{
+ bool init;
+ struct drv_event ev;
+};
+
+#endif
diff --git a/src/drv/stdin/src/CMakeLists.txt b/src/drv/stdin/src/CMakeLists.txt
new file mode 100644
index 0000000..0da5cc6
--- /dev/null
+++ b/src/drv/stdin/src/CMakeLists.txt
@@ -0,0 +1,22 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv_stdin PRIVATE
+ free.c
+ init.c
+ read.c
+ update.c
+)
diff --git a/src/drv/stdin/src/free.c b/src/drv/stdin/src/free.c
new file mode 100644
index 0000000..0f7d7af
--- /dev/null
+++ b/src/drv/stdin/src/free.c
@@ -0,0 +1,32 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/event.h>
+#include <drv/stdin.h>
+#include <drv/stdin/ops.h>
+#include <drv/stdin/types.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+void drv_stdin_free(struct drv_port *const p)
+{
+ if (!p)
+ return;
+
+ free(p);
+}
diff --git a/src/drv/stdin/src/init.c b/src/drv/stdin/src/init.c
new file mode 100644
index 0000000..c7a2e04
--- /dev/null
+++ b/src/drv/stdin/src/init.c
@@ -0,0 +1,35 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/event.h>
+#include <drv/stdin.h>
+#include <drv/stdin/ops.h>
+#include <drv/stdin/types.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+struct drv_port *drv_stdin_init(const struct drv_event *const ev)
+{
+ struct drv_port *ret = NULL;
+
+ if (!(ret = malloc(sizeof *ret)))
+ return NULL;
+
+ *ret = (const struct drv_port){.ev = *ev};
+ return ret;
+}
diff --git a/src/drv/stdin/src/read.c b/src/drv/stdin/src/read.c
new file mode 100644
index 0000000..a26f7df
--- /dev/null
+++ b/src/drv/stdin/src/read.c
@@ -0,0 +1,30 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/event.h>
+#include <drv/stdin.h>
+#include <drv/stdin/types.h>
+#include <drv/stdin/ops.h>
+#include <stddef.h>
+
+int drv_stdin_read(struct drv_port *const p, void *const buf, const size_t n,
+ const off_t offset, const struct drv_event_done *const d)
+{
+ /* TODO: how to set EOF? */
+ return 0;
+}
diff --git a/src/drv/stdin/src/update.c b/src/drv/stdin/src/update.c
new file mode 100644
index 0000000..cbfebca
--- /dev/null
+++ b/src/drv/stdin/src/update.c
@@ -0,0 +1,47 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/event.h>
+#include <drv/stdin.h>
+#include <drv/stdin/ops.h>
+#include <drv/stdin/types.h>
+#include <stdbool.h>
+
+static int init(struct drv_port *const p)
+{
+ if (p->init)
+ return 0;
+
+ const struct drv_event *const ev = &p->ev;
+ const struct drv_event_ops ops =
+ {
+ .read = drv_stdin_read,
+ .p = p
+ };
+
+ if (ev->status("stdin", &ops, true, 0666, ev->args))
+ return -1;
+
+ p->init = true;
+ return 0;
+}
+
+int drv_stdin_update(struct drv_port *const p)
+{
+ return init(p);
+}
diff --git a/src/drv/stdout/CMakeLists.txt b/src/drv/stdout/CMakeLists.txt
new file mode 100644
index 0000000..58f430a
--- /dev/null
+++ b/src/drv/stdout/CMakeLists.txt
@@ -0,0 +1,20 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_stdout)
+add_subdirectory(src)
+target_include_directories(drv_stdout PUBLIC include PRIVATE private_include)
+target_link_libraries(drv_stdout PUBLIC c PRIVATE drv_event)
diff --git a/src/drv/stdout/include/drv/stdout.h b/src/drv/stdout/include/drv/stdout.h
new file mode 100644
index 0000000..0fac80c
--- /dev/null
+++ b/src/drv/stdout/include/drv/stdout.h
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_STDOUT_H
+#define DRV_STDOUT_H
+
+#include <drv/event.h>
+
+struct drv_port *drv_stdout_init(const struct drv_event *ev);
+int drv_stdout_update(struct drv_port *p);
+void drv_stdout_free(struct drv_port *p);
+
+#endif
diff --git a/src/drv/stdout/private_include/drv/stdout/ops.h b/src/drv/stdout/private_include/drv/stdout/ops.h
new file mode 100644
index 0000000..af848e3
--- /dev/null
+++ b/src/drv/stdout/private_include/drv/stdout/ops.h
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_STDOUT_OPS_H
+#define DRV_STDOUT_OPS_H
+
+#include <drv/event.h>
+#include <drv/stdout/types.h>
+#include <stddef.h>
+
+int drv_stdout_write(struct drv_port *p, const void *buf, size_t n,
+ const struct drv_event_done *done);
+
+#endif
diff --git a/src/drv/stdout/private_include/drv/stdout/types.h b/src/drv/stdout/private_include/drv/stdout/types.h
new file mode 100644
index 0000000..a39ce64
--- /dev/null
+++ b/src/drv/stdout/private_include/drv/stdout/types.h
@@ -0,0 +1,32 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_STDOUT_TYPES_H
+#define DRV_STDOUT_TYPES_H
+
+#include <drv/event.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+struct drv_port
+{
+ bool init;
+ struct drv_event ev;
+};
+
+#endif
diff --git a/src/drv/stdout/src/CMakeLists.txt b/src/drv/stdout/src/CMakeLists.txt
new file mode 100644
index 0000000..490886d
--- /dev/null
+++ b/src/drv/stdout/src/CMakeLists.txt
@@ -0,0 +1,22 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv_stdout PRIVATE
+ free.c
+ init.c
+ update.c
+ write.c
+)
diff --git a/src/drv/stdout/src/free.c b/src/drv/stdout/src/free.c
new file mode 100644
index 0000000..4b7d733
--- /dev/null
+++ b/src/drv/stdout/src/free.c
@@ -0,0 +1,32 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/event.h>
+#include <drv/stdout.h>
+#include <drv/stdout/ops.h>
+#include <drv/stdout/types.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+void drv_stdout_free(struct drv_port *const p)
+{
+ if (!p)
+ return;
+
+ free(p);
+}
diff --git a/src/drv/stdout/src/init.c b/src/drv/stdout/src/init.c
new file mode 100644
index 0000000..86f566a
--- /dev/null
+++ b/src/drv/stdout/src/init.c
@@ -0,0 +1,35 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/event.h>
+#include <drv/stdout.h>
+#include <drv/stdout/ops.h>
+#include <drv/stdout/types.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+struct drv_port *drv_stdout_init(const struct drv_event *const ev)
+{
+ struct drv_port *ret = NULL;
+
+ if (!(ret = malloc(sizeof *ret)))
+ return NULL;
+
+ *ret = (const struct drv_port){.ev = *ev};
+ return ret;
+}
diff --git a/src/drv/stdout/src/update.c b/src/drv/stdout/src/update.c
new file mode 100644
index 0000000..8b47a52
--- /dev/null
+++ b/src/drv/stdout/src/update.c
@@ -0,0 +1,47 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/event.h>
+#include <drv/stdout.h>
+#include <drv/stdout/ops.h>
+#include <drv/stdout/types.h>
+#include <stdbool.h>
+
+static int init(struct drv_port *const p)
+{
+ if (p->init)
+ return 0;
+
+ const struct drv_event *const ev = &p->ev;
+ const struct drv_event_ops ops =
+ {
+ .write = drv_stdout_write,
+ .p = p
+ };
+
+ if (ev->status("stdout", &ops, true, 0666, ev->args))
+ return -1;
+
+ p->init = true;
+ return 0;
+}
+
+int drv_stdout_update(struct drv_port *const p)
+{
+ return init(p);
+}
diff --git a/src/drv/stdout/src/write.c b/src/drv/stdout/src/write.c
new file mode 100644
index 0000000..06d5980
--- /dev/null
+++ b/src/drv/stdout/src/write.c
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/event.h>
+#include <drv/stdout.h>
+#include <drv/stdout/types.h>
+#include <drv/stdout/ops.h>
+#include <stddef.h>
+
+int drv_stdout_write(struct drv_port *const p, const void *const buf,
+ const size_t n, const struct drv_event_done *const d)
+{
+ return n;
+}
diff --git a/src/drv/tty/private_include/drv/tty/ops.h b/src/drv/tty/private_include/drv/tty/ops.h
index b50b00a..ceab56a 100644
--- a/src/drv/tty/private_include/drv/tty/ops.h
+++ b/src/drv/tty/private_include/drv/tty/ops.h
@@ -23,8 +23,8 @@
#include <drv/tty/types.h>
#include <stddef.h>
-int drv_tty_write(const void *buf, size_t n, const struct drv_event_done *done,
- void *args);
+int drv_tty_write(struct drv_port *p, const void *buf, size_t n,
+ const struct drv_event_done *done);
int drv_tty_setdim(struct drv_port *p, unsigned x, unsigned y);
#endif
diff --git a/src/drv/tty/src/update.backup.c b/src/drv/tty/src/update.backup.c
index d072977..07e2a09 100644
--- a/src/drv/tty/src/update.backup.c
+++ b/src/drv/tty/src/update.backup.c
@@ -34,7 +34,7 @@ static int init(struct drv_port *const p)
const struct drv_event_ops ops =
{
.write = drv_tty_write,
- .args = p
+ .p = p
};
if (ev->status("tty", &ops, true, 0666, ev->args))
diff --git a/src/drv/tty/src/update.c b/src/drv/tty/src/update.c
index 7c01678..b5644d0 100644
--- a/src/drv/tty/src/update.c
+++ b/src/drv/tty/src/update.c
@@ -34,7 +34,7 @@ static int init(struct drv_port *const p)
const struct drv_event_ops ops =
{
.write = drv_tty_write,
- .args = p
+ .p = p
};
if (ev->status("tty", &ops, true, 0666, ev->args))
diff --git a/src/drv/tty/src/write.c b/src/drv/tty/src/write.c
index d4a988d..c7b90ed 100644
--- a/src/drv/tty/src/write.c
+++ b/src/drv/tty/src/write.c
@@ -23,11 +23,9 @@
#include <errno.h>
#include <stddef.h>
-int drv_tty_write(const void *const buf, const size_t n,
- const struct drv_event_done *const d, void *const args)
+int drv_tty_write(struct drv_port *const p, const void *const buf,
+ const size_t n, const struct drv_event_done *const d)
{
- struct drv_port *const p = args;
-
for (const char *s = buf; s - (const char *)buf < n; s++)
{
struct row *const r = p->last_row;
diff --git a/src/fs/devfs/src/open.c b/src/fs/devfs/src/open.c
index 229ff49..fb822a6 100644
--- a/src/fs/devfs/src/open.c
+++ b/src/fs/devfs/src/open.c
@@ -21,7 +21,9 @@
#include <devfs/ops.h>
#include <fs/fs.h>
#include <state.h>
+#include <unistd.h>
#include <stdlib.h>
+#include <string.h>
struct open
{
@@ -44,14 +46,27 @@ int devfs_open(const struct fs_open *const o, const struct fs_mp *const mp,
if (!op)
return -1;
-
- *op = (const struct open){.pr = r, .r = *r};
- *o->fd = (const struct fs_fd)
+ else
{
- .inode = *inode,
- .mp = *mp
- };
+ const struct fs_stdstreams *const ss = &o->ss;
+ const char *const name = inode->memi->name;
+ struct fs_fd *const fd = o->fd;
+ if (!strcmp(name, "stderr"))
+ *fd = ss->streams[STDERR_FILENO];
+ else if (!strcmp(name, "stdin"))
+ *fd = ss->streams[STDIN_FILENO];
+ else if (!strcmp(name, "stdout"))
+ *fd = ss->streams[STDOUT_FILENO];
+ else
+ *fd = (const struct fs_fd)
+ {
+ .inode = *inode,
+ .mp = *mp
+ };
+ }
+
+ *op = (const struct open){.pr = r, .r = *r};
*r = (const struct fs_ret){.f = done, .args = op};
return 0;
}
diff --git a/src/fs/devfs/src/read.c b/src/fs/devfs/src/read.c
index d7214ff..ec3c841 100644
--- a/src/fs/devfs/src/read.c
+++ b/src/fs/devfs/src/read.c
@@ -86,7 +86,7 @@ int devfs_read(const struct fs_read *const fr, struct fs_ret *const r)
const struct drv_event_ops *const ops = &o->ops;
- if (ops->read(fr->buf, fr->n, fd->start + fd->offset, &d, ops->args))
+ if (ops->read(ops->p, fr->buf, fr->n, fd->start + fd->offset, &d))
goto failure;
*r = (const struct fs_ret){.f = wait, .args = re};
diff --git a/src/fs/devfs/src/read_nb.c b/src/fs/devfs/src/read_nb.c
index 75b6c25..7b79bf8 100644
--- a/src/fs/devfs/src/read_nb.c
+++ b/src/fs/devfs/src/read_nb.c
@@ -37,5 +37,5 @@ int devfs_read_nb(const struct fs_read *const fr)
const struct drv_event_ops *const ops = &o->ops;
- return ops->read_nb(fr->buf, fr->n, ops->args);
+ return ops->read_nb(ops->p, fr->buf, fr->n);
}
diff --git a/src/fs/devfs/src/write.c b/src/fs/devfs/src/write.c
index fbb0ac8..dd4568f 100644
--- a/src/fs/devfs/src/write.c
+++ b/src/fs/devfs/src/write.c
@@ -83,7 +83,7 @@ int devfs_write(const struct fs_write *const fw, struct fs_ret *const r)
const struct drv_event_ops *const ops = &o->ops;
- if (ops->write(fw->buf, fw->n, &d, ops->args))
+ if (ops->write(ops->p, fw->buf, fw->n, &d))
goto failure;
*r = (const struct fs_ret){.f = wait, .args = w};
diff --git a/src/fs/include/fs/fs.h b/src/fs/include/fs/fs.h
index 60c1788..66bfe84 100644
--- a/src/fs/include/fs/fs.h
+++ b/src/fs/include/fs/fs.h
@@ -30,6 +30,23 @@ struct fs_mountpoint;
struct fs_mp_prv;
struct fs_fd_prv;
+struct fs_mp
+{
+ const char *src, *tgt;
+ const struct fs *fs;
+ struct fs_mp_prv *prv;
+};
+
+struct fs_fd
+{
+ int error;
+ off_t start, offset, size;
+ struct fs_fd_prv *prv;
+ struct fs_mp mp;
+ const struct fs_mp *tgt_mp;
+ union inode_result inode;
+};
+
struct fs_stat
{
const char *path;
@@ -62,6 +79,11 @@ struct fs_umount
gid_t gid;
};
+struct fs_stdstreams
+{
+ struct fs_fd streams[3];
+};
+
struct fs_open
{
const char *path;
@@ -70,6 +92,7 @@ struct fs_open
mode_t mode;
uid_t uid;
gid_t gid;
+ struct fs_stdstreams ss;
};
struct fs_read
@@ -114,23 +137,6 @@ struct fs
struct inode_ops iops;
};
-struct fs_mp
-{
- const char *src, *tgt;
- const struct fs *fs;
- struct fs_mp_prv *prv;
-};
-
-struct fs_fd
-{
- int error;
- off_t start, offset, size;
- struct fs_fd_prv *prv;
- struct fs_mp mp;
- const struct fs_mp *tgt_mp;
- union inode_result inode, tgt_inode;
-};
-
typedef int (*fs_update_fn)(struct fs_mp_prv *);
int fs_register(const struct fs *fs);
diff --git a/src/fs/include/fs/inode.h b/src/fs/include/fs/inode.h
index a7759f9..9447ab2 100644
--- a/src/fs/include/fs/inode.h
+++ b/src/fs/include/fs/inode.h
@@ -20,6 +20,7 @@
#define FS_INODE_H
#include <state.h>
+#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
diff --git a/src/fs/iso9660/src/eof.c b/src/fs/iso9660/src/eof.c
index 1c36b63..d53461b 100644
--- a/src/fs/iso9660/src/eof.c
+++ b/src/fs/iso9660/src/eof.c
@@ -21,10 +21,10 @@
#include <iso9660/types.h>
#include <fs/inode.h>
+/* TODO: eof seems redundant because of caio_eof */
int iso9660_eof(const struct fs_fd *const fd)
{
- const union inode_result *const i = &fd->tgt_inode;
- const off_t sz = i->cachei.size;
+ const off_t sz = fd->size;
if (!sz)
return 1;
diff --git a/src/fs/iso9660/src/open.c b/src/fs/iso9660/src/open.c
index 9818719..979ea91 100644
--- a/src/fs/iso9660/src/open.c
+++ b/src/fs/iso9660/src/open.c
@@ -31,6 +31,7 @@ struct open
struct fs_fd *fd;
struct fs_ret *pr, r;
struct fs_mp mp;
+ struct fs_stdstreams ss;
};
static int search_done(const enum state state, const char *const relpath,
@@ -57,7 +58,6 @@ static int search_done(const enum state state, const char *const relpath,
*fd = (const struct fs_fd)
{
.start = mpinode->prv->offset,
- .tgt_inode.cachei = op->inode,
.size = mpinode->size,
.tgt_mp = &op->mp,
.inode = *inode,
@@ -93,7 +93,8 @@ int iso9660_open(const struct fs_open *const o, const struct fs_mp *const mp,
.inode = *i,
.mp = *mp,
.pr = r,
- .r = *r
+ .r = *r,
+ .ss = o->ss
};
if (inode_search(&s, r))
diff --git a/src/fs/ramfs/src/search.c b/src/fs/ramfs/src/search.c
index 24e2a98..076603d 100644
--- a/src/fs/ramfs/src/search.c
+++ b/src/fs/ramfs/src/search.c
@@ -20,6 +20,7 @@
#include <ramfs/types.h>
#include <fs/fs.h>
#include <state.h>
+#include <errno.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
@@ -76,7 +77,10 @@ static int find_node(const char *const path, struct inode **const out,
}
if (!found)
+ {
+ errno = ENOENT;
goto end;
+ }
}
ret = 0;
diff --git a/src/init/private_include/init/types.h b/src/init/private_include/init/types.h
index 7f6114d..9bbb5bd 100644
--- a/src/init/private_include/init/types.h
+++ b/src/init/private_include/init/types.h
@@ -25,6 +25,7 @@
struct init
{
+ size_t path_i;
struct aio *aio;
struct stat sb;
unsigned retries;
diff --git a/src/init/ps1/private_include/init/ps1/types.h b/src/init/ps1/private_include/init/ps1/types.h
index 66702d1..33c2281 100644
--- a/src/init/ps1/private_include/init/ps1/types.h
+++ b/src/init/ps1/private_include/init/ps1/types.h
@@ -20,16 +20,19 @@
#define INIT_PS1_TYPES_H
#include <aio.h>
+#include <fs/fs.h>
#include <sys/stat.h>
#include <time.h>
struct init_ps1
{
+ size_t stream_i;
struct aio *aio;
struct stat *sb;
unsigned retries;
const char *path;
struct timespec last_retry;
+ struct fs_stdstreams ss;
int (*next)(struct init_ps1 *);
int (*success)(struct init_ps1 *);
int (*retry)(struct init_ps1 *);
diff --git a/src/init/ps1/src/boot.c b/src/init/ps1/src/boot.c
index 062078c..2b5e600 100644
--- a/src/init/ps1/src/boot.c
+++ b/src/init/ps1/src/boot.c
@@ -20,93 +20,112 @@
#include <init/ps1/types.h>
#include <aio.h>
#include <bin.h>
+#include <fs/fs.h>
#include <iso9660.h>
#include <kprintf.h>
#include <loop.h>
#include <net.h>
+#include <state.h>
#include <fcntl.h>
#include <sys/stat.h>
+#include <errno.h>
#include <stdlib.h>
-#include <state.h>
+#include <string.h>
#include <time.h>
-struct boot
-{
- struct aio *aio;
- struct init_ps1 *p;
-};
-
enum {RETRIES = 5};
static const char serial[] = "/dev/ttyS0";
+static const struct stream
+{
+ const char *path;
+ int flags;
+} streams[] =
+{
+ {.path = "/dev/null", .flags = O_RDONLY},
+ {.path = "/dev/tty", .flags = O_WRONLY},
+ {.path = "/dev/tty", .flags = O_WRONLY}
+};
static int retry_cd(struct init_ps1 *);
+static int open_stream(struct init_ps1 *p);
-static int wait_retry(struct init_ps1 *const p)
+static int exec(struct init_ps1 *const p)
{
- struct timespec ts;
- const time_t last = p->last_retry.tv_sec, timeout = 5;
+ const char *const args[] = {NULL};
- if (clock_gettime(CLOCK_REALTIME, &ts))
- return -1;
- else if (ts.tv_sec - last >= timeout)
- p->next = p->retry;
+ kprintf("Opening second-stage initd\n");
+ p->next = NULL;
- return 0;
+ /* TODO: create symbolic from /mnt/cdrom/bin to /bin */
+ return bin_exec("/mnt/cdrom/bin/initd", args, &p->ss, 0, 0, 0);
}
-static int stat_done(const enum state s, void *const args)
+static int stream_opened(const enum state state, void *const args)
{
- int ret = 0;
struct init_ps1 *const p = args;
+ const struct stream *const s = &streams[p->stream_i];
- if (s)
- {
- struct timespec ts;
+ if (loop_rm_aio(p->aio))
+ return -1;
- if (!--p->retries || clock_gettime(CLOCK_REALTIME, &ts))
- {
- ret = -1;
- goto end;
- }
+ aio_free(p->aio);
- p->last_retry = ts;
- p->next = wait_retry;
- }
+ if (state)
+ kprintf("Failed to open %s: %s\n", s->path, strerror(errno));
else
{
- p->next = p->success;
- kprintf("Successfully initialized %s (took %u attempts)\n",
- p->path, RETRIES - p->retries + 1);
+ kprintf("Successfully opened %s\n", s->path);
+
+ if (++p->stream_i >= sizeof streams / sizeof *streams)
+ p->next = exec;
+ else
+ p->next = open_stream;
}
-end:
- loop_rm_aio(p->aio);
- aio_free(p->aio);
- free(p->sb);
- return ret;
+ return 0;
+}
+
+static int open_stream(struct init_ps1 *const p)
+{
+ const struct stream *const s = &streams[p->stream_i];
+ const struct fs_open o =
+ {
+ .fd = &p->ss.streams[p->stream_i],
+ .path = s->path,
+ .flags = s->flags
+ };
+
+ const struct aio_done d =
+ {
+ .f = stream_opened,
+ .args = p
+ };
+
+ struct aio *const aio = aio_open(&o, &d);
+
+ if (!aio || loop_add_aio(aio))
+ return -1;
+
+ p->aio = aio;
+ p->next = NULL;
+ return 0;
}
static int mount_done(const enum state state, void *const args)
{
- struct boot *const b = args;
+ struct init_ps1 *const p = args;
- if (loop_rm_aio(b->aio))
+ if (loop_rm_aio(p->aio))
return -1;
- aio_free(b->aio);
- free(b);
+ aio_free(p->aio);
if (state)
kprintf("Failed to mount ISO9660 filesystem\n");
else
{
- const char *const args[] = {NULL};
-
kprintf("ISO9660 filesystem mounted successfully\n");
- kprintf("Opening second-stage initd\n");
-
- /* TODO: create symbolic from /mnt/cdrom/bin to /bin */
- return bin_exec("/mnt/cdrom/bin/initd", args, 0, 0);
+ p->next = open_stream;
}
return 0;
@@ -115,11 +134,6 @@ static int mount_done(const enum state state, void *const args)
static int mount_cd(struct init_ps1 *const p)
{
struct aio *aio = NULL;
- struct boot *const b = malloc(sizeof *b);
-
- if (!b)
- goto failure;
-
const struct aio_mount fm =
{
.mount =
@@ -134,7 +148,7 @@ static int mount_cd(struct init_ps1 *const p)
const struct aio_done d =
{
- .args = b,
+ .args = p,
.f = mount_done
};
@@ -142,7 +156,7 @@ static int mount_cd(struct init_ps1 *const p)
goto failure;
p->next = NULL;
- *b = (const struct boot){.aio = aio, .p = p};
+ p->aio = aio;
kprintf("Mounting ISO9660 filesystem from %s to %s\n",
fm.mount.src, fm.mount.tgt);
return 0;
@@ -150,10 +164,54 @@ static int mount_cd(struct init_ps1 *const p)
failure:
kprintf("Failed to mount ISO9660 filesystem\n");
aio_free(aio);
- free(b);
return -1;
}
+static int wait_retry(struct init_ps1 *const p)
+{
+ struct timespec ts;
+ const time_t last = p->last_retry.tv_sec, timeout = 5;
+
+ if (clock_gettime(CLOCK_REALTIME, &ts))
+ return -1;
+ else if (ts.tv_sec - last >= timeout)
+ p->next = p->retry;
+
+ return 0;
+}
+
+static int stat_done(const enum state s, void *const args)
+{
+ int ret = 0;
+ struct init_ps1 *const p = args;
+
+ if (s)
+ {
+ struct timespec ts;
+
+ if (!--p->retries || clock_gettime(CLOCK_REALTIME, &ts))
+ {
+ ret = -1;
+ goto end;
+ }
+
+ p->last_retry = ts;
+ p->next = wait_retry;
+ }
+ else
+ {
+ p->next = p->success;
+ kprintf("Successfully initialized %s (took %u attempts)\n",
+ p->path, RETRIES - p->retries + 1);
+ }
+
+end:
+ loop_rm_aio(p->aio);
+ aio_free(p->aio);
+ free(p->sb);
+ return ret;
+}
+
static int retry_cd(struct init_ps1 *const p)
{
static const char path[] = "/dev/cd0";
diff --git a/src/init/src/boot.c b/src/init/src/boot.c
index 30d9a9e..4c3e6ad 100644
--- a/src/init/src/boot.c
+++ b/src/init/src/boot.c
@@ -27,6 +27,14 @@
static int retry(struct init *);
enum {RETRIES = 5};
+static const char *const paths[] =
+{
+ "/dev/tty",
+ "/dev/null",
+ "/dev/stdout",
+ "/dev/stdin",
+ "/dev/stderr"
+};
static int run(struct init *const init)
{
@@ -35,13 +43,26 @@ static int run(struct init *const init)
static int port(struct init *const init)
{
- kprintf("tty initilization successful (took %u attempts)\n",
- RETRIES - init->retries + 1);
+ const size_t path_i = init->path_i + 1;
- if (init_port_boot())
- return -1;
+ kprintf("%s initilization successful (took %u attempts)\n",
+ paths[init->path_i], RETRIES - init->retries + 1);
+
+ if (path_i >= sizeof paths / sizeof *paths)
+ {
+ if (init_port_boot())
+ return -1;
+
+ init->next = run;
+ }
+ else
+ init_vars = (const struct init)
+ {
+ .retries = RETRIES,
+ .next = retry,
+ .path_i = path_i
+ };
- init->next = run;
return 0;
}
@@ -88,7 +109,8 @@ end:
static int retry(struct init *const init)
{
struct aio *aio = NULL;
- const struct fs_stat s = {.path = "/dev/tty", .sb = &init->sb};
+ const size_t path_i = init->path_i;
+ const struct fs_stat s = {.path = paths[init->path_i], .sb = &init->sb};
const struct aio_done d = {.f = stat_done, .args = init};
const unsigned retries = init->retries;
@@ -99,6 +121,7 @@ static int retry(struct init *const init)
{
.aio = aio,
.retries = retries,
+ .path_i = path_i,
.last_retry = {.tv_sec = (time_t)-1}
};
diff --git a/src/libc/include/fcntl.h b/src/libc/include/fcntl.h
index 282ced8..1edf2fc 100644
--- a/src/libc/include/fcntl.h
+++ b/src/libc/include/fcntl.h
@@ -19,11 +19,12 @@
#ifndef _FCNTL_H
#define _FCNTL_H
-enum
-{
- O_RDONLY = 1,
- O_WRONLY = 1 << 1,
- O_RDWR = O_RDONLY | O_WRONLY
-};
+#define O_RDONLY 1
+#define O_WRONLY (1 << 1)
+#define O_CREAT (1 << 2)
+#define O_APPEND (1 << 3)
+#define O_RDWR (O_RDONLY | O_WRONLY)
+
+int open(const char *__path, int __flags, ...);
#endif
diff --git a/src/libc/include/stdio.h b/src/libc/include/stdio.h
index b9c1a38..efa60dd 100644
--- a/src/libc/include/stdio.h
+++ b/src/libc/include/stdio.h
@@ -19,8 +19,23 @@
#ifndef _STDIO_H
#define _STDIO_H
-enum {EOF = -1};
+#include <stddef.h>
+#define BUFSIZ 128
+#define FOPEN_MAX 8
+#define FILENAME_MAX 128
+#define EOF -1
+#define stdin __stdin
+#define stdout __stdout
+#define stderr __stderr
+
+typedef struct __file FILE;
+extern FILE *__stdin, *__stdout, *__stderr;
+
+int fputc(int __c, FILE *__f);
+FILE *fopen(const char *__path, const char *__mode);
+size_t fwrite(const void *__p, size_t __sz, size_t __nmemb, FILE *__f);
+int putc(int __c, FILE *__f);
int puts(const char *__s);
int putchar(int __c);
diff --git a/src/libc/include/stdlib.h b/src/libc/include/stdlib.h
index 2704fca..b6e092e 100644
--- a/src/libc/include/stdlib.h
+++ b/src/libc/include/stdlib.h
@@ -57,10 +57,10 @@ div_t div(int __numerator, int __denominator);
#define RESET "\x1b[0m"
#define malloc(__n) ({void *__p; \
+ int Printf(const char *, ...); \
Printf(GREEN "-> %s:%d (%s)", __FILE__, __LINE__, __func__); \
__p = __malloc(__n); \
Printf(", p=%p" RESET "\n", __p); \
- int Printf(const char *, ...); \
size_t ta_num_free(); \
size_t ta_num_used(); \
size_t ta_num_fresh(); \
@@ -71,13 +71,13 @@ div_t div(int __numerator, int __denominator);
__p;})
#define realloc(__p, __n) ({void *__np; \
+ int Printf(const char *, ...); \
+ size_t ta_num_free(); \
+ size_t ta_num_used(); \
+ size_t ta_num_fresh(); \
Printf(YELLOW "-> %s:%d (%s)", __FILE__, __LINE__, __func__); \
__np = __realloc(__p, __n); \
Printf(", np=%p" RESET "\n", __np); \
- int Printf(const char *, ...); \
- size_t ta_num_free(); \
-size_t ta_num_used(); \
-size_t ta_num_fresh(); \
Printf("%s: free=%lu, used=%lu, fresh=%lu\n", __func__, \
(unsigned long)ta_num_free(), \
(unsigned long)ta_num_used(), \
@@ -85,13 +85,13 @@ size_t ta_num_fresh(); \
__np;})
#define calloc(__n, __sz) ({void *__p; \
+ int Printf(const char *, ...); \
+ size_t ta_num_free(); \
+ size_t ta_num_used(); \
+ size_t ta_num_fresh(); \
Printf(YELLOW "-> %s:%d (%s)", __FILE__, __LINE__, __func__); \
__p = __calloc(__n, __sz); \
Printf(", p=%p" RESET "\n", __p); \
- int Printf(const char *, ...); \
- size_t ta_num_free(); \
-size_t ta_num_used(); \
-size_t ta_num_fresh(); \
Printf("%s: free=%lu, used=%lu, fresh=%lu\n", __func__, \
(unsigned long)ta_num_free(), \
(unsigned long)ta_num_used(), \
@@ -100,18 +100,18 @@ size_t ta_num_fresh(); \
#define free(__p) ({ \
int Printf(const char *, ...); \
+ size_t ta_num_free(); \
+ size_t ta_num_used(); \
+ size_t ta_num_fresh(); \
Printf(RED "<- %s:%d (%s), p=%p" RESET "\n", \
__FILE__, __LINE__, __func__, __p); \
- size_t ta_num_free(); \
- size_t ta_num_used(); \
- size_t ta_num_fresh(); \
- __free(__p);\
- Printf("%s: free=%lu, used=%lu, fresh=%lu\n", \
- __func__, \
- (unsigned long)ta_num_free(), \
- (unsigned long)ta_num_used(), \
- (unsigned long)ta_num_fresh()); \
- })
+ __free(__p);\
+ Printf("%s: free=%lu, used=%lu, fresh=%lu\n", \
+ __func__, \
+ (unsigned long)ta_num_free(), \
+ (unsigned long)ta_num_used(), \
+ (unsigned long)ta_num_fresh()); \
+ })
#endif
#endif
diff --git a/src/libc/include/sys/stat.h b/src/libc/include/sys/stat.h
index 08fcf9a..b5ef13d 100644
--- a/src/libc/include/sys/stat.h
+++ b/src/libc/include/sys/stat.h
@@ -22,6 +22,35 @@
#include <sys/types.h>
#include <time.h>
+#define S_IRWXU 0700
+#define S_IRUSR 0400
+#define S_IWUSR 0200
+#define S_IXUSR 0100
+#define S_IRWXG 070
+#define S_IRGRP 040
+#define S_IWGRP 020
+#define S_IXGRP 010
+#define S_IRWXO 07
+#define S_IROTH 04
+#define S_IWOTH 02
+#define S_IXOTH 1
+
+#define S_IFBLK ((mode_t)1)
+#define S_IFCHR ((mode_t)(1 << 1))
+#define S_IFIFO ((mode_t)(1 << 2))
+#define S_IFREG ((mode_t)(1 << 3))
+#define S_IFDIR ((mode_t)(1 << 4))
+#define S_IFLNK ((mode_t)(1 << 5))
+#define S_IFSOCK ((mode_t)(1 << 6))
+
+#define S_ISBLK(__m) ((__m) & S_IFBLK)
+#define S_ISCHR(__m) ((__m) & S_IFCHR)
+#define S_ISDIR(__m) ((__m) & S_IFDIR)
+#define S_ISFIFO(__m) ((__m) & S_IFIFO)
+#define S_ISREG(__m) ((__m) & S_IFREG)
+#define S_ISLNK(__m) ((__m) & S_IFLNK)
+#define S_ISSOCK(__m) ((__m) & S_IFSOCK)
+
struct stat
{
dev_t st_dev;
@@ -37,6 +66,7 @@ struct stat
blkcnt_t st_blocks;
};
-int mkdir(const char *pathname, mode_t flags);
+int mkdir(const char *__pathname, mode_t __flags);
+mode_t umask(mode_t __mask);
#endif
diff --git a/src/libc/include/sys/types.h b/src/libc/include/sys/types.h
index 86ca604..fc231f1 100644
--- a/src/libc/include/sys/types.h
+++ b/src/libc/include/sys/types.h
@@ -22,5 +22,6 @@
typedef unsigned dev_t, mode_t, nlink_t, uid_t, gid_t, blksize_t, blkcnt_t;
typedef unsigned long ino_t, off_t;
typedef int pid_t;
+typedef long ssize_t;
#endif
diff --git a/src/libc/include/unistd.h b/src/libc/include/unistd.h
index ec4fc13..dcf0336 100644
--- a/src/libc/include/unistd.h
+++ b/src/libc/include/unistd.h
@@ -19,8 +19,20 @@
#ifndef _UNISTD_H
#define _UNISTD_H
+#include <stddef.h>
#include <stdint.h>
+#include <sys/types.h>
-void *sbrk(intptr_t increment);
+enum
+{
+ STDIN_FILENO,
+ STDOUT_FILENO,
+ STDERR_FILENO
+};
+
+void *sbrk(intptr_t __increment);
+ssize_t read(int __fd, void *__buf, size_t __n);
+ssize_t write(int __fd, const void *__buf, size_t __n);
+int close(int __fd);
#endif
diff --git a/src/libc/private_include/libc/file.h b/src/libc/private_include/libc/file.h
index dabeb89..8cb3fa0 100644
--- a/src/libc/private_include/libc/file.h
+++ b/src/libc/private_include/libc/file.h
@@ -1,4 +1,33 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
#ifndef LIBC_FILE_H
#define LIBC_FILE_H
+#include <stdio.h>
+
+struct __file
+{
+ int fd, eof, error;
+ char buf[BUFSIZ];
+ size_t i;
+};
+
+extern struct __file *__files[FOPEN_MAX];
+
#endif
diff --git a/src/libc/src/CMakeLists.txt b/src/libc/src/CMakeLists.txt
index 11e7a3c..cf88cdc 100644
--- a/src/libc/src/CMakeLists.txt
+++ b/src/libc/src/CMakeLists.txt
@@ -15,6 +15,7 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
target_sources(c PRIVATE
+ _putchar.c
errno.c
ta_init.c
)
@@ -25,6 +26,7 @@ add_subdirectory(stdlib)
add_subdirectory(string)
if(NOT LIBC_FREESTANDING)
+ target_sources(c PRIVATE malloc_init.c)
add_subdirectory(time)
add_subdirectory(unistd)
endif()
diff --git a/src/libc/src/_putchar.c b/src/libc/src/_putchar.c
new file mode 100644
index 0000000..df797c6
--- /dev/null
+++ b/src/libc/src/_putchar.c
@@ -0,0 +1,24 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+
+void _putchar(const char c)
+{
+ putchar(c);
+}
diff --git a/src/libc/src/malloc_init.c b/src/libc/src/malloc_init.c
new file mode 100644
index 0000000..1ec87e8
--- /dev/null
+++ b/src/libc/src/malloc_init.c
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <libc/malloc.h>
+#include <tinyalloc.h>
+#include <stdint.h>
+
+void __malloc_init(void)
+{
+ /* README.md states 16 is a "good default value". */
+ if (!ta_init(300, 16, sizeof (intmax_t)))
+ abort();
+}
diff --git a/src/libc/src/ps1/CMakeLists.txt b/src/libc/src/ps1/CMakeLists.txt
index 1bab87a..25d64a4 100644
--- a/src/libc/src/ps1/CMakeLists.txt
+++ b/src/libc/src/ps1/CMakeLists.txt
@@ -15,7 +15,6 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
target_sources(c PRIVATE
- putchar.c
setjmp.c
)
diff --git a/src/libc/src/stdio/CMakeLists.txt b/src/libc/src/stdio/CMakeLists.txt
index ca590a1..a4a60d9 100644
--- a/src/libc/src/stdio/CMakeLists.txt
+++ b/src/libc/src/stdio/CMakeLists.txt
@@ -15,5 +15,11 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
target_sources(c PRIVATE
+ fopen.c
+ fputc.c
+ fwrite.c
+ putchar.c
+ putc.c
puts.c
+ streams.c
)
diff --git a/src/libc/src/stdio/fopen.c b/src/libc/src/stdio/fopen.c
new file mode 100644
index 0000000..4c47f5a
--- /dev/null
+++ b/src/libc/src/stdio/fopen.c
@@ -0,0 +1,95 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <libc/file.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+static int find_free(void)
+{
+ for (size_t i = 0; i < sizeof __files / sizeof *__files; i++)
+ if (!__files[i])
+ return i;
+
+ return -1;
+}
+
+static int convert(const char *mode)
+{
+ int ret = 0;
+
+ if (!mode)
+ return -1;
+ else if (*mode == 'r')
+ ret |= O_RDONLY;
+ else if (*mode == 'w')
+ ret |= O_WRONLY | O_CREAT;
+ else if (*mode == 'a')
+ ret |= O_WRONLY | O_CREAT | O_APPEND;
+
+ if (*++mode == '+')
+ ret |= O_RDWR;
+
+ if (!ret)
+ return -1;
+
+ return ret;
+}
+
+FILE *fopen(const char *const path, const char *const mode)
+{
+ FILE *ret = NULL;
+ int i, flags, fd = -1;
+ mode_t mask;
+
+ if (!path || (flags = convert(mode)) < 0)
+ {
+ errno = EINVAL;
+ goto failure;
+ }
+ else if ((i = find_free()) < 0)
+ {
+ errno = EMFILE;
+ goto failure;
+ }
+
+ mask = umask(0);
+ umask(mask);
+
+ if ((fd = open(path, flags, 0666 & ~mask)) < 0)
+ goto failure;
+ else if (!(ret = malloc(sizeof *ret)))
+ goto failure;
+
+ *ret = (const struct __file){.fd = fd};
+ __files[i] = ret;
+ return ret;
+
+failure:
+
+ if (fd >= 0)
+ close(fd);
+
+ free(ret);
+ return NULL;
+}
diff --git a/src/libc/src/stdio/fputc.c b/src/libc/src/stdio/fputc.c
new file mode 100644
index 0000000..10fe4c6
--- /dev/null
+++ b/src/libc/src/stdio/fputc.c
@@ -0,0 +1,40 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <stddef.h>
+#include <stdio.h>
+#include <libc/file.h>
+
+int fputc(const int ic, FILE *const f)
+{
+ const unsigned char c = ic;
+
+ f->buf[f->i++] = c;
+
+ if (c == '\n' || f->i >= sizeof f->buf)
+ {
+ const size_t n = fwrite(f->buf, f->i, 1, f);
+
+ f->i = 0;
+
+ if (!n)
+ return EOF;
+ }
+
+ return c;
+}
diff --git a/src/libc/src/stdio/fwrite.c b/src/libc/src/stdio/fwrite.c
new file mode 100644
index 0000000..96a4daf
--- /dev/null
+++ b/src/libc/src/stdio/fwrite.c
@@ -0,0 +1,50 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <stddef.h>
+#include <stdio.h>
+#include <libc/file.h>
+#include <unistd.h>
+
+size_t fwrite(const void *const p, const size_t sz, const size_t nmemb,
+ FILE *const f)
+{
+ size_t ret = 0;
+ const char *b = p;
+
+ for (size_t i = 0; i < nmemb; i++, ret++)
+ {
+ size_t rem = sz;
+
+ while (rem)
+ {
+ const ssize_t n = write(f->fd, b, rem);
+
+ if (n < 0)
+ {
+ f->error = 1;
+ return 0;
+ }
+
+ b += n;
+ rem -= n;
+ }
+ }
+
+ return ret;
+}
diff --git a/src/libc/src/stdio/putc.c b/src/libc/src/stdio/putc.c
new file mode 100644
index 0000000..b8d015d
--- /dev/null
+++ b/src/libc/src/stdio/putc.c
@@ -0,0 +1,25 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <stddef.h>
+#include <stdio.h>
+
+int putc(const int c, FILE *const f)
+{
+ return fputc(c, f);
+}
diff --git a/src/libc/src/ps1/putchar.c b/src/libc/src/stdio/putchar.c
index 81c98ec..290ad97 100644
--- a/src/libc/src/ps1/putchar.c
+++ b/src/libc/src/stdio/putchar.c
@@ -20,10 +20,5 @@
int putchar(const int c)
{
- return EOF;
-}
-
-void _putchar(const char c)
-{
- putchar(c);
+ return putc(c, stdout);
}
diff --git a/src/libc/src/stdio/streams.c b/src/libc/src/stdio/streams.c
new file mode 100644
index 0000000..d88caa1
--- /dev/null
+++ b/src/libc/src/stdio/streams.c
@@ -0,0 +1,24 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <libc/file.h>
+#include <unistd.h>
+
+struct __file *__stdin, *__stdout, *__stderr;
+struct __file *__files[FOPEN_MAX];
diff --git a/src/libc/src/stdlib/malloc.c b/src/libc/src/stdlib/malloc.c
index 786f314..9025491 100644
--- a/src/libc/src/stdlib/malloc.c
+++ b/src/libc/src/stdlib/malloc.c
@@ -20,16 +20,12 @@
#include <libc/malloc.h>
#include <tinyalloc.h>
#include <errno.h>
-#include <stdint.h>
void *__malloc(const size_t n)
{
if (!__malloc_ta_init)
{
- /* README.md states 16 is a "good default value". */
- if (!ta_init(300, 16, sizeof (intmax_t)))
- abort();
-
+ __malloc_init();
__malloc_ta_init = 1;
}
diff --git a/src/libc/src/unistd/sbrk.c b/src/libc/src/unistd/sbrk.c
index b41c192..5d193da 100644
--- a/src/libc/src/unistd/sbrk.c
+++ b/src/libc/src/unistd/sbrk.c
@@ -25,9 +25,6 @@ static char *base = __bss_end;
void *sbrk(const intptr_t increment)
{
-
-
-
if (base + increment >= __ram_end)
return NULL;
diff --git a/src/libc/tinyalloc b/src/libc/tinyalloc
-Subproject fd8128d9b84e362abdbd05fafe252421edee8ab
+Subproject e32da5559962c6131e1f933a245526d699d45cf
diff --git a/src/loop/src/run.c b/src/loop/src/run.c
index 6c23365..3ce97b7 100644
--- a/src/loop/src/run.c
+++ b/src/loop/src/run.c
@@ -31,8 +31,6 @@
#include <drv/ps1/bios.h>
int loop_run(void)
{
- static unsigned iterations;
-
if (fs_update()
|| aio_poll(loop_aio_head, 0) < 0
|| init_run()
@@ -41,6 +39,9 @@ int loop_run(void)
|| gfx_update())
return -1;
+#if 0
+ static unsigned iterations;
+
iterations++;
static struct timespec ts;
@@ -59,6 +60,6 @@ int loop_run(void)
ts = now;
iterations = 0;
}
-
+#endif
return 0;
}
diff --git a/src/nanowasm b/src/nanowasm
-Subproject 1e3a4e9ff4d9963aa77dc6135f351f90d927e9e
+Subproject 4e4964c65700636e7411ea2d83b7f25ca4ad137
diff --git a/tools/nwc b/tools/nwc
-Subproject 15d2bb51e092d6dc34fa5fb5c1eb9b64c7c597b
+Subproject 690cfd848c81550aa96d1643eaf57ef28d7841f