From 5a6b17235a10aea87b3b74122df861536a6efdd2 Mon Sep 17 00:00:00 2001 From: _ov4 Date: Thu, 3 Sep 2026 12:40:05 +0000 Subject: add safe_output: async-signal-safe output --- .gitignore | 1 + include/util/io.h | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/eval.cc | 4 ++-- src/handler.cc | 19 +++++++--------- src/util/io.cc | 33 ++++++++++++++++++++++++++- 5 files changed, 109 insertions(+), 15 deletions(-) diff --git a/.gitignore b/.gitignore index 9922c48..a716061 100644 --- a/.gitignore +++ b/.gitignore @@ -70,3 +70,4 @@ Testing/ include/test.h src/test.cc +test/ diff --git a/include/util/io.h b/include/util/io.h index aaeac02..4f55fec 100644 --- a/include/util/io.h +++ b/include/util/io.h @@ -12,6 +12,7 @@ #include #include #include +#include #include "global.h" @@ -23,16 +24,80 @@ namespace ov4 struct LogVoidify { void operator&(std::ostream&) const {} }; inline constexpr int DECIMAL = 10; -inline constexpr int LENGTH = 32; +inline constexpr int NUMBER_LENGTH = 70; // even enough for binary +// async-signal-safe void safe_print(const char *s, bool ignore_wrap = false); + +// async-signal-safe void safe_print(int x); + +// async-signal-safe void safe_debug(const char *s, bool ignore_wrap = false); + +// async-signal-safe void safe_debug(int x); + +// async-signal-safe bool isnum(const char *s); + +// async-signal-safe void reverse(char *str, int length); + +// async-signal-safe char *itoa(int num, char* str, int base); +// async-signal-safe +// remove '\n' from the string +// when replacemen = '\0', '\n' is deleted (instead of really replacing by '\0' ) +void wrap_eliminator(char *s, char replacement = '\0'); + +// async-signal-safe +void _write_helper(const char *s); + +template +void _safe_output_handler(T x) +{ + int errno_old = errno; + + if constexpr (std::is_same_v) // int + { + char buffer[MAXLINE]; + itoa(x, buffer, DECIMAL); + _write_helper(buffer); + } + else if constexpr (std::is_same_v || std::is_same_v) // C-style string + { + _write_helper(x); + } + else // ??? + { + static_assert(false, "_safe_output_handler: unsopported type"); + } + + errno = errno_old; +} + +inline void safe_output() +{ + ; // empty +} + + +// async-signal-safe output function +// example: +// safe_output("string", 123, variable); +template +void safe_output(T x, T_arg ...arg) +{ + int errno_old = errno; + + _safe_output_handler(x); + safe_output(arg...); + + errno = errno_old; +} + void usage(void); void unix_error(const char *msg); void app_error(const char *msg); diff --git a/src/eval.cc b/src/eval.cc index c4862d2..3b3a3ba 100644 --- a/src/eval.cc +++ b/src/eval.cc @@ -70,8 +70,8 @@ void eval(char *cmdline) execve(cmd_c, argv, environ); - safe_print(cmdline, true); - safe_print(": Command not found\n"); + wrap_eliminator(cmdline); + cout << cmdline << ": Command not found" << endl; exit(-1); // if no command is found } diff --git a/src/handler.cc b/src/handler.cc index 2e966f6..77512ec 100644 --- a/src/handler.cc +++ b/src/handler.cc @@ -72,11 +72,7 @@ void sigchld_handler([[maybe_unused]] int sig) if (WIFSIGNALED(status) || WIFSTOPPED(status)) { int jid = pid2jid(pid); - safe_print("Job ["); - safe_print(jid); - safe_print("] ("); - safe_print(pid); - safe_print(") "); + safe_output("Job [", jid, "] (", pid, ") "); if (!WIFSTOPPED(status) && WTERMSIG(status) == SIGINT) safe_print("terminated"); else if (WIFSTOPPED(status)) @@ -93,17 +89,17 @@ void sigchld_handler([[maybe_unused]] int sig) if (WIFSTOPPED(status)) { - safe_debug("suspended pid: "); - safe_debug(pid); - safe_debug("\n"); + // safe_debug("suspended pid: "); + // safe_debug(pid); + // safe_debug("\n"); + safe_output("Process suspended PID: ", pid, "\n"); sigset_t prev_inner; block_all(&prev_inner); job_suspend(pid); sigprocmask(SIG_SETMASK, &prev_inner, nullptr); } else { - safe_debug("terminated pid: "); - safe_debug(pid); + safe_output("Process terminated PID: ", pid, "\n"); sigset_t prev_inner; block_all(&prev_inner); deletejob(pid); @@ -182,7 +178,8 @@ int block_handler(sigset_t *prev) void sigquit_handler([[maybe_unused]] int sig) { - printf("Terminating after receipt of SIGQUIT signal\n"); + //printf("Terminating after receipt of SIGQUIT signal\n"); + safe_output("Terminating after receipt of SIGQUIT signal\n"); exit(1); } diff --git a/src/util/io.cc b/src/util/io.cc index 1fe37e5..09479e6 100644 --- a/src/util/io.cc +++ b/src/util/io.cc @@ -22,7 +22,7 @@ void safe_print(const char *s, bool ignore_wrap) void safe_print(int x) { int errno_old = errno; - char msg[LENGTH]; + char msg[NUMBER_LENGTH]; itoa(x, msg, DECIMAL); safe_print(msg); errno = errno_old; @@ -110,6 +110,37 @@ char *itoa(int num, char* str, int base) return str; } +void wrap_eliminator(char *s, char replacement) +{ + if (replacement == '\0') + { + char *r = s; + char *w = s; + while (*r) { + if (*r != '\n') + *w++ = *r; + r++; + } + *w = '\0'; + return; + } + size_t len = strlen(s); + for (size_t i = 0; i < len; i++) + if (s[i] == '\n') + s[i] = replacement; +} + +void write_helper(const char *s) +{ + int errno_old = errno; + + size_t len = strlen(s); + for (size_t i = 0; i < len; i++) + write(STDIN_FILENO, &s[i], 1); + + errno = errno_old; +} + /* * usage - print a help message */ -- cgit v1.3.1-4-g156e