How to get response from "ping -c 1 example.com"? - perl

In BASH can I ping a server like so
for i in $MY_SERVER_LIST; do
if ping -c 1 $i > /dev/null 2>&1; then
# $i is alive
fi
done
and I would like to do the same in Perl, but how do I get the response from
my $response = `ping -c 1 google.com > /dev/null 2>&1`
Question
How do I do the same in Perl, but without using any packages like Net::Ping?

You are interested in the exitcode of ping not the output; forget about the $response and examine the exitcode in $?.

I'd use Net::Ping !
use Net::Ping;
$p = Net::Ping->new();
print "$host is alive.\n" if $p->ping($host);
$p->close();
$p = Net::Ping->new("icmp");
$p->bind($my_addr); # Specify source interface of pings
foreach $host (#host_array)
{
print "$host is ";
print "NOT " unless $p->ping($host, 2);
print "reachable.\n";
sleep(1);
}
$p->close();
http://perldoc.perl.org/Net/Ping.html

Related

Why doesn't my SIGPIPE print the message?

$ perl5.8 -w -e 'if (my $pid=open(my $P, "|-")) {
kill("SIGKILL",$pid); sleep(2); print $P "test1:$pid\n";}; '
Broken pipe
Now I'm trying to catch that broken pipe
$ perl5.8 -w -e '$SIG{PIPE} = sub {print "SIGPIPE\n";return 1};
if (my $pid=open(my $P, "|-")) {
kill("SIGKILL",$pid); sleep(2); print $P "test1:$pid\n"};
$
Nothing at all is printed when I would have expected SIGPIPE. It seems as if it treats my anonymous sub handler as if it was IGNORE instead.
Pretty much any content of the sub does not produce any effect (print, die, change package variable value)
The code doesn't die; if you print something to STDOUT in the end it will print.
What am I missing?
UPDATE : #jm666's answer led me to the issue: the pipe's writes were not flushed; and as such it was too early to get the SIGPIPE. Adding autoflush helped:
$ perl5.8 -w -e 'use IO::Handle ;$SIG{PIPE} = sub {print "SIGPIPE\n"};
if (my $pid=open(my $P, "|-")) {
$P->autoflush(1);
kill(SIGTERM,$pid); sleep(2);;print $P "test1:$pid\n"}; '
SIGPIPE
$
Physical writes to pipes are delayed, so you can catch them on the close. the next prints the message. (added the close $P)
perl -w -e '$SIG{PIPE} = sub {print "SIGPIPE\n";return 1}; if (my $pid=open(my $P, "|-")) { kill("SIGKILL",$pid); sleep(2); print $P "test1:$pid\n";close $P};'
more: http://perldoc.perl.org/perlipc.html

ssh login verification in perl

I am running following lines of code in perl script to find a df output of remote machines. this works fine and gather a info in #df_ret untill until ssh key is uptodate. if public is corrupted or changed, its not showing any sign of error in script. if i run manually then i will be asked for the password.
#df_ret = split /\n/, `ssh -q $server 'df -hP'`;
Is there any way i can verify that if ssh login is successful then this perl script line should be executed else not. been finding many searches on it but could not reach to the ONE. any help?
I have got one solution working as below;
#!/usr/local/bin/perl
my $line = `ssh $server -o 'BatchMode=yes' -o 'ConnectionAttempts=1' true`;
my $error = `echo $?`;
print "Error = $error";
if($error == 0 )
{
print "This is good";
#df_ret = split /\n/, `ssh -q $server 'df -hP'`;
}
else
{
print "This is bad";
}
Check the result of the ssh exec before splitting it:
$text = `ssh -q $server 'df -hP'` or die "unable to ssh\n";
#df_ret = split /\n/, $text;

socat blocking on stdin

