|
| 1 | +// What openkal-linux 0.23 changes beside openkal 0.22, as this kernel does it. |
| 2 | +// |
| 3 | +// THE NULL DEVICE AT A POSITION IS THE SYSTEM'S OWN: a started program finds a |
| 4 | +// character device at standard input and standard error, reads the end of input |
| 5 | +// there and has every write accepted (openkal 0.22, clause 7.15). The device is |
| 6 | +// opened in the started image, so the caller holds no descriptor for it |
| 7 | +// afterwards. |
| 8 | +#include <cstdio> |
| 9 | +#include <cstring> |
| 10 | +#include <fcntl.h> |
| 11 | +#include <sys/stat.h> |
| 12 | +#include <unistd.h> |
| 13 | +import openkal.types; |
| 14 | +import openkal.env; |
| 15 | +import openkal.fs; |
| 16 | +import openkal.process; |
| 17 | + |
| 18 | +namespace { |
| 19 | +int failures = 0; |
| 20 | +void check(bool held, const char* what) { |
| 21 | + if (!held) { std::printf("FAIL: %s\n", what); ++failures; } |
| 22 | +} |
| 23 | + |
| 24 | +kal_dir root() { |
| 25 | + for (kal_uintptr i = 0; i < kal_fs_preopen_count(); ++i) { |
| 26 | + kal_dir d{}; char n[8]; kal_uintptr l = 0; |
| 27 | + if (kal_fs_preopen(i, &d, n, sizeof n, &l) == kal_ok && l == 1 && n[0] == '/') return d; |
| 28 | + } |
| 29 | + return kal_dir{}; |
| 30 | +} |
| 31 | + |
| 32 | +int descriptors() { |
| 33 | + int n = 0; |
| 34 | + for (int fd = 0; fd < 1024; ++fd) n += ::fcntl(fd, F_GETFD) != -1; |
| 35 | + return n; |
| 36 | +} |
| 37 | + |
| 38 | +char g_self[4096]; |
| 39 | +} // namespace |
| 40 | + |
| 41 | +int main(int argc, char** argv) { |
| 42 | + if (argc > 1 && std::strcmp(argv[1], "--null") == 0) { |
| 43 | + struct stat in{}, err{}; |
| 44 | + if (::fstat(0, &in) != 0 || !S_ISCHR(in.st_mode)) return 41; |
| 45 | + if (::fstat(2, &err) != 0 || !S_ISCHR(err.st_mode)) return 42; |
| 46 | + if (in.st_rdev != err.st_rdev) return 43; |
| 47 | + char b[8]; |
| 48 | + if (::read(0, b, sizeof b) != 0) return 44; |
| 49 | + if (::write(2, "discarded", 9) != 9) return 45; |
| 50 | + return 0; |
| 51 | + } |
| 52 | + const kal_intptr n = kal_env_image(g_self, sizeof g_self - 1); |
| 53 | + if (n <= 0 || g_self[0] != '/') { std::printf("FAIL: the program's own image is named\n"); return 1; } |
| 54 | + g_self[n] = 0; |
| 55 | + |
| 56 | + const kal_dir r = root(); |
| 57 | + const char* args[] = { g_self, "--null" }; |
| 58 | + const kal_uintptr lens[] = { std::strlen(g_self), 6 }; |
| 59 | + const kal_spawn how{ r, r, nullptr, nullptr, 0, (kal::process::null_in_flag | kal::process::null_err_flag).bits }; |
| 60 | + const int before = descriptors(); |
| 61 | + kal_process p{}; |
| 62 | + const int e = kal_process_spawn(&how, g_self + 1, std::strlen(g_self + 1), args, lens, 2, |
| 63 | + nullptr, nullptr, 0, nullptr, &p); |
| 64 | + check(e == kal_ok, "a program is started with the null device at two positions"); |
| 65 | + check(descriptors() == before, "and the caller holds no descriptor for the device"); |
| 66 | + int status = -1, terminated = 0; |
| 67 | + if (e == kal_ok) { |
| 68 | + kal_process_wait(p, &status, &terminated); |
| 69 | + kal_process_close(p); |
| 70 | + } |
| 71 | + check(terminated == 0 && status == 0, |
| 72 | + "the started program finds one character device there, reads its end and writes to it"); |
| 73 | + if (status > 0) std::printf(" the started program reported %d\n", status); |
| 74 | + if (failures == 0) std::printf("openkal_0_22: ok\n"); |
| 75 | + return failures == 0 ? 0 : 1; |
| 76 | +} |
0 commit comments