Files
nt-lite/code/user/tests/posix_fd_smoke/posix_fd_smoke.c
T
maksw 73abd6f90d isolate POSIX builds from the host UCRT, wire lwext4 and ntfs-3g as ext4.sys and ntfs.sys, split the FAT driver into directory/file/async/driver/mount units, add posixsrv and dwm plus input/console/desktop syscall clients and a pile of new smoke targets, rename serial.sys to cereal.sys, name HDA/USB/lwIP/AHCI workers, harden ATA probing/reset/removal around actual hardware deadlines, absent-channel detection, diagnostics and explicit worker lifetime, redo ACPI S5 shutdown around GAS/MMIO and HW-reduced firmware, scan SSDTs for _S5 and deal with Intel SMI sleep trapping, make serial and SMP timeouts use real monotonic deadlines, add thread names and fix terminal thread teardown, scheduler and APC prepare/commit races, make advisory file locks queryable and preserve split ranges and add mutable file append state, add shared-memory pipes with kernel-assisted wait/wake, introduce capability-scoped input and display managers, split surface map rights into read/write, add explicit unmap and replace present with commit/generation/damage tracking while keeping physical presentation under the display manager, decouple native exception classes from Win32 exception numbers and translate them in kernel32, add opaque process startup data, bump the resource protocol to v3 with namespace directories, symlinks and enumeration and service control to v2 with generic READY handle exports, add the new POSIX errno/status surface and rebuild fds around posixsrv-owned shared open descriptions, descriptor-local flags, exact inheritance snapshots, dup/fcntl/record locks and shared-ring pipes, add waitpid, POSIX credentials/groups/sessions/passwd/group lookups and move sockets onto stable open descriptions, port the shells and apps to the new console/input services and surface commit API, teach init to load services.ini and start/supervise RSSRV, DWM and generic services under restricted capabilities while publishing their endpoints through RSSRV, split RSSRV into namespace, volume, display, session, input, console and resource components and make /SystemRoot a real symlink to the independently published system volume, shift the syscall table again, expand lock/resource/surface/POSIX/service/thread smoke coverage, make docs scream ASK QUESTIONS and DISCUSS at LLMs, replace MIT No Attribution with WTFPL+.
2026-09-16 10:33:20 +02:00

263 lines
9.4 KiB
C

