#!/usr/bin/perl

#Copyright (C) 1999-2002 by  Sebastien Chaumat <schaumat@debian.org>
#                        and Loic Prylli <Loic.Prylli@ens-lyon.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");
use lib (".","/usr/share/replicator");
require("repli-common");

$wget_options="--passive-ftp --dot-style=mega -c --glob=on --retr-symlinks";



#$dbs_exclude="info,cron,dhcp-client,exim,ipchains,mailx,man-db,manpages,ppp,pppconfig,pppoeconf,pppoe,tasksel";
$dbs_include="hdparm,dialog,rsync,perl,perl-modules,reiserfsprogs,xfsprogs,jfsutils";

#cfengine is in (non-us) so I use dpkg-repack to get it from the miniroot-server

if ($verbose) {$dbs_verbose="--verbose"};

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

sub is_installed {
  my $package=$_[0];
  unless (system("dpkg -s $package 2>/dev/null | grep  Status | grep -q Status.*install.*ok.*installed")){
    &verbose("$package is installed");
    return 1;
  }
  &verbose("$package is not installed");
  return undef;
}

sub copy_deb_content {
  my $package=$_[0];
  &is_installed($package) || &error("$package not installed");
  &is_installed("dpkg-repack") || &error("please install dpkg-repack");
  dosystem("mkdir -p $nfsroot/tmp/replicator");
  &verbose("repacking $package");
  dosystem("cd $nfsroot/tmp/replicator && dpkg-repack $package");
  my $endopt="";
  unless ($verbose) {$endopt=">/dev/null 2>&1"}
  dosystem("dpkg --root=$nfsroot  --unpack --force-depends --force-auto-select $nfsroot/tmp/replicator/$package*deb $endopt");
  dosystem("chroot $nfsroot /usr/bin/dpkg --configure --pending $endopt");
  unlink("$nfsroot/tmp/replicator/$package*deb");
}

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

