Confusing documentation about system(3) in 4.3BSD?

Richard A. O'Keefe ok at quintus.UUCP
Fri Feb 26 16:06:49 AEST 1988


In article <3161 at phri.UUCP>, roy at phri.UUCP (Roy Smith) writes:
> 
> 	I was recently surprised to discover that if you run the following
> program fragment:
> 	printf("%d\n", system("exit 0"));
...
> 	printf("%d\n", system("exit 3"));
> you get:
> 	0
...
> 	768
> 
> 	Clearly what is going on is that system() is returning the exit
> status as described in wait(2), i.e. with the argument to exit() shifted up
> one byte, and the low byte containing the termination status.  But, as I
> read the man pages, the above fragment should have printed 0, 1, 2, and 3.

The documentation has always been confusing.  It's not just 4.3BSD.
However, don't BSD systems come with a /usr/include/sys/wait.h which
makes it rather clearer?

The picture is (on a 32-bit machine)
	+----------------+--------+-+-------+
	|xxxxxxxxxxxxxxxx|exit-val|c|termval|
	+----------------+--------+-+-------+
	31 (MSB)	 15	 8 7 6	   0 (LSB)

exit-val is the least significant byte of the value passed to exit().
	 For a stopped process, it is the number of the signal which
	 caused the child to stop.
c	 is 1 if the child dumped core.
termval  is the "termination status" of the child.  It is 0 for
	 successful exit, 0177 for a stopped process, otherwise the
	 number of the signal which killed the child.

You aren't told about stopped processes unless you ask or they are
being traced; wait(2) is supposed to treat them as if they were still running.

system(3) adds its own complication: the *exit status* (NOT return
value!) 127 means "couldn't execute the shell".  That is, if it
couldn't fork a shell, you get ((system(...) >> 8) & 255) == 127.
Note that this is ambiguous!  Consider system("exit 127"), for example.

Summary:
	x = system(command_string);

#ifdef BSD
	if ((x & 0xFF) == 0x7F) {
	    cause_of_death = NOT_DEAD_BUT_SLEEPING;
	    childs_death_signal = (x >> 8) & 0xFF;
	} else
#endif
	if ((x & 0xFF) != 0) {
	    cause_of_death = KILLED_BY_SIGNAL;
	    childs_death_signal = x & 0x7F;
	    child_dumped_core = (x >> 7) & 1;
	} else
	if ((x & 0xFFFF) == 0x7F00) {
	    cause_of_death = COULD_NOT_EXECUTE_SHELL;
	} else {
	    cause_of_death = NATURAL_CAUSES;
	    childs_exit_status = (x >> 8) & 0xFF;
	}

This is what I have culled from manuals, and seems to be right.
Let's have it from someone who *knows*.



More information about the Comp.unix.wizards mailing list