How GNU treats a failure indicator from main - c++

I write a simple case to see how my system treats a failure indicator from main.
But nothing happened. I really want to know what's the difference between return 0 and return -1.
int main()
{
return -1;
}

That depends on what your "system" is. If you just run a program then this value is ignored.
The only time this is used is if your program is part of a larger workflow where your program's failure matters. For example, a makefile (or a C++ IDE) will stop building the program if there's a failure in one of the steps. This failure is signaled by an error code from main().

most of the times, the return value in main has no use, traditionally, we return 0 to indicate the program is success, especially in Windows. But in Linux, we often have a chain of programs, which means the second program's state depends on the first one's result. At that time, the return value has its position.
So, no matter what the return value is, most of the times its depends on your design, and it means nothing to system.
Hope that can help you.

Assuming you have compiled an executable named a.out, consider:
$ ./a.out # ignore the value returned from main
$ ./a.out && echo success # check the value returned from main
$ ./a.out || echo failure
In the second and third case, the echo will only occur if a.out is successful or not, respectively, where success is defined as returning zero from main. This is a convention that may be more clear with the following syntax:
if ./a.out; then
echo a.out returned zero from main
else
echo a.out returned non-zero from main
fi

The return value of main() is available:
To the shell, if the shell started it, as $status etc, depending on which shell you're using.
To the program that started it, via the status variable pointed to by the argument to wait(). See man 2 wait().
GNU has precisely nothing do to with it.

If using the bash shell (or similar), you can show the return value of the last command executed with echo $?. Sample bash terminal session:
$false
$echo $?
1
$true
$echo $?
0
$
On other systems the return value will be accessed differently. On DOS or Windows the return value can be checked with the ERRORLEVEL command or %ERRORLEVEL% variable.

Related

What is the safe way of get the return status from an executed shell command in c++

Since the function std::system(const char* command) from cstdlib doesn't guarantee that will return the correct return status from the shell, then how can I run a command in shell using c/c++ and have a guarantee that will give me the right return value?
In my case, for example, I ran a command with:
bool is_process_running(std::string p_name){
std::string command_str= "ps aux | grep '" + p_name + "' | egrep -v '(grep|bash)'";
int result(0);
result= system(command_str.c_str());
return result == 0;
}
If I run, for example, ps aux | grep 'my_process' | egrep -v '(grep|bash)' directly into the terminal and after that echo $?, I see it returning 0 because my_process is running and also returning 1 when I use a non running process. But, the code above returns a different value. This code used to work when I tested in CentOs 6 but now in CentOs 7 doesn't work anymore. So, what can I use to run the shell command and get the correct result?
I also found a solution using pidof command but I can't use this because pidof doesn't consider the parameters passed to my_process which I need since I have many instances of this process each with different arguments.
The problem is that the exit status of Bash isn't guaranteed to be the exit status of the last executed command. If there's an error in the command you pass, you can't really distinguish it from egrep failing to match anything.
What you need to do is to do is to both get the exit status and parse the output (both to standard output and standard error). This can be accomplished by copying much of what the system function does: First create a pipe for the output (both stderr and stdout could be using the same pipe), then fork a new process to run the shell, and then execute the shell and the pipeline.
In the parent process you wait for the child to exit, and get its exit status. If it's zero then you know everything worked fine, and you can discard all the output from the pipe. If it's non-zero you have to read the output from the pipe to see what happened, if there was some error except egrep failing.

What could cause unzip command returning -1 in my scenario?

I run unzip via a system() call in my C++ code in below format:
/usr/bin/unzip -o -q /<my_path_to_zip_file>/cfg_T-KTMAKUCB.zip -d /<my_path_to_dest>/../
This will almost 90% of times succeed. I cannot understand what could make it fail time to time with -1 return code. Any ideas?
According my local man system,
The value returned is -1 on error (e.g. fork(2) failed), and the return status of the command otherwise.
and the POSIX spec says,
If a child process cannot be created, or if the termination status for the command language interpreter cannot be obtained, system() shall return -1 and set errno to indicate the error
Finally, the manpage for unzip lists various return codes, but -1 isn't among them.
If the command itself can't return -1, the problem is probably with the initial fork/exec, due to something like a system-wide or per-user limit (memory exhausted; process table full; maximum processes, open files or VM size limit for the user etc. etc).
You should be checking errno when system fails anyway. Running the whole thing under strace -f will also show what happens.

