#! /usr/bin/perl


use strict;

use Getopt::Long;

use IO::File;
use IO::Pipe;
use File::Copy;

use Net::hostent;
use Socket;

use gateway_lib;

# rc.fedaccounts is going to send a TERM to any processes running as an old
# user, so insulate this (and children) process from propagated signals.
$SIG{'TERM'} = 'IGNORE';

chdir("/tmp");

my $TMCC = "/usr/local/etc/emulab/tmcc";
my $RC_ROUTE = "/usr/local/etc/emulab/rc/rc.route";
my $tmcc_p = new IO::Pipe() || die "Can't open pipe: $!\n";
my $shared_config_dir;
my $shared_seer_auth_dir;
my $local_config_dir = "/usr/local/federation/etc";
my %services;
my %aliases;
my %added;
my @hide;
my $perl;

my $gateway;
my $smbshare = "USERS";
my $smbuser;
my $smbproject;
my $exp;
my $proj;
my $install_smb;
my $smb_type = 'cifs';
chomp (my $uname = `uname`);
my $smbmount = "smbmount.$uname.pl";

GetOptions("install_samba" => \$install_smb);

# find perl
for my $p ("/usr/bin/perl", "/usr/local/bin/perl") {
    if ( -x $p ) {
	$perl = $p;
	last;
    }
}
$perl = "perl" unless $perl;

if (!-x '/sbin/mount.cifs' ) {
    if ( -x '/usr/bin/yum' ) {
	# Install samba
	system('/usr/bin/yum -y install samba-client');
	system('/usr/bin/yum -y install cifs-utils');
	# These tools expect the fstab to include cifs
	$smb_type = 'cifs';
    }
    elsif (-x '/usr/bin/apt-get') {
	# Install samba
	system('/usr/bin/apt-get -y install samba-client');
	system('/usr/bin/apt-get -y install smbfs');
	# These tools expect the fstab to include cifs
	$smb_type = 'cifs';
    }
}

if (!-e "$local_config_dir/client.conf" ) {
    $tmcc_p->reader("$TMCC -b status");
    while (<$tmcc_p>) {
	/ALLOCATED=([^\/]+)\/(\S+)/ && do {
	    ($proj, $exp) = ($1, $2);
	    $shared_config_dir = "/proj/$proj/exp/$exp/tmp";
	    $shared_seer_auth_dir = "/proj/$proj/exp/$exp/tbdata";
	    last;
	};
    }
    $tmcc_p->close();

    mkdir($local_config_dir);

    foreach my $fn ("seer.conf", "client.conf", "userconf", "hosts",
	    "ca.pem", "node.pem") {
	copy("$shared_config_dir/$fn", $local_config_dir )
	    if -e "$shared_config_dir/$fn";
    }

    # Copy seer authorization files into the location that standard SEER
    # invocations will look.  The above loop puts them where -F invocations
    # will look.
    foreach my $fn ("ca.pem", "node.pem") {
	copy("$shared_config_dir/$fn", $shared_seer_auth_dir )
	    if -e "$shared_config_dir/$fn" && -d $shared_seer_auth_dir;
    }
}

my $client = new IO::File("$local_config_dir/client.conf");
while (<$client>) {
    chomp;
    /ControlGateway:\s+(.*)/i && do { $gateway = $1; };
    /SMBShare:\s+(.*)/i && do { $smbshare = $1; };
    /ProjectUser:\s+(.*)/i && do { $smbuser = $1; };
    /ProjectName:\s+(.*)/i && do { $smbproject = $1; };
    /Service:\s+(.*)/i && do { $services{$1}++;};
    /PortalAlias:\s+(.*)/i && do { $aliases{$1}++;};
    /AddedNode:\s+(.*)/i && do { $added{$1}++; };
    /Hide:\s+(.*)/i && do { push(@hide, split(",", $1));};
}
$client->close();
# Create the /etc/hosts file
my $hosts = new IO::File("/etc/hosts") || die "Can't open /etc/hosts:$!\n";
my $new_hosts = new IO::File(">/tmp/hosts") || die "Can't open /tmp/hosts:$!\n";
my $config_hosts = new IO::File("$local_config_dir/hosts") || 
    die "Can't open $local_config_dir/hosts: $!\n";
my $has_control = 0;

