#!/usr/bin/perl
# cpanel12 - install (Tomcat)                Copyright(c) 2004-2007 cPanel, Inc.
#                                                           All rights Reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited

use lib '/usr/local/cpanel', '/scripts';
use strict;
use Carp qw ( croak );
use Sys::Hostname qw( hostname );
use POSIX;
use IPC::Open3;
use SafeFile;
use cPLimits;
use Cpanel::Rand ();
use Cpanel::SafeRun ();
require 'regsrep.pl';

eval {
    require Cpanel::Config;
    if ( defined &Cpanel::Config::is_ea3 ) {
        if ( Cpanel::Config::is_ea3() ) {
            print "This module is now managed via easyapache.\n";
            print "To keep this message from appearing: ";
            print "Remove its entry from /var/cpanel/addonmodules\n";
            exit;
        }
    }
};

my $apache_ver = get_httpd_version();
if ( $apache_ver !~ m/^1\.3/ ) {
    print <<"EOM";


!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Unable to install the Tomcat addon. This addon is designed specifically
for Apache 1.3. You are currently running Apache $apache_ver. This addon
has been included in the latest version of EasyApache.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


EOM
    exit;
}
else {
    print "Detected Apache $apache_ver\n";
}

umask(0022);

my $hostname = hostname();
my ( $sysname, $nodename, $release, $version, $machine ) = POSIX::uname();

if ( $sysname =~ m/freebsd/i ) {
    print "<b>FreeBSD cannot be supported due to lack of Java support from Sun Microsystems.</b>\n";
    exit;
}
elsif ( -e '/var/cpanel/cpresin' ) {
    print "<b>ERROR: Cannot install in conjunction with mod_resin. Please uninstall mod_resin first then try the install again!</b>\n";
    exit;
}

my $jkversion        = '1.2.14.1';
my $jsvcversion      = '1.0';
my $tomcatver        = '5.5.9';
my $mysqlconnversion = '3.0.15';

my $jkfile        = 'jakarta-tomcat-connectors-' . $jkversion . '-src.tar.gz';
my $jsvcfile      = 'daemon-' . $jsvcversion . '.tar.gz';
my $tomcatfile    = 'jakarta-tomcat-' . $tomcatver . '.tar.gz';
my $mysqlconnfile = 'mysql-connector-java-' . $mysqlconnversion . '-ga-bin.jar';

my $javapath   = '/usr/local/jdk/bin/java';
my $mirror     = 'http://layer1.cpanel.net/buildapache/1/';
my $nobodygid  = ( getpwnam('nobody') )[3];
my $tcpass     = Cpanel::Rand::getranddata( 12, 0 );
my $installdir = `pwd`;
chomp $installdir;

cPLimits::unsetrlimits();

print "Checking java installation\n";
system 'perl checkjava';

my $rebuildjsvc = 0;
$ENV{'JAVA_HOME'} = '/usr/local/jdk';

if ( -e '/var/cpanel/cptomcat' ) {
    print "<b>Backing up Tomcat conf files...</b>\n";
    mkdir '/tmp/cptomcat';
    if ( !-d '/tmp/cptomcat' ) { 
        die "Cannot backup config files - cannot continue!\n";
    }
    system 'cp', '-a', '/usr/local/jakarta/tomcat/conf', '/tmp/cptomcat';
    print "<b>Done</b>\n";
}

if ( !-e "/usr/local/jakarta/jakarta-tomcat-${tomcatver}" ) {
    $rebuildjsvc = "1";
    print "<b>Installing TomCat\n</b>";
    system 'perl', $installdir . '/scripts/stoptomcat';
    system 'rm',            '-Rf', '/usr/local/jakarta';
    system 'mkdir',         '/usr/local/jakarta';
    chdir '/usr/local/jakarta' or die "Unable to chdir into /usr/local/jakarta: $!";
    downloadfile( $tomcatfile, $mirror, 0 );
    system 'tar', '-zxf', $tomcatfile;
    symlink '/usr/local/jakarta/jakarta-tomcat-' . $tomcatver, '/usr/local/jakarta/tomcat';
}

chdir '/usr/src' or die "Unable to chdir into /usr/src: $!";

