Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

Populate $!

by tilly (Archbishop)
on Oct 11, 2000 at 21:47 UTC ( [id://36270]=CUFP: print w/replies, xml ) Need Help??

We are all used to checking $! in error messages after failed system calls. However when you reap a child you may know the return code (it is in $?), but would still like to get the system message. For instance the return is 2 and you would like to see No such file or directory. How can you get the translation?

The secret involves some deep magic of $! that is documented in perlvar. It is different when being treated as a string and a number. You can assign the numerical return code, and when used as a string it will have the text of the message. (If the return is being used as a string, there is no need to coerce it like I did. But enough magic is going on that I *prefer* doing that.)

# Turns numerical return codes into text. See perlvar. sub get_system_error { local $! = shift; return "$!"; } print "$_: ", get_system_error($_), "\n" foreach 1..50;

Replies are listed 'Best First'.
RE: Populate $!
by Fastolfe (Vicar) on Oct 11, 2000 at 21:50 UTC
    (Note that this is less for tilly's benefit than it is for any casual user that is trying to take advantage of this trick.) Unfortunately $! and system return values have nothing in common. You can (and must) never assume that an arbitrary program's return code would or should ever map to any standard error message (such as via $!). However, if you are making use of some external program that does define its return code behavior in this fashion (such as something you write specifically to this criteria), by all means give it a shot.

    Setting the value of $! is also useful for system-"like" functions of your own design, but generally setting this variable is only ever useful when your system-like function is doing some core-level operation that itself fails, in which case $! should already be set. Just don't change it when you return.

      Absolutely. In fact after some playing around with it, I came up with the following massive improvement:
      # Turns numerical return codes into text. See perlvar. sub get_system_error { my $code = shift; print "Code: $code\n"; unless ($code < 2**8) { $code >>= 8; } local $! = $code; return "$!"; }
      The win here is that you are automagically correcting the return codes that you get from wait or close in case the error is being passed through from an external program.

      And yes, this only makes sense if you are careful to preserve the return codes. However a lot of Perl code uses die, which tries to do that by default, so you have a shot. This applies if you are trying to figure out why something exited (note that the STDERR of that program is probably gone) so an educated guess for the problem is better than nothing. Not perfect, but pass *it* out in your log message, pointing out that this is a possible guess, and it will often be helpful. So the message would be something like this:

      if (0 < $?) { my $sys_msg = get_system_error($?); die "'$cmd' failed. ret code $?. (Guess: '$sys_msg'?)"; }
      You don't lose any information, but also try to make it easy for a mere human to understand you...
        I think you're digging yourself a velvet-lined grave here.

        Yes, for many Perl child programs, the trivial use of die in that child program propogates their errno to their exit code.

        But for the rest of the real world, no such propogation ever takes place. I think if you survey the exit status of nearly all other programs, you'll find a simple +1 or -1 (255) exit status, which your code will correctly misinterpret. {grin}

        So, feel free to post your code, but be sure the reader is clear that it is intended for Perl child processes only.

        -- Randal L. Schwartz, Perl hacker

RE: Populate $!
by merlyn (Sage) on Oct 11, 2000 at 22:27 UTC
    I gotta second the previous comment.

    There is no necessary correlation between what a child gets in its errno (which we see as $! in Perl) and what that child hands to exit(2) (which we get in the parent via $?). That they are both small numbers (errno under 100-ish, exit code one byte only) only adds to the confusion.

    So, while this is a beautiful snippet for turning an arbitary errno value into an errno string, this has nothing to do with explaining why a child went boom.

    -- Randal L. Schwartz, Perl hacker

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: CUFP [id://36270]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others admiring the Monastery: (3)
As of 2024-04-24 03:07 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found