Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

return value from system call, exit status, shift right 8, bitwise and, $?

by Anonymous Monk
on Feb 11, 2010 at 03:30 UTC ( [id://822569]=perlquestion: print w/replies, xml ) Need Help??

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I tend to use the system() function pretty often, and I want to make sure I detect any problems. So, I think this means I want to make sure that programs I run always have an exit status of 0.

My understanding of the system function is that it returns a 16-bit value, where the high 8 bits are the exit status, and the low 8 are the signal id. Is that correct?

It also seems that I don't actually have to save the exit status after every use of system(), since the value also gets stored in $?.

I don't expect the programs I'm running to be killed by any signals (unless I'm the one doing the sending) ... So, I think this means I'm only concerned that the high 8 bits are all off. Therefore, does this mean I should be carefully making my system calls like this:

system('some_shell_command') >> 8 and die "Failed!"; # or else (same thing), system('some_program'); if ($? >> 8 != 0) { die "Failed!"; }

or would the following suffice? :

system('foobar') == 0 or die "Failed!"; # or equivalently system('foobar'); if ($? != 0) { die "Failed!"; }

Also, I notice in the docs for system(), there's this:

if ($? == -1) { print "failed to execute: $!\n"; } elsif ($? & 127) { printf "child died with signal %d, %s coredump\n", ($? & 127), ($? & 128) ? 'with' : 'without'; } else { printf "child exited with value %d\n", $? >> 8; }

For the if expression, if the exit status is 16 bits, then the value goes from 0 to 655535. What does it mean to check if it's -1?

For the elsif expression, why are they bitwise anding it with 127? 127 in binary is 0b0111_1111. So, that's only giving me the bottom 7 bits of $?, not 8. Why throw away that top bit in the bottom byte?

Replies are listed 'Best First'.
Re: return value from system call, exit status, shift right 8, bitwise and, $?
by ikegami (Patriarch) on Feb 11, 2010 at 09:10 UTC

    and the low 8 are the signal id. Is that correct?

    No, the low 7 bits indicate the signal that ended the process. Bit 7 indicates whether a core dump was saved.

    What does it mean to check if it's -1?

    system itself encountered an error. For example, system will return -1 and set $! if the program to execute is not found.

    or would [system(...) == 0 or die "Failed!";] suffice?

    It can also be written as

    system(...) and die "Failed!";

    It will die on any error, but not saying what failed and not saying why it failed seems insufficient to me. The user should at least be told what failed for an error that's not a programming error; a line number doesn't cut it.

    Now, detecting whether a code dump occurred or not is going overboard.

    This is pretty minimal:

    sub _system { my $prog = shift; my $rv = system( { $prog } $prog => @_ ); if ($rv == -1) { die("Can't launch $prog: $!\n"); } elsif (my $s = $rv & 127) { die("$prog died from signal $s\n"); } elsif (my $e = $rv >> 8) { die("$prog exited with code $e\n"); } }

      Ok. I think I see now. If the system() call returns "-1", this is the same as a binary number of all 1's (since the system presumably uses the two's-complement representation), and it looks like it is:

      printf '%b', -1; print "\n"; # Output is: # 11111111111111111111111111111111

      So, if we get -1 back, then I can just stop checking bits right there.

      If the system() call does not return -1, but returns anything at all in those first 7 bits, then -- again -- I can stop checking anything else, because if those first 7 bits contain anything, that indicates that the program that was called received a signal and that's why it ended.

      Finally, if the system() call does not return -1, and those first 7 bits are all zeros, then only at that point do those next 8 bits contain anything of interest (the exit status of the program called).

      And to wrap this all up nicely, if the system() call returns 0, then that means all bits are off, thus:

      1. the value is not -1, so the program it called at least launched,
      2. the lower 8 bits are all zeros, so there was no signal caught (nor was a core dump saved),
      3. the higher 8 bits are all zeros, so exit status was zero too.

      and therefore the program that system() called evidently ran successfully.

      Thank you!

      and the low 8 are the signal id. Is that correct?
      No, the low 7 bits indicate the signal that ended the process. Bit 7 indicates whether a core dump was saved.

      By my math, the 8th bit signals the core dump. I assume that's a typo.

        No typo. The 8th bit is bit 7. They're numbered from 0
Re: return value from system call, exit status, shift right 8, bitwise and, $?
by 7stud (Deacon) on Feb 11, 2010 at 06:10 UTC
    For the if expression, if the exit status is 16 bits, then the value goes from 0 to 655535. What does it mean to check if it's -1?

    -1 is not an 'exit status' of a system() call. -1 means system() was unable to execute the specified command. Because the command never executed, it did not generate an exit status.

    EDIT: Apparently the -1 return value has some twists to it. The perl system() docs say that system() returns the return value of wait(). The perl wait() docs say:

    Behaves like the wait(2) system call on your system: it waits for a child process to terminate and returns the pid of the deceased process, or "−1" if there are no child processes. The status is returned in $? and "${^CHILD_ERROR_NATIVE}". Note that a return value of "−1" could mean that child processes are being automatically reaped, as described in perlipc.

    The perlipc docs say:

    On most Unix platforms, the CHLD (sometimes also known as CLD ) signal has special behavior with respect to a value of 'IGNORE' .... Calling wait() with $SIG{CHLD} set to 'IGNORE' usually returns -1 on such platforms.

    As far as I can tell, if you set $SIG{CHLD} = 'IGNORE', then you have told perl you don't want to wait for any children to finish executing. In that case, system() executes the command, but system() immediately returns -1 because your program is too impatient to wait and get the exit status from the child.

    Therefore, system() can return -1 when system() successfully started the command.

    For the elsif expression, why are they bitwise anding it with 127? 127 in binary is 0b0111_1111

    That checks whether any of the first 7 bits is 'on'.

    So, that's only giving me the bottom 7 bits of $?, not 8. Why throw away that top bit in the bottom byte?
    Presumably, the agreed upon protocol is to use only the first 7 bits to indicate which signal terminated the program. In the old ascii system, the maximum number of characters that could be represented by one byte was 128 (0-127) because the 8th bit was used for other purposes. Maybe that is why the protocol uses only the first 7 bits to indicate which signal terminated the process.

    In addition, I can imagine a system where there were only 2 possible signals. With that protocol, you would only need to write ($? & 3) to determine if a signal terminated the process. Maybe there were only 7 signals when the protocol was decided upon?

      Therefore, system() can return -1 when system() successfully started the command.

      Yes. It could mean it was unsuccessful in reaping the child. However, that will only happen when $SIG{CHLD} is overridden, and you shouldn't be using system when you do that.

Re: return value from system call, exit status, shift right 8, bitwise and, $?
by ikegami (Patriarch) on Feb 11, 2010 at 09:22 UTC
    And then there's IPC::System::Simple.
    use IPC::System::Simple qw( systemx ); systemx( perl => ( '-e', 'print "foo"' )); # Dies on error
Re: return value from system call, exit status, shift right 8, bitwise and, $?
by 7stud (Deacon) on Feb 11, 2010 at 07:23 UTC
    or would the following suffice? : system('foobar') == 0 or die "Failed!";

    Because I hate bit twiddling, that would be my choice.

    Also, as "Learning Perl(5th)" says in a footnote on p. 236:

    The return value of system is the "child exit code multiplied by 256, plus 128 if core was dumped, plus signal number triggering termination, if any."
    So you can do some regular math to get any additional information you need as well.
Re: return value from system call, exit status, shift right 8, bitwise and, $?
by rovf (Priest) on Feb 11, 2010 at 09:34 UTC
    My understanding of the system function is that it returns a 16-bit value, where the high 8 bits are the exit status, and the low 8 are the signal id.
    Can we really rely on this? I know that this is true for the Perl implementations I worked with, but I can't find anywhere in the docs that the exist status has to be 8 bit. This is certainly true for Unix-like systems. On Windows, programs can return 32 bit exitcode (although at least ActiveState Perl 5.8 and 5.10 throws away part of the bits). I could imagine that in later/different implementations, all 32 bits could be returned on Windows.

    -- 
    Ronald Fischer <ynnor@mm.st>
        I didn't find anything in this section of perlfaq8 about the number of significant bits in the result of system, but I believe ikegami of course ;-)

        -- 
        Ronald Fischer <ynnor@mm.st>
Re: return value from system call, exit status, shift right 8, bitwise and, $?
by bot403 (Beadle) on Feb 11, 2010 at 15:24 UTC

    Others have covered your original question pretty well so I'll just chip in that I'm a fan of this construct in my code to get both the output and the RC.

    This doesn't quite cover all the bases but can be expanded to do so.

    eval { open P,"$cmd 2>&1 |"; }; if($@) { die('Cant launch cmd') } my @output=<P>; close P; my $rc = $? >> 8;
Re: return value from system call, exit status, shift right 8, bitwise and, $?
by shawnhcorey (Friar) on Feb 11, 2010 at 14:15 UTC

    system() is one of those weird commands that do different things depending on their arguments. It you use a single string argument, the return status is the status of the shell (or CMD.EXE on Windows). Most often, this is zero (success) even if the shell could not find a program to run. If you use a list of arguments, then you get the return status of the program but none of the argument are interpoled. This may be a good thing or a bad thing, depending on what you expect.

    Example: a single string argument:

    my $status = system( "foobar arg1 arg2 arg3" );

    $status contains the status of the shell or CMD.EXE.

    Example: a list of arguments:

    my $status = system( "foobar", "arg1", "arg2", "arg3" );

    $status contains the status of foobar.

Re: return value from system call, exit status, shift right 8, bitwise and, $?
by 7stud (Deacon) on Feb 11, 2010 at 14:54 UTC
    system() is one of those weird commands that do different things depending on their arguments. It you use a single string argument, the return status is the status of the shell (or CMD.EXE on Windows). Most often, this is zero (success) even if the shell could not find a program to run.

    I'm not seeing that:

    use strict; use warnings; use 5.010; my $status = system( "foobar arg1 arg2 arg3" ); say $status; --output:-- Can't exec "foobar": No such file or directory at 2perl.pl line 5. -1
    os x 10.4.11

      YMMV. And here I thought I had it figured out. :(

      I wonder what happens on Windows.

Re: return value from system call, exit status, shift right 8, bitwise and, $?
by Anonymous Monk on Feb 11, 2010 at 04:08 UTC
    if the exit status is 16 bits, then the value goes from 0 to 655535.

    Sorry, typo. s/655535/65535/

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://822569]
Approved by ww
Front-paged by ww
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others sharing their wisdom with the Monastery: (3)
As of 2024-04-26 01:21 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found