]>
Commit | Line | Data |
---|---|---|
13be2733 CB |
1 | #ifndef _GNU_SOURCE |
2 | #define _GNU_SOURCE 1 | |
3 | #endif | |
4 | #include <errno.h> | |
38e5c2db CB |
5 | #include <sched.h> |
6 | #include <signal.h> | |
13be2733 CB |
7 | #include <stdio.h> |
8 | #include <stdlib.h> | |
9 | #include <sys/syscall.h> | |
10 | #include <unistd.h> | |
11 | ||
12 | #include "config.h" | |
38e5c2db CB |
13 | #include "macro.h" |
14 | #include "raw_syscalls.h" | |
13be2733 CB |
15 | |
16 | int lxc_raw_execveat(int dirfd, const char *pathname, char *const argv[], | |
17 | char *const envp[], int flags) | |
18 | { | |
19 | #ifdef __NR_execveat | |
20 | syscall(__NR_execveat, dirfd, pathname, argv, envp, flags); | |
21 | #else | |
22 | errno = ENOSYS; | |
13be2733 | 23 | #endif |
e4767d47 | 24 | return -1; |
13be2733 | 25 | } |
38e5c2db CB |
26 | |
27 | /* | |
28 | * This is based on raw_clone in systemd but adapted to our needs. This uses | |
29 | * copy on write semantics and doesn't pass a stack. CLONE_VM is tricky and | |
30 | * doesn't really matter to us so disallow it. | |
31 | * | |
32 | * The nice thing about this is that we get fork() behavior. That is | |
33 | * lxc_raw_clone() returns 0 in the child and the child pid in the parent. | |
34 | */ | |
35 | pid_t lxc_raw_clone(unsigned long flags) | |
36 | { | |
38e5c2db | 37 | /* |
b6991178 | 38 | * These flags don't interest at all so we don't jump through any hoops |
38e5c2db CB |
39 | * of retrieving them and passing them to the kernel. |
40 | */ | |
41 | errno = EINVAL; | |
42 | if ((flags & (CLONE_VM | CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | | |
43 | CLONE_CHILD_CLEARTID | CLONE_SETTLS))) | |
44 | return -EINVAL; | |
45 | ||
46 | #if defined(__s390x__) || defined(__s390__) || defined(__CRIS__) | |
47 | /* On s390/s390x and cris the order of the first and second arguments | |
48 | * of the system call is reversed. | |
49 | */ | |
50 | return (int)syscall(__NR_clone, NULL, flags | SIGCHLD); | |
51 | #elif defined(__sparc__) && defined(__arch64__) | |
52 | { | |
53 | /* | |
54 | * sparc64 always returns the other process id in %o0, and a | |
55 | * boolean flag whether this is the child or the parent in %o1. | |
56 | * Inline assembly is needed to get the flag returned in %o1. | |
57 | */ | |
58 | int in_child; | |
59 | int child_pid; | |
60 | asm volatile("mov %2, %%g1\n\t" | |
61 | "mov %3, %%o0\n\t" | |
62 | "mov 0 , %%o1\n\t" | |
63 | "t 0x6d\n\t" | |
64 | "mov %%o1, %0\n\t" | |
65 | "mov %%o0, %1" | |
66 | : "=r"(in_child), "=r"(child_pid) | |
67 | : "i"(__NR_clone), "r"(flags | SIGCHLD) | |
68 | : "%o1", "%o0", "%g1"); | |
69 | ||
70 | if (in_child) | |
71 | return 0; | |
72 | else | |
73 | return child_pid; | |
74 | } | |
75 | #elif defined(__ia64__) | |
76 | /* On ia64 the stack and stack size are passed as separate arguments. */ | |
77 | return (int)syscall(__NR_clone, flags | SIGCHLD, NULL, prctl_arg(0)); | |
78 | #else | |
79 | return (int)syscall(__NR_clone, flags | SIGCHLD, NULL); | |
80 | #endif | |
81 | } | |
82 | ||
83 | pid_t lxc_raw_clone_cb(int (*fn)(void *), void *args, unsigned long flags) | |
84 | { | |
85 | pid_t pid; | |
86 | ||
87 | pid = lxc_raw_clone(flags); | |
88 | if (pid < 0) | |
89 | return -1; | |
90 | ||
91 | /* | |
92 | * exit() is not thread-safe and might mess with the parent's signal | |
93 | * handlers and other stuff when exec() fails. | |
94 | */ | |
95 | if (pid == 0) | |
96 | _exit(fn(args)); | |
97 | ||
98 | return pid; | |
99 | } |