#!/usr/bin/perl -w

# Script for installing FreeVSD following compilation from source.
# (RedHat GNU Linux version)
# Copyright (c) 1999, 2000 Idaya Ltd.
#
# This file is part of the Virtual Server Administrator (FreeVSD)
#
# FreeVSD is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# FreeVSD is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with FreeVSD; see the file COPYING.  If not, write to
# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
#

use VSD;
use VSD::Change;
use VSD::Config;
use Fcntl;
use strict;
use DirHandle;
use Data::Dumper;

# We are being run because an installation already exists.
# Therefore, we must find out what needs to be upgraded:
my $TO_SOURCE = 0;
my $TO_RPM = 0;
my $FROM_SOURCE = 0;
my $FROM_RPM = 0;
my $PRE_148 = 1;

# VSD configuration file variables
my $vsdconf = "$path{vsdconf}";
my $old_vsdconf;
my $old_vsdconfdir;
my $vsdmap;
my $change;

# Useful variables relating to the localmachine.
my $localhost = `hostname`;
chomp $localhost;
$localhost =~ s/^\s*(\S+)\s*$/$1/;

my $ip = `hostname -i $localhost`;
chomp $ip;
$ip =~ s/^\s*(\S+)\s*$/$1/;

# Are we a source install or an RPM install?
# (Perl module will tell us because of path imported from VSD.pm)
if ($vsdconf =~ m%/usr/local/etc.*%){
  print "Upgrading to source, ";
  $TO_SOURCE = 1;
}
else {
  print "Upgrading to RPM, ";
  $TO_RPM = 1;
}

# Are we upgrading from an RPM or a source install?
# if we are source, and there is no /usr/sbin/vsd, then upgrading from source.
if (($TO_SOURCE == 1 && ! -e "/usr/sbin/vsd") || ($TO_RPM == 1 && -e "/usr/local/sbin/vsd")){
  $FROM_SOURCE = 1;
  $old_vsdconfdir = "/usr/local/etc/";
  print "from source.\n";
}
else {
  $FROM_RPM = 1;
  $old_vsdconfdir = "/etc/";
  print "from RPM.\n";
}

# if RPM -> source, need to modify /etc/services
# if source -> RPM, need to modify /etc/services
my $move_config = 0;

if ($FROM_RPM == 1 && $TO_SOURCE == 1){
  # change the path to vsd in /etc/services to /usr/local/sbin/vsd
  print "RPM -> source services change.\n";
  $move_config = 1;
  modify_inet ("/usr/sbin/vsd", "/usr/local/sbin/vsd");
  modify_inet ("/usr/sbin/virtuald", "/usr/local/sbin/virtuald");
}
elsif ($FROM_SOURCE == 1 && $TO_RPM == 1){
  # change the path to vsd in /etc/services to /usr/sbin/vsd
  print "source -> RPM services change.\n";
  $move_config = 1;
  modify_inet ("/usr/local/sbin/vsd", "/usr/sbin/vsd");
  modify_inet ("/usr/local/sbin/virtuald", "/usr/sbin/virtuald");
}

# Look for an old /etc/vsd.conf or /etc/vsd.conf.rpmsave, and transfer.
if (-e "$old_vsdconfdir/vsd.conf"){
    `mv $old_vsdconfdir/vsd.conf $vsdconf`;
    print "copied $old_vsdconfdir/vsd.conf to $vsdconf\n";
}
elsif (-e "$old_vsdconfdir/vsd.conf.rpmsave"){
    `mv $old_vsdconfdir/vsd.conf.rpmsave $vsdconf`;
    print "copied $old_vsdconfdir/vsd.conf.rpmsave $vsdconf\n";
}
elsif (! -e $vsdconf) {
    print "No previous vsd.conf file found, unable to upgrade installation.\n";
    print "Please remove the vsd entry from /etc/services and re-install.\n";
    exit;
}
else {
    if ($move_config && -e "$old_vsdconfdir/vsd/vsd.conf")
      {
        `mv $old_vsdconfdir/vsd/vsd.conf $vsdconf`;
      }
    undef $old_vsdconf;
    print "Upgrading from a 1.4.8+ install.\n";
    $PRE_148 = 0;
}

# Read configuration, and set up change log
$change = VSD::Change->new (file=>$vsdconf);
$vsdmap = VSD::Config->new (change=>$change);

# Check for loopback virtual server
# If not, create entry, create symlink
if (! defined ($vsdmap->getval ('VirtualServer', "$localhost"))){
    print "Creating loop back interface.........\n";

    $vsdmap->setval ( 'VirtualServer', $localhost, 'IP', $ip );
    $vsdmap->setval ( 'VirtualServer', $localhost, 'Status', 'active' );
    $vsdmap->setval ( 'VirtualServer', $localhost, 'Partition', '0' );

    my $mountpoint = $vsdmap->getval ('Partition', '0', 'Mount');
    -d "$mountpoint" or mkdir $mountpoint, 0755 or die "Can't create dir $mountpoint";
    -d "$mountpoint/vs" or mkdir "$mountpoint/vs", 0755 
                                                or die "Can't create dir $mountpoint/vs";

   $change->command (
                    "ln -s / $mountpoint/vs/$localhost",
                    "rm -f $mountpoint/vs/$localhost",
                    "unlink / from $mountpoint/vs/$localhost "
                    );
}