I have a bash script as follow on an AIX host, myscript.sh:
MODE="$1"
if [ "$MODE" == "start" ]; then
socat -T100 -lf $LOGF -d -d -d -x TCP4-LISTEN:$LISTENINGPORT,bind=$LISTENINGADDR,reuseaddr,fork EXEC:"$0 proxy" &
PID=$!
echo $PID > $PIDFILE
echo "$0 $MODE started (pid=$PID)"
elif [ "$MODE" == "proxy" ]; then
cat - > $TMPFILE
# process $TMPFILE before the SSL connection.
cat $TMPFILE | socat -T 100 -lf $LOGF -d - OPENSSL:$HOST
rm -f $TMPFILE
Everything is fine when I run:
$ cat somefile | myscript.sh proxy | xxd
The problem raise when I connect to the socat listener with a test script:
my $file = $ARGV[0];
my $fsize = -s $file;
my $socket = IO::Socket::INET->new("127.0.0.1:$port")
or die "Couldn't connect to remote host: $!";
$socket->autoflush(1);
binmode($socket);
open (FILE,$file);
binmode(FILE);
my $buffer ;
while(sysread(FILE, $buffer, $blocksize)) {
print $socket $buffer ;
}
print "sent\n" ;
close (FILE) ;
my $answer = <$socket>;
if (defined($answer)) {
print $answer; # never reached
print "...\n" ;
} else {
die "connection reset by peer\n";
}
In myscript.sh, it blocks on the line:
cat - > $TMPFILE
In the test script, it blocks on the line:
my $answer = <$socket>;
At this point, the data has been received by the socat listener (checked with tcpdump).
However, when I Ctrl+c the test script before the socat timeout, the data goes through the pipe (i.e., the SSL server is eventually contacted).
What am I doing wrong?
Update:
Thanks for the tips about cat and EOF. For the time being, I have worked around the problem like so:
timeout 0.2 cat -u - > $TMPFILE 2>>/dev/null
# process $TMPFILE before the SSL connection.
cat $TMPFILE | socat -T 100 -lf $LOGF -d - OPENSSL:$HOST
It's ugly, and a waste 0.2 seconds, I hope to find a better solution.
But it does the job for now. The 2>>/dev/null part is because AIX complains about an invalid counter (related to the timeout command).
My first thought is that there is no linefeed in the data you're trying to receive with cat - or <STDIN> . Both commands in their default behavior will return data once they have a linefeed or their buffers of the file-descriptor is full (4KB by default in Linux).

How to Convert While/Case statements in bash to perl