downloadfile( $jkfile, $mirror, 0 );
system 'tar', '-zxf', $jkfile;
chdir '/usr/src/jakarta-tomcat-connectors-' . $jkversion . '-src/jk/native' or die "Unable to chdir: $!";
system './configure', '--with-apxs=/usr/local/apache/bin/apxs';
system 'make';
chdir '/usr/src/jakarta-tomcat-connectors-' . $jkversion . '-src/jk/native/apache-1.3' or die "Unable to chdir: $!";
system '/usr/local/apache/bin/apxs', '-i', '-a', '-n', 'jk', 'mod_jk.so';
system 'libtool', '--finish', '/usr/local/apache/libexec';

# workers.properties
print "<b>Configuring workers.properties...</b>";
regsrep( "/usr/local/jakarta/tomcat/conf/workers.properties", "^[\s\t]*workers.tomcat_home=/var/tomcat3",      "workers.tomcat_home=/usr/local/jakarta/tomcat" );
regsrep( "/usr/local/jakarta/tomcat/conf/workers.properties", "^[\s\t]*workers.java_home=/opt/IBMJava2-13",    "workers.java_home=/usr/local/jdk/jre" );
regsrep( "/usr/local/jakarta/tomcat/conf/workers.properties", '^[\s\t]*worker.inprocess.jvm_lib=.*jvm.dll',    '#worker.inprocess.jvm_lib=\$(workers.java_home)\$(ps)jre\$(ps)bin\$(ps)classic\$(ps)jvm.dll' );
regsrep( "/usr/local/jakarta/tomcat/conf/workers.properties", '^[\s\t]*#worker.inprocess.jvm_lib=.*libjvm.so', 'worker.inprocess.jvm_lib=.*libjvm.so' );
print "<b>Done\n</b>";

# workers2.properties
print "<b>Configuring workers2.properties...</b>";
regsrep( "/usr/local/jakarta/tomcat/conf/workers2.properties", '^[\s\t]*\[logger\]',                                                         '#[logger]' );
regsrep( "/usr/local/jakarta/tomcat/conf/workers2.properties", "^[\s\t]*level=DEBUG",                                                        "#level=DEBUG" );
regsrep( "/usr/local/jakarta/tomcat/conf/workers2.properties", '^[\s\t]*\[lb:lb\]',                                                          '#[lb:lb]' );
regsrep( "/usr/local/jakarta/tomcat/conf/workers2.properties", "^[\s\t]*info=Default load balancer.",                                        "#info=Default load balancer." );
regsrep( "/usr/local/jakarta/tomcat/conf/workers2.properties", '^[\s\t]*\[lb:lb_1\]',                                                        '#[lb:lb_1]' );
regsrep( "/usr/local/jakarta/tomcat/conf/workers2.properties", "^[\s\t]*info=A second load balancer.",                                       "#info=A second load balancer." );
regsrep( "/usr/local/jakarta/tomcat/conf/workers2.properties", '^[\s\t]*\[channel.socket:localhost:8019\]',                                  '#[channel.socket:localhost:8019]' );
regsrep( "/usr/local/jakarta/tomcat/conf/workers2.properties", '^[\s\t]*info=A second tomcat instance.',                                     '#info=A second tomcat instance.' );
regsrep( "/usr/local/jakarta/tomcat/conf/workers2.properties", '^[\s\t]*tomcatId=localhost:8019',                                            '#tomcatId=localhost:8019' );
regsrep( "/usr/local/jakarta/tomcat/conf/workers2.properties", '^[\s\t]*lb_factor=1',                                                        '#lb_factor=1' );
regsrep( "/usr/local/jakarta/tomcat/conf/workers2.properties", '^[\s\t]*group:lb:lb',                                                        '#group:lb:lb' );
regsrep( "/usr/local/jakarta/tomcat/conf/workers2.properties", '^[\s\t]*group:lb:lb_1',                                                      '#group:lb:lb_1' );
regsrep( "/usr/local/jakarta/tomcat/conf/workers2.properties", '^[\s\t]*\[channel.un:/opt/33/work/jk2.socket\]',                             '#[channel.un:/opt/33/work/jk2.socket]' );
regsrep( "/usr/local/jakarta/tomcat/conf/workers2.properties", '^[\s\t]*info=A second channel connecting to localhost:8019 via unix socket', '#info=A second channel connecting to localhost:8019 via unix socket' );
regsrep( "/usr/local/jakarta/tomcat/conf/workers2.properties", '^[\s\t]*\[channel.jni:jni\]',                                                '#\[channel.jni:jni\]' );
regsrep( "/usr/local/jakarta/tomcat/conf/workers2.properties", '^[\s\t]*info=The jni channel, used if tomcat is started inprocess',          '#info=The jni channel, used if tomcat is started inprocess' );
print "<b>Done\n</b>";