sub ask_for_debootstrap_mirror{
  my $title="Source of packages";
  my $message=">Give me the path to your favorite (http:// or file:/) Debian  mirror. 
>It should contain the \"dists\" directory";
  my $width=80;
  if (rhs_inputbox($title,$message,$width,"http://ftp.debian.org/debian"))
    {
      $remote_debiandir_to_test=$dialog_result;
      #lets go
      if (-d $nfsroot) {};
      my $dbs_command="/usr/sbin/debootstrap $dbs_verbose --arch $debarch --include=$dbs_include --exclude=$dbs_exclude woody $nfsroot $remote_debiandir_to_test";
      if (system($dbs_command)){
	if ($debug){ print $dbs_command;
		     exit 0;
		   }
	rhs_msgbox("Error",">It'seems that debootstrap failed.
>Maybe the mirror you choose is invalid.
>You should try again and see if debootstrap can resume 
>the installation.
>Otherwise remove 
>$nfsroot
>and try another mirror.",70);
	return undef;
      }
      else{
	if (&is_installed("cfengine")) {
	  &copy_deb_content("libssl0.9.6",$nfsroot);
	  &copy_deb_content("cfengine",$nfsroot);
	  unlink("$nfsroot/tmp/replicator");
	}
	unlink "$nfsroot/tmp/$testfile";
	return $remote_debiandir_to_test;
      }
    }
  else{
    exit 0;
  }
}

sub install_woody{
  $woody=&ask_for_debootstrap_mirror until $woody;
}

sub update_config {
  #remove hostname (it is passed on the kernel command line)
  unlink "$nfsroot/etc/hostname";
  #kernel kmap
  docopy($default_kmap.".gz","$nfsroot/$default_kmap".".gz");
  #securetty
  echo_to "$nfsroot/etc/securetty","tty1\ntty2\ntty3\ntty4\ntty5\ntty6\nttyS0\nttyS1";

  #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
  my $f="$nfsroot/etc/network/interfaces";
  print STDERR "Creating $f...";
  if ($debian_version>2.9){echo_to($f,"auto lo\n")};
  echo_to("$f","iface lo inet loopback\n");
  print STDERR "done\n";

  #inittab
  if ($serial) {
    &dosystem("perl -i -lpe 's/#T0/T0/' $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' || test `tty` = '/dev/ttyS0' ; 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
#";

  #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...\n";
  #make the directories
  mkdir("$nfsroot/$confdir",0755);
  mkdir("$nfsroot/$sharedir_in_miniroot",0755);
  mkdir("$nfsroot/usr/sbin",0755);

  #copy shared files
  docopy("$sharedir/repli-common","$nfsroot/$sharedir_in_miniroot/repli-common");
  chmod(0644,"$nfsroot/$sharedir/repli-common");
  docopy("$sharedir/$default_rules_file","$nfsroot/$sharedir_in_miniroot/$default_rules_file");

  #copy scripts from sharedir to $nfsroot/usr/sbin
  @scripts=qw(repli-dialog repli-install);
  foreach $script (@scripts){
    my $dest="$nfsroot/usr/sbin/$script";
    docopy("$sharedir/$script",$dest);
    chmod(0744,$dest);
  }

  #copy scripts from /usr/sbin to $nfsroot/usr/sbin
  @scripts=qw(repli-update);
  foreach $script (@scripts){
    my $dest="$nfsroot/usr/sbin/$script";
    docopy("$sbindir/$script",$dest);
    chmod(0744,$dest);
  }

  print STDERR "done\n";

  print STDERR "Installing replicator\'s configuration in $nfsroot/$confdir...";
  &dosystem("cp -rv $confdir $nfsroot/etc/");
  #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/$confdir/repli-postinst");
  chmod(0755,"$nfsroot/$confdir/repli-postinst");
  #default model is miniroot_server
  unless ($model){$model=$miniroot_server};
  echo_to "$nfsroot/$confdir/$model_info","
#AUTOMATICALY CREATED BY repli-miniroot. DO NOT EDIT.
\$model=\"$model\";";
  print STDERR "done\n";
  #copy the lilo and the fstab of the miniroot_server (=model for this use)
  if ($lilo_template)
    {
      docopy($lilo_template,"$nfsroot/$confdir/lilo.conf.templ");
      chmod (0600, "$nfsroot/$confdir/lilo.conf.templ");
    }
  #  docopy("/etc/fstab","$nfsroot/root/fstab-$model"); #not used yet. Can be useful anyway.
  #in order to support copying the miniroot (for the target to become a model for a further install):
  print STDERR "(Re)Creating $nfsroot/etc/hosts...";
  my $fh = new FileHandle ">$nfsroot/etc/hosts" or error "cannot open $nfsroot/etc/host:$1\n";
  print $fh "127.0.0.1 localhost\n".
    "$miniroot_server_addr $miniroot_server ".
      fullname($miniroot_server,$miniroot_domainname)."\n";
  foreach $n (@networks) {
    my $dname = $n->[$DOMAINNAME];
    foreach $host (@{$n->[$TARGETS]}) {
      my $addr = get_ip_of($host);
      print $fh "$addr ".fullname($host,$dname)." $host\n";
    }
  }
  $fh->close;
  print STDERR "done\n";

}

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;
 while(system("chroot $nfsroot passwd")){};
}

sub mirror_one {
  my $host = $_[0];
  mkpath(["$nfsroot-$host"],1);
  &dosystem("rm -rf $nfsroot-$host/*");
  &dosystem("cp -dRl $nfsroot/. $nfsroot-$host/.");
  &dosystem("rm -rf $nfsroot-$host/var/log");
  &dosystem("cp -dRp $nfsroot/var/log $nfsroot-$host/var/.");
  &dosystem("rm -rf $nfsroot-$host/etc");
  &dosystem("cp -dRp $nfsroot/etc $nfsroot-$host/.");
}

sub mirror_tree {
  foreach $n (@networks) {
    foreach $host (@{$n->[$TARGETS]}) {
      if (@mach_patterns == 0) {
	&mirror_one($host);
      } else {
	foreach $pat (@mach_patterns) {
	  if ($host =~ m|^$pat|) {
	    &mirror_one($host);
	    break;
	  }
	}
      }
    }
  }
}

sub end_message {
  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);
}

sub create_initrd {
  my $initrd_size = "2000";
  my ($dir,$file) = ("/var/tmp/miniroot-tmp/mnt_initrd","/var/tmp/miniroot-tmp/initrd.img");
  mkpath(["$dir"],1,0755) or error "making dir";
  &dosystem("dd bs=1k count=2000 < /dev/zero > $file");
  &dosystem("mke2fs -F $file $initrd_size");
  &dosystem("mount $file -oloop $dir");
  mkpath(["$dir/sbin","$dir/bin","$dir/etc","$dir/dev","$dir/var/run",
	  "$dir/nfsroot","$dir/mod","$dir/proc"],1,0755) or error "making dir";
  echo_to "$dir/etc/pump.conf","device eth0 \n { \n no-dns \n } \n";
  &dosystem("mknod $dir/dev/console c 5 1");
  do_copy("$sharedir/repli-busybox","$dir/sbin/repli-busybox");
  foreach (qw(sbin/init sbin/pump bin/mount sbin/insmod)) {
    symlink("../sbin/repli-busybox","$dir/$_") or error "symlink to $dir/$_:$!";
  }
  my $mod = new FileHandle "$dir/etc/bootmod.list","w" or error "opening $dir/etc/bootmod.list:$!";
  foreach (@net_mod) {
    docopy ("$nfsroot/lib/modules/2.2.19/net/$_.o","$dir/mod/$_.o");
    print $mod "/mod/$_.o" or error "print:$!";
  }
  $mod->close or error "closing";
  &dosystem("umount $dir");
  &dosystem("gzip $file");
  docopy("$file.gz","$nfsroot/boot/initrd-miniroot");
}

#
#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.")};

#check for debootstrap
&dosystem("which debootstrap","debootstrap not found");

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

@mach_patterns=@ARGV;

$multi_install || @mach_patterns == 0 or usage();

check_var(qw(nfsroot));

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

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

unless ($fast) {
  if ($debian_version<3.0){require("repli-miniroot-potato")}
  else {&install_woody;}
  #  &create_initrd;
  &update_config;
  &set_miniroot_pwd;
  if ($multi_install) {&mirror_tree;}
  &end_message;
}
else {
  &update_config ;
  if ($multi_install) {&mirror_tree};
}
