#!/usr/bin/perl 

#Copyright (C) 1999-2001 by  Sbastien Chaumat <schaumat@ens-lyon.fr>
#                        and Loc Prylli <lprylli@lhpca.univ-lyon1.fr>

#    This program 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 of the License, or
#    (at your option) any later version.

#    This program 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.

#    A copy of the GNU General Public License is available as
#    `/usr/share/common-licences/GPL' in the Debian GNU/Linux distribution
#    or on the World Wide Web at http://www.gnu.org/copyleft/gpl.html.  You
#    can also obtain it by writing to the Free Software Foundation, Inc.,
#    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

use FileHandle;
use File::Path;
use File::Copy;
use Getopt::Long;

require "dialog.pl";
require("/usr/share/replicator/repli-common");

@debs_cd1=qw(net/netstd
	     net/bootpc
	     net/ftp
	     net/rsh-client
	     net/rusers
	     net/tftp
	     net/ruptime
	     net/fping
	     net/rdist
	     net/traceroute
	     net/rwhod
	     net/rwho
	     net/finger
	     net/rwall
	     net/icmpinfo
	     net/rdate
	     net/ftpd
	     net/pidentd
	     net/cfingerd
	     interpreters/perl-5.005 
	     utils/strace 
	     admin/psmisc 
	     libs/zlib1g 
	     libs/libgmp2 );

@debs_cd2=qw(admin/cfengine libs/dialog  oldlibs/ncurses3.4 net/rsync);

@debs=(@debs_cd1,@debs_cd2);

$remote_debiandir="ftp.debian.org/debian";
$local_debiandir="/usr/local/debian";

sub dosystem;
sub docopy;
sub error;
sub echo_to;
sub get_ip_of;
sub check_var;

sub usage {
  print STDERR "@_\nusage: repli-miniroot [-u/--update-config]\n\n";
  exit 0;
}

sub ask_for_base {
  $title_base="Where can I fetch the file base2_2.tgz?";
  $message_base=">I need the file base2_2.tgz. 
>I can get it from an official Debian Potato mirror. 
>Which mirror should I use?
";
  @choices_base=("cdrom","use my official bin 1 CD",
		 "net","use a mirror on the Internet",
		 "local","use my local mirror");
  $width="70";
  $num_item_base=3;
  rhs_menu($title_base,$message_base,$width,$num_item_base,@choices_base) || exit 0;
  if ($dialog_result eq "cdrom") {&get_base_from_cd}
  if ($dialog_result eq "net") {&get_base_from_net}
  if ($dialog_result eq "local") {&get_base_from_local}
}

sub ask_for_debs {
  $title_debs="Where can I fetch other needed deb packages?";
  $message_debs=">I need to fetch some official debian packages. 
>I can get them from an official Debian Potato mirrors. 
>Which method should I use to find those files?";
  @choices_debs=("cdrom","use my official CD set",
		 "ftp","fetch from an official ftp Debian mirror on the Internet",
		 "local","use my local mirror");
  $width="70";
  $num_item_debs=3;
  rhs_menu($title_debs,$message_debs,$width,$num_item_debs,@choices_debs) || exit 0;
  if ($dialog_result eq "cdrom") {&get_debs_using_cdrom}
  if ($dialog_result eq "ftp") {&get_debs_using_wget}
  if ($dialog_result eq "local") {&get_debs_using_local}
}

sub ask_for_cd{
  $cd_number=$_[0];
  system("umount /cdrom");
  if (&rhs_yesno("CD $cd_number",">Please insert the Debian 2.2 binary $cd_number CD.
>Select \"Yes\" when done.
>Select \"No\" to cancel.",50)) 
    { $continue=1;
      system("mount /cdrom");
      if (-e "/cdrom/.disk/info") {
	$good_cd=(not system "grep -c Binary-$cd_number /cdrom/.disk/info >/dev/null");
      }
      unless ( $good_cd) {rhs_msgbox("Error","This is not Debian Potato  Binary-$cd_number CD.",50)}
    }
  else
    {$continue=0}
}


