1/*
2 * Copyright 2004-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6#include <image.h>
7
8#include <errno.h>
9#include <pthread.h>
10#include <stdlib.h>
11#include <string.h>
12#include <sys/wait.h>
13#include <unistd.h>
14
15#include <errno_private.h>
16#include <syscall_utils.h>
17
18
19extern "C" int
20system(const char *command)
21{
22	if (!command)
23		return 1;
24
25	const char *argv[] = { "/bin/sh", "-c", command, NULL };
26	int argc = 3;
27
28	thread_id thread = load_image(argc, argv, (const char **)environ);
29	if (thread < 0)
30		RETURN_AND_SET_ERRNO_TEST_CANCEL(thread);
31
32	// block SIGCHLD ...
33	sigset_t mask, oldMask;
34	sigemptyset(&mask);
35	sigaddset(&mask, SIGCHLD);
36	sigprocmask(SIG_BLOCK, &mask, &oldMask);
37
38	// and ignore SIGINT and SIGQUIT while waiting for completion
39	struct sigaction intSave, quitSave, sa;
40	memset(&sa, 0, sizeof(sa));
41	sigemptyset(&sa.sa_mask);
42	sa.sa_handler = SIG_IGN;
43	sigaction(SIGINT, &sa, &intSave);
44	sigaction(SIGQUIT, &sa, &quitSave);
45
46	resume_thread(thread);
47
48	int exitStatus;
49	pid_t result;
50	while ((result = waitpid(thread, &exitStatus, 0)) < 0
51		&& errno == B_INTERRUPTED) {
52		// waitpid() was interrupted by a signal, retry...
53	}
54
55	// unblock and reset signal handlers
56	sigprocmask(SIG_SETMASK, &oldMask, NULL);
57	sigaction(SIGINT, &intSave, NULL);
58	sigaction(SIGQUIT, &quitSave, NULL);
59
60	if (result < 0)
61		return -1;
62
63	return exitStatus;
64}
65