dguntner has asked for the wisdom of the Perl Monks concerning the following question:

Greetings, Oh Most Monkly of Monks! :-)

My quest to produce a script which will give me a sorted list of hosts pinged is coming along nicely, thanks to some people here who pointed me in the right direction to find the information I needed to get started. All was going along pretty well, until I decided to Get Clever and have it return the hostname of an IP being pinged. That's when it Got Interesting. :-) Now when I try to run the script, I get:

Use of uninitialized value in printf at ./pingit.pl line 33.

Line 33 is the printf line which says the host is alive. Here's the script so far:

#!/usr/bin/perl -w # # Ping a range of IP addresses, and list sorted by ping time. # # This uses the ICMP echo method instead of UDP echo, as # some routers don't pass UDP echo. Also, if the remote host # doesn't have an appropriate service listening on the UDP # echo port, it won't answer. # # D. Guntner, 21-July-2007 # Ver 1.0, 21-July-2007 use Net::Ping; use Net::Netmask; die "I need root privs to run, dude.\n" unless $> == 0; # Get the IP address(es) my $netaddr = shift(@ARGV); usage() unless $netaddr; # Give usage message if no input my $hostname=""; my $block = new Net::Netmask($netaddr); my @hosts = $block->enumerate(); my $p = Net::Ping->new("icmp"); $p->hires(); # Comment out this line if no Time::HiRes installed # (Or better yet, install Time::HiRes... :-) ) foreach $host (@hosts) { ($ret, $duration, $ip) = $p->ping($host, 5.5); if ($ret) { printf("%s [ip: $ip] is alive %.2f ms)\n", gethostbyip($host), 10 +00 * $duration); } } $p->close(); sub gethostbyip { use Socket; my $hostip = @_ ; my $iaddr = inet_aton($hostip); my $hostname = gethostbyaddr($iaddr, AF_INET); return $hostname; } sub usage { use File::Basename; my $progname = basename($0); print <<"EO_USAGE"; This script will ping scan a range if IP addresses, and return a list sorted by ping time. Give address in CIDR format. Usage: $progname {IP/NETMASK} Example: $progname 1.2.3.4/24 You *could* put in only a single IP address, but there wouldn't be much point to that, now would there? :-) EO_USAGE exit; }
No, it's not actually doing the sort yet. :-) I'm still making sure it pings all hosts and returns the right values. I *could* do without the host names if I had to, but it would be nice to have them. I'm at a loss as to what value is uninitialized, however. It doesn't seem to matter if I put "1.2.3.4" as an address or "1.2.3.4/24" (just as an example - I'm not actually using those as input when I run this) as one; the error message keeps coming up. Anyone know what it might be talking about?

--Dave

Replies are listed 'Best First'.
Re: Getting "uninitialized value" that I can't figure out...
by syphilis (Archbishop) on Jul 22, 2007 at 05:15 UTC
    You can probably deduce where the uninitialized value lies by examining carefully the output of the printf().
    I expect it's the gethostbyip($host) that's returning undef. In the getgostbyip sub you'll want to replace my $hostip = @_; with my $hostip = $_[0];. The way you've got it coded, $hostip will be set to the number of elements in @_ (which is "1" in this case.)

    Cheers,
    Rob
      That took care of it! Thanks!

      --Dave

Re: Getting "uninitialized value" that I can't figure out...
by jZed (Prior) on Jul 22, 2007 at 05:20 UTC
    You could add checks for $ip and $duration in your if($ret) condition. Or you could do sometheting like:
    $ip = "No IP found" unless defined $ip; $duration = "No Duration found" unless defined $duration;
    That will let you see exactly in which circumstances you are getting undefined values and which values are undefined. Generally it's a good idea to check for definedness of values and either skip trying to print them or else substitute a default value.
      Thanks, ikegami & jZed. The one I was trying at the time did have a hostname, so it wasn't that which was causing my immediate problem. However, once I applied the fix suggested by syphilis, I was no longer getting the undefined message. Then I did a range, and sure enough, as soon as I hit an address that didn't have a name, the undefined message came back. I applied a version of your '$ip = "no name" unless' fix, and now that part is working just great!

      --Dave

      The added benefit is that the question then changes from Why does this printf produce an undef warning? to Why does gethostbyip($host) return undef?.

      print is your friend...
        Are you saying that using print instead of printf there would have given a better idea as to what was causing the error? Yea, the problem is resolved now, but your statement has me curious. Always nice to know if something like that will help me in the future... :-)

        --Dave

Re: Getting "uninitialized value" that I can't figure out...
by ikegami (Patriarch) on Jul 22, 2007 at 05:19 UTC

    Looks like gethostbyip returns undef which means gethostbyaddr returned undef.

    Not every IP address has a name associated with it. gethostbyip should return the IP address in that case.

    Or maybe there was a DNS error while looking up the host name.