sub ask_for_local_mirror {
  $title="Getting base from a local mirror";
  $message=">Give me the path to your local Debian potato mirror. 
>It should contain the \"dists\" directory.";
  $width=80;
  if (rhs_inputbox($title,$message,$width,$local_debiandir)){ 
    $base="$dialog_result/dists/potato/main/disks-i386/current/base2_2.tgz";
    $continue=1;
    unless ( -e "$base") { rhs_msgbox("Error","There's no file\n$base",70)}
    else {
      $local_debiandir=$dialog_result;
      $base_located=1;
    }
  }
  else {$continue=0}
}

sub ask_for_remote_mirror {
  $wget_options="--dot-style=mega -c";
  $title="Getting base from a remote mirror";
  $message=">Give me the path to your favorite remote (ftp) Debian potato mirror. 
>It should contain the \"dists\" directory";
  $width=80;
  if (rhs_inputbox($title,$message,$width,$remote_debiandir)) 
    { $continue=1;
      $remote_debiandir_to_test=$dialog_result;
      #to test if the mirror is good we try to download a small file.
      my $testfile="dists/potato/main/disks-i386/current/md5sum.txt";
      if (system("wget $wget_options -P $nfsroot/tmp ftp://$remote_debiandir_to_test/$testfile")) {
	rhs_msgbox("Error","It'seems that $remote_debiandir_to_test is not a valid mirror.",70)}
      else
      {
      unlink "$nfsroot/tmp/$testfile";
      $good_mirror=1;
      $remote_debiandir=$remote_debiandir_to_test;
      }
    } 
  else {$continue=0}
}

sub get_base_from_cd {
  $debiandir="/cdrom";
  $base="$debiandir/dists/potato/main/disks-i386/current/base2_2.tgz";
  $good_cd=0;
  do { &ask_for_cd("1") } while ((not  $good_cd) and $continue);
  $base_located=$good_cd;
}

sub get_base_from_net {
  $good_mirror=0;
  do { &ask_for_remote_mirror } while ((not $good_mirror) and $continue);
  if ($good_mirror){
    $remote_base="$remote_debiandir/dists/potato/main/disks-i386/current/base2_2.tgz";
    unless (system("wget $wget_options -P /tmp ftp://$remote_base")) {
      $base="/tmp/base2_2.tgz";
      $base_located=1;
    }
    else {
      rhs_msgbox("Error","I can't get ftp://$remote_base.",70)}
  }
}

sub get_base_from_local {
  do {&ask_for_local_mirror} while ((not $base_located) and $continue);
}


