Perl system() call return results

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 *

You May Also Like…

How to Research a CPU Upgrade

How to Research a CPU Upgrade

Upgrade Time! Doing a lot of VMWare Workstation virtualization to create labs for self-study and training. Finding...