// User-mode smoke test for POSIX descriptor and open-description semantics.
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <poll.h>
#include <spawn.h>
#include <sys/wait.h>
#include <ntlite/posix_extensions.h>
// Writes one NUL-terminated diagnostic to stdout.
static void print(const char* text) {
(void)write(1, text, strlen(text));
}
// Terminates the smoke test with one diagnostic.
static void fail(const char* message) {
print("posix_fd_smoke: ");
print(message);
print("\n");
exit(1);
}
#define INHERIT_FILE_FD 10
#define INHERIT_PIPE_A_READ 11
#define INHERIT_PIPE_A_WRITE 12
#define INHERIT_CLOEXEC_FD 13
#define INHERIT_PIPE_B_READ 14
#define INHERIT_PIPE_B_WRITE 15
// Returns whether this invocation is the descriptor-inheritance child.
static int is_inheritance_child(void) {
const char* command = posix_get_command_line();
return command && strstr(command, "--inherit-child") != NULL;
}
// Runs the receiving side of the cross-process descriptor inheritance contract.
static int run_inheritance_child(void) {
char bytes[3] = {0, 0, 0};
if (read(INHERIT_FILE_FD, bytes, 2) != 2 || strcmp(bytes, "cd") != 0)
fail("inherited shared file offset failed in child");
errno = 0;
if (fcntl(INHERIT_CLOEXEC_FD, F_GETFD) != -1 || errno != EBADF)
fail("FD_CLOEXEC descriptor survived spawn inheritance");
if ((fcntl(INHERIT_PIPE_A_READ, F_GETFL) & O_NONBLOCK) == 0)
fail("inherited pipe status flags were not shared");
if (fcntl(INHERIT_FILE_FD, F_SETFL, O_APPEND) != 0)
fail("child F_SETFL failed");
if (write(INHERIT_PIPE_A_WRITE, "R", 1) != 1)
fail("child ready signal failed");
char byte = 0;
if (read(INHERIT_PIPE_B_READ, &byte, 1) != 1 || byte != 'x')
fail("cross-process pipe read failed");
if (close(INHERIT_PIPE_B_READ) != 0)
fail("child read endpoint close failed");
if (write(INHERIT_PIPE_A_WRITE, "C", 1) != 1)
fail("child close signal failed");
if (close(INHERIT_PIPE_A_WRITE) != 0)
fail("child write endpoint close failed");
return 0;
}
// Moves one descriptor to an exact number and closes the original alias.
static void move_fd(int source, int target) {
if (source < 0 || dup2(source, target) != target)
fail("inheritance dup2 setup failed");
if (source != target && close(source) != 0)
fail("inheritance source close failed");
}
// Waits for and consumes one byte from the inherited control pipe.
static char wait_control_byte(void) {
struct pollfd descriptor;
descriptor.fd = INHERIT_PIPE_A_READ;
descriptor.events = POLLIN | POLLHUP;
descriptor.revents = 0;
if (poll(&descriptor, 1, 5000) <= 0)
fail("inheritance control poll timed out");
char value = 0;
if (read(INHERIT_PIPE_A_READ, &value, 1) != 1)
fail("inheritance control read failed");
return value;
}
// Proves open-description sharing across two distinct native processes.
static void run_cross_process_inheritance(void) {
const char* path = "posix_fd_inherit.tmp";
(void)unlink(path);
int file = open(path, O_CREAT | O_TRUNC | O_RDWR);
if (file < 0 || write(file, "abcdef", 6) != 6 || lseek(file, 0, SEEK_SET) != 0)
fail("inheritance file setup failed");
char prefix[3] = {0, 0, 0};
if (read(file, prefix, 2) != 2 || strcmp(prefix, "ab") != 0)
fail("inheritance initial offset setup failed");
move_fd(file, INHERIT_FILE_FD);
if (dup2(INHERIT_FILE_FD, INHERIT_CLOEXEC_FD) != INHERIT_CLOEXEC_FD ||
fcntl(INHERIT_CLOEXEC_FD, F_SETFD, FD_CLOEXEC) != 0)
fail("inheritance CLOEXEC setup failed");
int pipeA[2];
int pipeB[2];
if (pipe(pipeA) != 0 || pipe(pipeB) != 0)
fail("inheritance pipe setup failed");
move_fd(pipeA[0], INHERIT_PIPE_A_READ);
move_fd(pipeA[1], INHERIT_PIPE_A_WRITE);
move_fd(pipeB[0], INHERIT_PIPE_B_READ);
move_fd(pipeB[1], INHERIT_PIPE_B_WRITE);
if (fcntl(INHERIT_PIPE_A_READ, F_SETFL, O_NONBLOCK) != 0)
fail("inheritance nonblock setup failed");
char self[512];
const char* command = posix_get_command_line();
size_t length = 0;
while (command && command[length] && command[length] != ' ' && command[length] != '\t' &&
length + 1 < sizeof(self)) {
self[length] = command[length];
++length;
}
self[length] = '\0';
if (length == 0 || (command[length] && command[length] != ' ' && command[length] != '\t'))
fail("could not resolve self path");
char* childArgv[] = { self, "--inherit-child", NULL };
pid_t child = 0;
if (posix_spawn(&child, self, NULL, NULL, childArgv, NULL) != 0)
fail("inheritance child spawn failed");
if (close(INHERIT_PIPE_A_WRITE) != 0 || close(INHERIT_PIPE_B_READ) != 0)
fail("parent endpoint close failed");
if (wait_control_byte() != 'R')
fail("unexpected child ready signal");
if ((fcntl(INHERIT_FILE_FD, F_GETFL) & O_APPEND) == 0)
fail("child F_SETFL was not visible in parent");
if (fcntl(INHERIT_CLOEXEC_FD, F_GETFD) != FD_CLOEXEC)
fail("parent descriptor-local CLOEXEC changed");
char suffix[3] = {0, 0, 0};
if (read(INHERIT_FILE_FD, suffix, 2) != 2 || strcmp(suffix, "ef") != 0)
fail("child did not advance shared native file offset");
if (write(INHERIT_PIPE_B_WRITE, "x", 1) != 1)
fail("write while inherited reader alive failed");
if (wait_control_byte() != 'C')
fail("unexpected child close signal");
errno = 0;
if (write(INHERIT_PIPE_B_WRITE, "y", 1) != -1 || errno != EPIPE)
fail("final cross-process reader close did not produce EPIPE");
int childStatus = 0;
if (waitpid(child, &childStatus, 0) != child || childStatus != 0)
fail("inheritance child failed");
char eof = 0;
if (read(INHERIT_PIPE_A_READ, &eof, 1) != 0)
fail("final cross-process writer close did not produce EOF");
if (close(INHERIT_FILE_FD) != 0 || close(INHERIT_CLOEXEC_FD) != 0 ||
close(INHERIT_PIPE_A_READ) != 0 || close(INHERIT_PIPE_B_WRITE) != 0)
fail("inheritance cleanup close failed");
if (unlink(path) != 0)
fail("inheritance cleanup unlink failed");
}
// Runs descriptor duplication and shared-open-description tests.
int main(void) {
if (is_inheritance_child())
return run_inheritance_child();
const char* path = "posix_fd_smoke.tmp";
(void)unlink(path);
int fd = open(path, O_CREAT | O_TRUNC | O_RDWR);
if (fd < 0)
fail("open failed");
if (write(fd, "abcdef", 6) != 6)
fail("write failed");
if (lseek(fd, 0, SEEK_SET) != 0)
fail("initial seek failed");
int duplicate = dup(fd);
if (duplicate < 0 || duplicate == fd)
fail("dup failed");
char bytes[3] = {0, 0, 0};
if (read(duplicate, bytes, 2) != 2 || strcmp(bytes, "ab") != 0)
fail("duplicate read failed");
memset(bytes, 0, sizeof(bytes));
if (read(fd, bytes, 2) != 2 || strcmp(bytes, "cd") != 0)
fail("shared file offset failed");
if (fcntl(duplicate, F_GETFD) != 0)
fail("new duplicate inherited descriptor flags");
if (fcntl(duplicate, F_SETFD, FD_CLOEXEC) != 0)
fail("F_SETFD failed");
if (fcntl(duplicate, F_GETFD) != FD_CLOEXEC)
fail("F_GETFD failed");
if (fcntl(fd, F_GETFD) != 0)
fail("descriptor flags were shared");
int duplicate20 = dup2(fd, 20);
if (duplicate20 != 20)
fail("dup2 failed");
if ((fcntl(duplicate20, F_GETFL) & O_ACCMODE) != O_RDWR)
fail("F_GETFL lost access mode");
int duplicate30 = fcntl(fd, F_DUPFD, 30);
if (duplicate30 < 30)
fail("F_DUPFD failed");
if (close(fd) != 0)
fail("close original failed");
memset(bytes, 0, sizeof(bytes));
if (read(duplicate, bytes, 2) != 2 || strcmp(bytes, "ef") != 0)
fail("duplicate did not retain open description");
if (fcntl(duplicate, F_SETFL, O_APPEND | O_NONBLOCK) != 0)
fail("F_SETFL failed");
int sharedFlags = fcntl(duplicate20, F_GETFL);
if ((sharedFlags & (O_APPEND | O_NONBLOCK)) != (O_APPEND | O_NONBLOCK))
fail("F_SETFL status was not shared");
if (lseek(duplicate, 0, SEEK_SET) != 0)
fail("append setup seek failed");
if (write(duplicate20, "Z", 1) != 1)
fail("append write failed");
if (lseek(duplicate, 6, SEEK_SET) != 6)
fail("append verify seek failed");
char appended = 0;
if (read(duplicate, &appended, 1) != 1 || appended != 'Z')
fail("O_APPEND did not append");
if (fcntl(duplicate, F_SETFL, 0) != 0 ||
(fcntl(duplicate30, F_GETFL) & (O_APPEND | O_NONBLOCK)) != 0)
fail("F_SETFL clear was not shared");
struct flock lock;
memset(&lock, 0, sizeof(lock));
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 4;
if (fcntl(duplicate, F_SETLK, &lock) != 0)
fail("F_SETLK failed");
struct flock query = lock;
if (fcntl(duplicate20, F_GETLK, &query) != 0 || query.l_type != F_UNLCK)
fail("F_GETLK reported this process's own lock");
lock.l_type = F_UNLCK;
if (fcntl(duplicate30, F_SETLK, &lock) != 0)
fail("fcntl unlock failed");
if (close(duplicate) != 0 || close(duplicate20) != 0 || close(duplicate30) != 0)
fail("duplicate close failed");
if (unlink(path) != 0)
fail("unlink failed");
run_cross_process_inheritance();
print("posix_fd_smoke: PASS\n");
return 0;
}