sub install_base {
  print STDERR "\nInstalling base system in $nfsroot...";
  -d "$nfsroot" or mkdir "$nfsroot",0777 or error "creating $nfsroot:$!";
  $nfsroot =~ /[a-zA-Z0-9]/ or die "$nfsroot does not seem a valid target\n";
  $taropt="xzPf";
  if ($verbose){$taropt="xzvPf";};
  dosystem("tar $taropt $base -C $nfsroot");
  unlink("$nfsroot/sbin/unconfigured.sh");
  unlink("$nfsroot/root/setup.sh");
  unlink("$nfsroot/root/.bash_profile");
  rename("$nfsroot/root/.profile.real","$nfsroot/root/.profile");
  print STDERR "done\n";
  
  
  &update_config;

  #kernel kmap
  docopy("/etc/console-tools/default.kmap.gz","$nfsroot/etc/console-tools/default.kmap.gz");

  #securetty
  echo_to "$nfsroot/etc/securetty","tty1\ntty2\ntty3\ntty4\ntty5\ntty6\n";

  #fstab
  print STDERR "Creating $nfsroot/etc/fstab...";
  echo_to  "$nfsroot/etc/fstab","/dev/root / nfs-root defaults 0 0\n".
    "none     /proc proc  defauts 0 0\n";
  print "done\n";
  
  #network
  print STDERR "Creating $nfsroot/etc/network/intefaces...";
  echo_to  "$nfsroot/etc/network/interfaces","
iface lo inet loopback
";
  print STDERR "done\n";
  
  print STDERR "Creating $nfsroot/etc/hosts...";
  echo_to "$nfsroot/etc/hosts","127.0.0.1 localhost
$miniroot_server_add $miniroot_server $miniroot_server.$miniroot_domainname\n";
  print STDERR "done\n";

  #inittab
  docopy "/etc/inittab","$nfsroot/etc/inittab";

  #ssh
#  unlink("$nfsroot/etc/init.d/ssh"); #disable server
# mkpath(["$nfsroot/root/.ssh"],1);
#  if ($sshfile) {
#    docopy "$sshfile","$nfsroot/root/.ssh/identity" or error "copying identity";
#  }
#  echo_to "$nfsroot/root/.ssh/config","Cipher =  arcfour
#";
  
  #
  #preparing replicator startup at root login 
  #
  echo_to "$nfsroot/root/.bashrc","
if test `tty` = '/dev/tty1' ; then
  export PATH=/usr/local/sbin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/bin/X11
  /usr/sbin/repli-dialog
fi

";
  
#  echo_to "$nfsroot/root/.bash_profile","
#PATH=/usr/bin:/bin:/usr/sbin:/sbin/:/root:.
#test -x /usr/bin/ssh-agent && exec ssh-agent bash
#source .bashrc
#";
  
}

sub update_config {
  #if we upgrade replicator we need to transfert new scripts into the miniroot.
  #Thus update-config also copy scripts.
  print STDERR "Installing replicator's scripts in $nfsroot...";
  #make the directories
  mkdir("$nfsroot/$confdir",0755);
  mkdir("$nfsroot/$sharedir",0755);
  mkdir("$nfsroot/$scriptsdir_in_miniroot",0755);
  #copy shared files
  docopy("$sharedir/repli-common","$nfsroot/$sharedir/repli-common");
  chmod(0644,"$nfsroot/$sharedir/repli-common");
  docopy("$default_rules_file","$nfsroot/$default_rules_file");
  #copy scripts
  @scripts=qw(repli-install repli-update repli-dialog);
  foreach $script (@scripts){
    #if there are outdated symlink, remove them
    my $dest="$nfsroot/$scriptsdir_in_miniroot/$script";
    if (-l $dest){
      print STDERR "Warning : removing old symlink $dest\n";
    }
    docopy("$scriptsdir_on_server/$script",$dest);
    chmod(0744,$dest);
  }

  print STDERR "done\n";

  print STDERR "Installing replicator\'s configuration in $nfsroot/$confdir...";
  $rules_file="$sharedir/$default_rules_file";
  if (-r "$user_rules_file") {
  docopy("$user_rules_file","$nfsroot/$user_rules_file");
  }
  dosystem("cp $confdir/replicator.conf* $nfsroot/$confdir");
  #    docopy("$conffile","$nfsroot/$conffile");
  if (!(-r $postinst)){echo_to($postinst,"#/bin/sh\n")}
  docopy("$postinst","$nfsroot/root/repli-postinst");
  chmod(0755,"$nfsroot/root/repli-postinst");
  #default model is miniroot_server
  unless ($model){$model=$miniroot_server};
  echo_to "$nfsroot/root/replicator-model-name","$model";
  print STDERR "done\n";
}

