coreutils icon indicating copy to clipboard operation
coreutils copied to clipboard

Usage errors from clap produce exit status 2 but GNU programs produce exit status 1

Open jfinkels opened this issue 3 years ago • 5 comments
trafficstars

This is the same issue I reported previously in #2951, but I noticed that this is a general problem with all programs. The problem is that usage errors that arise from argument parsing (for example, due to conflicting options or missing arguments) in uutils programs cause the process to terminate with exit status 2. But in GNU programs, the process terminates with exit status 1.

For example,

GNU head:

$ head --lines
head: option '--lines' requires an argument
Try 'head --help' for more information.
$ echo $?
1

uutils head:

$ ./target/debug/head --lines
error: The argument '--lines <[-]NUM>' requires a value but none was supplied

USAGE:
    head [FLAG]... [FILE]...

For more information try --help
$ echo $?
2

If there is a uniform solution that could be applied to all programs, that would likely help with a lot of test cases in the GNU test suite. For example, there are several test cases in tests/misc/uniq.pl that expect exit code 1 where we currently return exit code 2.

jfinkels avatar Feb 09 '22 03:02 jfinkels

I think we should ask clap for some customization for this. If they don't want to add something for this, I would suggest that we use try_get_matches_of with ? and provide Into<UResult> for ClapError, where we set the exit code to 1.

tertsdiepraam avatar Feb 09 '22 08:02 tertsdiepraam

I have opened https://github.com/clap-rs/clap/issues/3426 on the clap repository.

tertsdiepraam avatar Feb 09 '22 09:02 tertsdiepraam

All right, that issue was (understandably) a wontfix for them, so we'll have to go with a custom solution. To expand on my previous suggestion, I think we should implement UResult either directly on the clap error or through a wrapper type and provide a method for conversion (like IO errors). I'm not sure yet.

tertsdiepraam avatar Feb 09 '22 16:02 tertsdiepraam

I think the feature introduced in pull request #3457 provides a way to solve this problem now.

jfinkels avatar May 07 '22 02:05 jfinkels

It does! We just have to figure out what all the right exit codes are and use that.

tertsdiepraam avatar May 07 '22 09:05 tertsdiepraam

I try to fix all the utils that should return 1 (see below) soon in a PR.

I wrote a little script to find all these cases (please excuse my terrible bash skills 😄)

for path in src/uu/*; do
    util=${path#src/uu/};
    env $util --definitely-invalid &> /dev/null
    gnu_code=$?
    cargo run --features unix -- $util --definitely-invalid &> /dev/null
    uutils_code=$?
    if [ $gnu_code != $uutils_code ]; then
        echo $util;
        echo "GNU:    $gnu_code";
        echo "UUTILS: $uutils_code";
    fi
done

Below is some summarized output.

# utils that return 2 but should return 1
arch
basename
chgrp
chmod
chown
cksum
comm
csplit
cut
date
dd
df
dircolors
dirname
du
expand
factor
fmt
fold
groups
head
id
install
join
kill
link
ln
logname
mkdir
mkfifo
mknod
mv
nl
nproc
numfmt
od
paste
pathchk
pinky
ptx
pwd
readlink
rm
rmdir
seq
shred
shuf
split
stat
stty
sum
sync
tac
tail
tee
touch
tr
tsort
uname
unexpand
uniq
unlink
uptime
users
wc
who
whoami
yes

# Commands that run other commands and therefore should return 125 to distinguish from errors by the called command
chroot # (already being worked on)
env
nohup
stdbuf
timeout

# and hostname is just being weird?
hostname
GNU:    64
UUTILS: 2

tertsdiepraam avatar Sep 10 '22 11:09 tertsdiepraam