valgrind --error-exitcode , negative values - bash

I'm trying to set a custom error code if valgrind reports an error(building a test script), but it doesn't seem to work as expected when setting a negative value, this how I run valgrind:
valgrind --leak-check=full --error-exitcode=-1 -q ./leaks
This however, returns 0 (which is the return value of leaks), instead of -1.
echo $?
0
If a positive value is set, it works as expected:
valgrind --leak-check=full --error-exitcode=1 -q ./leaks
echo $?
1
The Valgrind manual, specifies:
--error-exitcode=<number> [default: 0]
Specifies an alternative exit code to return if Valgrind reported any errors in the run. When set to the default value (zero), the
return value from Valgrind will always be the return value of the
process being simulated. When set to a nonzero value, that value is
returned instead, if Valgrind detects any errors. This is useful for
using Valgrind as part of an automated test suite, since it makes it
easy to detect test cases for which Valgrind has reported errors, just
by inspecting return codes.
Anybody knows why this behavior occurs?
Using Valgrind-3.10.0

The manual is inaccurate, Valgrind can't return a negative value, it is in Valgrind's source. It assigns the option's value to clo_eror_exitcode:
else if VG_INT_CLO (arg, "--error-exitcode", VG_(clo_error_exitcode)) {}
and then checks if it is positive, otherwise it ignores the option.
if (VG_(clo_error_exitcode) > 0
&& VG_(get_n_errs_found)() > 0) {
VG_(client_exit)( VG_(clo_error_exitcode) );
} else {
/* otherwise, return the client's exit code, in the normal
way. */
VG_(client_exit)( VG_(threads)[tid].os_state.exitcode );
}
Even if it could, it would not be useful as per Linux, negative exit codes?

Related

Why echo $? returns different value than expected?

I know that echo $? returns the exit status of the previous process.
In my program I get 0 if my program ends with a status code of 0. But when the program ends with status code -1 echo $? shows 255. Similar questions are there on StackOverflow, but is not explained why is it so. Plus one of the answers says generally values above 128 indicates some error and negative exit code. Like for example, 147 - we can get the real exit code by subtracting 128 from 147, 128 - 147 = -19, so the exit code was -19.
In my computer I find 256 as that number. For example 255 - 256 = -1, which was what my program was returning.
Why on different systems do these numbers vary 128, 256 and why can't they print the original negative code instead of adding these numbers to the original exit status code.
For historical reasons, exit code is interpreted as unsigned one-byte value. "Normal" error codes are positive (<127), while "abnormal" error codes (e.g. those produced by terminating on signal) are negative (>=128).
Try pressing Ctrl-C on a sleep 10 command. The exit code is 130.
127 is the result of "command not found".
It's really not a recommended practice to use negative error codes explicitly.
For more information, take a look at wait() man page (man 2 wait), in particular WFEXITED() and friends.
WEXITSTATUS(status)
returns the exit status of the child. This consists of the least significant 8 bits of the status argument that the
child specified in a call to exit(3) or _exit(2) or as the argument for a return statement in main(). This macro should
only be employed if WIFEXITED returned true.
(Emphasis added)

Exit Code when called with No Arguments