sub get_debs_using_cdrom {
  $debiandir="/cdrom/debian/dists/potato/";
  $base="$debiandir/main/disks-i386/current/base2_2.tgz";
  #process first CD
  $good_cd=0;
  do { &ask_for_cd("1") } while ((not  $good_cd) and $continue);
  unless ( $continue) {return $debs_installed=0}
  @pack=();
  foreach (@debs_cd1) {
    push @pack,"$debiandir/main/binary-i386/${_}_*deb";
  }
  dosystem("cp @pack $nfsroot/tmp/");
  #process second CD
  $good_cd=0;
  do { &ask_for_cd("2") } while ((not  $good_cd) and $continue);
  unless ( $continue) {return $debs_installed=0}
  @pack=();
  foreach (@debs_cd2) {
    push @pack,"$debiandir/main/binary-i386/${_}_*deb";
  }
  dosystem("cp @pack $nfsroot/tmp/");
  $debs="$nfsroot/tmp/*.deb";
  $debs_located=1;
}

sub get_debs_using_wget {
  $good_mirror=0;
  do { &ask_for_remote_mirror } while ((not $good_mirror) and $continue);
  if ($good_mirror) {
    foreach (@debs) {
      push @pack,"ftp://$remote_debiandir/dists/potato/main/binary-i386/${_}_*deb";
    }
    $wget_options="--dot-style=mega -c --glob=on --retr-symlinks";
    system("wget $wget_options -P $nfsroot/tmp @pack");
    $debs_located=1;
    $debs="$nfsroot/tmp/*.deb";  
  }
}

sub get_debs_using_local {
  $base_located=0;
#  $default_debiandir=$local_debiandir || {$default_debiandir="/usr/local/debian"};
  do { &ask_for_local_mirror } while ((not $base_located) and $continue);
  if ($base_located) {
    foreach (@debs) {
      dosystem("cp $local_debiandir/dists/potato/main/binary-i386/${_}_*deb $nfsroot/tmp/");
    }
    $debs_located=1;
    $debs="$nfsroot/tmp/*.deb";
  }
}

sub install_debs {
  $endopt="";
  unless ($verbose) {$endopt=">/dev/null 2>&1"}
  dosystem("dpkg --root=$nfsroot  --unpack --force-depends --force-auto-select $debs $endopt");
  #rwhod refuse to configure becasue /proc is not mounted in the nfsroot
  #anyway we don't need any daemon to be started now
  rename("$nfsroot/usr/sbin/rwhod","$nfsroot/usr/sbin/rwhod.disable");  
  dosystem("chroot $nfsroot /usr/bin/dpkg --configure --pending $endopt");
}

sub set_miniroot_pwd {
 rhs_msgbox("Setting the root password","You will now be prompted twice for a password. 
>This is the root password you should give after booting a target 
>with the installation bootdisk.",80);
 rhs_clear;
 dosystem("chroot $nfsroot passwd");
}

#
#the real stuff
#

#sanity checks

#check if you are root
$ui=(getpwuid($<))[3];
unless ($ui eq "0"){error("You must run this script as root.")};

#read command line arguments
my $fast='';
GetOptions('update-config|u' => \$fast) or usage();

check_var(qw(nfsroot));

#default miniroot server is the machine where replicator is installed
$miniroot_server=`uname -n`;
chomp($miniroot_server);
$miniroot_domainame=`domainname`;
chomp($miniroot_domainname);

#check if we can resolv server IP address
$miniroot_server_add = get_ip_of($miniroot_server);

$base_located=0;
$debs_located=0;


unless ($fast) {
  do { &ask_for_base } while (not $base_located);
  &install_base;
  do {&ask_for_debs} while (not $debs_located);
  &install_debs;
  &set_miniroot_pwd;
  rhs_msgbox("Finished",">repli-miniroot has sucessfully created the nfsroot filesystem.
Don\'t forget to export $nfsroot for your copies
>with options: rw,no_root_squash\n",80);
  rhs_msgbox("Warning",">If you remove replicator from your system, the filesystem under
>$nfsroot 
>will not be removed automatically.
>
>You will have to delete it by hand.\n",80);
} 
else { &update_config } 
