Written by James McDonald

March 5, 2009

Just been trying to create a Perl script to run ping and return results

#!/usr/bin/perl

use strict;

# this is a heap of notes to try and come to grips with Perl
# a bit better.
# 
# Looks at how the system() call works
#
# How to build the command arguments to get 
# shell redirection working inside system()
#
# What the return value from system() means and how return it
# 
# Using bitwise `&' and  bitwise `>>' to pull 
# the correct value from the system() return value
#

my $down = 1;	# in perl 1 is true 0 is false -1 is also true
		# undefined is false
		# e.g. perl -e 'if($blah){ print "It is true\n" };'
		# prints nothing
		# defined is true
		# e.g. perl -e 'my $blah="Anything"; if($blah) {print "It is true\n"};'
		# returns It is true
		#
my $sleep = 1; # time in seconds for loop to sleep


my $host = "220.233.0.3"; # my ISP's DNS Server
		       # successful ping returns 0
		       # failed ping reply returns 1

#$host = "192.168.1.1"; # bogus IP to test ping exit value
		       # system() returns 256 
		       # equals ping's exit value of 1

#$host = "www.notahostblahlahlah.com"; 
                        # bogus hostname to test ping exit value
			# returns "ping: unknown host www.notahostblahlahlah.com"
			# system() returns 512 ( 100 000 000 )
			# equals child (ping's) exit value of 2

while($down) {
	# for some reason I couldn't give the recommended array of args
        # @args = ( "ping", "-c 2", "-W 2", $host, '2>&1 > /dev/null');
	# this returns "ping: unknown host 2>&1 > /dev/null"
	
	# this works however if it's one argument only
	my @args = ('ping -c 2 -W 4 ' . $host . ' 2>&1 > /dev/null');

	# this test is to trigger the -1 if block
	# @args = ("badjh");
	# returns "failed: No such file or directory"
	print "Start Ping\n";
	system(@args) ; 
	print "End Ping\n";

	# don't do the normal 
	# system(@args) == 0 or die "Blah blach $!\n";
	# because we want to test $? as below

	# can't do a succesful bit shift on -1
	# e.g.
	# perl -e 'print -1 >> 8'
	# returns: "16777215"
	# 
	print "Checking/Converting return value $?\n";
	if ($? == -1) { 
		print "failed: $!\n";
		$down = 0; # it's still down continue loop and ping test
	} elsif ( $? & 127 ) {
		
		# the docs (perldoc perlfaq8) say re system() calls return value:
		#
		# system() runs a command and returns exit status information 
		# (as a 16 bit value: the low 7 bits 
		# are the signal the process died from, if any, 
		# and the high 8 bits are the actual exit value).
		#
		# this section of the if statement code checks
		# for signal the process was killed by 
		# try running this script and pressing control C
		# to trigger this block
		#
		# so my question from reading the docs was:
		# if you have the low 7 doing the signal process bit
		# and the high 8 doing the called programs exit value
		# what is that bit doing in the middle?
		#
		# e.g.
		# Bits number from lowest value (right) to highest value (Left)
		# 16 15 14 13 12 10 09 08 07 06 05 04 03 02 01
		# |-----high 8 ------| ?? |-------low 7------|    
		#
		# the answer is that number eight bit is 
		# the "core dumped" bit as this code from the web
		# shows 
		#
		printf "child died with signal %d, %s coredump\n",
		($? & 127), ($? & 128) ? 'with' : 'without';

		# so if the binary value has the 8th bit set 
		# it indicates a core dump occurred 
		# 
		# we don't need to do any bitwise shifting to get at the low 7 bits
		# because they return the right values unmoved so only `&' is needed
		# 
		# the eight bit is the same because it's either on or off
		#
		# the high 8 need shifting because we want the number as if it was 
		# in the same position as low 7 
		# (huh? it's too late at night I'm going to bed)

	} else {

		# we have gotten to this block because the system() calls child
		# hasn't coredumped or been killed by an external signal
		# and it has completed and exited returning a exit value
		#
		# hopefully zero and success but it could be 
		# any number of other result
		# we are only interested in the high 8 bits
		# that system() has returned on behalf of the child process
		#
		# a system() return value of 256 equals in 16 bit binary:
		# |high 8| |low 7|
		# 0000000100000000
		#
		# we need to shift the high eight right to 
		# make it return the correct value 
		# i.e. the first high 8 bit becomes the lowest bit
		#
				
		my $exit_value = $? >> 8;
		# in effect we are doing the following
		# 0000000100000000 
		# original system() return value is 256
		# so we are now shifting
		# the bits right >> 8 times
		# 0000000010000000 shifted 1 bit to right
		# 0000000001000000 shifted 2 bits to right
		# 0000000000100000 etc
		# 0000000000010000
		# 0000000000001000
		# 0000000000000100
		# 0000000000000010
		# 0000000000000001 
		# shifted 8 bits to right return value becomes 1
		# because the first bits possible values are 0 or 1
		# and this is set as 1 so it's 1 ok?
		

		# This is a table showing the possible 
                # range of numbers that can occur
		# as each bit bit is set going from right to left
		#
		# (16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1)
		#
		# 1st bit set value 1 or not set 0 (0=0 1=1)
		# 2nd bit values 2-3 (2=10 3=11)
		# 3rd bit values 4-7 (4=100 5=101 6=110 7=111)
		# 4rd bit values 8-15 (8=1000 ... 15=1111)
		# 5th bit values 16-31 (etc etc)
		# 6th bit values 32-63
		# 7th bit values 64-127
		# 8th bit values 128-255
		# 9th bit values 256-511
		# 10th bit values 512-1023
		# 11th bit values 1024-2047
		# 12th bit values 2048-4095
		# 13th bit values 4096-8191
		# 14th bit values 8192-16383
		# 15th bit set possible values ranges are 16384-32767
		# 16th bit value 32768-65535

		printf "child exited with value %d\n", $exit_value ;
		
		if ($exit_value == 0) {
			print "Successful ping exiting\n";
			$down = 0;
		}
	}

	sleep $sleep;

}

2 Comments

  1. Phil Goetz

    Yes; but what do the numbers returned mean?

    Reply
  2. admin

    That depends on what the system() call is launching. Each program returns a different return result.

    For the ping example above: Try the following in bash shell
    ping localhost
    echo $?
    returns 0
    ping ahostthatresolvestoanIPbutWontReply
    echo $?
    returns 1
    ping adjflkajlkd
    echo $?
    returns 2

    Reply

Submit a Comment

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

The reCAPTCHA verification period has expired. Please reload the page.

You May Also Like…

Squarespace Image Export

To gain continued access to your Squarespace website images after cancelling your subscription you have several...

MySQL 8.x GRANT ALL STATEMENT

-- CREATE CREATE USER 'tgnrestoreuser'@'localhost' IDENTIFIED BY 'AppleSauceLoveBird2024'; GRANT ALL PRIVILEGES ON...

Exetel Opt-Out of CGNAT

If your port forwards and inbound and/or outbound site-to-site VPN's have failed when switching to Exetel due to their...