Here is the loop in bash:
while [ $# -ge 1 ]; do
case $1 in
-a)
shift
NUM_AGENTS=$1
;;
-h)
shift
HOST_NAME=$1
;;
-t)
shift
TIME_STAGGER=$1
;;
-un)
shift
USER_NAME=$1
;;
-pw)
shift
USER_PASS=$1
;;
-p)
shift
TARGET_PAGE=$1
;;
-s)
shift
COMMON_SID=$1
;;
esac
shift
done
How can i convert this in perl so that the argument would populate the values in the command line
php loadAgent_curl.php $NUM_AGENTS $HOST_NAME $procStartTime $i $TARGET_PAGE $reqlogfile $resplogfile $USER_NAME $USER_PASS $execDelay $COMMON_SID &
------- appended to question:
this certainly helps, and i really appreciate it, is there any way to access these parameters outside the getOptions ? here is rest of the bash script: my $i="0";
my $startTime=date +%s;
startTime=$[$startTime+$NUM_AGENTS+10]
my $PWD=pwd;
my $logdir="\$PWD/load-logs";
system(mkdir $logdir/$startTime);
my $reqlogfile="$logdir/$startTime/req.log";
my $resplogfile="$logdir/$startTime/resp.log";
print "\n";
print "##################\n";
print "LAUNCHING REQUESTS\n";
print " HOST NAME : \$HOST_NAME\n ";
print " TARGET PAGE : \$TARGET_PAGE\n ";
print " # AGENTS : \$NUM_AGENTS\n ";
print " EXECUTION TIME : \$startTime (with random stagger between 0 and \$TIME_STAGGER seconds)\n ";
print " REQ LOG FILE : $reqlogfile\n ";
print " RESP LOG FILE : $resplogfile\n ";
print "##################\n";
print "\n";
#
#
highestStart=$startTime
$startTime += $ARGV[0] + 5;
my $dTime = localtime( $startTime );
print "\n##################\nLAUNCHING REQUESTS\n
COUNT: $ARGV[0]\n
DELAY: | 1 \n
The scripts will fire at : $dTime\n##################\n\n";
while ( $ARGV[0] > $i )
{
$i++;
system("php avtestTimed.php $ARGV[0] $ARGV[2] $startTime");
print "RUN system('php avtestTimed.php $ARGV[0] $ARGV[2] $startTime'); \n";
sleep 1;
}
#
#
while [ $NUM_AGENTS -gt "$i" ]
do
i=$[$i+1]
execDelay=$((RANDOM % $TIME_STAGGER))"."$((RANDOM % 100))
procStartTime=$[$startTime]
procStartTime=$[$startTime+$execDelay]
if [ $procStartTime -gt $highestStart ]
then
highestStart=$procStartTime
fi
echo "STATUS: Queueing request $i with a delay of $execDelay seconds"
echo " '--> COMMAND: php loadAgent_curl.php $NUM_AGENTS $HOST_NAME $procStartTime $i $TARGET_PAGE $reqlogfile $resplogfile $USER_NAME $USER_PASS $execDelay $COMMON_SID"
php loadAgent_curl.php $NUM_AGENTS $HOST_NAME $procStartTime $i $TARGET_PAGE $reqlogfile $resplogfile $USER_NAME $USER_PASS $execDelay $COMMON_SID &
sleep 1
done
echo "STATUS: Waiting for queued requests to be ready"
while [ date +%s -lt $startTime ]
do
sleep 1
done
#
echo "STATUS: Waiting for last request to issue"
while [ date +%s -lt $highestStart ]
do
sleep 1
done
#
echo "STATUS: Last response issued"
#
echo "STATUS: Waiting for response log file to be created"
while [ ! -e "$resplogfile" ]
do
sleep 1
done
#
while [ wc -l "$resplogfile"| awk '{print $1'} -lt $NUM_AGENTS ]
do
#echo "(wc -l "$resplogfile"| awk '{print $1'} of $NUM_AGENTS responses recorded)"
sleep 1
done
echo "STATUS: FINISHED"
while true; do
read -p "Do you wish to view the request log? [y/n]" yn
case $yn in
[Yy]* ) cat $reqlogfile; break;;
[Nn]* ) exit;;
* ) echo "Please answer yes or no.";;
esac
done
while true; do
read -p "Do you wish to view the response log? [y/n]" yn
case $yn in
[Yy]* ) cat $resplogfile; break;;
[Nn]* ) exit;;
* ) echo "Please answer yes or no.";;
esac
done
Getopt::Long library is a standard Perl way to process command line options.
Something like this will work. Not tested - caveat emptor!
Please note that since your PHP parameters are a mix between command line options AND some unidentified variables, I have designed the first example so that ALL the possible options should be stored in %args hash (e.g. your program should use $args{procStartTime} instead of $procStartTime). This allowed me to make it very short and generic.
If this is hard to read/understand, I also have a second example that's more straightforward but less generic
use Getopt::Long;
my #php_arg_order = qw(a h procStartTime i p reqlogfile
resplogfile un pw execDelay s);
my %args = map {$_ => ""} #php_arg_order;
$args{procStartTime} = "something";
$args{reqlogfile} = "a.log";
# More defaults for variables NOT passed in via command line.
# Populate them all in %args as above.
# Now load actual command line parameters.
GetOptions(\%args, map { "$_=s" } #php_arg_order) or die "Unknown parameter!\n";
system(join(" ",
"php", "loadAgent_curl.php",map { $args{$_} } #php_arg_order}, "&"));
A second, less advanced but more direct option is:
use Getopt::Long;
my %args = ();
# Now load actual command line parameters.
GetOptions(\%args,
"NUM_AGENTS|a=s"
,"HOST_NAME|h=s"
,"USER_NAME|un=s"
# ... the rest of options
# The "XXX|x" notaion allows using alias "-x" parameter
# but stores in $args{XXX} instead for better readability
) or die "Unknown parameter!\n";
system("php loadAgent_curl.php $args{NUM_AGENTS} $args{HOST_NAME} $procStartTime $i $args{TARGET_PAGE} $reqlogfile $resplogfile $args{USER_NAME} $args{USER_PASS} $execDelay $args{COMMON_SID} &");

How can I ping a host with a Perl one-liner with Net::Ping?

Trying to integrate the following Perl one-liner into a shell script. This code works within a Perl script but not as a one-liner executed from a shell script.
I've tried replacing $host with a real hostname with no luck.
#!/bin/ksh
hosts="host1 host2 host3"
PERL=/usr/bin/perl
# Check to see if hosts are accessible.
for host in $hosts
do
#echo $host
$PERL -e 'use Net::Ping; $timeout=5; $p=Net::Ping->new("icmp", $timeout) or die bye ; print "$host is alive \n" if $p->ping($host); $p->close;'
done
The single quotes in the shell stop the $host from being interpreted. So you can just stop and restart the single quotes as required:
perl -MNet::Ping -e 'if (Net::Ping->new("icmp", 5)->ping("'$host'")) {print "'$host' is alive\n"}'
Alternatively, you can pass the host in as a parameter - see the other answer.
Try to replace $host:
$PERL -e 'use Net::Ping; $timeout=5; $p=Net::Ping->new("icmp", $timeout) or die bye ; print "$host is alive \n" if $p->ping($host); $p->close;'
with $ARGV[0], the first command line argument:
$PERL -e 'use Net::Ping; $timeout=5; $p=Net::Ping->new("icmp", $timeout) or die bye ; print "$ARGV[0] is alive \n" if $p->ping($ARGV[0]); $p->close;' $host
If you want to use Perl, then use the Perl interpreter to run your script.
#!/usr/bin/env perl -w
use Net::Ping;
$timeout=5;
$p=Net::Ping->new("icmp", $timeout) or die bye ;
#hosts=qw/localhost 10.10.10.10/;
foreach my $host (#hosts) {
print "$host is alive \n" if $p->ping($host);
}
$p->close;
Otherwise, you might as well use the ping command directly from the shell
#!/bin/bash
for hosts in host1 host2 host3
do
if ping ...... "$hosts" >/dev/null ;then
.....
fi
done