tuxreaperd: split into libc and freestanding AMD64/ARM64 asm implementations for 0.3
This commit is contained in:
parent
d31ab6af07
commit
97abfa249f
7 changed files with 519 additions and 9 deletions
|
|
@ -99,5 +99,5 @@ if(BUILD_TESTING)
|
|||
add_test(NAME tuxreaperd-zombie-tests
|
||||
COMMAND sh ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_tuxreaperd.sh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/tuxreaperd
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tuxreaperd.c)
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tuxreaperdgnu.c)
|
||||
endif()
|
||||
|
|
|
|||
10
DEVLOG.md
10
DEVLOG.md
|
|
@ -6,10 +6,12 @@ This release introduces `tuxreaperd`, a micro init system for containers.
|
|||
|
||||
### Micro init
|
||||
|
||||
- Added `tuxreaperd.c`, a small C daemon used as PID 1 inside containers created by tux-dock.
|
||||
- Runs as a subreaper (`PR_SET_CHILD_SUBREAPER`) with a SIGCHLD handler that reaps every reparented/terminated descendant, so orphaned processes never accumulate as zombies.
|
||||
- Forwards SIGTERM/SIGINT/SIGHUP to the primary workload and propagates its exit status (128 + signal for signal deaths).
|
||||
- `compile.sh` statically builds it (`gcc -O2 -static -Wall -Wextra tuxreaperd.c -o build/tuxreaperd`) alongside the rest of the tree.
|
||||
- Split the reaper into two implementations:
|
||||
- `tuxreaperdgnu.c`: the original standard POSIX/libc daemon used as PID 1 inside containers created by tux-dock.
|
||||
- `tuxreaperdasm.c`: a new freestanding `-nostdlib` syscall engine for `x86_64` and `aarch64` with a tiny static footprint.
|
||||
- Both run as subreapers (`PR_SET_CHILD_SUBREAPER`) with a SIGCHLD handler that reaps every reparented/terminated descendant, so orphaned processes never accumulate as zombies.
|
||||
- Both forward SIGTERM/SIGINT/SIGHUP to the primary workload and propagate its exit status (128 + signal for signal deaths).
|
||||
- `compile.sh` detects the host architecture and builds the freestanding implementation when possible, falling back to `tuxreaperdgnu.c` on failure or unsupported hosts.
|
||||
- `DockerManager::createContainer` bind-mounts `tuxreaperd` into the container as PID 1 and resolves the binary next to the `tux-dock` executable when it is not in the current directory.
|
||||
|
||||
### Tests
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ sudo ./build/tux-dock
|
|||
./compile.sh --web-test-view 9000
|
||||
```
|
||||
|
||||
`compile.sh` also statically builds the `tuxreaperd` micro init (`gcc -O2 -static -Wall -Wextra tuxreaperd.c -o build/tuxreaperd`) so containers can be created with it as PID 1.
|
||||
`compile.sh` builds the `tuxreaperd` micro init before the main project. On supported hosts (`x86_64`/`amd64`/`aarch64`/`arm64`) it first tries the freestanding syscall implementation in `tuxreaperdasm.c`; on other architectures, or if the freestanding build fails, it falls back to the standard POSIX implementation in `tuxreaperdgnu.c`.
|
||||
|
||||
The web report is generated under `/tmp` and includes exact CTest output, test summaries, Docker integration output, a text rendition of the TUI flow, and the tuxreaperd zombie-reaping results. It requires `nc`, `netcat`, or Nmap's `ncat`; press `Ctrl-C` to stop the server. The default port is `8095`; pass a port after `--web-test-view` to override it. `--web-test-view --no-test` is invalid. Normal test runs include a Docker integration test using `debian:forky`, so Docker must be available. On systems with 1 GB or less of available memory, the script automatically uses a smaller build configuration and a single build job.
|
||||
|
||||
|
|
|
|||
23
compile.sh
23
compile.sh
|
|
@ -78,7 +78,28 @@ command -v gcc >/dev/null 2>&1 || {
|
|||
printf '%s\n' "gcc is required to build tuxreaperd" >&2
|
||||
exit 1
|
||||
}
|
||||
gcc -O2 -static -Wall -Wextra tuxreaperd.c -o build/tuxreaperd
|
||||
|
||||
host_arch=$(uname -m)
|
||||
asm_archs='x86_64 amd64 aarch64 arm64'
|
||||
build_tuxreaperd() {
|
||||
case " $asm_archs " in
|
||||
*" $host_arch "*)
|
||||
printf '%s\n' "[compile] Building freestanding tuxreaperd for $host_arch"
|
||||
if gcc -nostdlib -static -fno-stack-protector -fno-asynchronous-unwind-tables \
|
||||
-fno-builtin -O2 -s -Wl,--build-id=none -Wl,-z,noseparate-code \
|
||||
-Wall -Wextra tuxreaperdasm.c -o build/tuxreaperd 2>/tmp/tuxreaperd-asm-build.log; then
|
||||
printf '%s\n' "[compile] Freestanding tuxreaperd built successfully"
|
||||
return 0
|
||||
fi
|
||||
printf '%s\n' "[compile] Freestanding build failed, falling back to libc implementation" >&2
|
||||
cat /tmp/tuxreaperd-asm-build.log >&2
|
||||
;;
|
||||
esac
|
||||
|
||||
printf '%s\n' "[compile] Building standard tuxreaperd for $host_arch"
|
||||
gcc -O2 -static -Wall -Wextra tuxreaperdgnu.c -o build/tuxreaperd
|
||||
}
|
||||
build_tuxreaperd
|
||||
|
||||
CMAKE_BUILD_PARALLEL_LEVEL="$build_jobs" cmake --build build
|
||||
|
||||
|
|
|
|||
2
main.cpp
2
main.cpp
|
|
@ -699,7 +699,7 @@ void TuxDockApp::ActionExecDetachedCommand() {
|
|||
}
|
||||
|
||||
void TuxDockApp::ActionAbout() {
|
||||
OpenMessage("About Tux-Dock", "Tux-Dock 0.2-beta | Created by markmental");
|
||||
OpenMessage("About Tux-Dock", "Tux-Dock 0.3-beta | Created by markmental");
|
||||
}
|
||||
|
||||
void TuxDockApp::ExecuteSelectedAction() {
|
||||
|
|
|
|||
488
tuxreaperdasm.c
Normal file
488
tuxreaperdasm.c
Normal file
|
|
@ -0,0 +1,488 @@
|
|||
struct k_sigaction {
|
||||
void (*handler)(int);
|
||||
unsigned long flags;
|
||||
void (*restorer)(void);
|
||||
unsigned long mask;
|
||||
};
|
||||
|
||||
#if defined(__x86_64__)
|
||||
|
||||
static inline long sys_write(int fd, const void *buf, long n) {
|
||||
long ret;
|
||||
__asm__ volatile (
|
||||
"syscall"
|
||||
: "=a"(ret)
|
||||
: "a"(1), "D"((long)fd), "S"(buf), "d"(n)
|
||||
: "rcx", "r11", "memory"
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline long sys_exit_group(int status) {
|
||||
long ret;
|
||||
__asm__ volatile (
|
||||
"syscall"
|
||||
: "=a"(ret)
|
||||
: "a"(231), "D"((long)status)
|
||||
: "rcx", "r11", "memory"
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline long sys_fork(void) {
|
||||
long ret;
|
||||
__asm__ volatile (
|
||||
"syscall"
|
||||
: "=a"(ret)
|
||||
: "a"(57)
|
||||
: "rcx", "r11", "memory"
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline long sys_execve(const char *path, char *const argv[], char *const envp[]) {
|
||||
long ret;
|
||||
__asm__ volatile (
|
||||
"syscall"
|
||||
: "=a"(ret)
|
||||
: "a"(59), "D"(path), "S"(argv), "d"(envp)
|
||||
: "rcx", "r11", "memory"
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline long sys_wait4(long pid, int *status, int options, void *rusage) {
|
||||
long ret;
|
||||
register long r10 __asm__("r10") = (long)rusage;
|
||||
__asm__ volatile (
|
||||
"syscall"
|
||||
: "=a"(ret)
|
||||
: "a"(61), "D"(pid), "S"(status), "d"(options), "r"(r10)
|
||||
: "rcx", "r11", "memory"
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline long sys_kill(long pid, int sig) {
|
||||
long ret;
|
||||
__asm__ volatile (
|
||||
"syscall"
|
||||
: "=a"(ret)
|
||||
: "a"(62), "D"(pid), "S"((long)sig)
|
||||
: "rcx", "r11", "memory"
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
|
||||
unsigned long arg4, unsigned long arg5) {
|
||||
long ret;
|
||||
register long r10 __asm__("r10") = (long)arg4;
|
||||
register long r8 __asm__("r8") = (long)arg5;
|
||||
__asm__ volatile (
|
||||
"syscall"
|
||||
: "=a"(ret)
|
||||
: "a"(157), "D"((long)option), "S"(arg2), "d"(arg3), "r"(r10), "r"(r8)
|
||||
: "rcx", "r11", "memory"
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline long sys_rt_sigaction(int sig, const struct k_sigaction *act,
|
||||
struct k_sigaction *oldact, unsigned long sigsetsize) {
|
||||
long ret;
|
||||
register long r10 __asm__("r10") = (long)sigsetsize;
|
||||
__asm__ volatile (
|
||||
"syscall"
|
||||
: "=a"(ret)
|
||||
: "a"(13), "D"((long)sig), "S"(act), "d"(oldact), "r"(r10)
|
||||
: "rcx", "r11", "memory"
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline long sys_rt_sigprocmask(int how, const unsigned long *set,
|
||||
unsigned long *oldset, unsigned long sigsetsize) {
|
||||
long ret;
|
||||
register long r10 __asm__("r10") = (long)sigsetsize;
|
||||
__asm__ volatile (
|
||||
"syscall"
|
||||
: "=a"(ret)
|
||||
: "a"(14), "D"((long)how), "S"(set), "d"(oldset), "r"(r10)
|
||||
: "rcx", "r11", "memory"
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline long sys_rt_sigsuspend(const unsigned long *mask, unsigned long sigsetsize) {
|
||||
long ret;
|
||||
__asm__ volatile (
|
||||
"syscall"
|
||||
: "=a"(ret)
|
||||
: "a"(130), "D"(mask), "S"(sigsetsize)
|
||||
: "rcx", "r11", "memory"
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
__asm__(
|
||||
".text\n"
|
||||
".globl restore_rt\n"
|
||||
"restore_rt:\n"
|
||||
" movq $15, %rax\n"
|
||||
" syscall\n"
|
||||
);
|
||||
|
||||
__asm__(
|
||||
".text\n"
|
||||
".globl _start\n"
|
||||
"_start:\n"
|
||||
" xorl %ebp, %ebp\n"
|
||||
" movq (%rsp), %rdi\n" /* argc */
|
||||
" leaq 8(%rsp), %rsi\n" /* argv */
|
||||
" movq %rsi, %rdx\n" /* scan pointer = argv */
|
||||
"1:\n"
|
||||
" addq $8, %rdx\n"
|
||||
" cmpq $0, (%rdx)\n"
|
||||
" jne 1b\n"
|
||||
" addq $8, %rdx\n" /* envp */
|
||||
" andq $-16, %rsp\n" /* align stack */
|
||||
" call main\n"
|
||||
" movq %rax, %rdi\n"
|
||||
" movq $231, %rax\n" /* exit_group */
|
||||
" syscall\n"
|
||||
);
|
||||
|
||||
#elif defined(__aarch64__)
|
||||
|
||||
static inline long sys_write(int fd, const void *buf, long n) {
|
||||
register long x8 __asm__("x8") = 64;
|
||||
register long x0 __asm__("x0") = fd;
|
||||
register long x1 __asm__("x1") = (long)buf;
|
||||
register long x2 __asm__("x2") = n;
|
||||
__asm__ volatile (
|
||||
"svc #0"
|
||||
: "+r"(x0)
|
||||
: "r"(x8), "r"(x1), "r"(x2)
|
||||
: "memory", "cc"
|
||||
);
|
||||
return x0;
|
||||
}
|
||||
|
||||
static inline long sys_exit_group(int status) {
|
||||
register long x8 __asm__("x8") = 94;
|
||||
register long x0 __asm__("x0") = status;
|
||||
__asm__ volatile (
|
||||
"svc #0"
|
||||
: "+r"(x0)
|
||||
: "r"(x8)
|
||||
: "memory", "cc"
|
||||
);
|
||||
return x0;
|
||||
}
|
||||
|
||||
static inline long sys_fork(void) {
|
||||
/* AArch64 has no legacy fork syscall; clone(SIGCHLD, 0) gives fork semantics. */
|
||||
register long x8 __asm__("x8") = 220; /* __NR_clone */
|
||||
register long x0 __asm__("x0") = 17; /* SIGCHLD */
|
||||
register long x1 __asm__("x1") = 0; /* newsp = 0 */
|
||||
__asm__ volatile (
|
||||
"svc #0"
|
||||
: "+r"(x0)
|
||||
: "r"(x8), "r"(x1)
|
||||
: "memory", "cc"
|
||||
);
|
||||
return x0;
|
||||
}
|
||||
|
||||
static inline long sys_execve(const char *path, char *const argv[], char *const envp[]) {
|
||||
register long x8 __asm__("x8") = 221;
|
||||
register long x0 __asm__("x0") = (long)path;
|
||||
register long x1 __asm__("x1") = (long)argv;
|
||||
register long x2 __asm__("x2") = (long)envp;
|
||||
__asm__ volatile (
|
||||
"svc #0"
|
||||
: "+r"(x0)
|
||||
: "r"(x8), "r"(x1), "r"(x2)
|
||||
: "memory", "cc"
|
||||
);
|
||||
return x0;
|
||||
}
|
||||
|
||||
static inline long sys_wait4(long pid, int *status, int options, void *rusage) {
|
||||
register long x8 __asm__("x8") = 260;
|
||||
register long x0 __asm__("x0") = pid;
|
||||
register long x1 __asm__("x1") = (long)status;
|
||||
register long x2 __asm__("x2") = options;
|
||||
register long x3 __asm__("x3") = (long)rusage;
|
||||
__asm__ volatile (
|
||||
"svc #0"
|
||||
: "+r"(x0)
|
||||
: "r"(x8), "r"(x1), "r"(x2), "r"(x3)
|
||||
: "memory", "cc"
|
||||
);
|
||||
return x0;
|
||||
}
|
||||
|
||||
static inline long sys_kill(long pid, int sig) {
|
||||
register long x8 __asm__("x8") = 129;
|
||||
register long x0 __asm__("x0") = pid;
|
||||
register long x1 __asm__("x1") = sig;
|
||||
__asm__ volatile (
|
||||
"svc #0"
|
||||
: "+r"(x0)
|
||||
: "r"(x8), "r"(x1)
|
||||
: "memory", "cc"
|
||||
);
|
||||
return x0;
|
||||
}
|
||||
|
||||
static inline long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
|
||||
unsigned long arg4, unsigned long arg5) {
|
||||
register long x8 __asm__("x8") = 167;
|
||||
register long x0 __asm__("x0") = option;
|
||||
register long x1 __asm__("x1") = arg2;
|
||||
register long x2 __asm__("x2") = arg3;
|
||||
register long x3 __asm__("x3") = arg4;
|
||||
register long x4 __asm__("x4") = arg5;
|
||||
__asm__ volatile (
|
||||
"svc #0"
|
||||
: "+r"(x0)
|
||||
: "r"(x8), "r"(x1), "r"(x2), "r"(x3), "r"(x4)
|
||||
: "memory", "cc"
|
||||
);
|
||||
return x0;
|
||||
}
|
||||
|
||||
static inline long sys_rt_sigaction(int sig, const struct k_sigaction *act,
|
||||
struct k_sigaction *oldact, unsigned long sigsetsize) {
|
||||
register long x8 __asm__("x8") = 134;
|
||||
register long x0 __asm__("x0") = sig;
|
||||
register long x1 __asm__("x1") = (long)act;
|
||||
register long x2 __asm__("x2") = (long)oldact;
|
||||
register long x3 __asm__("x3") = sigsetsize;
|
||||
__asm__ volatile (
|
||||
"svc #0"
|
||||
: "+r"(x0)
|
||||
: "r"(x8), "r"(x1), "r"(x2), "r"(x3)
|
||||
: "memory", "cc"
|
||||
);
|
||||
return x0;
|
||||
}
|
||||
|
||||
static inline long sys_rt_sigprocmask(int how, const unsigned long *set,
|
||||
unsigned long *oldset, unsigned long sigsetsize) {
|
||||
register long x8 __asm__("x8") = 135;
|
||||
register long x0 __asm__("x0") = how;
|
||||
register long x1 __asm__("x1") = (long)set;
|
||||
register long x2 __asm__("x2") = (long)oldset;
|
||||
register long x3 __asm__("x3") = sigsetsize;
|
||||
__asm__ volatile (
|
||||
"svc #0"
|
||||
: "+r"(x0)
|
||||
: "r"(x8), "r"(x1), "r"(x2), "r"(x3)
|
||||
: "memory", "cc"
|
||||
);
|
||||
return x0;
|
||||
}
|
||||
|
||||
static inline long sys_rt_sigsuspend(const unsigned long *mask, unsigned long sigsetsize) {
|
||||
register long x8 __asm__("x8") = 133;
|
||||
register long x0 __asm__("x0") = (long)mask;
|
||||
register long x1 __asm__("x1") = sigsetsize;
|
||||
__asm__ volatile (
|
||||
"svc #0"
|
||||
: "+r"(x0)
|
||||
: "r"(x8), "r"(x1)
|
||||
: "memory", "cc"
|
||||
);
|
||||
return x0;
|
||||
}
|
||||
|
||||
__asm__(
|
||||
".text\n"
|
||||
".globl restore_rt\n"
|
||||
"restore_rt:\n"
|
||||
" mov x8, #139\n"
|
||||
" svc #0\n"
|
||||
);
|
||||
|
||||
__asm__(
|
||||
".text\n"
|
||||
".globl _start\n"
|
||||
"_start:\n"
|
||||
" ldr x0, [sp]\n" /* argc */
|
||||
" add x1, sp, #8\n" /* argv */
|
||||
" mov x2, x1\n" /* scan pointer = argv */
|
||||
"1:\n"
|
||||
" ldr x3, [x2]\n"
|
||||
" add x2, x2, #8\n"
|
||||
" cbnz x3, 1b\n" /* x2 now points to envp */
|
||||
" mov x4, sp\n"
|
||||
" bic x4, x4, #15\n" /* align stack via scratch register */
|
||||
" mov sp, x4\n"
|
||||
" bl main\n"
|
||||
" mov x8, #94\n" /* exit_group */
|
||||
" svc #0\n"
|
||||
);
|
||||
|
||||
#else
|
||||
#error "tuxreaperdasm.c supports x86_64 and aarch64 only"
|
||||
#endif
|
||||
|
||||
static long my_strlen(const char *s) {
|
||||
long n = 0;
|
||||
while (s[n]) n++;
|
||||
return n;
|
||||
}
|
||||
|
||||
static int my_strncmp(const char *a, const char *b, long n) {
|
||||
for (long i = 0; i < n; i++) {
|
||||
unsigned char ca = a[i];
|
||||
unsigned char cb = b[i];
|
||||
if (ca != cb) return (int)ca - (int)cb;
|
||||
if (ca == 0) return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *my_strchr(const char *s, char c) {
|
||||
while (*s) {
|
||||
if (*s == c) return s;
|
||||
s++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void my_memcpy(char *dst, const char *src, long n) {
|
||||
for (long i = 0; i < n; i++) dst[i] = src[i];
|
||||
}
|
||||
|
||||
static const char *my_getenv(const char *name, char *const *envp) {
|
||||
long nlen = my_strlen(name);
|
||||
for (int i = 0; envp[i]; i++) {
|
||||
if (my_strncmp(envp[i], name, nlen) == 0 && envp[i][nlen] == '=') {
|
||||
return envp[i] + nlen + 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void my_execvp(const char *file, char *const argv[], char *const envp[]) {
|
||||
if (my_strchr(file, '/')) {
|
||||
sys_execve(file, argv, envp);
|
||||
return;
|
||||
}
|
||||
|
||||
const char *path = my_getenv("PATH", envp);
|
||||
if (!path) path = "/bin:/usr/bin";
|
||||
|
||||
long flen = my_strlen(file);
|
||||
const char *p = path;
|
||||
|
||||
while (*p) {
|
||||
const char *colon = my_strchr(p, ':');
|
||||
long dirlen = colon ? (colon - p) : my_strlen(p);
|
||||
char full[512];
|
||||
|
||||
if (dirlen + 1 + flen + 1 <= (long)sizeof(full)) {
|
||||
my_memcpy(full, p, dirlen);
|
||||
full[dirlen] = '/';
|
||||
my_memcpy(full + dirlen + 1, file, flen);
|
||||
full[dirlen + 1 + flen] = '\0';
|
||||
sys_execve(full, argv, envp);
|
||||
}
|
||||
|
||||
if (!colon) break;
|
||||
p = colon + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static volatile long g_main_child = 0;
|
||||
static volatile int g_child_exited = 0;
|
||||
static volatile int g_main_status = 0;
|
||||
|
||||
static void forward_sig(int sig) {
|
||||
if (g_main_child > 0) {
|
||||
sys_kill(g_main_child, sig);
|
||||
}
|
||||
}
|
||||
|
||||
static void sigchld_handler(int sig) {
|
||||
(void)sig;
|
||||
int status;
|
||||
long pid;
|
||||
|
||||
while ((pid = sys_wait4(-1, &status, 1 /* WNOHANG */, 0)) > 0) {
|
||||
if (pid == g_main_child) {
|
||||
g_child_exited = 1;
|
||||
g_main_status = status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define WIFEXITED(s) (((s) & 0x7f) == 0)
|
||||
#define WEXITSTATUS(s) (((s) >> 8) & 0xff)
|
||||
#define WIFSIGNALED(s) ((((s) & 0x7f) != 0) && (((s) & 0x7f) != 0x7f))
|
||||
#define WTERMSIG(s) ((s) & 0x7f)
|
||||
|
||||
void restore_rt(void);
|
||||
|
||||
int main(int argc, char **argv, char **envp) {
|
||||
if (argc < 2) {
|
||||
static const char usage[] = "Usage: tuxreaperd <command> [args...]\n";
|
||||
sys_write(2, usage, sizeof(usage) - 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (sys_prctl(36 /* PR_SET_CHILD_SUBREAPER */, 1, 0, 0, 0) < 0) {
|
||||
static const char err[] = "prctl(PR_SET_CHILD_SUBREAPER) failed\n";
|
||||
sys_write(2, err, sizeof(err) - 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct k_sigaction sa;
|
||||
sa.handler = sigchld_handler;
|
||||
sa.flags = 0x10000000 /* SA_RESTART */ | 1 /* SA_NOCLDSTOP */ | 0x04000000 /* SA_RESTORER */;
|
||||
sa.restorer = restore_rt;
|
||||
sa.mask = 0;
|
||||
sys_rt_sigaction(17 /* SIGCHLD */, &sa, 0, sizeof(sa.mask));
|
||||
|
||||
sa.handler = forward_sig;
|
||||
sa.flags = 0x10000000 /* SA_RESTART */ | 0x04000000 /* SA_RESTORER */;
|
||||
sa.restorer = restore_rt;
|
||||
sa.mask = 0;
|
||||
sys_rt_sigaction(15 /* SIGTERM */, &sa, 0, sizeof(sa.mask));
|
||||
sys_rt_sigaction(2 /* SIGINT */, &sa, 0, sizeof(sa.mask));
|
||||
sys_rt_sigaction(1 /* SIGHUP */, &sa, 0, sizeof(sa.mask));
|
||||
|
||||
unsigned long block_mask =
|
||||
(1UL << (17 - 1)) | (1UL << (15 - 1)) |
|
||||
(1UL << (2 - 1)) | (1UL << (1 - 1));
|
||||
unsigned long old_mask;
|
||||
sys_rt_sigprocmask(0 /* SIG_BLOCK */, &block_mask, &old_mask, sizeof(block_mask));
|
||||
|
||||
g_main_child = sys_fork();
|
||||
if (g_main_child == 0) {
|
||||
sys_rt_sigprocmask(2 /* SIG_SETMASK */, &old_mask, 0, sizeof(old_mask));
|
||||
my_execvp(argv[1], &argv[1], envp);
|
||||
static const char err[] = "execvp failed\n";
|
||||
sys_write(2, err, sizeof(err) - 1);
|
||||
sys_exit_group(127);
|
||||
}
|
||||
|
||||
while (!g_child_exited) {
|
||||
sys_rt_sigsuspend(&old_mask, sizeof(old_mask));
|
||||
}
|
||||
|
||||
int status;
|
||||
while (sys_wait4(-1, &status, 1 /* WNOHANG */, 0) > 0);
|
||||
|
||||
if (WIFEXITED(g_main_status)) {
|
||||
return WEXITSTATUS(g_main_status);
|
||||
} else if (WIFSIGNALED(g_main_status)) {
|
||||
return 128 + WTERMSIG(g_main_status);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -88,4 +88,3 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue