65 #include <sys/prctl.h>
66 #include <sys/resource.h>
70 #include <amxc/amxc_macros.h>
71 #include <amxc/amxc.h>
74 #define AMXP_SUB_PROC_NR_PIPES 3
76 #define AMXP_SUBPROC_FD_PARENT 0
77 #define AMXP_SUBPROC_FD_CHILD 1
83 amxc_var_t* exit_info = NULL;
90 amxc_var_new(&exit_info);
91 amxc_var_set_type(exit_info, AMXC_VAR_ID_HTABLE);
93 amxc_var_set(int64_t, &data, subproc->
pid);
94 amxc_var_set_key(exit_info,
"PID", &data, AMXC_VAR_FLAG_COPY);
96 if(WIFEXITED(status)) {
97 amxc_var_set(int64_t, &data, WEXITSTATUS(status));
98 amxc_var_set_key(exit_info,
"ExitCode", &data, AMXC_VAR_FLAG_COPY);
99 }
else if(WIFSIGNALED(status)) {
100 if(WCOREDUMP(status)) {
101 amxc_var_set(
bool, &data,
true);
102 amxc_var_set_key(exit_info,
"CoreDump", &data, AMXC_VAR_FLAG_COPY);
104 amxc_var_set(
bool, &data,
true);
105 amxc_var_set_key(exit_info,
"CoreDump", &data, AMXC_VAR_FLAG_COPY);
107 amxc_var_set(
bool, &data,
true);
108 amxc_var_set_key(exit_info,
"Signalled", &data, AMXC_VAR_FLAG_COPY);
109 amxc_var_set(int64_t, &data, WTERMSIG(status));
110 amxc_var_set_key(exit_info,
"Signal", &data, AMXC_VAR_FLAG_COPY);
117 amxc_var_delete(&exit_info);
127 int max_files = 1024;
129 int ret = getrlimit(RLIMIT_NOFILE, &limit);
131 max_files = limit.rlim_cur;
134 for(
int i = 3; i < max_files; i++) {
144 prctl(PR_SET_PDEATHSIG, SIGKILL);
146 fd_null = open(
"/dev/null", O_RDWR);
160 pthread_sigmask(SIG_SETMASK, NULL, &sig_set);
161 pthread_sigmask(SIG_UNBLOCK, &sig_set, NULL);
163 execvp(argv[0], argv);
169 UNUSED const amxc_var_t*
const data,
170 UNUSED void*
const priv) {
175 while((ret = waitpid(-1, &status, WNOHANG)) > 0) {
177 if(subproc == NULL) {
189 struct timespec stop;
190 int remaining_timeout = 0;
196 err = clock_gettime(CLOCK_REALTIME, &stop);
197 when_failed(err, exit);
199 sec_to_msec = (( stop.tv_sec - start->tv_sec ) * ((time_t) 1000));
200 nsec_to_msec = (( stop.tv_nsec - start->tv_nsec) / ((
long) 1000000));
202 msec_passed = (int) sec_to_msec + (
int) nsec_to_msec;
203 remaining_timeout = timeout_msec - msec_passed;
205 if(remaining_timeout < 0) {
208 remaining_timeout = 0;
212 return remaining_timeout;
217 when_null(subproc, exit);
218 when_not_null(*subproc, exit);
221 when_null(*subproc, exit);
241 when_null(subproc, exit);
242 when_null(*subproc, exit);
253 amxc_llist_it_take(&(*subproc)->it);
265 when_null(subproc, exit);
266 when_true(requested < STDIN_FILENO ||
267 requested > STDERR_FILENO, exit)
270 if(pipe2(subproc->
fd[requested], O_NONBLOCK | O_CLOEXEC) < 0) {
273 if(requested == STDIN_FILENO) {
274 int swap = subproc->
fd[STDIN_FILENO][0];
275 subproc->
fd[STDIN_FILENO][0] = subproc->
fd[STDIN_FILENO][1];
276 subproc->
fd[STDIN_FILENO][1] = swap;
292 sigset_t original_mask;
295 when_null(subproc, exit);
296 when_null(argv, exit);
297 when_null(*argv, exit);
300 sigfillset(&block_mask);
301 sigprocmask(SIG_SETMASK, &block_mask, &original_mask);
305 waitpid(pid, NULL, WNOHANG);
306 sigprocmask(SIG_SETMASK, &original_mask, NULL);
318 }
else if(pid == -1) {
337 when_null(subproc, exit);
338 when_null(cmd, exit);
342 while(va_arg(ap,
char*)) {
347 argv = (
char**) calloc(argc + 2,
sizeof(
char*));
348 when_null(argv, exit);
353 for(
int i = 1; i <= argc; i++) {
354 argv[i] = va_arg(ap,
char*);
369 when_null(subproc, exit);
370 when_null(cmd, exit);
371 when_true(amxc_array_is_empty(cmd), exit);
374 argv = (
char**) calloc(amxc_array_capacity(cmd) + 1,
sizeof(
char*));
375 when_null(argv, exit);
377 for(
size_t i = 0; i < amxc_array_capacity(cmd); i++) {
378 if(amxc_array_get_data_at(cmd, i) == NULL) {
381 argv[i] = (
char*) amxc_array_get_data_at(cmd, i);
393 when_null(subproc, exit);
396 retval = kill(subproc->
pid, sig);
406 if(subproc->
pid == pid) {
416 return subproc != NULL ? subproc->
pid : -1;
420 return subproc != NULL ? subproc->
sigmngr : NULL;
424 return subproc != NULL ? subproc->
is_running :
false;
431 struct pollfd pollfd;
432 struct timespec start;
433 int remaining_timeout_msec = timeout_msec;
435 when_null(subproc, exit);
438 pollfd.events = POLLIN;
440 err = clock_gettime(CLOCK_REALTIME, &start);
441 when_failed(err, exit);
444 err = poll(&pollfd, 1, remaining_timeout_msec);
455 if(remaining_timeout_msec > 0) {
470 when_failed(retval, exit);
473 when_failed(retval, exit);
487 when_null(subproc, exit);
488 when_null(cmd, exit);
491 while(va_arg(ap,
char*)) {
496 argv = (
char**) calloc(argc + 2,
sizeof(
char*));
497 when_null(argv, exit);
502 for(
int i = 1; i <= argc; i++) {
503 argv[i] = va_arg(ap,
char*);
508 when_failed(retval, exit_free);
520 when_null(subproc, exit);
522 retval = WIFEXITED(subproc->
status);
530 when_null(subproc, exit);
532 retval = WIFSIGNALED(subproc->
status);
540 when_null(subproc, exit);
542 retval = WEXITSTATUS(subproc->
status);
550 when_null(subproc, exit);
552 retval = WTERMSIG(subproc->
status);
static int amxp_subproc_child_status(amxp_subproc_t *subproc, int status)
static int amxp_recalculate_timeout(struct timespec *start, int timeout_msec)
static void amxp_subproc_exec_child(amxp_subproc_t *const subproc, char **argv)
static void amxp_subproc_close_fds(void)
#define AMXP_SUBPROC_FD_CHILD
#define AMXP_SUBPROC_FD_PARENT
#define AMXP_SUB_PROC_NR_PIPES
static void amxp_subproc_sigchild(UNUSED const char *const sig_name, UNUSED const amxc_var_t *const data, UNUSED void *const priv)
static amxc_llist_t amxp_subprocs
int amxp_sigmngr_add_signal(amxp_signal_mngr_t *const sig_mngr, const char *name)
Adds a signal to a signal manager.
int amxp_sigmngr_new(amxp_signal_mngr_t **sig_mngr)
Constructor function, creates a new signal manager instance.
int amxp_sigmngr_delete(amxp_signal_mngr_t **sig_mngr)
Destructor function, deletes a signal manager instance.
int amxp_sigmngr_emit_signal(const amxp_signal_mngr_t *const sig_mngr, const char *name, const amxc_var_t *const data)
Emits a signal.
int amxp_slot_connect(amxp_signal_mngr_t *const sig_mngr, const char *const sig_name, const char *const expression, amxp_slot_fn_t fn, void *const priv)
Connects a slot (function) to a named signal of a signal manager.
amxp_subproc_t * amxp_subproc_find(const int pid)
Retrieve a amxp_subproc_t for a child process using it's process identifier.
int amxp_subproc_open_fd(amxp_subproc_t *subproc, int requested)
Opens standard file descriptor to the child process.
bool amxp_subproc_is_running(const amxp_subproc_t *const subproc)
Checks if the child process is running.
int amxp_subproc_new(amxp_subproc_t **subproc)
Constructor function, creates a new child process data structure.
int amxp_subproc_get_exitstatus(amxp_subproc_t *subproc)
Gets the exit code of the child process.
int amxp_subproc_start(amxp_subproc_t *const subproc, char *cmd,...)
Start a child process.
int amxp_subproc_kill(const amxp_subproc_t *const subproc, const int sig)
Sends a Linux signal to the child process.
int amxp_subproc_ifexited(amxp_subproc_t *subproc)
Checks if the child process terminated normally.
int amxp_subproc_start_wait(amxp_subproc_t *subproc, int timeout_msec, char *cmd,...)
Starts a child process and waits until it exits.
int amxp_subproc_wait(amxp_subproc_t *subproc, int timeout_msec)
Waits until the child process has stopped.
int amxp_subproc_vstart(amxp_subproc_t *const subproc, char **argv)
Start a child process.
int amxp_subproc_vstart_wait(amxp_subproc_t *subproc, int timeout_msec, char **cmd)
Starts a child process and waits until it exits.
int amxp_subproc_astart(amxp_subproc_t *const subproc, amxc_array_t *cmd)
Start a child process.
int amxp_subproc_ifsignaled(amxp_subproc_t *subproc)
Checks if the child process was stopped because of an uncaught Linux signal.
amxp_signal_mngr_t * amxp_subproc_get_sigmngr(const amxp_subproc_t *const subproc)
Get the Signal managers of the child process.
int amxp_subproc_get_termsig(amxp_subproc_t *subproc)
Gets the Linux signal id that caused the child process to stop.
int amxp_subproc_delete(amxp_subproc_t **subproc)
Destructor function, deletes a child process data structure.
pid_t amxp_subproc_get_pid(const amxp_subproc_t *const subproc)
Get the PID of a child process.
int amxp_syssig_get_fd(void)
Returns a file descriptor that can be used in an eventloop.
int amxp_syssig_read(void)
Reads from the file descriptor.
int amxp_syssig_enable(const int sigid, const bool enable)
Enables or disables monitoring of a system signal.
Structure containing the signal manager information.
Child process information structure.
amxp_signal_mngr_t * sigmngr