// User-mode smoke test for POSIX descriptor and open-description semantics. #include #include #include #include #include #include #include #include #include #include #include // 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); } // Prints one decimal integer without depending on stdio. static void print_int(int value) { char buffer[16]; unsigned int magnitude = value < 0 ? (unsigned int)(-(value + 1)) + 1u : (unsigned int)value; size_t count = 0; if (value < 0) print("-"); do { buffer[count++] = (char)('0' + magnitude % 10u); magnitude /= 10u; } while (magnitude && count < sizeof(buffer)); while (count) { char c[2] = { buffer[--count], '\0' }; print(c); } } // Terminates the smoke test with one POSIX error value. static void fail_error(const char* message, int error) { print("posix_fd_smoke: "); print(message); print(" error="); print_int(error); 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 bool 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; int spawnError = posix_spawn(&child, self, NULL, NULL, childArgv, NULL); if (spawnError != 0) fail_error("inheritance child spawn failed", spawnError); 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"); sighandler_t previousPipe = signal(SIGPIPE, SIG_IGN); if (previousPipe == SIG_ERR) fail("ignore inherited SIGPIPE failed"); errno = 0; if (write(INHERIT_PIPE_B_WRITE, "y", 1) != -1 || errno != EPIPE) fail("final cross-process reader close did not produce EPIPE"); if (signal(SIGPIPE, previousPipe) == SIG_ERR) fail("restore inherited SIGPIPE failed"); 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; }