print "<b>Configuring tomcat-user.xml...</b>";
regsrep( '/usr/local/jakarta/tomcat/conf/tomcat-users.xml', '^[\s\t]*</tomcat-users>', '  <user name="root"   password="' . "${tcpass}" . '" roles="admin,manager" />' . "\n" . '</tomcat-users>' );
print "<b>Done\n</b>";

if ($rebuildjsvc) {
    print "<b>Installing jsvc...</b>\n";
    chdir '/usr/local/jakarta/tomcat/bin/' or die "Unable to chdir: $!";
    system 'tar', '-zxf', 'jsvc.tar.gz';
    chdir '/usr/local/jakarta/tomcat/bin/jsvc-src/';
    system 'chmod', '+x', 'configure';
    system './configure';
    system 'make';
    system 'cp', 'jsvc', '/usr/local/jakarta/tomcat/bin';
    chdir '/usr/local';
    print "<b>Done<b>\n";
}

print "<b>Installing starttomcat and stoptomcat files...</b>\n";
chdir $installdir . '/scripts';
system 'cp', '-f', 'starttomcat', '/usr/sbin';
system 'cp', '-f', 'stoptomcat',  '/usr/sbin';
system 'cp', '-f', 'jk.conf',     '/usr/local/apache/conf';
chmod '0700', '/usr/sbin/starttomcat';
chmod '0700', '/usr/sbin/stoptomcat';
chown 'root:root', '/usr/sbin/starttomcat';
chown 'root:root', '/usr/sbin/stoptomcat';
print "<b>Done</b>\m";

if ( !getpwnam('tomcat') ) {
    print "<b>Adding TomCat user...</b>";
    nooutputsystem( 'useradd', 'tomcat', '-g', $nobodygid, '-r' );
    print "<b>Done</b>\n";
}

print "<b>Adding includes to httpd.conf...</b>\n";
system 'cp', $installdir . '/scripts/jk.conf', '/usr/local/apache/conf/';
addinclude();
print "<b>Done</b>\n";

print "<b>Adding TomCat to chkserv.d...</b>\n";
system 'cp', '-f', $installdir . '/scripts/tomcat', '/etc/chkserv.d';
system '/etc/init.d/chkservd', 'restart';
print "<b>Done</b>\n";

print "<b>Setting up the web.xml...</b>\n";
setupwebxml();
print "<b>Done</b>\n";

if ( -e '/tmp/cptomcat' ) {
    print "<b>Restoring Tomcat conf files...</b>\n";
    system 'mv', '-f', '/tmp/cptomcat/conf', '/usr/local/jakarta/tomcat';
    system 'rm', '-rf', '/tmp/cptomcat';
    print "<b>Done</b>\n";
}

print "<b>Setting up rc.local...</b>\n";
my $rcl = '/etc/rc.d/rc.local';
if ( !-e $rcl && -e '/etc/rc.local' ) {
    $rcl = '/etc/rc.local';
}
my $rlock = SafeFile::safeopen( \*RCL, '+<', $rcl );
my @RCL = <RCL>;
if ( ( grep( /starttomcat/, @RCL ) )[0] eq "" ) {
    print RCL "/usr/sbin/starttomcat\n\n";
}
SafeFile::safeclose( \*RCL, $rlock );
print "<b>Done</b>\n";