I have a script that requires at least one argument. If the arguments are incorrect I will obviously return a non-zero exit code.
I have decided to print the usage instructions when called with no arguments, but I'm uncertain of the exit code. Should it be
0 (success)
one of the values [1-125] (error)
An argument could be made either way. Is some option recommended?
It depends on whether you want the callers of your script to know programatically why it failed.
If, for example, it will only ever be run by a human, you could just return 1 and rely on the error text to inform them.
You could even return zero regardless if you only ever want a human to easily know (via the output) if it failed but I would consider this very bad form - Microsoft have made this mistake in the past with some of their commands not setting %errorlevel%, making it very difficult for a script to figure out whether it's worked or not.
Even if you decide not to indicate why it failed, you should at least indicate that it failed.
If you want a program to easily figure out why it failed, return a different code for each discernible error type.
Any Unix command when it returns control to its parent process returns a code, number between 0 and 255.
Success is traditionally represented with exit 0; failure is normally indicated with a non-zero exit-code. This value can indicate different reasons for failure.
So what you have also is another case of unsuccessful completion of your program which should be treated as returning a proper error code and not 0.
Also note that traditional Unix system calls don't signal an error code for empty arguments, they have to be caught explicitly. There are ones for argument list too long (E2BIG) and invalid arguments (EINVAL).
This is what I decided on using, based mostly on Inians answer and the reserved exit codes presented here.
I decided on somewhat reusing the exit codes defined in /usr/include/asm-generic/errno-base.h1. There was nothing suitable for "too little arguments", so I picked the first one from the 64-113 range.
# Error codes
E2BIG=7
EINVAL=22
E2SMALL=64
NAME="my-script"
USAGE=$(cat << END
the help text
RETURN CODES
$NAME has the following return codes:
0 success
$E2BIG Argument list too long
$EINVAL Invalid argument
$E2SMALL Argument list too short
END
)
# This script requires exactly one argument. If less are provided it prints
# the USAGE instructions
if [ ${#} -lt 1 ] ; then
printf '%s\n' "${USAGE}"
exit $E2SMALL
fi
if [ "${1}" = "-h" ] || [ "${1}" = "--help" ] ; then
printf '%s\n' "${USAGE}"
exit 0
fi
if [ ${#} -gt 1 ] ; then
printf '%s\n' "${USAGE}"
exit $E2BIG
fi
It's a bit verbose, but at least there's a properly defined error code if the script is called improperly.
1 This may be debatable, but since the codes were already defined...

Why AND && logic is used in chained commands in most shells, not OR || logic

I am curious about the logic behind && in continuous commands execution in shell.
Lets see an example: command_a && command_b && command_c
In shell, this means that once a command fails, the consequent commands will not execute and the chain should stop.
If we replace each command by its exit code, the chain becomes, for example this expression 0 && 1 && 0. (command_a succeed, command_b failed, command_c succeed)
If we try evaluating this expression, the evaluation should stop right after the first command, 0 value.
If && logic is replaced by ||, the expression would be more fit to the meaning of original chained command.
0 || 1 || 0.
Expression's evaluation stops after command_b execution
There's a difference between the semantics of a successful command and the representation of success via the numeric value of the exit code. If you consider the abstract "is a command successful", && makes more sense, since the "success" abstract boolean is true. That's why && is used. You need A to run, AND you need B to run.
But, due to the fact that there's usually only one status for success, but many different types of errors, the value 0 has been defined long ago to be used for exit status to indicate success.
So, the exit status of a command can simply not replace the command itself in such an expression. The semantics and the representation are just different.
Check out this post.
"The right side of && will only be evaluated if the exit status of the left side is zero. || is the opposite: it will evaluate the right side only if the left side exit status is nonzero..."
$ false && echo howdy!
$ true && echo howdy!
howdy!
$ true || echo howdy!
$ false || echo howdy!
howdy!
I have seen || used in some shell script too. I think it depends on the occasions. You may use command-a && command-b when you want command-b to be executed only after command-a success.
Likewise, you may use command-a || command-b to deal with the situation when command-a fails.
Update: After reading your question three times I now understand what puzzles you: That 0 represents success, and/or (sic) that logical operators treat it as true. Yes, that can be confusing, coming from C. The other Peter's answer explains that well. I let my original answer stand anyway because it is not "wrong".
It is what logic dictates if commands are impossible to perform or don't make sense unless their predecessors succeeded. That happens quite often: "Retrieve a HTML document from the web, verify the time stamp, parse a value out of it, and write that value as an updated data somewhere." Each step depends on the success of all preceding steps.
If, instead, you have something "retrieve a document from the web, or from the cache, or from disk, or take a default here document, in this order of preference", then the appropriate way to write that is indeed with logical ORs. This happens but is less common.
ORing is a common idiom though for error handling, because subsequent commands are exactly performed if the pervious failed. Consider Perl's idiomatic cmd() || die();. (You have more lives. Phew.)

Let bash treat error inside condition as error

I want to write a robust bash script and I use set -e to make sure the script will stop running whenever something goes wrong. It works great but there is still one hole: conditions. If I write if f; then .... fi and function f fails on executing some command, the script will not be terminated. Therefore I need to check return code of every command in f, as well as in all the subroutines f invoke, recursively. This is annoying.
Is there something, e.g. some flag or option in bash, that makes it fail even inside a condition. The only exception is return statement directly inside f. If f calls g and g returns 1, then it is still considered as error, with the exception that g is also called as condition, i.e. if g; then ... fi, then return statement inside g is allowed. So on so forth.
Succinctly, No.
If you want the shell to exit on failure, don't test f; simply run it. The code in the then clause should simply follow the invocation of f because you'll only ever get to execute it if f succeeded.
Old code:
set -e
if f; then echo "f succeeded"; fi
New code:
set -e
f
echo "f succeeded"
You'll only see "f succeeded" if it does succeed; if it fails, the set -e ensures the script exits.
What you're asking to do is slightly odd. I can imagine two possibilities for why you're asking:
You want the script to exit if anything goes wrong inside the body of the function f, even if the function itself still returns success.
You want to distinguish between the function successfully computing what turns out to be a legitimate false value, and failing.
For case 1 - don't do that. If anything goes wrong inside f, the function should absolutely return false (if not exit the whole script itself). And if it returns false, you're good - see #JonathanLeffler's answer.
For case 2, you're effectively trying to make $? serve two duties. It can be either an error indicator or a Boolean result; it can't be both.
If you want your script to exit if something goes wrong, you could just have the function itself call exit when that happens, so the caller doesn't have to worry about that case.
Alternatively, you could have the function echo its computed Boolean value instead of returning it, and reserve $? for success/failure. Something like this, maybe:
f() {
if that thing is true; then
echo 1
else
echo 0
fi
if something went wrong; then
return 1
else
return 0
fi
}
result=$(f) # we'll blow up and exit if f returns nonzero in `$?`
if (( result )); then
...
fi
You would have to distinguish between f being false and f encountering an error.
Traditionally both falsehood and error conditions are signaled in the same way: by setting $? to a non-zero value.
Some commands do make such a distinction. For example, the grep command sets $? to 0 if the pattern was found, 1 if it wasn't, and 2 if there was an error (such as a missing file). So for the grep command, you could do something like:
grep ...
case $? in
0) # ok
;;
1) # pattern not found
;;
*) # error
;;
esac
But that's specific to grep. There is no universal convention for distinguishing between a command yielding a "false" result and failing, and in many cases there is no such distinction to make.
To do what you want, you'll have to define just what constitutes an error, and then determine for each command you might execute how to detect an error condition.

How to return from shell script with return value 1 with successful completion of script

How to return from shell script with return value 1 with successful completion of script?
Firstly, returning a value of 1 to indicate success is exactly the opposite of expected behavior, so you really should not do it. However, if you want to, then just do
exit 1
However, this typically indicates failure, and you would do well to respect the convention.
0 indicates success, non-zero indicates failure.
You should use exit or exit 0 in case of success. In case of failure, use exit 1. If you want to return information why your program has failed, you can use several different return values, i. e. 1, 2, 3, -1, 255, etc.

Resources