Monday, July 26, 2010

Cogito Errno Sum


Ah, POSIX error codes. When systems programming, do you ever find yourself with an unfamiliar error code, and then you're off Googling what the heck it actually means? Where's the command line utility to just do this for you, right where you're at, in a terminal? It's actually pretty easy, with a glorified grep...

Try this script, which I store in ~/bin/errno:

#!/bin/sh -e
headers="/usr/include/asm-generic/errno*.h"
code="$1"
if echo "$code" | grep -qs "[0-9]"; then
grep -hw "\W$code\W" $headers | sed 's/^#define\s*//'
else
grep -hi "$code" $headers | sed 's/^#define\s*//'
fi

Now, you can run:

errno 36
ENAMETOOLONG 36 /* File name too long */

Or:

errno EEXIST
EEXIST 17 /* File exists */

Is this useful to you? It has been really useful to me any time I'm doing system level programming or debugging.

I have long wanted to drop this little script in /usr/bin/errno, but I haven't found the right package to own something like this. Maybe a kernel package, since it uses the kernel headers? Opinions? Let me hear them!

:-Dustin

I think, an error number, I am :-)

14 comments:

  1. Very good! Sometimes, it's the little things that count, especially when trying to fix an "Abort/Retry/Fail"-style error message in a program!
    Something to look at if you ever have too much time on your hands; I found a little bug in it. If you search for errno 2 or 3, you get three results, because other numbers have '2' and '3' in their descriptions. Not sure if it happens for other numbers, or if you can filter it out (my bash-fu is very weak). It's not really a big deal, since I know which number I was looking for and can just ignore the other two.
    Thanks again for coming up with this, it'll be really helpful!

    ReplyDelete
  2. Wow, really useful, thanks! Only one set of \W metachars around the $code doesn't weed out unwanted lines, however:
    errno 3
    ESRCH 3 /* No such process */
    EL3HLT 46 /* Level 3 halted */
    EL3RST 47 /* Level 3 reset */

    Either
    grep -h "\W\W$code\W\W" $headers
    or
    grep -wh "\W$code\W" $headers

    does the trick:
    errno 3
    ESRCH 3 /* No such process */

    ReplyDelete
  3. You can do something similar with a perl one-liner. For instance, the following prints the errors from 1 to 131:

    perl -e 'foreach $a (@ARGV){$!=$a;printf("%d\t%s\n",$!+0,$!)}' {1..131}

    ReplyDelete
  4. Of course decent operating systems contain a manual page for all error codes...

    ReplyDelete
  5. Kay, et al., Thanks for the suggestions!

    I have added -w to the grep to fix the problem where multiple results are returned.

    And yes, of course, Ubuntu has a manpage for errno(3), but this tool grabs just the one line I need ;-)

    :-Dustin

    ReplyDelete
  6. I've always used

    perl -e 'print $!=36, "\n"'

    (which is too much typing for my tastes, and doesn't show the short EXXX name).

    However just a note: POSIX *error* codes have nothing to do with program *exit* codes, so this post doesn't really have anything to do with your previous one. *Exit* codes are either an arbitrary value that a program decides to return (0 for success, non-zero for error) _or_ 128 + signal number (so a SIGSEGV would result in the program returning 139). kill -l displays signal numbers.

    ReplyDelete
  7. Marius, good point. Updated the post text ;-)

    :-Dustin

    ReplyDelete
  8. I use:

    perl -MPOSIX -e 'print strerror('$1'),"\n";'

    or

    python -c 'import os;print os.strerror('$1');'

    ReplyDelete
  9. I Hate, Hate, HATE useless pipes and extra overhead. I use them too often and I'm trying to teach myself better.

    #!/bin/bash
    headers="/usr/include/asm-generic/errno*.h"

    if grep -q '[0-9]' <<< "$1"; then
    awk -v c="$1" '$1=""; $3==c {print}' $headers
    else
    awk -v c="$1" '$1=""; $2==c {print}' $headers
    fi

    ReplyDelete
  10. Took your alert alias from the other day and did the following so that I have a text representation of the error in the alert:

    function errno_helper {
    REALNUM=$?
    NUM=$REALNUM

    if [[ $NUM -eq 0 ]]; then
    TXT="GOOD"
    else
    TXT=`errno $NUM | awk '{print \$1;}'`
    fi

    if [[ -z $TXT ]] ; then
    TXT="unknown"
    fi

    echo -n "$REALNUM:$TXT"
    }

    alias alert_helper='history|tail -n1|sed -e "s/^\s*[0-9]\+\s*//" -e "s/;\s*alert$//"'
    alias alert='notify-send -i /usr/share/icons/gnome/32x32/apps/gnome-terminal.png "[$(errno_helper)] $(alert_helper)"'

    ReplyDelete
  11. Interesting. Oracle has long had a utility, oerr:

    $ oerr ora 12544
    12544, 00000, "TNS:contexts have different wait/test functions"
    // *Cause: Two protocol adapters have conflicting wait/test functions.
    // *Action: Not normally visible to the user. For further details, turn
    // on tracing and reexecute the operation. If error persists, contact
    // Oracle Customer Support.

    ReplyDelete
  12. I have written far too many one-liners to do this. It would be nice to have a script bundled with some standard package.

    How about linux-tools?

    ReplyDelete
  13. Sounds good, Matt. See Bug #612267:

    https://bugs.edge.launchpad.net/ubuntu/+source/linux-meta/+bug/612267

    :-Dustin

    ReplyDelete
  14. Proposed fixes in that branch. I see a number of people have suggested some code and code improvements to solving that. If you would, please create a branch and link it to that bug.

    Thanks!
    :-Dustin

    ReplyDelete

Please do not use blog comments for support requests! Blog comments do not scale well to this effect.

Instead, please use Launchpad for Bugs and StackExchange for Questions.
* bugs.launchpad.net
* stackexchange.com

Thanks,
:-Dustin