From a1ee7d0030eda1838932af29e986859c820cd2b8 Mon Sep 17 00:00:00 2001 From: Sunrisepeak Date: Tue, 27 Oct 2026 08:37:25 +0900 Subject: [PATCH 1/5] 0.15.1: the closing of the terminal is a request to end, taken over with SIGTERM and SIGINT Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- README.md | 2 +- mcpp.toml | 2 +- src/process.cpp | 5 +++-- tests/stop_word_and_sigpipe.cpp | 18 ++++++++++++++++++ 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c3b2959..44f1cf0 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ written on the kernel's own calls. openkal = "0.17.0" [target.'cfg(os = "macos")'.dependencies] -openkal-macos = "0.15.0" +openkal-macos = "0.15.1" ``` Its purpose is as much to test the specification as to be used. A specification diff --git a/mcpp.toml b/mcpp.toml index 933edff..5daacfa 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -1,7 +1,7 @@ [package] namespace = "mcpplibs" name = "openkal-macos" -version = "0.15.0" +version = "0.15.1" description = "An implementation of openkal for macOS, written on the kernel's own calls. Its purpose is as much to test the specification as to be used." license = "Apache-2.0" diff --git a/src/process.cpp b/src/process.cpp index 4a1723f..6da054d 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -865,9 +865,10 @@ const kal_u32* kal_process_stop_requested(void) { int state = __atomic_load_n(&g_stop_armed, __ATOMIC_ACQUIRE); if (state == 0) { // SIGTERM is the one `kal_process_terminate' sends here; SIGINT is what - // an interactive stream delivers. Both are requests to end, which is the + // an interactive stream delivers; SIGHUP is the terminal that started + // the program closing (0.15.1). All are requests to end, which is the // whole of what this word reports. - const bool ok = arm_one(15) && arm_one(2); + const bool ok = arm_one(15) && arm_one(2) && arm_one(1); state = ok ? 1 : -1; __atomic_store_n(&g_stop_armed, state, __ATOMIC_RELEASE); } diff --git a/tests/stop_word_and_sigpipe.cpp b/tests/stop_word_and_sigpipe.cpp index 6a86c39..c26151f 100644 --- a/tests/stop_word_and_sigpipe.cpp +++ b/tests/stop_word_and_sigpipe.cpp @@ -23,6 +23,15 @@ void check(bool held, const char* what) { } int main(int argc, char** argv) { + if (argc > 1 && std::strcmp(argv[1], "--hang-up") == 0) { + const kal_u32* word = kal_process_stop_requested(); + if (word == nullptr) return 90; + ::kill(::getpid(), SIGHUP); + for (int i = 0; i < 1000 && *word == 0; ++i) ::usleep(1000); + if (*word == 0) return 91; + kal_process_end_as_requested(); + return 92; + } if (argc > 1 && std::strcmp(argv[1], "--end-as-requested") == 0) { const kal_u32* word = kal_process_stop_requested(); if (word == nullptr) return 90; @@ -57,6 +66,15 @@ int main(int argc, char** argv) { ::waitpid(child, &st, 0); check(WIFSIGNALED(st) && WTERMSIG(st) == SIGTERM, "a program that ends as requested is reported to its starter as ended by the request"); + const pid_t hung = ::fork(); + if (hung == 0) { + ::execl(self, argv[0], "--hang-up", nullptr); + ::_exit(93); + } + st = 0; + ::waitpid(hung, &st, 0); + check(WIFSIGNALED(st) && WTERMSIG(st) == SIGHUP, + "a hang-up is taken over as a request, and the program ends as it would have (0.15.1)"); #else (void)word; (void)argv; #endif From f4dc428fa01289815e215065566425ac2767bb6e Mon Sep 17 00:00:00 2001 From: Sunrisepeak Date: Tue, 27 Oct 2026 09:05:26 +0900 Subject: [PATCH 2/5] openkal 0.17.1 is followed by its branch until it is published Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- mcpp.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mcpp.toml b/mcpp.toml index 5daacfa..f4869b3 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -57,7 +57,7 @@ provides-interfaces = [ ] [dependencies] -openkal = "0.17.0" +openkal = { git = "https://github.com/mcpplibs/openkal.git", branch = "openkal-0.17.1" } [build] # The flags are attached to this package's own sources rather than to the whole From 86232e2d88bed6970bb022e01397fea9de0feb6d Mon Sep 17 00:00:00 2001 From: Sunrisepeak Date: Tue, 27 Oct 2026 09:30:31 +0900 Subject: [PATCH 3/5] 0.15.1: an image built for a processor this machine lacks is not a program (EBADARCH, EBADMACHO), as ENOEXEC is Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- src/sys.h | 5 +- tests/foreign_image_not_program.cpp | 80 +++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 tests/foreign_image_not_program.cpp diff --git a/src/sys.h b/src/sys.h index e9b78fc..6aeedf7 100644 --- a/src/sys.h +++ b/src/sys.h @@ -270,6 +270,9 @@ enum : int { e_inval = 22, e_nfile = 23, e_mfile = 24, e_notty = 25, e_fbig = 27, e_nospc = 28, e_spipe = 29, e_rofs = 30, e_pipe = 32, e_range = 34, e_nametoolong = 63, e_nosys = 78, e_notempty = 66, e_loop = 62, + // A file this machine cannot start: built for another processor, or not + // an image this loader reads. + e_badarch = 86, e_badmacho = 88, // This system has two values for an operation the object does not support, // and they are different numbers: 45 is the one a call upon a resource of // the wrong kind returns, and 102 is the one a socket returns. @@ -341,7 +344,7 @@ inline int translate(okm_long r) { case e_notempty: return 11; // not empty case e_isdir: return 12; // is directory case e_notdir: return 13; // not directory - case e_noexec: return 14; // not program + case e_noexec: case e_badarch: case e_badmacho: return 14; // not program default: return 3; // io } } diff --git a/tests/foreign_image_not_program.cpp b/tests/foreign_image_not_program.cpp new file mode 100644 index 0000000..3c7dd78 --- /dev/null +++ b/tests/foreign_image_not_program.cpp @@ -0,0 +1,80 @@ +// A file this machine cannot start is "not a program" (kal_err_not_program), +// whichever of this kernel's values says so (0.15.1): ENOEXEC for a file that +// is no image, EBADARCH for an image built for a processor this machine does +// not have. Before, only ENOEXEC was translated, and an image of another +// processor --- the case a runner asks about --- arrived as an input/output +// error. +// +// The foreign image is a Mach-O header naming a processor that does not exist; +// the kernel refuses it by its header before reading anything else. +#include +#include +#include +#include +import openkal.types; +import openkal.fs; +import openkal.process; + +namespace { +int failures = 0; +void check(bool held, const char* what) { + if (!held) { std::printf("FAIL: %s\n", what); ++failures; } +} + +kal_dir root() { + for (kal_uintptr i = 0; i < kal_fs_preopen_count(); ++i) { + kal_dir d{}; char n[8]; kal_uintptr l = 0; + if (kal_fs_preopen(i, &d, n, sizeof n, &l) == kal_ok && l == 1 && n[0] == '/') return d; + } + return kal_dir{}; +} + +// The refusal a start of `path' (absolute) meets. +int start(const char* path) { + const kal_dir r = root(); + const char* argv[] = { path }; + const kal_uintptr lens[] = { std::strlen(path) }; + const kal_spawn how{ r, r, nullptr, nullptr, 0, 0 }; + kal_process p{}; + const int e = kal_process_spawn(&how, path + 1, std::strlen(path + 1), argv, lens, 1, + nullptr, nullptr, 0, nullptr, &p); + if (e == kal_ok) { + int status = 0, terminated = 0; + kal_process_wait(p, &status, &terminated); + } + return e; +} + +// A file of `bytes', executable, at a fresh name under /tmp. +bool place(char* path, const unsigned char* bytes, std::size_t n) { + const int fd = ::mkstemp(path); + if (fd < 0) return false; + const bool written = ::write(fd, bytes, n) == static_cast(n); + ::fchmod(fd, 0755); + ::close(fd); + return written; +} +} // namespace + +int main() { + // mach_header_64: magic, a processor type no machine has, a subtype, MH_EXECUTE. + const unsigned char foreign[32] = { + 0xcf, 0xfa, 0xed, 0xfe, 0x45, 0x23, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + }; + char image[] = "/tmp/okm-foreign-XXXXXX"; + check(place(image, foreign, sizeof foreign), "a foreign image is written"); + check(start(image) == kal_err_not_program, "an image of a processor this machine lacks is not a program"); + ::unlink(image); + + const unsigned char text[] = { 'n', 'o', 't', ' ', 'a', 'n', ' ', 'i', 'm', 'a', 'g', 'e', '\n' }; + char plain[] = "/tmp/okm-plain-XXXXXX"; + check(place(plain, text, sizeof text), "a file of text is written"); + const int e = start(plain); + // A file with no `#!' and no image header: the kernel's ENOEXEC. + check(e == kal_err_not_program, "a file that is no image is not a program"); + ::unlink(plain); + + if (failures == 0) std::printf("openkal-macos: a file this machine cannot start is not a program\n"); + return failures == 0 ? 0 : 1; +} From 24a0e61a725de0b53a275ae0a536f025af6563fd Mon Sep 17 00:00:00 2001 From: Sunrisepeak Date: Tue, 27 Oct 2026 10:54:28 +0900 Subject: [PATCH 4/5] tests: fchmod is declared by sys/stat.h Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- tests/foreign_image_not_program.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/foreign_image_not_program.cpp b/tests/foreign_image_not_program.cpp index 3c7dd78..196832a 100644 --- a/tests/foreign_image_not_program.cpp +++ b/tests/foreign_image_not_program.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include import openkal.types; import openkal.fs; From e9da5c199ea4a593bdd29f8b1f44d8bc89ecb95a Mon Sep 17 00:00:00 2001 From: Sunrisepeak Date: Tue, 27 Oct 2026 10:57:11 +0900 Subject: [PATCH 5/5] openkal 0.17.1, as published Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- mcpp.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mcpp.toml b/mcpp.toml index f4869b3..91f6190 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -57,7 +57,7 @@ provides-interfaces = [ ] [dependencies] -openkal = { git = "https://github.com/mcpplibs/openkal.git", branch = "openkal-0.17.1" } +openkal = "0.17.1" [build] # The flags are attached to this package's own sources rather than to the whole