print "<b>Finishing Install...</b>";
system( "chown", "-R", "tomcat:nobody", "/usr/local/jakarta" );
system( "rm", "-rf", "/usr/src/jakarta-tomcat-connectors-1.2.8-src" );
unlink("/usr/src/$jkfile");
unlink("/usr/local/jakarta/${tomcatfile}");
symlink( "/usr/local/jdk/jre", "/usr/local/jre" );
system( "rm", "-rf", "/usr/java" );
symlink( "/usr/local/jdk",               "/usr/java" );
symlink( "/usr/local/jdk/lib/tools.jar", "/usr/local/jakarta/tomcat/common/lib/tools.jar" );
chdir("/usr/local/jakarta/tomcat/common/lib");
downloadfile( $mysqlconnfile, $mirror, 0 );
mkdir( "/usr/local/jakarta/tomcat/samples", 0755 );
opendir( TESTS, "${installdir}/tests" );

while ( my $file = readdir(TESTS) ) {
    next if ( $file =~ /^\./ );
    system( "cp", "-f", "${installdir}/tests/${file}", "/usr/local/jakarta/tomcat/samples" );
}
closedir(TESTS);
system( "cp", "-f", "${installdir}/scripts/addservlets2", "/scripts" );
chown( 0, 0, "/usr/local/cpanel/bin/addservlets" );
chmod( 0700, "/usr/local/cpanel/bin/addservlets" );
system( "cp", "-f", "${installdir}/scripts/gentomcatlist2", "/scripts" );
chown( 0, 0, "/usr/local/cpanel/bin/gentomcatlist" );
chmod( 0700, "/usr/local/cpanel/bin/gentomcatlist" );
print "<b>Done\n</b>";

print "<b>Restarting httpd...</b>";
doomedprocess("httpd");
sleep(3);
system( "/scripts/restartsrv_httpd", "restart" );
print "<b>Done\n</b>";

print "<b>Starting TomCat...</b>";
system("/scripts/gentomcatlist");
sleep(8);
print "<b>Done\n</b>";

print "<b>Install Complete\n</b>";

if ( !-e '/var/cpanel/cptomcat' ) {
    system( 'touch', '/var/cpanel/cptomcat' );
    print "<b><i>The admin url is http://${hostname}:8080/\n";
    print "The admin user is root\n";
    print "The admin password is ${tcpass}</b></i>\n";
}

sub addinclude {
    my $conflock  = SafeFile::safeopen( \*HC, "+<", "/usr/local/apache/conf/httpd.conf" );
    my $line      = 0;
    my $addmodule = 0;
    my (@HC);
    while (<HC>) {
        next if ( /Include/ && /jk.conf/i );
        $line++;
        if (/^[\s\t]*AddModule/) { $addmodule = $line; }
        push( @HC, $_ );
    }
    seek( HC, 0, 0 );
    my $line = 0;
    foreach (@HC) {
        $line++;
        if ( $line == ( $addmodule + 1 ) ) {
            print HC "Include \"/usr/local/apache/conf/jk.conf\"\n\n";
        }
        print HC $_;
    }
    truncate( HC, tell(HC) );
    SafeFile::safeclose( \*HC, $conflock );
}

