roy@phri.UUCP (Roy Smith) (02/26/88)
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 1")); printf ("%d\n", system ("exit 2")); printf ("%d\n", system ("exit 3")); you get: 0 256 512 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. System(3) says, "...returns the exit status of the shell." Sh(1) says, under "Special commands ... exit [n]", "the exit status is that of the last command executed." and, under "Commands", "The value of a simple-command is its exit status...", and under "Parameter substition", describing the "?" parameter, "the value returned by the last executed command in decimal." I would (and in fact, did) put all those together, and assume that the following two code fragments (the first in a C program, the latter in a shell script) would produce the same output. printf ("%d\n", system ("exit 1")); #!/bin/sh sh -c "exit 1" echo $? but they don't; the first prints "256", the latter "1". Is this a case of my being thick (wouldn't be the first time) or is the documentation indeed misleading? -- Roy Smith, {allegra,cmcl2,philabs}!phri!roy System Administrator, Public Health Research Institute 455 First Avenue, New York, NY 10016
ok@quintus.UUCP (Richard A. O'Keefe) (02/26/88)
In article <3161@phri.UUCP>, roy@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*.
dave@galaxia.zone1.com (David H. Brierley) (02/27/88)
In article <3161@phri.UUCP> roy@phri.UUCP (Roy Smith) writes: > > printf ("%d\n", system ("exit 1")); >you get: > 256 > > 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. This subject has come up several times recently so I thought I'd put my two cents worth in. As you have guessed, system() is indeed returning the exit status as defined by wait(). The initial reason for this is obvious if you think about it. The way the system() routine works is to fork off another process, wait for it to complete, and return the status. Since system() must use wait() to wait for the process, the reason for returning the status that was returned by wait() is initially simply laziness. Before anyone gets all up in arms about my calling any of the Supreme UNIX Gods lazy, let me add that returning the status as defined by wait() is also a good thing. It's entirely possible that whoever wrote system() returned the wait() status on purpose and if not they probably looked back and said "this is a good thing, leave it alone" when they realized what they had done. The exit status has other information in it other than just the value that was passed to exit() and that information could be of use to someones program. For example, I might want to take one action if the program exited with a status of 1 and a different action if the program died with a segmentation fault. I think whats really needed is for someone to rewrite the manual page for system() to clearly indicate that the exit status is defined by wait(). -- David H. Brierley Home: dave@galaxia.zone1.com ...!rayssd!galaxia!dave Work: dhb@rayssd.ray.com {sun,decuac,cbosgd,gatech,necntc,ukma}!rayssd!dhb
ron@topaz.rutgers.edu (Ron Natalie) (02/27/88)
You're confusing shell exit status (to itself) and the process exit status available to C programs (via wait). Read the wait(2) manual page. The high byte during normal operation contains the arghument from the exit sys-call in the child. The low byte contains the process termination status. This usually means whether the process died of some signal (like Illegal Instruction, Memory Fault, Bus Error, etc...) and whether or not it dumped core. -Ron
roy@phri.UUCP (Roy Smith) (02/28/88)
ron@topaz.rutgers.edu (Ron Natalie) writes: > You're confusing shell exit status (to itself) and the process > exit status available to C programs (via wait). The point is, if you read the man pages (including wait(2)), you can't help but get confused. Why? Because there are two different things being discussed (shell-type exit codes where the argument to exit(2) is available directly and wait-type exit codes where the argument to exit(2) is up-shifted a byte) but the same terms are used haphazardly to refer to either or both. -- Roy Smith, {allegra,cmcl2,philabs}!phri!roy System Administrator, Public Health Research Institute 455 First Avenue, New York, NY 10016
rbj@icst-cmr.arpa (Root Boy Jim) (03/01/88)
From: Ron Natalie <ron@topaz.rutgers.EDU> You're confusing shell exit status (to itself) and the process exit status available to C programs (via wait). Read the wait(2) manual page. The high byte during normal operation contains the arghument from the exit sys-call in the child. The low byte contains the process termination status. This usually means whether the process died of some signal (like Illegal Instruction, Memory Fault, Bus Error, etc...) and whether or not it dumped core. -Ron Yes, he is. But aren't these two bytes mutually exclusive? Why not just return the exit status byte, or the negative of the signal number that killed it? Core dumping adds 256 to the signal number, and being stopped adds 128 to the signal. Why is it so complex? (Root Boy) Jim Cottrell <rbj@icst-cmr.arpa> National Bureau of Standards Flamer's Hotline: (301) 975-5688 Tex SEX! The HOME of WHEELS! The dripping of COFFEE!! Take me to Minnesota but don't EMBARRASS me!!
ron@topaz.rutgers.edu (Ron Natalie) (03/06/88)
Your idea is supposed to be easier? -Ron
rbj@icst-cmr.arpa (Root Boy Jim) (03/09/88)
Your idea is supposed to be easier? -Ron In the default case (normal exit), yes. Of course for some people, perhaps death by signal is the default case :-) (Root Boy) Jim Cottrell <rbj@icst-cmr.arpa> National Bureau of Standards Flamer's Hotline: (301) 975-5688 Please come home with me... I have Tylenol!! P.S. And I didn't put any cyanide in it either!