Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Propagate WTERMSIG exit code from child process on exit

I’m writing a wrapper command that invokes a child process, waits for it to exit, and propagates its exit code. Simple enough.

I want to propagate the exit status of the child process to my own process’s exit code even if the child exited with a signal. If WIFSIGNALED(cmdret) is true for some int cmdret that contains the result of a waitpid(...) call or similar, I want to set my process exit code the WTERMSIG(cmdret) such that WIFSIGNALED will return true on the exit code of my own process.

How do I do it? Lets assume I don’t want to send my own process a fatal signal that matches that of the child process – if the child exited with SIGABRT or SIGSEGV I don’t want to send an abort or segfault signal to my wrapper.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel


glibc defines the relevant macros as

/* If WIFEXITED(STATUS), the low-order 8 bits of the status.  */
#define __WEXITSTATUS(status)   (((status) & 0xff00) >> 8)

/* If WIFSIGNALED(STATUS), the terminating signal.  */
#define __WTERMSIG(status)      ((status) & 0x7f)

/* If WIFSTOPPED(STATUS), the signal that stopped the child.  */
#define __WSTOPSIG(status)      __WEXITSTATUS(status)

/* Nonzero if STATUS indicates normal termination.  */
#define __WIFEXITED(status)     (__WTERMSIG(status) == 0)

/* Nonzero if STATUS indicates termination by a signal.  */
#define __WIFSIGNALED(status) \
  (((signed char) (((status) & 0x7f) + 1) >> 1) > 0)

and exit(...) docs say:

The exit() function causes normal process termination and the least significant byte of status (i.e., status & 0xFF) is returned to the parent (see wait(2)).

Similarly _exit(...) returns status & 0xFF, and the return value from main uses the low 8 bits for normal exit codes.

The shell convention is to use exit codes less than 125 for the child process exit, 126 as "found but not executable", 127 as "not found", and 128+N as "exited with signal N". That works, but requires the caller to be aware of whether they’re invoking the process via an intermediate shell or not to interpret the exit code correctly.

This makes it impossible to differentiate between processes that themselves exited with codes greater than 125 and a signal exit or failure of the wrapper or shell. It could break commands that invoke the wrapped command if they use test macros like WIFEXITED, WTERMSIG etc on the return code of the original command. The wrapper will appear to have exited normally even if the child exited on a signal.

I want my wrapper to be completely transparent to the invoker, so calling WEXITSIG(ret) on my wrapper’s return code will return the signal if the wrapped process in turn exited with a signal.

Is that possible at all?

>Solution :

If you want to replicate the wait status of a child in the parent,
then if WIFEXITED(ws) returns true, you can_exit(WEXITSTATUS(ws)) and if WIFSIGNALED(ws) returns true, you can do signal(WTERMSIG(ws),SIG_DFL); raise(WTERMSIG(ws)); (i.e., raise the same signal after resetting it to its default disposition so that raising it surely will kill the process).

I don’t think Unix kernels will let you fake signal death without actually going through signal death. If you’re trying to avoid it to prevent coredumps, then you could possibly use platform-specific solutions to disable coredumps just for your wrapper process. E.g., on Linux, you can call prctl(PR_SET_DUMPABLE,0);.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading