system() not working as expected with %ERRORLEVEL% - c

I was trying to find a way to see if a host is alive in C on Windows so I ran system with a ping command and then ran system checking %ERRORLEVEL% but it was always showing 0 even if the host was not reachable.
system("ping -w 1000 -n 1 192.168.0.4 | findstr /r /c:\"[0-9] *ms\"");
system("echo %ERRORLEVEL%");
Furthermore even I system call something that will defintely fail like:
system("call dir");
system("echo %ERRORLEVEL%");
%ERRORLEVEL% will still print a 0. Even after the call command failed with:
"'poop' is not recognized as an internal or external command,
operable program or batch file".
Moreover I noticed some strange behavior that if I tried to see the %ERRORLEVEL% on the same command as the ping in cmd:
ping -n 1 192.168.0.1 | findstr /r /c:"[0-9] *ms" & echo %ERRORLEVEL%
it would always return the previous %ERRORLEVEL%. For example if i pinged 192.168.0.1 which is reachable I would 1 or 0 depending on my last command. But if I ran the command again I would get 0. Now if I checked 192.168.0.4 which is not reachable I would get 0. But if I checked it again I would get 1.
Can anyone help me possibly find a better way to see if hosts are available or find out what im doing wrong with %ERRORLEVEL% and system()?

Each call to system() spawns a new instance of cmd.exe, that is why you are losing the error info. The return value of system() is defined as an "implementation-defined value", but it is usually the exit code of the spawned process.
Or, you can use CreateProcess() to run ping directly, and use GetExitCodeProcess() to get its exit code.
Or, simply don't run ping at all. You can use IcmpSendEcho() (or related function) instead.

With each system call you spawn a new cmd shell. So the exit value of a program run in a previous shell (system call) is not available in the next one.
To get the exit value and use it, make a batch job that you run with the system command. All commands in the batch job (.bat) are executed in the same shell so the exit value of the previous command is available for your echo.

The WinAPI function IcmpSendEcho will check if a host is alive. You can see if the host received the request when IcmpSendEcho is finished and the response is stored in the ICMP_ECHO_REPLY structure. Check the Status member for details about the request.

Related

How to stop a .bat process from within

So, I have a program for the Windows Command Prompt, which is for changing the directory (so I can go to a language directory without having to do cd everytime)
and I want to kill it after I select an option. However, I have tried some
methods, which do one of the following:
a. taskkill /IM ... (blows up with a process not found error)
and
b. exit [as shown here] (does what I want, but it also closes the command prompt)
This is my program (the important part):
:C++
cd C:\Users\S.G.\Documents\C++ Scripts
echo What's in C++ Scripts:
dir
pause
exit
:Python
cd C:\Users\S.G.\AppData\Local\Programs\Python\Python36-32
echo What's in Python:
dir
exit
The reason why I'm stuck as to how one does this is because say I choose option "C++".
If I choose it, it runs what I have described, but it also runs the "Python" function. If I run the "Python"function however, it runs fine and doesn't display whatever's in the "C++" function.
Why is function "C++" also running "Python" when I intend not to?
You should use exit /b, followed by an optional error code (eg. exit /b 0). An alternative way to do this is to skip to the end of the file using GOTO:EOF.

Using call <file.bat> results in "sleep is not recognized as an internal or external command.."

I have a script that calls other commands in a for loop:
for %%x in (%CMDS::= %) do (
call C:\%%x %1%
echo "%%x complete"
)
However, running this results the console spitting out :
'sleep' is not recognized as an internal or external command,
operable program or batch file.
This is because the files i loop through and run have these commands in them. Why is it that if i run these files one by one they work, but when chained using call they don't? I can sleep in my terminal outside of this script..
Regards
Thanks to another answer, I solved this error by replacing sleep 5 in my .bat file with:
powershell -Command "& {sleep 5}"
Works fine now. Better still, also tested Stephan's suggestion:
timeout 5
Simpler, and shows a nice message like
Waiting for 0 seconds, press a key to continue ...
Note that some Windows versions require the /t option to define the time.
timeout /t 5
There is no sleep command in batch. That's why you are getting this error.
EDIT:
There is no sleep command in Windows CMD or Batch. BUT: as you can use the command in your console, I suppose there might be a script or a program called sleep. This script or program might be situated in your working directory or in some other directory included in your %PATH% variable. If this is the case, it's possible that your script gives you this error because of a path issue.
Say, you are in C:\SomeFolder and there is a sleep.exe in there. You are calling another script or command which changes the current directory to D:\AnotherFolder. Now another script or command tries to execute your mysterious sleep command assuming the working dir to be C:\SomeFolder but as you are in a different folder (D:\SnotherFolder) now, sleep can't be found. Further, when using call the variable scope of the calling script becomes also the scope for the called script. So it's also possible that variables are being overwritten by different scripts. Such a variable might contain the path to your sleep command. This could also cause an error.

cygwin getting invoked and end of stack error in bat file

I am running the following bat file and got an error
assertion "root_idx != -1" failed:
file "/ext/build/netrel/src/cygwin-1.7.1-1/winsup/cygwin/mount.cc",
line 363, function: void mount_info::init()
Stack trace: Some random stack trace
ENd of stack Trace
batch code
#echo off
:top
set /a run=1
echo "Beginning of Loop"
echo %run%
wmic process where "name like '%%java%%' and CommandLine like '%%abc%%'" get caption, CommandLine | findstr "abc" 1>nul || set /a run=0
if %run%==0 (
echo "Process Not Running"
start cmd /c 'path to file')
echo "Taking a Pause"
sleep 10
goto :top
Why is cygwin getting invoked in the first place?
and why did i get the error and the infinite loop halted (the loop checks for the existence of a program and starts it if it is killed somehow
Don't know how to avoid the Cygwin error but if you don't want it to be invoked, check your PATH variable so that the Cygwin path is not in it, or at least it is at the end of the path list.
This is a Cygwin bug http://cygwin.1069669.n5.nabble.com/cygwin-crash-assertion-quot-root-idx-1-quot-failed-reliably-reproduced-on-my-system-td2659.html.
In my case it started to reproduce after some build processes (and the Cygwin consoles associated with them) got into Suspended state. I saw it with the Process Explorer tool (the one from https://live.sysinternals.com/).
I don't know the cause why they were suspended. Perhaps the parent process was killed at the moment they waited for something. It does not really matter. But what does matter is that after that every new Cygwin console hanged when I opened it. The fix for me was to find the old suspended Cygwin processes and kill them.
Why is cygwin getting invoked in the first place?
When you run something in the cmd.exe, but your PATH is configured to use Cygwin it tries to run your command in Cygwin first (depending on the order in the PATH).
why did i get the error and the infinite loop halted
I suppose you had the same issue like me. That is every new Cygwin console hangs until you kill the first problematic one.

Jenkins always considers a build successful using batch/bat

I just joined a company that uses batch files to build a C++ project. The batch does all sorts of things (updates svn, which is now done by jenkins), creates build folders, deletes unnecessary files after building, copies library files to the build folder, etc.
My problem is Jenkins always considers the build successful, even when it´s not. The .bat file creates a file called errormake.txt when something goes wrong. How do I make jenkins read that and mark the build as a failure?
Also, is there any way I can find out the build folder Jenkins created from inside the .bat file (maybe send a variable when I call the batch file)?
This is the single line I'm currently using to call the .bat file:
call "C:\Source\BuildVersion\AppName\build_version.bat"
Edit: Also, this project is split up into several SVN repositories. %SVN_REVISION% is blank. How can I get the correct %SVN_REVISION% from the first repository (the main one)?
To answer each of your questions -
Jenkins always return "SUCCESS", even when the Job actually failed:
Jenkins sets the status of the Job, based on the return-code of the last command
that ran in each "Execute windows batch command" block.
If your last command is copy some.log D:,
Jenkins thinks everything is OK
(If the 'copy' command went fine...)
Use EXIT xx or EXIT /B xx, depending on your OS,
where 'xx' is some integer greater than zero.
How do I make Jenkins mark the build as a failure, based on a log-file:
Use the Text-finder Plugin, as mentioned by sdmythos_gr .
Is there any way I can find out the build folder Jenkins created:
There are a few parameters that are available as environment-variables
for each script that runs under Jenkins - see here for the list of those parameters:
Jenkins Environment Variables.
To your question:
%WORKSPACE% - The absolute path of the workspace
%BUILD_NUMBER% - The current build number, such as "153"
%BUILD_ID% - The current build id, such as "2005-08-22_23-59-59"
(YYYY-MM-DD_hh-mm-ss)
How can I get the correct %SVN_REVISION% from the first repository:
This answer is from the same link:
%SVN_REVISION% - For Subversion-based projects,
this variable contains the revision number of the module.
If you have more than one module specified, this won't be set.
Hope that helps
Jenkins use the windows error code to know whether a build failed or not.
You should return a value different from 0 when your build failed, with "exit /B 1" for example.
On "newer" versions of Windows (I tested on Server 2012 R2), put the following at the end of each Windows batch command:
#EXIT /b %ERRORLEVEL%
This will pass the error code that the cmd.exe received back to the caller (i.e. Jenkins). The "#" turns off echoing so you don't clutter up your log.
If you have multiple lines in the command and want to stop after the first failure, put the following after each line that you want to check (yes, this is not pretty):
#IF NOT %ERRORLEVEL% == 0 EXIT /b %ERRORLEVEL%
For example:
step1.exe
#IF NOT %ERRORLEVEL% == 0 EXIT /b %ERRORLEVEL%
step2.exe
#IF NOT %ERRORLEVEL% == 0 EXIT /b %ERRORLEVEL%
call "C:\Source\BuildVersion\AppName\build_version.bat"
#EXIT /b %ERRORLEVEL%
I'm also going to answer just part of your question.
There is a Text Finder plugin for Jenkins that you could use.
https://wiki.jenkins-ci.org/display/JENKINS/Text-finder+Plugin
You can mark the build as unstable or failed at the end of the build depending on the contents of a file or the console output.
Maybe this could help...
I know the question is quite older but may be useful to some people. To execute your bat file, instead of using following line,
call "C:\Source\BuildVersion\AppName\build_version.bat"
You can use below format,
<someRelativeOrAbsolutePath>\<.batFileName> <param1> <param2> <and so on>
Executing the command in this way inside Execute Windows Batch Command of Build section of Jenkins will use your last return code of the command. ${BUILD_STATUS} will depend on that. And you will not have to modify your script to return some condition based error codes.
As other users have stated your batch files should use "exit /B 1". Here is a trick to chain together your calls causing Jenkins to return a failure if one fails:
call a.bat &&^
echo "a success" &&^
call b.bat &&^
echo "b success"
"&&" denotes that the next action should only run on success (exit code 0). "^" lets us split the command into multiple lines. The downside to this approach is the build progress bar doesn't display accurately.

DOS CMD send failure to Autosys

In Autosys, I have a job that executes a fairly simple DOS batch file (.CMD). How do I communicate back to Autosys if the job has conditionally failed? If it runs and terminates, Autosys reports a success no matter what. I would like to programmatically tell Autosys if the script failed based on conditions determined within.
Any help would be appreciated. Thanks in advance.
You can use ERRORLEVEL, open a DOS box and type 'help if'
These bits are relevant:
C:\help if
Performs conditional processing in batch programs.
IF [NOT] ERRORLEVEL number command
IF [NOT] string1==string2 command
IF [NOT] EXIST filename command
NOT Specifies that Windows should carry out
the command only if the condition is false.
ERRORLEVEL number Specifies a true condition if the last program run
returned an exit code equal to or greater than the number
specified.
%ERRORLEVEL% will expand into a string representation of
the current value of ERRORLEVEL, provided that there is not already
an environment variable with the name ERRORLEVEL, in which case you
will get its value instead. After running a program, the following
illustrates ERRORLEVEL use:
goto answer%ERRORLEVEL%
:answer0
echo Program had return code 0
:answer1
echo Program had return code 1
What you need to do is the last line of your .bat file should say the following:
EXIT /B %ErrorLevel%

Resources