How to mark Jenkins builds as SUCCESS only on specific error exit values (other than 0)?

When I run an Execute shell build step to execute a script and that script returns 0, Jenkins flags the build as SUCCESS, otherwise it flags it as FAILURE which is the expected default behaviour as 0 means no errors and any other value represents an error.
Is there a way to mark a build as SUCCESS only if the return value matches a specific value other than 0 (e.g. 1,2,3...)?
PS: in case you're wondering why I'm looking for that, this will allow me to perform unit testing of Jenkins itself as my scripts are written to return different exit values depending on various factors, thus allowing me to expect certain values depending on certain setup mistakes and making sure my whole Jenkins integration picks up on those.
Alright, I went on IRC #jenkins and no-one new about a plugin to set a particular job status depending on a particular exit code :( I managed to do what I wanted by creating an Execute shell step with the following content:
bash -c "/path/to/myscript.sh; if [ "\$?" == "$EXPECTED_EXIT_CODE" ]; then exit 0; else exit 1; fi"
-Running the script under bash -c allows catching the exit code and prevents Jenkins from stopping build execution when that exit code is different than 0 (which it normally does).
-\$? is interpreted as $? after the script execution and represents its exit code.
-$EXPECTED_EXIT_CODE is one of my job parameters which defines the exit code I'm expecting.
-The if statement simply does the following: if I get the expected exit code, exit with 0 so that the build is marked as SUCCESS, else exit with 1 so that the build is marked as FAILURE.
/path/to/myscript.sh || if [ "$?" == "$EXPECTED_EXIT_CODE" ]; then continue; else exit 1; fi
I would use continue instead of exit 0 in case you have other items below that you need to run through.
Can handle it via the Text-finder Plugin:
Have your script print the exit-code it is about to exit with, like: Failed on XXX - Exiting with RC 2
Use the Text-finder Plugin to catch that error-message and mark the build as 'Failed' or 'Unstable',for example, if you decide RC 2, 3 and 4 should mark the build as 'Unstable', look for text in this pattern: Exiting with RC [2-4].
Create a wrapper for your shell script. Have that wrapper execute your tests and then set the resturn value according to whatever criteria you want.
I do it like this:
set +e
./myscript.sh
rc="$?"
set -e
if [ "$rc" == "$EXPECTED_CODE_1" ]; then
#...actions 1 (if required)
exit 0
elif [ "$rc" == "$EXPECTED_CODE_2" ]; then
#...actions 2 (if required)
exit 0
else
#...actions else (if required)
exit "$rc"
fi
echo "End of script" #Should never happen, just to indicate there's nothing further
Here +e is to avoid default Jenkins behavior to report FAILURE on any sneeze during your script execution. Then get back with -e.
So that you can handle your exit code as appropriate, else eventually FAIL with the returned code.
robocopy "srcDir" "destDir" /"copyOption" if %ERRORLEVEL% LEQ 2 exit 0
If robocopy exit code is less than or equal to 2 then it will exit successfully.
Robocopy Exit Codes:
0×00 0 No errors occurred, and no copying was done.
The source and destination directory trees are completely synchronized.
0×01 1 One or more files were copied successfully (that is, new files have arrived).
0×02 2 Some Extra files or directories were detected. No files were copied
Examine the output log for details.
0×04 4 Some Mismatched files or directories were detected.
Examine the output log. Housekeeping might be required.
0×08 8 Some files or directories could not be copied
(copy errors occurred and the retry limit was exceeded).
Check these errors further.
0×10 16 Serious error. Robocopy did not copy any files.
Either a usage error or an error due to insufficient access privileges
on the source or destination directories.

Checking return value of a C++ executable through shell script

