Changeset View
Changeset View
Standalone View
Standalone View
head/lib/libc/gen/posix_spawn.c
Show All 24 Lines | |||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||||
* SUCH DAMAGE. | * SUCH DAMAGE. | ||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include "namespace.h" | #include "namespace.h" | ||||
#include <sys/param.h> | |||||
#include <sys/queue.h> | #include <sys/queue.h> | ||||
#include <sys/wait.h> | #include <sys/wait.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <fcntl.h> | #include <fcntl.h> | ||||
#include <sched.h> | #include <sched.h> | ||||
#include <spawn.h> | #include <spawn.h> | ||||
#include <signal.h> | #include <signal.h> | ||||
▲ Show 20 Lines • Show All 158 Lines • ▼ Show 20 Lines | struct posix_spawn_args { | ||||
const posix_spawn_file_actions_t *fa; | const posix_spawn_file_actions_t *fa; | ||||
const posix_spawnattr_t *sa; | const posix_spawnattr_t *sa; | ||||
char * const * argv; | char * const * argv; | ||||
char * const * envp; | char * const * envp; | ||||
int use_env_path; | int use_env_path; | ||||
volatile int error; | volatile int error; | ||||
}; | }; | ||||
#define PSPAWN_STACK_ALIGNMENT 16 | |||||
#define PSPAWN_STACK_ALIGNBYTES (PSPAWN_STACK_ALIGNMENT - 1) | |||||
#define PSPAWN_STACK_ALIGN(sz) \ | |||||
(((sz) + PSPAWN_STACK_ALIGNBYTES) & ~PSPAWN_STACK_ALIGNBYTES) | |||||
#if defined(__i386__) || defined(__amd64__) | #if defined(__i386__) || defined(__amd64__) | ||||
/* | |||||
* Below we'll assume that _RFORK_THREAD_STACK_SIZE is appropriately aligned for | |||||
* the posix_spawn() case where we do not end up calling _execvpe and won't ever | |||||
* try to allocate space on the stack for argv[]. | |||||
*/ | |||||
#define _RFORK_THREAD_STACK_SIZE 4096 | #define _RFORK_THREAD_STACK_SIZE 4096 | ||||
_Static_assert((_RFORK_THREAD_STACK_SIZE % PSPAWN_STACK_ALIGNMENT) == 0, | |||||
"Inappropriate stack size alignment"); | |||||
#endif | #endif | ||||
static int | static int | ||||
_posix_spawn_thr(void *data) | _posix_spawn_thr(void *data) | ||||
{ | { | ||||
struct posix_spawn_args *psa; | struct posix_spawn_args *psa; | ||||
char * const *envp; | char * const *envp; | ||||
Show All 24 Lines | do_posix_spawn(pid_t *pid, const char *path, | ||||
const posix_spawn_file_actions_t *fa, | const posix_spawn_file_actions_t *fa, | ||||
const posix_spawnattr_t *sa, | const posix_spawnattr_t *sa, | ||||
char * const argv[], char * const envp[], int use_env_path) | char * const argv[], char * const envp[], int use_env_path) | ||||
{ | { | ||||
struct posix_spawn_args psa; | struct posix_spawn_args psa; | ||||
pid_t p; | pid_t p; | ||||
#ifdef _RFORK_THREAD_STACK_SIZE | #ifdef _RFORK_THREAD_STACK_SIZE | ||||
char *stack; | char *stack; | ||||
size_t cnt, stacksz; | |||||
stack = malloc(_RFORK_THREAD_STACK_SIZE); | stacksz = _RFORK_THREAD_STACK_SIZE; | ||||
if (use_env_path) { | |||||
/* | |||||
* We need to make sure we have enough room on the stack for the | |||||
* potential alloca() in execvPe if it gets kicked back an | |||||
* ENOEXEC from execve(2), plus the original buffer we gave | |||||
* ourselves; this protects us in the event that the caller | |||||
* intentionally or inadvertently supplies enough arguments to | |||||
* make us blow past the stack we've allocated from it. | |||||
*/ | |||||
for (cnt = 0; argv[cnt] != NULL; ++cnt) | |||||
; | |||||
stacksz += MAX(3, cnt + 2) * sizeof(char *); | |||||
stacksz = PSPAWN_STACK_ALIGN(stacksz); | |||||
} | |||||
stack = aligned_alloc(PSPAWN_STACK_ALIGNMENT, stacksz); | |||||
if (stack == NULL) | if (stack == NULL) | ||||
return (ENOMEM); | return (ENOMEM); | ||||
#endif | #endif | ||||
psa.path = path; | psa.path = path; | ||||
psa.fa = fa; | psa.fa = fa; | ||||
psa.sa = sa; | psa.sa = sa; | ||||
psa.argv = argv; | psa.argv = argv; | ||||
psa.envp = envp; | psa.envp = envp; | ||||
Show All 9 Lines | #endif | ||||
*/ | */ | ||||
#ifdef _RFORK_THREAD_STACK_SIZE | #ifdef _RFORK_THREAD_STACK_SIZE | ||||
/* | /* | ||||
* x86 stores the return address on the stack, so rfork(2) cannot work | * x86 stores the return address on the stack, so rfork(2) cannot work | ||||
* as-is because the child would clobber the return address om the | * as-is because the child would clobber the return address om the | ||||
* parent. Because of this, we must use rfork_thread instead while | * parent. Because of this, we must use rfork_thread instead while | ||||
* almost every other arch stores the return address in a register. | * almost every other arch stores the return address in a register. | ||||
*/ | */ | ||||
p = rfork_thread(RFSPAWN, stack + _RFORK_THREAD_STACK_SIZE, | p = rfork_thread(RFSPAWN, stack + stacksz, _posix_spawn_thr, &psa); | ||||
_posix_spawn_thr, &psa); | |||||
free(stack); | free(stack); | ||||
#else | #else | ||||
p = rfork(RFSPAWN); | p = rfork(RFSPAWN); | ||||
if (p == 0) | if (p == 0) | ||||
/* _posix_spawn_thr does not return */ | /* _posix_spawn_thr does not return */ | ||||
_posix_spawn_thr(&psa); | _posix_spawn_thr(&psa); | ||||
#endif | #endif | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 270 Lines • Show Last 20 Lines |