3

I simply forgot to use sudo:

usr@arch ~[0] $ iptables -L
iptables v1.4.21: can't initialize iptables table `filter': Permission
denied (you must be root)
Perhaps iptables or your kernel needs to be upgraded.
usr@arch ~[3] $ <---

My bash PS1 prompt echoes the last command exit status ($?). The iptables manpages doesn't refer to a return code of 3:

Various error messages are printed to standard error. The exit code is 0 for correct functioning. Errors which appear to be caused by invalid or abused command line parameters cause an exit code of 2, and other errors cause an exit code of 1.

The SUSv3/POSIX discusses exit status for commands.1 A command such as mount - which has 7 different exit statuses for error conditions - executed without privileges returns 1; something that's documented in its manpages: incorrect invocation or permissions.


Q. So why does iptables and mount differ in that respect - is it purely application specific? Why is it that doing an strace on the former outputs things such as: socket(PF_INET, SOCK_RAW, IPPROTO_RAW) = -1 EPERM (Operation not permitted) - shouldn't it be EACCES instead? Why is it that tracing unprivileged mount calls does not reveal similar errors and do these have an impact on the exit status; or is -1 a failure whatever the reason? Where does that 3 come from?


1. Also: GNU Bash; more generally; random weirdness; recent question with reference to codes being application specific + historical /usr/include/sysexits.h etc.

Glorfindel
  • 815
  • 2
  • 10
  • 19
  • EACCESS is generally used when you lack permission to a file, EPERM is used when a system call requires privileges that you don't have. – Barmar Nov 06 '14 at 17:06

2 Answers2

5

The documentation is incomplete. The code contains the following list of error codes used internally:

enum xtables_exittype {
    OTHER_PROBLEM = 1,
    PARAMETER_PROBLEM,
    VERSION_PROBLEM,
    RESOURCE_PROBLEM,
    XTF_ONLY_ONCE,
    XTF_NO_INVERT,
    XTF_BAD_VALUE,
    XTF_ONE_ACTION,
};

And when it tries to initialize, it does:

if (!*handle)
    xtables_error(VERSION_PROBLEM,
           "can't initialize iptables table `%s': %s",
           *table, iptc_strerror(errno));

xtables_error prints the error message and exits with the given exit code.

The code seems to be deficient, IMHO, in assuming that a failure here is due to a version problem, without checking the errno to see that it's actually EPERM.

Barmar
  • 9,927
  • 1
    This is all just specific to iptables and ip6tables. VERSION_PROBLEM is hard-coded, it uses that error code whenever it gets an error trying to initialize the iptables table. I've already deleted my download of the source code. You can download it yourself and grep for xtables_exittype to find the header file. – Barmar Nov 07 '14 at 16:15
  • Thank you, I looked, in xtables.h and found the exit types. So from your A and comments I gather it's something completely idiosyncratic; the program starts, the condition arises, it's not met, VERSION_PROBLEM is passed, that happens to be the 3rd item in the types, and that 3 is returned. And is not documented. Thank you! –  Nov 11 '14 at 04:58
2

The only rule for exit codes is that 0 means success and any other value means failure. This rule goes beyond unix: it's also a common convention on other operating systems (including DOS, Windows, and many embedded systems that have a notion of exit code, but VMS does things differently). In Unix systems, it's baked into the shell's boolean constructs (if, while, &&, ||, !, set -e, …), into make, and followed by all the standard utilities. In POSIX C programs,EXIT_SUCCESS is 0 and EXIT_FAILURE is some non-zero value (usually 1).

There is no rule or widespread convention regarding the choice of exit codes for failure. Only a few POSIX utilities mandate specific failure status codes:

  • cmp and diff return 1 for different files and ≥2 for error conditions.
  • expr returns 1 if the expression evaluates to zero or null, 2 for an invalid expression, and ≥3 for other errors.
  • grep returns 1 for “not found” and ≥2 for error conditions. Many search commands follow this (but not find, which returns 0 if no file matches).
  • mesg returns 0 for yes, 1 for no, and ≥2 for error.
  • patch returns 1 if a hunk was rejected and ≥2 for other errors.
  • sort -c returns 1 if the file data isn't sorted and ≥2 for errors.
  • compress and localedef define some small values for specific errors.

There is a common, but not universal idea that larger values mean worse failures. For commands that test a boolean condition such as grep (is this pattern present?) and diff (are these files identical), 1 means “no” and higher values indicate an error. In addition, values from 126 up are rarely used, as they are baked into the shell (and command, env, nice, nohup and time): 126 and 127 indicate a failure to invoke an external command, and values above 128 in $? indicate a command that was terminated by a signal. /usr/include/sysexits.h is from sendmail and I've only seen it followed in email systems, especially by mail delivery agents such as procmail.

Many programs just always return 1 or always return 2 for any failure. It happens that iptables defines a few different error codes.

The return values shown by strace are from system calls. System calls return -1 to indicate an error and store the error code in the errno variable. Strace shows the value of errno in brackets after the return code. The distinction between EACCES (“Permission denied”) and EPERM (“Operation not permitted”) is a bit subtle; the general idea is that EACCES indicates that the permissions on the target object do not allow the action, while EPERM indicates some other permission problem (for example, the object cannot be reached at all, or the operation is restricted to root).

psmears
  • 465
  • 3
  • 8
  • Thank you, that's very insightful. I had read a bit about the difference between EACCES and EPERM(the "impossible" case). But I have to be reminded that I have execute rights on iptables here as a normal user - and somehow looking at the calls made me lose sight of that. Otherwise I'd get 126 from the shell. At least I get that straight! Thanks again! –  Nov 07 '14 at 07:00