while (<$hosts>) {
    /^127\.0\.0\.1/ && do { print $new_hosts $_; };
    # If aliases conflict with existing nodes, delete the alias
    for my $n (split($_)) {
	chomp $n;
	delete $aliases{$n} if $aliases{$n};
    }
}
$hosts->close();
HOST:
while (<$config_hosts>) {
    # Trim out hosts that were hidden by their home testbeds
    for my $h (@hide) {
	next HOST if /^\d+\.\d+\.\d+\.\d+\s+$h-/;
    }
    print $new_hosts $_;
}
print $new_hosts "\n";
$config_hosts->close();

# Add gateway aliases
for my $k (keys %aliases) {
    # If we added a node, it's a node without a local address.  Bind the name
    # to the IP in /etc/hosts.  If we didn't add a node, it's the gateway node.
    (my $lname = $gateway) =~ s/^[^\.]+/$k/;
    my $ip = gateway_lib::get_ip($added{$k} ? $lname : $gateway);
    if ($ip) { 
	# We have an IP.  Make a hosts entry for the key and the key plus the
	# first two subdomains (which is an emulab setup)
	my @x = split(/\./, $lname);
	if (@x > 3 ) { splice(@x, 3); }
	my $out = join(".", @x);
	print $new_hosts "$ip\t$out $k\n";
    }
    else { print $new_hosts "# Can't get ip for $lname\n"; }
}
$new_hosts->close();
copy("/tmp/hosts", "/etc/hosts");


# If there are tunnelip interfaces to bring up, bring 'em up.  Record any such
# interfaces in /usr/local/federation/interfaces, so SEER can find them later.
system("$perl -I/usr/local/federation/lib " . 
    "/usr/local/federation/bin/config_from_tunnelip.pl " . 
    "--record=/usr/local/federation/etc/interfaces");

if ($uname =~ /Linux/ ) {
    system("$perl /usr/local/federation/bin/gated_routing.pl")
	if -r "/usr/local/federation/bin/gated_routing.pl";
}
elsif ($uname =~/FreeBSD/ ) {
    # FreeBSD needs to have ospfs installed and a router config created and
    # run.
    system("$perl /usr/local/federation/bin/ospf_routing.pl")
	if -r "/usr/local/federation/bin/ospf_routing.pl";
}


if ($services{'userconfig'}) {
    if (!-e "$local_config_dir/old_accts") {
	$tmcc_p = new IO::Pipe() || die "Can't open pipe for accounts:$!\n";
	my $old_accounts = new IO::File(">$local_config_dir/old_accts") || 
	    die "Can't open $local_config_dir/old_accts: $!\n";

	$tmcc_p->reader("$TMCC -b accounts");
	while (<$tmcc_p>) {
	    print $old_accounts $_;
	}
	$tmcc_p->close();
	$old_accounts->close();
    }
    print("Updating accounts");
    system("/usr/local/federation/bin/rc.fedaccounts");
}

if ($services{'SMB'}) {
    if ($uname =~ /FreeBSD/ ) {
	system("umount -A -f -t nfs,smbfs,cifs");
	$smb_type = "smbfs";
    }
    elsif ($uname =~ /Linux/ ) {
	# Pass individual filestems to Linux umount.  No -A.
	my $mtab = new IO::File("/etc/mtab") || die "Can't open /etc/mtab:$!\n";
	while (<$mtab>) {
	    chomp;
	    my @F = split($_);
	    next unless $F[2] =~ /(nfs|cifs|smbfs)/;
	    system("umount -f $F[1]");
	}
    }

    print "Waiting for SMB server\n";
    gateway_lib::wait_for_port($gateway, 139, 60*60) || 
	die "SMB server never came up\n";
    print "Mounting via SMB\n";
    system("$perl /usr/local/federation/bin/$smbmount $smbshare $gateway " . 
	"$smbuser $smbproject $smb_type");
}

if ($uname =~ /FreeBSD/ ) {
    # Restart ntp
    system("/etc/rc.d/ntpd stop; /usr/sbin/ntpdate boss; " . 
	"/etc/rc.d/ntpd start;");
					       
}
elsif ($uname =~ /Linux/ ) {
    # restart ntp
    system("/etc/rc.d/init.d/ntpd stop; /usr/sbin/ntpdate boss; ". 
	"/etc/rc.d/init.d/ntpd start");
}

# startcmd
if ($ARGV[0] && $ARGV[1]) {
    if ($uname =~ /FreeBSD/) {
	system("su -l \"$ARGV[0]\" -c \"$ARGV[1]\"");
    }
    elsif ($uname =~ /Linux/) {
	system("su \"$ARGV[0]\" --command \"$ARGV[1]\"");
    }
}
exit(0);
