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

Hi,

I have a problem with my code. I'm writing a program to parse a list of apache config files, and print out all the Listen directives e.g. Listen 1.2.3.4, followed by the corresponding hostname.

This is my hash to store the information it parses:

if(/\s*Listen\s+(\S*)/){ $instdetails{$instnum}{Listen}{$1}=1; $instdetails{$instnum}{Listen}{$1}{host}=gethost($1); next; }

However when it comes to printing out the hash, the hostname is the same on each line, eventhough the ip address changes. e.g.

1.2.3.4 www.test.com
5.6.7.8 www.test.com
4.3.2.1 www.test.com
etc.

This is the code I'm using:

printf "\n%-20s","Listen:"; $hashref=$instdetails{$instnum}{Listen}; foreach $listen(keys %$hashref){ $host=$instdetails{$instnum}{Listen}{$listen}{host}; printf "\n%-20s$listen ($host)",""; }

Can anyone see my mistake?

Thanks,

js1.

2006-08-16 Retitled by holli, as per Monastery guidelines
Original title: 'problem in code'

Replies are listed 'Best First'.
Re: Problem parsing Apache configuration
by McDarren (Abbot) on Aug 16, 2006 at 12:25 UTC
    A couple of quick comments:
    • Your pattern match does not account for the fact that the Listen directive may also include a listening port, ie: 1.2.3.4:8080
    • You don't tell us anything about your gethost() method. Are you sure that it always returns a meaningful value?

    Here is a bit of working (tested) code that emulates what you are trying to do (except for poulating the hash), and does hostname lookups using gethostbyaddr. Perhaps this will help:

    #!/usr/bin/perl -w use strict; use Socket; while (<DATA>) { if (/^Listen/) { chomp; my ($ip) = $_ =~ m/^Listen\s([\d\.]+):?/; my $host = gethostname($ip) || "unknown"; print "IP:$ip HOST:$host\n"; } } sub gethostname { my $ip = shift; my $iaddr = inet_aton($ip); return gethostbyaddr($iaddr, AF_INET); } __DATA__ Listen 1.2.3.4 Listen 5.6.7.8:9735 rubbish Listen 209.131.36.158 Listen 11.12.1.4:8080 more rubbish
    Output:
    IP:1.2.3.4 HOST:unknown IP:5.6.7.8 HOST:unknown IP:209.131.36.158 HOST:f1.www.vip.sp1.yahoo.com IP:11.12.1.4 HOST:unknown

    To check the contents of your hash, you might consider using Data::Dumper.

    Cheers,
    Darren

Re: Problem parsing Apache configuration
by friedo (Prior) on Aug 16, 2006 at 12:31 UTC
Re: Problem parsing Apache configuration
by bangers (Pilgrim) on Aug 16, 2006 at 12:12 UTC
    You appear to be grabing everything after the space following 'Listen', you need to take it from the next space:
    if(/\s*Listen\s+\S+\s+(\S*)/){
Re: problem in code
by js1 (Monk) on Aug 16, 2006 at 12:47 UTC

    This is my gethost method. I had taken the ports into account.

    sub gethost{ my ($val)=@_; if($val=~/(\d+\.\d+\.\d+\.\d+)/){ my $host=gethostbyaddr(inet_aton($1),AF_INET); return $host; } return ""; }

    If I use print the hash values after they're assigned, I get the expected output. It's just when I try to reuse the hash, the host values seem to be all the same.

    if(/\s*Listen\s+(\S*)/){ $instdetails{$instnum}{Listen}{$1}=1; $instdetails{$instnum}{Listen}{$1}{host}=gethost($1); print ERR "$instnum $listen $instdetails{$instnum}{Listen}{$1}{ +host}"; next; }

    Also I don't want take this off topic, but I can't use a module for this. I'm distributing the script to a large num of servers, which all have different versions of perl.

Re: Problem parsing Apache configuration
by js1 (Monk) on Aug 16, 2006 at 12:56 UTC

    I've fixed it by commenting out the other line:

    if(/\s*Listen\s+(\S*)/){ #$instdetails{$instnum}{Listen}{$1}=1; $instdetails{$instnum}{Listen}{$1}{host}=gethost($1); next; }