Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions mcpp.toml
Original file line number Diff line number Diff line change
@@ -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"

Expand Down Expand Up @@ -57,7 +57,7 @@ provides-interfaces = [
]

[dependencies]
openkal = "0.17.0"
openkal = "0.17.1"

[build]
# The flags are attached to this package's own sources rather than to the whole
Expand Down
5 changes: 3 additions & 2 deletions src/process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
5 changes: 4 additions & 1 deletion src/sys.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
}
}
Expand Down
81 changes: 81 additions & 0 deletions tests/foreign_image_not_program.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// 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 <cstdio>
#include <cstring>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
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<ssize_t>(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;
}
18 changes: 18 additions & 0 deletions tests/stop_word_and_sigpipe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
Loading