I am running a shell script on windows with cygwin in which I execute a program multiple times with different arguments each time. Sometimes, the program generates segmentation fault for some input arguments. I want to generate a text file in which the shell script can write for which of the inputs, the program failed. Basically I want to check return value of the program each time it runs. Here I am assuming that when program fails, it returns a different value from that when it succeeds. I am not sure about this. The executable is a C++ program.
Is it possible to do this? Please guide. If possible, please provide a code snippet for shell script.
Also, please tell what all values are returned.
My script is .sh file.
The return value of the last program that finished is available in the environment variable $?.
You can test the return value using shell's if command:
if program; then
echo Success
else
echo Fail
fi
or by using "and" or "or" lists to do extra commands only if yours succeeds or failed:
program && echo Success
program || echo Fail
Note that the test succeeds if the program returns 0 for success, which is slightly counterintuitive if you're used to C/C++ conditions succeeding for non-zero values.
if it is bat file you can use %ERRORLEVEL%
Assuming no significant spaces in your command line arguments:
cat <<'EOF' |
-V
-h
-:
-a whatnot peezat
!
while read args
do
if program $args
then : OK
else echo "!! FAIL !! ($?) $args" >> logfile
fi
done
This takes a but more effort (to be polite about it) if you must retain spaces. Well, a bit more effort; you probably use an eval in front of the 'program'.

How to capture ping's return value in C++

Does anyone know, how to capture ping's return value in c++? According to this link:
ping should return 0 on success, 1 on failure such as unknown host, illegal packet size, etc. and 2 On a unreachable host or network.
In C++ I called ping with the system (), e.g. int ret = system("ping 192.168.1.5");.
My problem is, that ret's value is 0 or 1. It will never 2! If I think correctly, this is because, this return value I get, is the system functions return value, not ping's. So how could i get ping's return vlaue?
Thanks in advance!
kampi
Edit:
Right now i use this system("ping 192.169.1.5 > ping_res.txt"); but i don't want to work with files (open, and read them), that's why i want to capture, th return value , if possible :)
If you are on Windows, it might be better to use IcmpSendEcho2 directly to implement the ping functionality in your application.
A simple solution would be pipe the output of ping to to a file and read it.
E.g.
system("ping 192.169.1.5 > ping_res.txt");
And read ping_res.txt to get the info you need.
From man 3 system on Linux:
RETURN VALUE
The value returned is -1 on error (e.g. fork(2) failed), and the return status of the command otherwise. This latter return status is in the format specified in wait(2).
Then from man 2 wait on Linux:
If status is not NULL, wait() and waitpid() store status information in the int to which it points. This integer can be inspected with the following macros (which take the integer itself as an argument, not a pointer to it, as is done in wait() and wait- pid()!):
WIFEXITED(status)
returns true if the child terminated normally, that is, by calling exit(3) or _exit(2), or by returning from main().
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.
From sys/wait.h on Linux:
# define WEXITSTATUS(status) __WEXITSTATUS(__WAIT_INT(status))
From bits/waitstatus.h on Linux:
/* If WIFEXITED(STATUS), the low-order 8 bits of the status. */
#define __WEXITSTATUS(status) (((status) & 0xff00) >> 8)
In other words, you will wan to use these macros if you are using Linux. Are you using HP-UX? I notice you link to information for HP-UX. If so, what does your man 3 system page say?
Also, keep in mind that system invokes "sh -c command" and you will receive the return value of sh:
EXIT STATUS
The following exit values shall be returned:
0 The script to be executed consisted solely of zero or more blank lines or comments, or both.
1-125 A non-interactive shell detected a syntax, redirection, or variable assignment error.
127 A specified command_file could not be found by a non-interactive shell.
Otherwise, the shell shall return the exit status of the last command it invoked or attempted to invoke (see also the exit utility in Special Built-In Utilities).
What return value do you find if you attempt, e.g., system("exit 203");?
So you just want to know the return value: i.e. "0 on success, 1 on failure such as unknown host, illegal packet size, etc. and 2 On a unreachable host or network." I think using ping is an overkill in this case. Writing to file and reading from it is apparently a little bit ugly.
I think you should just try **open()**ing a connection to the host on port 7 (Echo). Then you would get the information that ping return value would tell you. If you further want to get response durations, you can measure it yourself by sending arbitrary data to the host on echo port. It would take some time to write the code but i think it's worth for flexibility and accuracy.