my %all_partitions = $vsdmap->getval ('Partition');
my @partitions = (keys %all_partitions);
my @skel_names;
my $new_skel_name = "skel";

my %listed_virtual_servers = $vsdmap->getval ('VirtualServer');
my @virtual_servers = keys (%listed_virtual_servers);

# Foreach partition
foreach my $partition (@partitions) {

  my @skel_to_register;
  my $created_dir = 0;

  
  my $mountpoint = $vsdmap->getval ('Partition', $partition, 'Mount');
  my $skel_dir = new DirHandle "$mountpoint/skel";

  while (defined (my $dir = $skel_dir->read)) {

    next if $dir =~ /^\.\.?$/;

    if ($dir =~ /bin/ || $dir =~ /dev/ || $dir =~ /etc/ || $dir =~ /home/
            || $dir =~ /lib/ || $dir =~ /proc/ || $dir =~ /sbin/ || $dir =~ /tmp/
            || $dir =~ /usr/ || $dir =~ /var/){

      # An old skel has been found, create a directory for it
      if ( !$created_dir && -d "$mountpoint/skel/$new_skel_name"){
        push (@skel_to_register, $new_skel_name);
        print "Please enter a name for the pre 1.4.8 style skel on Partition $partition:\n";
        $new_skel_name = <>;
        chomp $new_skel_name;
      }

      if (! -d "$mountpoint/skel/$new_skel_name") {
        mkdir ("$mountpoint/skel/$new_skel_name", 0755);
        push (@skel_to_register, $new_skel_name);
        $created_dir = 1;
      }

      system ("mv", "$mountpoint/skel/$dir", "$mountpoint/skel/$new_skel_name");
    }
    else {
      push (@skel_to_register, $dir);
    }
  }

  foreach my $skel (@skel_to_register) {
    $vsdmap->setval ('Partition', $partition, 'Skel', $skel);
  }

  # Best register the new skel with all virtual servers on that partition.
  foreach my $vs (@virtual_servers) {
    if ((my $vs_partition = 
           ($vsdmap->getval ('VirtualServer', $vs, 'Partition')) == $partition) 
        && (! defined ($vsdmap->getval ('VirtualServer', $vs, 'Skel')))) {
      $vsdmap->setval ('VirtualServer', $vs, 'Skel', $new_skel_name);
    }
  }
}
  
#print Dumper ($vsdmap);

# Make sure the most important change is rolled back
if ($PRE_148)
  {
    if ( -e "/etc/inetd.conf.pre-freevsd")
      {
        $change->command ('touch /etc/inetd.conf.pre-freevsd',
                          'mv /etc/inetd.conf.pre-freevsd /etc/inetd.conf',
                          'undo changes to /etc/inetd.conf');
      }

    if ( -e "/etc/services.pre-freevsd")
      {
        $change->command ('touch /etc/services.pre-freevsd',
                          'mv /etc/services.pre-freevsd /etc/services',
                          'undo changes to /etc/services');
      }  
    else 
      {
        $change->command('touch /etc/services', 
                         'cat /etc/services | sed -e \'s/^.vsd .*//\' > /etc/services.tmp; \
                          mv /etc/services.tmp /etc/services',
                         'undo changes to /etc/services');
      }
  }

sub modify_inet {

  my $from = $_[0];
  my $to = $_[1];

  # Need to modify /etc/[x]inetd.conf
  if (-e "/etc/xinetd.conf")
    {
      `mv /etc/xinetd.conf /etc/xinetd.conf.tmp`; 
      open (CONF, "/etc/xinetd.conf.tmp");
      open (NEW_CONF, ">/etc/xinetd.conf");
    }
  else 
    {
      `mv /etc/inetd.conf /etc/inetd.conf.tmp`; 
      open (CONF, "/etc/inetd.conf.tmp");
      open (NEW_CONF, "/etc/inetd.conf");
    }

  while (<CONF>) {
    s%$from%$to%g;
    print NEW_CONF $_;
  }

  close (NEW_CONF);
  close (CONF);

  # remove temp files and kick the process:
  if (-e "/etc/xinetd.conf.tmp")
    {
      `rm -f /etc/xinetd.conf.tmp`;
      `/etc/rc.d/init.d/xinetd restart`;
    }
  else
    {
      `rm -f /etc/inetd.conf.tmp`;
      `/etc/rc.d/init.d/inetd restart`;
    }
}