sub setupwebxml {

    my $smap .= <<'EOM';
    <servlet-mapping>
        <servlet-name>httpservlet</servlet-name>
        <url-pattern>/servlet/*</url-pattern>
    </servlet-mapping>
                                                                                                                                                       
    <servlet-mapping>
        <servlet-name>httpservlets</servlet-name>
        <url-pattern>/servlets/*</url-pattern>
    </servlet-mapping>
EOM

    my $s .= <<'EOM';
   <servlet>
        <servlet-name>httpservlet</servlet-name>
        <servlet-class>
          org.apache.catalina.servlets.InvokerServlet
        </servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <load-on-startup>2</load-on-startup>
    </servlet>
 
    <servlet>
        <servlet-name>httpservlets</servlet-name>
        <servlet-class>
          org.apache.catalina.servlets.InvokerServlet
        </servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <load-on-startup>2</load-on-startup>
    </servlet>
EOM

    my $conflock    = SafeFile::safeopen( \*HC, "+<", "/usr/local/jakarta/tomcat/conf/web.xml" );
    my $line        = 0;
    my $incomment   = 0;
    my $endsmapline = 0;
    my $endsline    = 0;
    my (@HC);
    while (<HC>) {
        $line++;
        if (/[\s\t]*\<!/)     { $incomment = 1; }
        if (/[\s\t]*[\-]+\>/) { $incomment = 0; }
        if ( !$incomment ) {
            if (/^[\s\t]*\<\/servlet\-mapping\>/) { $endsmapline = $line; }
            if (/^[\s\t]*\<\/servlet\>/)          { $endsline    = $line; }
        }
        push( @HC, $_ );
    }
    seek( HC, 0, 0 );
    my $line = 0;
    foreach (@HC) {
        $line++;
        if ( $line == ( $endsmapline + 1 ) ) {
            print HC "$smap\n";
        }
        if ( $line == ( $endsline + 1 ) ) {
            print HC "$s\n";
        }
        print HC $_;
    }
    truncate( HC, tell(HC) );
    SafeFile::safeclose( \*HC, $conflock );
}

sub doomedprocess {
    my ($process) = @_;
    nooutputsystem( "/scripts/ckillall", "-TERM", $process );
    nooutputsystem( "killall",           "-TERM", $process );
    nooutputsystem( "/scripts/ckillall", "-9",    $process );
    nooutputsystem( "killall",           "-9",    $process );
}

sub nooutputsystem {
    my @unsafecmd = @_;
    my @cmd;
    while ( $unsafecmd[$#unsafecmd] eq '' ) { pop(@unsafecmd); }
    foreach (@unsafecmd) {
        my @cmds = split( / /, $_ );
        foreach (@cmds) { push( @cmd, $_ ); }
    }
    if ( my $pid = fork() ) {
        waitpid( $pid, 0 );
    }
    else {
        close(STDOUT);
        close(STDERR);
        close(STDIN);
        open( STDIN,  "<", "/dev/null" );
        open( STDOUT, ">", "/dev/null" );
        open( STDERR, ">", "/dev/null" );
        exec @cmd;
    }
    
}

sub downloadfile {
    my $file     = shift;
    my $mirror   = shift;
    my $md5check = shift;
    my $md5checksum;
    if ( $md5check == 1 ) {
        my $md5size = 0;
        my $md5try  = 1;
        while ( $md5size == 0 ) {
            if ( $md5try == 5 ) {
                croak "ERROR: Attempted to download md5sum check file 5 times and failed! Exiting now!\n";
            }
            elsif ( $md5try == 1 ) {
                print "Downloading md5sum check file...\n";
            }
            else {
                print "\nDownload failed for md5sum check file, trying attempt # " . ( $md5try + 1 ) . "\n";
            }
            system( "wget", "-q", "-O", $file . ".md5", $mirror . $file . ".md5" );
            if ( -e "$file.md5" ) {
                $md5size = ( stat(_) )[7];
            }
            $md5try++;
        }
        open( MD5, $file . ".md5" );
        while (<MD5>) {
            $md5checksum = $_;
            chomp($md5checksum);
            unlink( "/usr/local/" . $file . ".md5" );
            if ( $md5checksum eq "" ) {
                croak "ERROR: Unable to determine the md5 checksum value for $file";
            }
        }
        close(MD5);
    }
    my $size = 0;
    my $try  = 1;
    while ( $size == 0 ) {
        if ( $try == 5 ) {
            croak "ERROR: Attempted to download $file 5 times and failed! Exiting now!\n";
        }
        elsif ( $try == 1 ) {
            print "Downloading $file...\n";
        }
        else {
            print "\nDownload failed, trying attempt # " . ( $try + 1 ) . "\n";
        }
        system( "wget", "-q", "-O", $file, $mirror . $file );
        if ( -e $file ) {
            $size = ( stat(_) )[7];
        }
        $try++;
    }
    if ( $md5check == 1 ) {
        my $realmd5sum = `md5sum $file`;
        chomp($realmd5sum);
        if ( $realmd5sum ne $md5checksum ) {
            croak "ERROR: md5sum mismatch (actual: $realmd5sum) (expected: $md5checksum)\n";
        }
    }
}

sub get_httpd_version {
    my $bin = '/usr/local/apache/bin/httpd';
    return 'UNKNOWN' if !-x $bin;
    if ( Cpanel::SafeRun::saferunallerrors( $bin, '-v' ) =~ m{Apache/(\d+\.\d+\.\d+)}m ) {
        return $1;
    }
    return 'UNKNOWN';
}

