#!/usr/bin/perl # Makefile for Net::Ident # # $Id: Makefile.PL,v 1.57 1999/08/27 00:00:09 john Exp $ use strict; use ExtUtils::MakeMaker qw(:DEFAULT prompt); use Getopt::Long; use Pod::Text; use Socket; use FileHandle; use FindBin qw($Bin); $| = 1; my $intro = < "Produce this helptext", 'force-compat|c' => q{ Force installation of Net::Ident compatible with version 1.11. By default, the installer checks if version 1.11 is installed, and if so, offers the option to install the compatible version. Here ``compatible'' means that C will install the C method in package C.}, 'test-apache|a' => q{ Makes the installer go into the dialogue to configure the apache mod_perl test. This is normally only done when a few basic almost fail-safe tests confirm that you can run this test.}, ); # files that need adapting when we install compatibility mode my @compat_files = qw(Ident.pm); # option processing GetOptions(keys %options) or $opt_help++; # provide help if necessary if ( $opt_help ) { open(POD, "|-") or pod2text("<&STDIN", *STDOUT), exit 0; print POD "=head1 Net::Ident installation\n\n"; print POD $intro; print POD "=over 4\n\n"; for my $opt ( sort keys %options ) { my $txtopt = join(" ", map { "-" x (length > 1 ? 2 : 1) . $_ } split /\|/, $opt ); print POD "=item $txtopt\n\n"; $options{$opt} =~ s/^\s+//mg; print POD $options{$opt}, "\n\n"; } print POD "=back\n\n"; exit 0; } # check and ask if we possibly need compatibility-install sub check_compat () { my $forcetxt = <0 or ($c,$p)=/@@(\d*) (.*) @@/}, @compat_files); } # initial checks to see if apache is possible at all sub check_initial_apache ($) { my $apinfo = shift; print "\nChecking for Apache.pm... "; eval { require Apache }; if ( $@ ) { print "not found\n"; return; } print "found version $Apache::VERSION\n"; $apinfo->{Apache_pm_version} = $Apache::VERSION; print "Checking for mod_perl.pm... "; eval { require mod_perl }; if ( $@ ) { print "not found\n"; return; } print "found version $mod_perl::VERSION\n"; $apinfo->{mod_perl_pm_version} = $mod_perl::VERSION; print "Checking for identd... "; my $tcpproto = getprotobyname('tcp') || 6; my $identport = (getservbyname('ident', 'tcp'))[2] || 113; socket(S, PF_INET, SOCK_STREAM, $tcpproto) or die "socket: $!\n"; if ( ! connect(S, sockaddr_in($identport, inet_aton("127.1"))) ) { print "cannot connect: $!\n"; return; } print "OK\n"; close S; my $forcetxt = <autoflush(1); if ( ! connect(S, sockaddr_in($httpport, inet_aton("127.1"))) ) { print "You don't have a webserver running: $!\n\n$forcetxt"; return; } print S "HEAD / HTTP/1.0\r\n\r\n"; my $reply; { # slurp in reply in one go local $/ = undef; $reply = ; } close S; if ( $reply !~ m{^Server:.*mod_perl/([\d.]+)\b}mi ) { print "Your webserver isn't mod_perl enabled\n\n$forcetxt"; return; } print "you have mod_perl/$1\n"; $apinfo->{mod_perl_parsed_version} = $1; # verify versions... but don't do anything with it, just warn # (can this be the cause of trouble???) if ( $apinfo->{mod_perl_parsed_version} != $apinfo->{mod_perl_pm_version} ) { print <{apache_parsed_version} = $1; } print <$errfile"); exec(@_) or die "Couldn't execute @_: $!\n"; } else { # parent. slurp in output. local $/ = undef; $apout = ; } # wait for child to terminate. close APOUT; # check return status my $error = ''; if ( $? ) { $error = "`@_' returned with a non-zero exit status: " . ($? >> 8) . "\n"; } # check stderr output if ( -s $errfile ) { $error .= "`@_' returned the following on STDERR:\n"; open(ERR, $errfile) or die "odd... opening $errfile: $!\n"; { local $/ = undef; $error .= ; } close ERR; } unlink $errfile; return ($error, $apout); } # parse httpd output and return info sub parse_httpd_version ($$) { my($binary, $arg) = @_; my($error, $apout) = safe_exec_httpd($binary, $arg); return $error if $error; my($version) = $apout =~ m{version.*Apache/([\d.]+)}; my($httpd_root) = $apout =~ m{HTTPD_ROOT="([^"]+)"}; my($httpd_conf) = $apout =~ m{SERVER_CONFIG_FILE="([^"]+)"}; return ("", $version, $httpd_root, $httpd_conf); } # parse the httpd.conf to extract User and Group statements sub extract_usergroup ($) { my $apinfo = shift; my $conf = my $usergroup = ""; $usergroup .= "User $1\n" if $apinfo->{httpd_conf_contents} =~ /^\s*user\s+(\w+)/mi; $usergroup .= "Group $1\n" if $apinfo->{httpd_conf_contents} =~ /^\s*group\s+(\w+)/mi; $usergroup; } # parse the httpd.conf and extract LoadModule and AddModule statements # to make sure mod_perl.c gets loaded sub extract_module_statements ($) { my $apinfo = shift; my $httpdconf = $apinfo->{orig_httpd_conf}; my $conf = $apinfo->{httpd_conf_contents}; # first make sure mod_perl.c is added unless ( $conf =~ /^\s*AddModule\s+mod_perl\.c\s*$/mi ) { print "Cannot find mod_perl.c module in $httpdconf\n"; return; } # remove all comments $conf =~ s/^\s*#.*//gm; # remove runs of empty lines $conf =~ s/^\s*$//gm; # remove all .. and .. parts 1 while ( $conf =~ s{((?:(?!).)*)}{}is or $conf =~ s{((?:(?!).)*)}{}is ); # check that we didn't lose mod_perl.c in the process unless ( $conf =~ /^\s*AddModule\s+mod_perl\.c\s*$/mi ) { print <{apache_root} = $apache_root; # find current apache root my($orig_apache_root) = grep { -d } qw( /usr/local/apache /opt/apache /usr/local/etc/httpd /etc/httpd /Local/Library/WebServer /boot/home/apache /usr/local /usr ); print <{orig_apache_root} = $orig_apache_root = $answ; # find httpd binary my($apache_bin) = grep { -x } map { m-^/- ? $_ : "$orig_apache_root/$_" } qw( httpd sbin/httpd bin/httpd libexec/httpd /sbin/httpd /usr/sbin/httpd /usr/libexec/httpd ); $answ = prompt("Where is your httpd executable?", $apache_bin); if ( ! defined $answ ) { print "cannot find httpd executable, no apache test performed.\n"; return; } if ( ! -x $answ ) { print "$answ is not executable, no apache test performed.\n"; return; } $apinfo->{apache_bin} = $apache_bin = $answ; my($error, $version, $orig_apache_root2, $orig_httpd_conf) = parse_httpd_version($apache_bin, "-V"); if ( ! defined $version ) { # try httpd -v ($error, $version, $orig_apache_root2, $orig_httpd_conf) = parse_httpd_version($apache_bin, "-v"); if ( ! defined $version ) { # now give up print "I cannot use $apache_bin:\n$error\n"; return; } } print "$apache_bin is version Apache/$version\n"; $apinfo->{orig_httpd_conf} = $orig_httpd_conf; # verify this version against running version, if possible if ( $apinfo->{apache_parsed_version} && $version ne $apinfo->{apache_parsed_version} ) { print <{orig_apache_root} = $orig_apache_root = $orig_apache_root2; } my $httpdconf = $apinfo->{orig_httpd_conf}; # find proper httpd.conf if ( ! $httpdconf || ! -r $httpdconf ) { # oh dear. we need the original httpd.conf, but we don't know # where it is exactly, or can't read it. Provide guesses. ($httpdconf) = grep { -r } map { m-^/- ? $_ : "$orig_apache_root/$_" } qw( etc/httpd.conf conf/httpd.conf etc/httpd/httpd.conf Configuration/httpd.conf /usr/local/apache/conf/httpd.conf /usr/local/apache/etc/httpd.conf /opt/apache/conf/httpd.conf /opt/apache/etc/httpd.conf /etc/opt/apache/httpd.conf /etc/httpd/conf/httpd.conf ); } $httpdconf = "$orig_apache_root/$httpdconf" unless $httpdconf =~ m-^/-; $answ = prompt("Where is your httpd.conf?", $httpdconf); if ( ! defined $answ ) { print "I cannot perform the apache test without httpd.conf\n"; return; } if ( ! -r $answ ) { print "Cannot read $answ, cannot proceed without it\n"; return; } $httpdconf = $answ; $apinfo->{orig_httpd_conf} = $httpdconf; # read httpd.conf if ( ! open(CONF, $httpdconf) ) { print "Cannot read $httpdconf: $!\nCannot proceed without it\n"; return; } my $conf; { # slurp in config local $/ = undef; $conf = ; } close CONF; $apinfo->{httpd_conf_contents} = $conf; # extract User/Group info $apinfo->{usergroup} = extract_usergroup($apinfo); # verify mod_perl module is present, if not, find LoadModule statement. my $modlist; ($error, $modlist) = safe_exec_httpd($apache_bin, "-l"); if ( $error ) { print "Odd... `$apache_bin -l' returned an error:\n$error\n"; print "I give up!\n"; return; } # check for mod_perl.c my $LoadModule = ""; if ( $modlist !~ /^\s*mod_perl\.c\s*$/m ) { # not present! we need to find the proper Module statements! print "Oops... mod_perl.c isn't in your standard module list...\n"; $LoadModule = extract_module_statements($apinfo) or return; print <{LoadModule} = $LoadModule; # find a usable port my $port = 2706; my $tcpproto = getprotobyname('tcp') || 6; socket(S, PF_INET, SOCK_STREAM, $tcpproto) or die "socket: $!\n"; $port++ while $port < 2801 && !bind(S, pack_sockaddr_in($port, INADDR_ANY)); close S; if ( $port >= 2801 ) { print "Couldn't find a usable port, strange enough...\n"; return; } $apinfo->{port} = $port; # return success return 1; } # substitute the lot into the config files. sub install_apache ($) { my $apinfo = shift; print <{apache_root}; my $version = $apinfo->{apache_parsed_version}; for my $file ( @configfiles ) { # read .in file open(IN, "$serverroot/$file.in") or die "cannot open $serverroot/$file.in: $!\n"; my $conf; { local $/ = undef; $conf = ; } close IN; # handle $ifversion{}{}. allow 1-level nesting of {} # note: this is a nominee for the "most scary regexp '99" award. # no user serviceable parts inside. flammable. explosive. do not touch. $conf =~ s<\$ifversion([\d.]+)\{([^{}]*(?:\{[^{}]*\}[^{}]*)*)\}\{([^{}]*(?:\{[^{}]*\}[^{}]*)*)\}> < $version ge $1 ? $2 : $3 >gems; # handle $var $conf =~ s{\\(.)|\$(\w+)} { $1 || $apinfo->{$2} }ge; # write config file print "Writing $serverroot/$file ...\n"; open(OUT, ">$serverroot/$file") or die "cannot write $serverroot/$file: $!\n"; print OUT $conf; close OUT; } print < 'Net::Ident', 'VERSION_FROM' => 'Ident.pm', # finds $VERSION 'clean' => {FILES => "t/apache/conf/access.conf t/apache/conf/apache_config.pl t/apache/conf/httpd.conf t/apache/conf/srm.conf t/apache/logs/access_log t/apache/logs/error_log t/apache/perl/inc"}, );