#!/usr/bin/perl -X
#
# Copyright (C) 2002-2003 by NCHC, Steven Shiau, K. L. Huang
# (steven _at nchc org tw, klhaung _at_ gmail com)
#
# 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, 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.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# Version 0.1, by K. L. Huang, klhaung _at_ gmail com, especially for Debian
# Modified by Steven Shiau, steven _at_ nchc org tw DRBL for Redhat

# setting 
# timed login to GDM default time (seconds)
our $TIMED_GDM_TIME_DEFAULT="30";

# Swap size for client to open
our $MAXSWAPSIZE_DEFAULT="128";

# default autologin or timed login account password length
our $ACCOUNT_PASSWD_LENGTH_DEFAULT="8";

# default client no connected to some ethernet port
our $DEFAULT_CLIENT_NO_EACH_PORT="12";
# $assign_client_no_each_port is assign by -p or --port_client_no
our $assign_client_no_each_port;

# default boot prompt timeout for PXE client 
our $DEFAULT_CLIENT_SYSTEM_BOOT_TIMEOUT="70";

#
our $DEFAULT_NISDOMAINNAME="penguinzilla";
our $DEFAULT_DOMAINNAME="drbl.sf.net";

# This parameters are also defined in /opt/drbl/conf/drbl.conf!!!
# They need to be consistent!!!
# TODO: find a better way to do.
our $DRBL_SCRIPT_PATH="/opt/drbl";
our $drbl_setup_path="$DRBL_SCRIPT_PATH/setup";
our $drbl_syscfg="/etc/drbl";

# file name to record the auto login ID and passwd
our $AUTO_LOGIN_ID_PASSWD="$drbl_syscfg/auto_login_id_passwd.txt";

# the craeted config filename
our $DRBLPUSH_CONF="drblpush.conf";
# file to record the hosts
our $hosts_list="hosts_list.drbl";
# file to record the public IP for clients
our $public_ip_list="public_ip.drbl";
our @ip_sys_prefix;
our @ip_sys;
our $public_ip_port;
our $public_ip_addr;
# $pub_port_NAT is when there is no public IP in this drbl server, one of those
# private IPs which is connected to NAT server.
our $pub_port_NAT;

our $purge_client;
our $keep_client;
our $client_startup_mode;
# DRBL SSI (Single System Image) MODE: clients use the tarball template in /tftpboot/node_root/drbl_ssi for etc, var. There is a program "drbl_ssi_client_prepare" will be run in init.drbl to modify the necessary config of etc when client boots.
# Clonezilla box mode = DRBL SSI mode + runlevel 1 in client
our $drbl_ssi_mode;
our $clonezilla_box_mode;
# switch for local swap in client
our $swap_create;
our $client_exist_flag;

# use some perl modules
use Term::ANSIColor;
use File::Path;
# Import locale-handling tool set from POSIX module.
use POSIX qw(locale_h);
# set the locale to C
setlocale(LC_ALL, "C");

#
# ------------------------------------------------------------------------
# Begin of the program
# subroutines
require "$DRBL_SCRIPT_PATH/sbin/drbl-perl-functions";

chomp($orig_wd=`LC_ALL=C pwd`);
chomp($drblpush_wd=`LC_ALL=C mktemp -d /tmp/drblpush_wd.tmp.XXXXXX`);
# before changing to working directory, we copy the macadr-eth* into working dir
system("cp -f macadr-eth*.txt $drblpush_wd &> /dev/null");
chdir ($drblpush_wd) || die ("Could not change to new working directory!!!");

sub set_client_public_ip {
  # $_[0]: file to input containing client IPs (input)
  # $_[1]: file to output containing client public IPs parameters (return)
  my @drbl_ip=`cat $_[0]`;
  my $public_ip_file="$_[1]";
  
  my $saved_ip="";
  my $saved_gw="";
  my $saved_netmask="255.255.255.0";
  my $public_ip;
  my $public_gw;
  my $public_netmask;
  my @public_network_param;
  my $first_saved_ip;

sub check_net_digit {
    my $check_ip="$_[0]";
    my $check_type="$_[1]"; # 2 values: IP or NETMASK
    my @check_ip_each=split(/\./,$check_ip);
    if (@check_ip_each != "4") { return "failed"; }
    if ($check_type eq "IP") {
      # check the first and last digit, it can not be 255 or 0. 
      if ($check_ip_each[$#$check_ip_each] eq "0" || $check_ip_each[$#$check_ip_each] eq "255" ) {
         print "$check_ip_each[$#$check_ip_each] $lang_deploy{\"can_not_be_the_last_IP\"}!!!\n";
         return "failed";
      }
      if ($check_ip_each[0] eq "0" || $check_ip_each[0] eq "255" ) {
         print "$check_ip_each[0] $lang_deploy{\"can_not_be_the_first_IP\"}!!!\n";
         return "failed";
      }
    }

    foreach $DIG (@check_ip_each) {
      if ($check_type eq "IP") {
        if ($DIG > "255" || $DIG < "0") {
          return "failed";
        }
      }elsif ($check_type eq "NETMASK"){
        if ($DIG >= "256") {
          return "failed";
        }
      }
    }
} # end of sub check_net_digit

sub get_network_param {
    $IP="$_[0]";
    $saved_ip="$_[1]";
    $saved_gw="$_[2]";
    $saved_netmask="$_[3]";
    print "$lang_deploy{\"enter_public_IP_for_the_client\"} ($lang_deploy{\"its_IP_in_DRBL_is\"} $IP)\n[$saved_ip] ";
    chomp($public_ip=<STDIN>);
    if ($public_ip eq ""){
      $public_ip=$saved_ip;
    }
    my $chk_rlt=check_net_digit($public_ip,"IP");
    while ($chk_rlt eq "failed") {
       print "$lang_deploy{\"wrong_entered_IP\"}\n";
       chomp($public_ip=<STDIN>);
       $chk_rlt=check_net_digit($public_ip,"IP");
    }
    print "public_ip $public_ip\n" if $verbosity >=2;
    
    @networkIp=split(/\./,$public_ip);
    my $IP_PREFIX=$networkIp[0].".".$networkIp[1].".".$networkIp[2];
    $saved_ip=$IP_PREFIX.".".++$networkIp[3];
    print "network $IP_PREFIX.0\n" if $verbosity >=2;
    print "saved_ip $saved_ip\n" if $verbosity >=2;
    $saved_gw=$IP_PREFIX.".".254;
    
    # public ip gateway
    print "$lang_deploy{\"enter_gateway_for_client\"} ($lang_deploy{\"its_IP_in_DRBL_is\"} $IP) \n[$saved_gw] ";
    chomp($public_gw=<STDIN>);
    if ($public_gw eq "") { $public_gw=$saved_gw; }
    my $chk_rlt=check_net_digit($public_gw,"IP");
    while ($chk_rlt eq "failed") {
       print "$lang_deploy{\"wrong_entered_IP\"}\n";
       chomp($public_gw=<STDIN>);
       $chk_rlt=check_net_digit($public_gw,"IP");
    }
    $saved_gw=$public_gw;
    print "public_gw is $public_gw\n" if $verbosity >=2;
    print "saved_gw is $saved_gw\n" if $verbosity >=2;
    
    
    # public ip netmask
    print "$lang_deploy{\"enter_netmask_for_client\"} ($lang_deploy{\"its_IP_in_DRBL_is\"} $IP) \n[$saved_netmask] ";
    chomp($public_netmask=<STDIN>);
    if ($public_netmask eq "") { $public_netmask="$saved_netmask" }
    my $chk_rlt=check_net_digit($public_netmask,"NETMASK");
    while ($chk_rlt eq "failed") {
       print "$lang_deploy{\"wrong_entered_netmask\"}\n";
       chomp($public_netmask=<STDIN>);
       $chk_rlt=check_net_digit($public_netmask,"NETMASK");
    }
    $saved_netmask=$public_netmask;
    print "public_netmask is $public_netmask\n" if $verbosity >=2;
    print "saved_netmask is $saved_netmask\n" if $verbosity >=2;
    
    return $saved_ip, $saved_gw, $saved_netmask, $public_ip, $public_gw, $public_netmask;
}
#end of sub get_network_param
  
  chomp($public_ip_tmp=`LC_ALL=C mktemp /tmp/public_ip_tmp.XXXXXX`);
  chomp($public_ip_guess=`LC_ALL=C mktemp /tmp/public_ip_guess.XXXXXX`);
  open(PUBLIC_IP_FILE,">$public_ip_tmp") or die "$lang_deploy{\"failed_to_open_file\"}  \"$public_ip_tmp\"\n";
  open(PUBLIC_IP_GUESS_FILE,">$public_ip_guess") or die "$lang_deploy{\"failed_to_open_file\"}  \"$public_ip_guess\"\n";
  print "Clients' IPs: @drbl_ip\n" if $verbosity >=2;
  
# prepare the public ip file, one for guessed from first input, the other for
# entering one by one.
  print PUBLIC_IP_FILE <<END_PUBLIC_IP;
# The private IP is for the client connected to DRBL server.
# The public IP is for the client connected to WAN.
#------------------------------------------------------------
#private IP \t public IP \t netmask \t gateway
END_PUBLIC_IP

  print PUBLIC_IP_GUESS_FILE <<END_PUBLIC_IP_GUESS;
# The private IP is for the client connected to DRBL server.
# The public IP is for the client connected to WAN.
#------------------------------------------------------------
#private IP \t public IP \t netmask \t gateway
END_PUBLIC_IP_GUESS
  
  chomp($IP=@drbl_ip[0]);
  # get first public ip for client
  get_network_param($IP, $saved_ip, $saved_gw, $saved_netmask);
  $first_saved_ip=$saved_ip;
  
  print PUBLIC_IP_FILE <<END_PUBLIC_IP;
$IP \t $public_ip \t $public_netmask \t $public_gw
END_PUBLIC_IP

  print PUBLIC_IP_GUESS_FILE <<END_PUBLIC_IP_GUESS;
$IP \t $public_ip \t $public_netmask \t $public_gw
END_PUBLIC_IP_GUESS
  
  foreach $IP (@drbl_ip[1..$#drbl_ip]) {
    chomp($IP);
    $public_ip=$saved_ip;
    @networkIp=split(/\./,$public_ip);
    my $IP_PREFIX=$networkIp[0].".".$networkIp[1].".".$networkIp[2];
    $saved_ip=$IP_PREFIX.".".++$networkIp[3];
   
    $public_netmask=$saved_netmask;
    $public_gw=$saved_gw;
    print PUBLIC_IP_GUESS_FILE <<END_PUBLIC_IP_GUESS;
$IP \t $public_ip \t $public_netmask \t $public_gw
END_PUBLIC_IP_GUESS
  }
  
  print "#$delimiter{\"dash_line\"}\n";
  print "$lang_deploy{\"set_client_public_IP_as\"}\n";
  print "#$delimiter{\"dash_line\"}\n";
  system("LC_ALL=C cat $public_ip_guess");
  print "#$delimiter{\"dash_line\"}\n";
  print "$lang_text{\"Accept\"} ? [Y/n] ";
  chomp($value=<STDIN>);
  SWITCH: for ($value) {
	  /^n$|^no$/i && do {
            # Enter each one by one
            foreach $IP (@drbl_ip[1..$#drbl_ip]) {
              chomp($IP);
              # use the first one saved for initial prompt value to user
              $saved_ip=$first_saved_ip;
              get_network_param($IP, $saved_ip, $saved_gw, $saved_netmask);
              print PUBLIC_IP_FILE <<END_PUBLIC_IP;
$IP \t $public_ip \t $public_netmask \t $public_gw
END_PUBLIC_IP
            }
            close(PUBLIC_IP_FILE);
            # put the result file to working directory
            system("LC_ALL=C cp -f $public_ip_tmp $public_ip_file");
            last SWITCH;
	  };
	  /.*/ && do {
            # accept the guess one, output the result
            close(PUBLIC_IP_GUESS_FILE);
            # put the result file to working directory
            system("LC_ALL=C cp -f $public_ip_guess $public_ip_file");
            last SWITCH;
	  };
  }
  
  unlink ($public_ip_tmp) if -f $public_ip_tmp;
  unlink ($public_ip_guess) if -f $public_ip_guess;
} #end of sub set_client_public_ip
#
sub set_autologin_passwd{
  print "$lang_deploy{\"use_random_password\"}\n".
        "[Y/n] ";
  chomp($auto_login_random_passwd=<STDIN>);
  if ($auto_login_random_passwd eq "n" || $auto_login_random_passwd eq "N" || $auto_login_random_passwd eq "no" || $auto_login_random_passwd eq "NO") {
      # input password for client auto-login account
      print "$lang_deploy{\"enter_password_for_autologin_accounts\"}\n";
      # we set 2 different passwords to make while loop works.
      $client_autologin_passwd1="init1";
      $client_autologin_passwd2="init2";
      while ($client_autologin_passwd1 ne $client_autologin_passwd2 || ($client_autologin_passwd1 eq "" && $client_autologin_passwd2 eq "" )) { 
           print "$lang_deploy{\"whats_client_autologin_passwd\"}\n";
  	 # turn off echo
           system "LC_ALL=C stty -echo";
           chomp($client_autologin_passwd1=<STDIN>);
  	 # turn on echo
           system "LC_ALL=C stty echo";
           print "$lang_deploy{\"retype_autologin_passwd\"}\n";
           system "LC_ALL=C stty -echo";
           chomp($client_autologin_passwd2=<STDIN>);
           system "LC_ALL=C stty echo";
        if ($client_autologin_passwd1 ne $client_autologin_passwd2) { 
  	  print colored ("$lang_deploy{\"sorry_passwd_not_match\"}\n", 'red');
        }elsif ($client_autologin_passwd1 eq "" && $client_autologin_passwd2 eq "" ){ 
  	  print colored ("$lang_deploy{\"sorry_passwd_can_not_empty\"}\n", 'red');
        }
      }
      $client_autologin_passwd=$client_autologin_passwd1;
  }else{
      # Random password for client auto-login account
      $client_autologin_passwd="$ACCOUNT_PASSWD_LENGTH_DEFAULT";
      print "$lang_deploy{\"ok_let_continue\"}\n";
  }
} # end of set_autologin_passwd

#
sub interactive_mode {
        my $domain_sys, $nisdomain_sys, $hostname_sys;
	#we will scan the ethernet from $ethernet_list[0]...
	#use public IP in alias interface, private IP in real interface, 
	#Ex: eth0: 192.168.0.254, eth0:1 61.216.116.23

	my $ethernet_list_;
	print "Finding the available ethernet ports...\n" if $verbosity >=2;
	chomp($ethernet_list_=`$DRBL_SCRIPT_PATH/bin/get-all-nic-ip -d`);
	my @ethernet_list=split(/ /,$ethernet_list_);
	my @ethernet_sys; # the private ethernet we found and useful, ex:"eth1"
	my @range_start;
	my @range_end;
	my @MAC_file;

        # Try to get setting from system 
        chomp($domain_sys=`$DRBL_SCRIPT_PATH/bin/parse_net_conf all domainname`);
        chomp($nisdomain_sys=`$DRBL_SCRIPT_PATH/bin/parse_net_conf all nisdomainname`);
	chomp($hostname_sys=`$DRBL_SCRIPT_PATH/bin/parse_net_conf all hostname`);
        my @client_hostname_prefix_default=split(/\./,$hostname_sys);
        print "DOMAIN in system is $domain_sys\n" if $verbosity >= 2;
        print "NISDOMAIN in system is $nisdomain_sys\n" if $verbosity >= 2;
        print "Client hostname prefix default is $client_hostname_prefix_default[0]\n" if $verbosity >= 2;

        unlink ($DRBLPUSH_CONF) if -f $DRBLPUSH_CONF;
	open(CONFIG_FILE,">$DRBLPUSH_CONF") or die "$lang_deploy{\"failed_to_open_file\"} \"$DRBLPUSH_CONF\"\n";

        unless ( $domain_sys ) {
           print "$delimiter{\"dash_line\"}\n".
                 "$lang_deploy{\"domain_unset_prompt\"}\n".
	         "[$DEFAULT_DOMAINNAME] ";
           while (<STDIN>) {
              chomp;
              $domain_sys=$_;
	      if ( "$domain_sys" =~ / |\/|\\/ ) {
  	        print "\" \" ($lang_text{\"space\"}), \"/\", $lang_text{\"or\"} \"\\\" $lang_deploy{\"not_allowed_domainname\"}\n";
              } else {
	        # if empty, use default name
                if ($domain_sys eq "") { $domain_sys="$DEFAULT_DOMAINNAME"; }
	        print "$lang_deploy{\"set_domain_as\"} $domain_sys\n";
                last;
              }
           }
        }
	if ( $nisdomain_sys eq "localdomain" || ! $nisdomain_sys ) {
           print "$delimiter{\"dash_line\"}\n".
                 "$lang_deploy{\"nisdomain_unset_prompt\"}\n".
	         "[$DEFAULT_NISDOMAINNAME] ";
           while (<STDIN>) {
              chomp;
              $nisdomain_sys=$_;
	      if ( "$nisdomain_sys" =~ / |\/|\\|\.|^[0-9]/ ) {
  	        print "\" \" ($lang_text{\"space\"}), \"/\", \".\", \"\\\" $lang_text{\"or\"} \"$lang_word{\"initial_digit\"}\" $lang_deploy{\"not_allowed_nisdomain_sys\"}\n";
              } else {
	        # if empty, use default name
                if ($nisdomain_sys eq "") { $nisdomain_sys="$DEFAULT_NISDOMAINNAME"; }
	        print "$lang_deploy{\"set_domain_as\"} $nisdomain_sys\n";
                last;
              }
           }
        }
        print "$delimiter{\"dash_line\"}\n".
              "$lang_deploy{\"enter_client_hostname_prefix\"}\n".
	      "[$client_hostname_prefix_default[0]] ";
           while (<STDIN>) {
              chomp;
              $client_hostname_prefix=$_;
	      if ( "$client_hostname_prefix" =~ / |\/|\\|\.|^[0-9]/ ) {
		# "-" should be ok, but we need to parse the /etc/dhcpd.conf
		# then if make it like fc1-1=00:2A:00:AB:CD:EF, run 
		#  fc1-1=00:2A:00:AB:CD:EF in shell will fail. So we skip
		#  "-"
  	        print "\" \" ($lang_text{\"space\"}), \"/\", \".\", \"\\\" $lang_text{\"or\"} \"$lang_word{\"initial_digit\"}\" $lang_deploy{\"not_allowed_hostname\"}\n";
              } else {
	        # if empty, use default name
                if ($client_hostname_prefix eq "") {
                  $client_hostname_prefix="$client_hostname_prefix_default[0]";
                }
                print "$lang_deploy{\"set_client_hostname_prefix\"} $client_hostname_prefix\n".
                "$delimiter{\"dash_line\"}\n";
                last;
              }
           }
        # try to find all the NIC for clients, i.e. eth1, eth2...
        foreach my $ethx (@ethernet_list) {
	 print "Finding the IP address for $ethx...\n" if $verbosity >=2;
	 chomp($nic_ethx_ip=`$DRBL_SCRIPT_PATH/bin/get_ip $ethx`);
   	 if ( $nic_ethx_ip ) {
	   # Specially, we do not want the alias interface, such as:eth0:1
           my $IP=`$DRBL_SCRIPT_PATH/bin/get_ip $ethx`;
	   chomp($IP);
	   if ( "$IP" =~ /^(192.168\..*|172\.(1[6-9]|2[0-9]|3[01])\..*|10\..*)/ ) {
             # A ClassG10.0.0.0 - 10.255.255.255
             # B ClassG172.16.0.0  - 172.31.255.255 
             # C ClassG192.168.0.0 - 192.168.255.255 
  	     print "Found private IP \"$IP\" in $ethx on your system!\n";
  	     push @ethernet_sys, $ethx;
           } elsif ( ! $IP ) {
             print "Can NOT find $ethx IP in your system!\n".
	           "$lang_deploy{\"we_will_skip\"} $ethx!\n";
           } else {
             print "Found $ethx IP ($IP) in your system, $lang_deploy{\"but_not_private_IP_or_configured\"}\n".
	           "$lang_deploy{\"we_will_skip\"} $ethx!\n";
           }

         }
        }
	if ( @ethernet_sys <= 0 ) {
 	  print "$lang_deploy{\"no_NIC_setup\"}\n".
	        "$lang_deploy{\"we_can_NOT_continue\"}\n";
	  exit;
	} else { 
       	  print "$lang_deploy{\"configured_nic\"} ". 
	         colored ("@ethernet_sys \n", 'red');
          print "$delimiter{\"dash_line\"}\n";

	  # Find the ethernet port connected to WAN.
	  print "Finding the available public IP address...\n" if $verbosity >=2;
	  chomp($public_ip_addr=`$DRBL_SCRIPT_PATH/bin/get-all-nic-ip -a`);
	  chomp($public_ip_port=`$DRBL_SCRIPT_PATH/bin/get-all-nic-ip -p`);
	  if ($public_ip_port) {
            print "$lang_deploy{\"ethernet_port_for_internet\"} $public_ip_port\n";
            @ethernet_sys = grep { $_ ne "$public_ip_port" } @ethernet_sys;
            print "$lang_deploy{\"ethernet_port_for_DRBL\"} ".
	          colored ("@ethernet_sys \n", 'red');

          }else{
            my $private_eth_ports_;
            chomp($private_eth_ports_=`$DRBL_SCRIPT_PATH/bin/get-all-nic-ip -t`);
            my @private_eth_ports=split(/ /,$private_eth_ports_);
	    my $guess_uplink_port;
	    # we just want one port, so use "head -n 1" to get the 1st one.
            chomp($guess_uplink_port=`PATH=$PATH:/sbin/:/usr/sbin route -n | awk '/^0.0.0.0/ {print \$8}' | sort | head -n 1`);
            print "$lang_deploy{\"unable_to_find_public_IP\"}\n".
                  "$lang_deploy{\"for_internet_access_prompt\"}\n".
		  "$lang_deploy{\"available_eth_ports\"}:\n";
            foreach my $ethx (@private_eth_ports){
                  my $IP=`$DRBL_SCRIPT_PATH/bin/get_ip $ethx`;
	          chomp($IP);
                  print "$ethx ($IP), ";
            }
	    print "\n";
            print "[$guess_uplink_port] ";
            while (<STDIN>) {
              chomp;
	      $pub_ans=$_;
              if ($pub_ans eq "") { $pub_ans="$guess_uplink_port"; }
	      foreach my $k (@private_eth_ports) {
	        if ( "$pub_ans" eq "$k" ) {
	          # if empty, use default name
	          $pub_port_NAT=$pub_ans;
                  last;
                } 
	      }
	      if ( $pub_port_NAT ) {
		 last;
              }else{
  	         print "\"$pub_ans\" $lang_deploy{\"is_not_in_the_lists\"} (@private_eth_ports). $lang_deploy{\"enter_it_again\"}!\n";
              }
            }
	    print "$lang_deploy{\"the_eth_port_you_choose_for_wan\"}: ".
	          colored ("$pub_port_NAT\n", 'red');
            @ethernet_sys = grep { $_ ne "$pub_port_NAT" } @ethernet_sys;
            print "$lang_deploy{\"ethernet_port_for_DRBL\"} ".
	          colored ("@ethernet_sys \n", 'red');
          }
	  # if not ethernet port is available for DRBL, quit.
	  if ( @ethernet_sys <= 0 ) {
	    print colored ("$lang_deploy{\"no_DRBL_port\"}\n", 'red').
	          colored ("$lang_deploy{\"we_can_NOT_continue\"}\n", 'red');
	    exit;
	  }
	  # Checking if class A/B private IP ? If so, set warning about multicast clonezilla
          for($i=0;$i<=$#ethernet_sys;$i++) {
	    my $ethx="$ethernet_sys[$i]";
            my $IP=`$DRBL_SCRIPT_PATH/bin/get_ip $ethx`;
	    chomp($IP);
	    if ( "$IP" =~ /^(172\.(1[6-9]|2[0-9]|3[01])\..*|10\..*)/ ) {
              # A ClassG10.0.0.0 - 10.255.255.255
              # B ClassG172.16.0.0  - 172.31.255.255 
	      print "$delimiter{\"star_line\"}\n";
  	      print "Found class A or B private IP \"$IP\" in $ethx for your DRBL system! ".
              colored ("$lang_deploy{\"class_c_IP_for_multicast_clonezilla\"}\n", 'yellow');
              print "$delimiter{\"star_line\"}\n".
                    "$lang_deploy{\"press_enter_to_continue\"}";
                    chomp($line=<STDIN>);
            }
	  };
	  print "$delimiter{\"star_line\"}\n";
        }

# detect the mac address
    print "$delimiter{\"star_line\"}\n".
          "$lang_deploy{\"collect_MAC_prompt\"}\n".
	  "[y/N] ";
    chomp($line=<STDIN>);
    SWITCH: for ($line) {
	    /^y$|^yes$/i && do {
		  $collect_mac="yes";
                  print "$delimiter{\"star_line\"}\n".
                        "$lang_deploy{\"ok_let_do_it\"}\n";
                  my $whoiam = `LC_ALL=C id -nu`;
                  chomp($whoiam);
                  if ("$whoiam" eq "root") { 
                    system("LC_ALL=C $DRBL_SCRIPT_PATH/sbin/drbl-collect-mac @ethernet_sys");
                  }else{
                     print "$lang_deploy{\"you_are_not_root\"},\n". 
                           "$lang_word{\"please_enter\"} ". colored("$lang_word{\"root_passwd\"} ",'red'). "to collect those MAC addresses...\n"; 
                     my $su_rlt=system("LC_ALL=C su -c \"$DRBL_SCRIPT_PATH/sbin/drbl-collect-mac @ethernet_sys\" root");
                     while ($su_rlt == 256) { 
                            $su_rlt=system("LC_ALL=C su -c \"$DRBL_SCRIPT_PATH/sbin/drbl-collect-mac @ethernet_sys\" root");
                     }
                  }
		  last SWITCH;
	    };
	    /.*/ && do {
		  $collect_mac="no";
		  last SWITCH;
	    };
    }

    print "$delimiter{\"star_line\"}\n".
          "$lang_deploy{\"ok_let_continue\"}\n".
          "$delimiter{\"star_line\"}\n";

# ask user to input client no.
        for($i=0;$i<=$#ethernet_sys;$i++) {
	 $ethx="$ethernet_sys[$i]";
          # Try to get setting from system also
          # get the ipaddress of NIC "eth1, eth2..." 
          my $ip_sys_tmp;
          chomp($ip_sys_tmp=`$DRBL_SCRIPT_PATH/bin/get_ip $ethx`);
	  # We must get the static IP for this NIC, NO DHCP...
          if ( "$ip_sys_tmp" eq "" ) {
	    print "$delimiter{\"star_line\"}\n".
  	          "$lang_deploy{\"unable_to_get_ethx_IP\"} ".
	           colored("$ethx \n",'red').
            	  "$lang_deploy{\"program_stop\"}\n";
            exit (1);
          };
          my @ip_sys_sp=split(/\./,$ip_sys_tmp);
          $ip_sys[$i]=$ip_sys_tmp;
          $ip_sys_prefix[$i]="$ip_sys_sp[0].$ip_sys_sp[1].$ip_sys_sp[2]";

  	  print "$lang_deploy{\"fix_eth_IP_prompt\"} ".
	         colored("$ethx",'red').
		 " ?\n".
	  "[y/N] ";
	  chomp($MAC=<STDIN>);
          my $mac_f_tmp="";
	  if ($MAC eq "y" || $MAC eq "Y" || $MAC eq "yes" || $MAC eq "YES") {
            # user want to fix the IP address for DRBL client 
	    print "$delimiter{\"star_line\"}\n".
	          "$lang_deploy{\"MAC_file_prompt\"} $ethx.\n".
		  "[macadr-$ethx.txt] ";
            while (<STDIN>) {
	      chomp;
	      if ( $_ eq "" ) {
	        $mac_f_tmp="macadr-$ethx.txt";
	      }else{
	        $mac_f_tmp=$_;
	      }

              # 2 cases filename user entered (1) without path (2) with path
              # we will try both cases, and copy the file to working dir.
              $MAC_file[$i]=`basename $mac_f_tmp 2>/dev/null`;
              chomp($MAC_file[$i]);
              my $mac_dir=`dirname $mac_f_tmp 2>/dev/null`;
              chomp($mac_dir);
              # if user does not specify the path, then it is the original wd
              if ( $mac_dir eq "." ) { $mac_dir="$orig_wd"; }
              print "MAC_file[$i], mac_dir: $MAC_file[$i], $mac_dir\n" if $verbosity >= 2;

              # (1) w/o path: copy the entered file from orig_wd if they exist
              # this is the case if user specified file like "mac1.txt"
              # (2) whith path: copy the entered file if they exist
              # this is the case if user specified file like "/root/mac1.txt"
              system("[ -f $mac_dir/$MAC_file[$i] ] && cp -f $mac_dir/$MAC_file[$i] ./");

              # check MAC address files
              check_MAC_file(".","$MAC_file[$i]");

	      # Find the available start IP which will not conflict with the server
	      my $range_start_default = $ip_sys_sp[3]+1;
	      if ($range_start_default >= 254) { $range_start_default=1; }

              # get the client no from user input
	      # 1st, get the initial value of the last set of digits in the IP address in this subnet
	      print "$delimiter{\"star_line\"}\n".
	            "$lang_deploy{\"IP_start_prompt\"} $ethx.\n",
		    "[$range_start_default] ";

              unless ( $range_start[$i] ) {
                 while (<STDIN>) {
                   chomp;
	           my $start_input=$_;
                   if ($start_input eq "") {
                     $range_start[$i]=$range_start_default;
	             last;
	           } elsif ( $start_input =~ /[^0-9]/ ) {
	               print "$lang_deploy{\"not_initial_value\"}\n";
                   } else {
	               $range_start[$i]=$start_input;
	               last;
                   }
                 }
              }
	      # use wc -l to count the lines of file user input
              # we use the MAC file in working dir ($MAC_file[$i]) so it been
              # processed by check_MAC_file. Ex. the space line is stripped.
              $line=`LC_ALL=C cat $MAC_file[$i] 2>/dev/null| wc -l |tr -d \" \" `;
	      chomp($line);
	      if ($line >= 254) {
	       print "The file \"$mac_dir/$MAC_file[$i]\" you set for the clients connected to $ethx is empty or invalid, $lang_word{\"please_enter\"} the filename again, or press \"ctrl-c\" to quit!\n";
              } else {
               $range_end[$i]=$range_start[$i] + $line - 1;
	       last;
              }
	    }
	  } else {
	    print "$delimiter{\"star_line\"}\n".
	          "$lang_deploy{\"range_prompt\"}\n";
	    # Find the available start IP which will not conflict with the server
	    my $range_start_default = $ip_sys_sp[3]+1;
	    if ($range_start_default >= 254) { $range_start_default=1; }

            # user does NOT want to fix the IP address for DRBL client 
            # get the client no from user input
	    print "$delimiter{\"star_line\"}\n".
	          "$lang_deploy{\"IP_start_prompt\"} $ethx.\n",
		  "[$range_start_default] ";
            unless ( $range_start[$i] ) {
               while (<STDIN>) {
                 chomp;
	         my $start_input=$_;
                 if ($start_input eq "") {
                   $range_start[$i]=$range_start_default;
	           last;
	         } elsif ( $start_input =~ /[^0-9]/ ) {
	             print "$lang_deploy{\"not_initial_value\"}\n";
                 } else {
	             $range_start[$i]=$start_input;
	             last;
                 }
               }
            }
            # count the clients no which already exist to prompt user
            my $client_no;
	    if ( ! $assign_client_no_each_port ) { 
              $client_no=`LC_ALL=C unalias ls 2> /dev/null; ls -d /tftpboot/nodes/$ip_sys_prefix[$i].* 2>/dev/null |wc -w|sed -e "s/ //g"`;
              chomp($client_no);
              # if 0, set the default no for user
	      if ($client_no eq "0") { $client_no="$DEFAULT_CLIENT_NO_EACH_PORT";}
            } else {
              $client_no=$assign_client_no_each_port;
            }
            print "client_no:$client_no\n" if $verbosity >=2;
	    print "$delimiter{\"star_line\"}\n".
  	          "$lang_deploy{\"client_number_connected_to_eth\"} $ethx ?\n".
                  "$lang_deploy{\"enter_the_no\"} \n".
                  "[$client_no] ";
            while (<STDIN>) {
	      chomp;
	      my $line=$_;
	      if ($line eq "") { $line=$client_no;}
	      if ($line >= 254) {
	       print "The value \"$line\" you input for the number of clients connected to $ethx is INVALID, $lang_word{\"please_enter\"} again!\n";
	      }
	      else {
               $range_end[$i]=$range_start[$i] + $line - 1;
	       last;
              }
	    }
	  }

          if ( ! $MAC_file[$i] ){ 
            # use the range for clients.
	    print "$delimiter{\"star_line\"}\n".
	          "$lang_deploy{\"the_value_you_set\"} \"$range_end[$i]\".\n".
  	          "$lang_deploy{\"set_the_IP_connected_to_eth\"} ".
                  colored ("$ethx $lang_text{\"as\"}: $ip_sys_prefix[$i].$range_start[$i] - $ip_sys_prefix[$i].$range_end[$i]\n",'red').
                  "$lang_text{\"Accept\"} ? [Y/n] ";
	  }else{
            # use the fixed IP address for clients.
	    print "$delimiter{\"star_line\"}\n".
	          "$lang_deploy{\"filename_you_set\"} \"$MAC_file[$i]\".\n".
		  "$lang_deploy{\"client_no_in_MAC_file\"} $line.\n".
  	          "$lang_deploy{\"set_the_IP_connected_to_eth\"} $ethx $lang_deploy{\"by_MAC_file\"} ".
                  colored ("$ethx $lang_text{\"as\"}: $ip_sys_prefix[$i].$range_start[$i] - $ip_sys_prefix[$i].$range_end[$i]\n",'red').
                  "$lang_text{\"Accept\"} ? [Y/n] ";
          }

	  chomp($line=<STDIN>);
	  if ($line eq "n" || $line eq "N" || $line eq "no" || $line eq "NO") {
	   print "$delimiter{\"exclamation_line\"}\n".
	         "$lang_deploy{\"let_restart_it_again\"}\n";
	   redo;
	  }
	  else {
	   print "$delimiter{\"star_line\"}\n".
	         "$lang_deploy{\"ok_let_continue\"}\n";
          }
  
	}

	# print the schematic network
        my $PUB_NIC;
        my $IP_PUB_NIC;
	if ( $public_ip_port ) {
          $PUB_NIC=$public_ip_port;
	  $IP_PUB_NIC=$public_ip_addr;
        }else{
          $PUB_NIC=$pub_port_NAT;
          chomp($IP_PUB_NIC=`$DRBL_SCRIPT_PATH/bin/get_ip $pub_port_NAT`);
	}
	print "$delimiter{\"star_line\"}\n".
       	      "$lang_deploy{\"layout_for_DRBL\"} \n".
  	      "$delimiter{\"star_line\"}\n";
        print color 'bold red';
        print
"          NIC    NIC IP                    Clients\n".
"+-----------------------------+\n".
"|         DRBL SERVER         |\n".
"|                             |\n".
"|    +-- [$PUB_NIC] $IP_PUB_NIC +- to WAN\n".
"|                             |\n";
	  my @grp_no;
          my $total_client_no=0;
          for($i=0;$i<=$#ethernet_sys;$i++) {
	   $ethx="$ethernet_sys[$i]";
	   my $grp=$ethx;
	   # extract group for ethx, i.e. group 1 for eth1, group 3 for eth3... 
	   # For interface like vmnet1, we will not extract that so that the
	   # hostname will not conflict.
	   $grp=~ s/eth//;
	   # calculate the clients number
	   $grp_no[$i] = $range_end[$i]-$range_start[$i]+1;
	   # get the total client number
           $total_client_no += $grp_no[$i];
	   #
           print 
"|    +-- [$ethx] $ip_sys[$i] +- to clients group $grp [ $grp_no[$i] clients, their IP \n".
"|                             |            from $ip_sys_prefix[$i].$range_start[$i] - $ip_sys_prefix[$i].$range_end[$i]]\n";
          }
  
	  print
"+-----------------------------+\n";
          print color 'reset';
          print
		"$delimiter{\"star_line\"}\n";

        print "Total clients: ". 
	      colored ("$total_client_no\n", 'red');

	# Ask user if clonezilla box mode ?
	print "$delimiter{\"star_line\"}\n";
	if ( ! $clonezilla_box_mode ) {
          print "$delimiter{\"dash_line\"}\n".
                "$lang_deploy{\"clonezilla_box_mode_for_client\"}\n".
	        "[y/N] ";
          chomp($clonezilla_box_mode=<STDIN>);
        }
        SWITCH: for ($clonezilla_box_mode) {
          /^y$|^yes$/i && do {
            $clonezilla_box_mode="yes";
	    # Clonezilla box mode is yes, then drbl SSI mode must be yes.
	    $drbl_ssi_mode="yes";
	    # suppress some modes.
	    $swap_create="no";
	    $client_startup_mode="2";  # text mode
            $set_client_root_passwd="no";
            $set_DBN_client_audio_plugdev="no";
            $set_client_alias_IP="no";
            $open_thin_client_option="no";
            print "$lang_deploy{\"clonezilla_box_mode_is_set\"}\n".
                  "$delimiter{\"star_line\"}\n";
            last SWITCH;
	  };
          /.*/ && do {
            $clonezilla_box_mode="no";
            print "$lang_deploy{\"clonezilla_box_mode_not_set\"}\n".
                  "$delimiter{\"star_line\"}\n";
            last SWITCH;
          };
        }
	# Ask user if DRBL SSI mode ?
	print "$delimiter{\"star_line\"}\n";
	if ( ! $drbl_ssi_mode ) {
          print "$delimiter{\"dash_line\"}\n".
                "$lang_deploy{\"drbl_ssi_mode_for_client\"}\n".
	        "[y/N] ";
          chomp($drbl_ssi_mode=<STDIN>);
        }
        SWITCH: for ($drbl_ssi_mode) {
          /^y$|^yes$/i && do {
            $drbl_ssi_mode="yes";
            print "$lang_deploy{\"drbl_ssi_mode_is_set\"}\n".
                  "$delimiter{\"star_line\"}\n";
            last SWITCH;
	  };
          /.*/ && do {
            $drbl_ssi_mode="no";
            print "$lang_deploy{\"drbl_ssi_mode_not_set\"}\n".
                  "$delimiter{\"star_line\"}\n";
            last SWITCH;
          };
        }

        # ask if use need local HD space as swap file ?
	if ( ! $swap_create ) {
	  print "$delimiter{\"dash_line\"}\n".
                "$lang_deploy{\"swap_prompt\"}\n".
	        "[Y/n] ";
          chomp($swap_create=<STDIN>);
	}
	SWITCH: for ($swap_create) {
	  /^n$|^no$/i && do {
            $localswapfile="no";
            last SWITCH;
	  };
	  /.*/ && do {
            $localswapfile="yes";
	    print "$delimiter{\"star_line\"}\n".
                  "$lang_deploy{\"try_to_create_swap\"}\n".
                  "$delimiter{\"dash_line\"}\n".
                  "$lang_deploy{\"max_swap_size\"}\n".
	          "[$MAXSWAPSIZE_DEFAULT] ";
            chomp($maxswapsize=<STDIN>);
	    if ( "$maxswapsize" eq "" ) {
	          $maxswapsize="$MAXSWAPSIZE_DEFAULT";
	          print colored ("maxswapsize=$maxswapsize\n", 'red');
            }
            last SWITCH;
	  };
        }

	# Ask which mode is preferred for clients
	print "$delimiter{\"star_line\"}\n";
	if ( ! $client_startup_mode ) {
          print "$delimiter{\"dash_line\"}\n".
                "$lang_deploy{\"mode_for_client_init\"}\n".
	        "[1] ";
          chomp($client_startup_mode=<STDIN>);
        }
        if ($client_startup_mode eq "2") {
            $CLIENT_INIT="text";
            print "$lang_deploy{\"client_text_mode\"}\n".
                  "$delimiter{\"star_line\"}\n";
	}else{
            $CLIENT_INIT="graphic";
            print "$lang_deploy{\"client_graphic_mode\"}\n".
                  "$delimiter{\"star_line\"}\n";
            print "$delimiter{\"dash_line\"}\n".
                  "$lang_deploy{\"login_mode_for_client\"}\n".
	          "[0] ";
            chomp($login_gdm_opt=<STDIN>);
            if ($login_gdm_opt eq "1") {
                $LOGIN_GDM_OPT="auto_login";
		set_autologin_passwd;
                print "$lang_deploy{\"auto_login\"}\n".
                      "$delimiter{\"star_line\"}\n";
                print "[$total_client_no] $lang_deploy{\"created_account_for_auto_login\"}".
                      " \"$AUTO_LOGIN_ID_PASSWD\"\n";
            } elsif ($login_gdm_opt eq "2") {
                $LOGIN_GDM_OPT="timed_login";
                print "$delimiter{\"dash_line\"}\n".
                      "$lang_deploy{\"time_for_countdown\"}\n".
	              "[$TIMED_GDM_TIME_DEFAULT] ";
                chomp($timed_time=<STDIN>);
                if ($timed_time eq "") {
                   $TIMED_LOGIN_TIME = "$TIMED_GDM_TIME_DEFAULT";
                }else{
                   $TIMED_LOGIN_TIME = $timed_time;
                }
                print "$lang_deploy{\"timed_login_prompt\"} $TIMED_LOGIN_TIME $lang_text{\"seconds\"}.\n".
                      "$delimiter{\"star_line\"}\n";
                print "[$total_client_no] $lang_deploy{\"created_account_for_auto_login\"}".
                      " \"$AUTO_LOGIN_ID_PASSWD\"\n";
            } else {
                $LOGIN_GDM_OPT="login";
                print "$lang_deploy{\"normal_login_prompt\"}\n".
                      "$delimiter{\"star_line\"}\n";
            }
        }
	# Ask if user want to set the root password of clients
	if ( ! $set_client_root_passwd ){
          print "$delimiter{\"dash_line\"}\n".
                "$lang_deploy{\"set_client_root_passwd\"}\n".
	        "[y/N] ";
          chomp($set_client_root_passwd=<STDIN>);
	}
	SWITCH: for ($set_client_root_passwd) {
	  /^y$|^yes$/i && do {
            $set_client_root_passwd="yes";
	    # we set 2 different passwords to make while loop works.
	    $client_root_passwd_1="init1";
	    $client_root_passwd_2="init2";
	    while ($client_root_passwd_1 ne $client_root_passwd_2 || ($client_root_passwd_1 eq "" && $client_root_passwd_2 eq "" )) { 
                 print "$lang_deploy{\"whats_client_root_passwd\"}\n";
		 # turn off echo
                 system "LC_ALL=C stty -echo";
                 chomp($client_root_passwd_1=<STDIN>);
		 # turn on echo
                 system "LC_ALL=C stty echo";
                 print "$lang_deploy{\"retype_root_passwd\"}\n";
                 system "LC_ALL=C stty -echo";
                 chomp($client_root_passwd_2=<STDIN>);
                 system "LC_ALL=C stty echo";
	      if ($client_root_passwd_1 ne $client_root_passwd_2) { 
		  print colored ("$lang_deploy{\"sorry_passwd_not_match\"}\n", 'red');
	      }elsif ($client_root_passwd_1 eq "" && $client_root_passwd_2 eq "" ){ 
		  print colored ("$lang_deploy{\"sorry_passwd_can_not_empty\"}\n", 'red');
	      }
	    }
	    $client_root_passwd=$client_root_passwd_1;
            last SWITCH;
	  };
          /.*/ && do {
            $set_client_root_passwd="no";
            print "$lang_deploy{\"ok_let_continue\"}\n";
            last SWITCH;
          };
	}

	# Ask if user want to set the pxelinux password of clients
        print "$delimiter{\"dash_line\"}\n".
              "$lang_deploy{\"set_client_pxelinux_passwd\"}\n".
	      "[y/N] ";
        chomp($set_client_pxelinux_passwd=<STDIN>);
	SWITCH: for ($set_client_pxelinux_passwd) {
	  /^y$|^yes$/i && do {
            $set_client_pxelinux_passwd="yes";
	    # we set 2 different passwords to make while loop works.
	    $client_pxelinux_passwd_1="pxeinit1";
	    $client_pxelinux_passwd_2="pxeinit2";
	    while ($client_pxelinux_passwd_1 ne $client_pxelinux_passwd_2 || ($client_pxelinux_passwd_1 eq "" && $client_pxelinux_passwd_2 eq "" )) { 
                 print "$lang_deploy{\"whats_client_pxelinux_passwd\"}\n";
		 # turn off echo
                 system "LC_ALL=C stty -echo";
                 chomp($client_pxelinux_passwd_1=<STDIN>);
		 # turn on echo
                 system "LC_ALL=C stty echo";
                 print "$lang_deploy{\"retype_root_passwd\"}\n";
                 system "LC_ALL=C stty -echo";
                 chomp($client_pxelinux_passwd_2=<STDIN>);
                 system "LC_ALL=C stty echo";
	      if ($client_pxelinux_passwd_1 ne $client_pxelinux_passwd_2) { 
		  print colored ("$lang_deploy{\"sorry_passwd_not_match\"}\n", 'red');
	      }elsif ($client_pxelinux_passwd_1 eq "" && $client_pxelinux_passwd_2 eq "" ){ 
		  print colored ("$lang_deploy{\"sorry_passwd_can_not_empty\"}\n", 'red');
	      }
	    }
	    $client_pxelinux_passwd=$client_pxelinux_passwd_1;
            last SWITCH;
	  };
	  /.*/ && do {
            $set_client_pxelinux_passwd="no";
            print "$lang_deploy{\"ok_let_continue\"}\n";
            last SWITCH;
          };
        }

	# Ask if user want to set the boot prompt for clients
	if ( $set_client_pxelinux_passwd eq "no" ) {
          print "$delimiter{\"dash_line\"}\n".
                "$lang_deploy{\"set_client_system_select\"}\n".
	        "[Y/n] ";
          chomp($set_client_system_select=<STDIN>);
	  SWITCH: for ($set_client_system_select) {
	    /^n$|^no$/i && do {
              $set_client_system_select="no";
	      last SWITCH;
	    };
	    /.*/ && do {
              $set_client_system_select="yes";
	      while ($client_system_boot_timeout eq "") { 
                   print "$lang_deploy{\"whats_client_system_boot_timeout\"}\n".
                         "[$DEFAULT_CLIENT_SYSTEM_BOOT_TIMEOUT] ";
                   chomp($client_system_boot_timeout_=<STDIN>);
	        if ( "$client_system_boot_timeout_" =~ /[^0-9]/ ) { 
	  	  print colored ("$lang_deploy{\"sorry_timeout_must_be_number\"}\n", 'red');
	        } else { 
	            # if empty, use default timeout
                    if ($client_system_boot_timeout_ eq "") {
                      $client_system_boot_timeout_="$DEFAULT_CLIENT_SYSTEM_BOOT_TIMEOUT";
                    }
                    $client_system_boot_timeout="$client_system_boot_timeout_";
	        }
	      }
              print "$lang_deploy{\"ok_let_continue\"}\n";
              print "$delimiter{\"dash_line\"}\n";
	      last SWITCH;
            };
          }
        }

	# If Debian, ask if user want to set group plugdev and audio open
	# to all users
        if (-f "/etc/debian_version") {
	  if ( ! $set_DBN_client_audio_plugdev ) {
            print "$delimiter{\"dash_line\"}\n".
                  "$lang_deploy{\"set_DBN_client_audio_plugdev_etc_open_to_all\"}\n".
	          "[Y/n] ";
            chomp($set_DBN_client_audio_plugdev=<STDIN>);
	  }
	  SWITCH: for ($set_DBN_client_audio_plugdev) {
	    /^n$|^no$/i && do {
              $set_DBN_client_audio_plugdev="no";
	      last SWITCH;
	    };
	    /.*/ && do {
              $set_DBN_client_audio_plugdev="yes";
              print "$lang_deploy{\"ok_let_continue\"}\n";
              print "$delimiter{\"dash_line\"}\n";
	      last SWITCH;
            };
          }
        }

        # Ask if user want to set the public IP for clients
	if ( ! $set_client_alias_IP ) {
          print "$delimiter{\"dash_line\"}\n".
                "$lang_deploy{\"set_client_alias_IP\"}\n".
                "[y/N] ";
          chomp($set_client_alias_IP=<STDIN>);
	}
        SWITCH: for ($set_client_alias_IP) {
            /^y$|^yes$/i && do {
                $set_client_public_ip_opt="yes";
                last SWITCH;
            };
            /.*/ && do {
                $set_client_public_ip_opt="no";
                last SWITCH;
            };
        }

	# Ask if user want to open the thin-client mode
	if ( ! $open_thin_client_option ) {
          print "$delimiter{\"dash_line\"}\n".
                "$lang_deploy{\"open_thin_client_option\"}\n".
	        "[y/N] ";
          chomp($open_thin_client_option=<STDIN>);
	}
	SWITCH: for ($open_thin_client_option) {
	  /^y$|^yes$/i && do {
            $open_thin_client_option="yes";
	    last SWITCH;
	  };
	  /.*/ && do {
            $open_thin_client_option="no";
            print "$lang_deploy{\"ok_let_continue\"}\n";
            print "$delimiter{\"dash_line\"}\n";
	    last SWITCH;
	  };
        }

	# Ask if user want to purge client files if they exist
        $client_exist_flag=system("LC_ALL=C ls -d /tftpboot/nodes/* &>/dev/null") / 256;
        if ($client_exist_flag eq 0) {
	   # old clients exist
	   if ( ! $keep_client ) {
             print "$delimiter{\"dash_line\"}\n".
                   "$lang_deploy{\"keep_client_setting_question\"}\n".
	           "[Y/n] ";
             chomp($keep_client=<STDIN>);
           }
	   SWITCH: for ($keep_client) {
	     /^n$|^no$/i && do {
               $purge_client="yes";
               print "$lang_deploy{\"remove_client_setting\"}\n".
                     "$delimiter{\"star_line\"}\n";
	       last SWITCH;
	     };
	     /.*/ && do {
               $purge_client="no";
               print "$lang_deploy{\"keep_client_setting\"}\n".
                     "$delimiter{\"star_line\"}\n";
	       last SWITCH;
             };
           }
        }else{
	   # old clients do NOT exist, so it's not necessary to clean old files
           $purge_client="no";
        }

	#
        print "$delimiter{\"star_line\"}\n";

# output the config file
  	  print CONFIG_FILE <<END_CFG;
#Setup for general
[general]
domain=$domain_sys
nisdomain=$nisdomain_sys
localswapfile=$localswapfile
client_init=$CLIENT_INIT
login_gdm_opt=$LOGIN_GDM_OPT
timed_login_time=$TIMED_LOGIN_TIME
maxswapsize=$maxswapsize
total_client_no=$total_client_no
create_account=$create_account
account_passwd_length=$ACCOUNT_PASSWD_LENGTH_DEFAULT
hostname=$client_hostname_prefix
purge_client=$purge_client
client_autologin_passwd=$client_autologin_passwd
client_root_passwd=$client_root_passwd
client_pxelinux_passwd=$client_pxelinux_passwd
set_client_system_select=$set_client_system_select
set_DBN_client_audio_plugdev=$set_DBN_client_audio_plugdev
open_thin_client_option=$open_thin_client_option
client_system_boot_timeout=$client_system_boot_timeout
language=$language
set_client_public_ip_opt=$set_client_public_ip_opt
config_file=$DRBLPUSH_CONF
collect_mac=$collect_mac
sh_debug=$sh_debug
clonezilla_box_mode=$clonezilla_box_mode
drbl_ssi_mode=$drbl_ssi_mode

END_CFG


        for($i=0;$i<=$#ethernet_sys;$i++) {
          my $ethx=$ethernet_sys[$i];
          if ( ! $MAC_file[$i] ){ 
	  # output the range format
  	  print CONFIG_FILE <<END_CFG;
#Setup for $ethx
[$ethx]
interface=$ethx
range=$range_start[$i]-$range_end[$i]

END_CFG
  	  }else{
 	    # output the MAC format
  	    print CONFIG_FILE <<END_CFG;
#Setup for $ethx
[$ethx]
interface=$ethx
mac=$MAC_file[$i]
ip_start=$range_start[$i]

END_CFG
	  }
	}

        close(CONFIG_FILE);
	# set mode for more secure
	system("LC_ALL=C chmod 600 $DRBLPUSH_CONF");

}#end of interactive_mode

# subroutine to read file, parse them as parameters
# in: config_file
# out: hash of hash reference 
sub read_config {

  my %HoH = ();
  my $KoH="general";
  my $key="",$value="";

  open(CONFIG,$_[0]) or die "Can NOT find file \"$_[0]\"! \nPlease check your config file!\n";
  while(<CONFIG>) {
    if($_=~/^#.*/) {
      # ignore comment
      #print "ignore $_\n";
    }
    elsif($_=~/\[.*\]/) {
      # has key 
      chop;
      my $key_ = $_;
      # skip the comments
      $key_ =~ s/#.*//;
      # delete the spaces
      $key_ =~ s/ //g;
      $KoH=substr($key_,1,length($key_)-2); 
    }
    else { 
      # hash value
      chop;
      if( 0 == length($_) ) { next; }
      ($key,$value)=split(/=/);
      # Turn all the key to uppercase
      $key=uc($key);
      # skip the comments
      $value =~ s/#.*//;
      # delete the spaces
      $value =~ s/ //g;
      #print "KoH=$KoH, key=$key, value=$value\n";
      $HoH{ $KoH }{ $key }= $value;
    }
  }
  close(CONFIG);

  return( \%HoH );  
}

sub drbl_server_parse {
# Part 1,
# get enough information, setup the DRBL server
#
  my $DNS_sys="/etc/resolv.conf";
  my $rHoH = read_config($_[0]);

  my $nameserver=$rHoH->{"general"}{"NAMESERVER"};
  my $domain=$rHoH->{"general"}{"DOMAIN"};
  my $nisdomain=$rHoH->{"general"}{"NISDOMAIN"};
  my $nfsserver_default=$rHoH->{"general"}{"NFSSERVER_DEFAULT"};
  my $localswapfile=$rHoH->{"general"}{"LOCALSWAPFILE"};
  my $CLIENT_INIT=$rHoH->{"general"}{"CLIENT_INIT"};
  my $maxswapsize=$rHoH->{"general"}{"MAXSWAPSIZE"};
  my $purge_client=$rHoH->{"general"}{"PURGE_CLIENT"};
  my $language=$rHoH->{"general"}{"LANGUAGE"};
  my $set_client_system_select=$rHoH->{"general"}{"SET_CLIENT_SYSTEM_SELECT"};
  my $set_DBN_client_audio_plugdev=$rHoH->{"general"}{"SET_DBN_CLIENT_AUDIO_PLUGDEV"};
  my $open_thin_client_option=$rHoH->{"general"}{"OPEN_THIN_CLIENT_OPTION"};
  my $client_system_boot_timeout=$rHoH->{"general"}{"CLIENT_SYSTEM_BOOT_TIMEOUT"};
  my $set_client_public_ip_opt=$rHoH->{"general"}{"SET_CLIENT_PUBLIC_IP_OPT"};
  my $config_file=$rHoH->{"general"}{"CONFIG_FILE"};
  my $collect_mac=$rHoH->{"general"}{"COLLECT_MAC"};
  
  # for login GDM
  my $login_gdm_opt=$rHoH->{"general"}{"LOGIN_GDM_OPT"};
  my $timed_login_time=$rHoH->{"general"}{"TIMED_LOGIN_TIME"};

  # for auto login or timed login account
  my $create_account=$rHoH->{"general"}{"CREATE_ACCOUNT"};
  my $account_prefix=$rHoH->{"general"}{"ACCOUNT_PREFIX"};
  my $total_client_no=$rHoH->{"general"}{"TOTAL_CLIENT_NO"};
  my $passwd_length=$rHoH->{"general"}{"ACCOUNT_PASSWD_LENGTH"};
  my $hostname_prefix=$rHoH->{"general"}{"HOSTNAME"};

  print "The GDM login option: $login_gdm_opt\n" if $verbosity >=2;
  print "timed_login_time: $timed_login_time\n" if $verbosity >=2;
  print "account_prefix: $account_prefix\n" if $verbosity >=2;
  print "total_client_no: $total_client_no\n" if $verbosity >=2;
  print "passwd_length: $passwd_length\n" if $verbosity >=2;
  print "maxswapsize in system is $maxswapsize\n" if $verbosity >= 2;
  print "The hostname_prefix from config file: \"$hostname_prefix\".\n" if $verbosity >= 2;

  # Try to get setting from system also
  my $nameserver_sys=`LC_ALL=C grep ^nameserver $DNS_sys | awk -F\" \" '{print \$2}'`;
  chomp $nameserver_sys;  # clean the last \n before substitute them as ","
  $nameserver_sys =~ s/\n/,/g;
  print "nameserver in system is $nameserver_sys\n" if $verbosity >= 2;

  # get some setting in this server so that if some parameters are not set,
  # we can use the one in this system.
  chomp($domain_sys=`$DRBL_SCRIPT_PATH/bin/parse_net_conf all domainname`);
  chomp($nisdomain_sys=`$DRBL_SCRIPT_PATH/bin/parse_net_conf all nisdomainname`);
  print "DOMAIN in system is $domain_sys\n" if $verbosity >= 2;
  print "NISDOMAIN in system is $nisdomain_sys\n" if $verbosity >= 2;
  
  # set nameserver, domain, nisdomain, the priority: use the config file first, if unset, then use the value in system
  if ( ! $nameserver ) { 
   $nameserver = $nameserver_sys; 
   print "* nameserver is not set in config file, \nthe one \"$nameserver\" got from system will be used.\n" if $verbosity >= 2;   
  }
  if ( ! $nisdomain ) { 
   $nisdomain = $nisdomain_sys; 
   print "* nisdomain is not set in config file, \nthe one \"$nisdomain\" got from system will be used.\n" if $verbosity >= 2;   
  }
  if ( ! $domain ) { 
   $domain = $domain_sys; 
   print "* domain is not set in config file, \nthe one got \"$domain\" from system will be used.\n" if $verbosity >= 2;   
  }

  # check if the values are set in config file or system  
  if ( ! $nameserver ) {
     print "Error! NAMESERVER is unset!\n";
     print "Please set it in config file \"$_[0]\" or $DNS_sys.\n";
     exit;
  }

  if ( ! $nisdomain ) {
     print "Error! NISDOMAIN is unset!\n"; 
     print "Please set it in config file \"$_[0]\" or system config file.\n";
     exit;
  }
  if ( ! $domain ) {
     print "Error! DOMAIN unset!\n"; 
     print "Please set it in config file \"$_[0]\" or system config file.\n";
     exit;
  }

  if ("$mode" eq "load_config_file") {
    # check public IP setting
    if ("$set_client_public_ip_opt" eq "yes" && ! -f "$drbl_syscfg/$public_ip_list") {
        print "$delimiter{\"star_line\"}\n".
              colored ("Unable to find the $drbl_syscfg/$public_ip_list; If you want to create the $drbl_syscfg/$public_ip_list, you must run \"drblpush\" in interactive mode (with -i option)!\n", 'red').
              "$lang_deploy{\"press_enter_to_continue\"}";
              chomp($line=<STDIN>);
        print "$delimiter{\"dash_line\"}\n";
    }
    # check MAC address files
    if ("$collect_mac" eq "yes" ){ check_MAC_file("$drbl_syscfg","macadr-eth"); }
  }

  #
  if ($localswapfile eq "y" || $localswapfile eq "Y" || $localswapfile eq "yes" || $localswapfile eq "YES") {
      $mkswapfile="mkswapfile";
  }else{
      $mkswapfile="";
  }

  if ( "$login_gdm_opt" eq "timed_login" && ! $timed_login_time ) {
     print "You set to timed login GDM, but there is no timed time!\n". 
           "We will set the timed time as $TIMED_GDM_TIME_DEFAULT seconds.\n";
  }

  # detect kernel in server support udp over NFS or tcp over NFS (tcp is the default seting one for DRBL environment)
  # try to get if the kernel running the server supports NFS over TCP, if not, ust NFS over UDP
  $nfsd_tcp_rlt=system(". $DRBL_SCRIPT_PATH/sbin/drbl-functions; check_kernel_nfsd_tcp_config");
  if ($nfsd_tcp_rlt == 256) { 
  	# set the protocol as udp
          $nfs_protocol="udp";
  }else{
  	# set the protocol as tcp
          $nfs_protocol="tcp";
  }
  $nfs_protocol_uc=uc $nfs_protocol;
  print "$lang_deploy{\"server_kernel_nfsd_support\"} ".
        colored ("NFS over $nfs_protocol_uc", 'red').
        "!\n".
        colored ("$lang_deploy{\"change_kernel_notes\"}\n", 'red').
        "$lang_deploy{\"press_enter_to_continue\"}";
        chomp($line=<STDIN>);
  print "$delimiter{\"dash_line\"}\n";

  #
  my $nameserver_=$nameserver;
  $nameserver_=~ s/\,/ /g;

  # generate dhcpd.conf, hosts, $main_sh...

  $main_sh="drbl_deploy.sh";
  # delete the old files
  unlink ($main_sh) if -f $main_sh;
  unlink (dhcpd.conf) if -f dhcpd.conf;
  unlink (nfsserver_all) if -f nfsserver_all;
  unlink (yp.conf) if -f yp.conf;
  unlink ($hosts_list) if -f $hosts_list;
  unlink ($public_ip_list) if -f $public_ip_list;
  #unlink ($AUTO_LOGIN_ID_PASSWD) if -f $AUTO_LOGIN_ID_PASSWD;

  # open the config files for DRBL server
  open(DHCPD_OUT,">dhcpd.conf") or die "Can NOT write file \"dhcpd.conf\" \n";
  open(NETGROUP_OUT,">netgroup") or die "Can NOT write file \"netgroup\"! \n";
  open(DISKLESS_OUT,">$main_sh") or die "Can NOT write file \"$main_sh\" \n";
  open(NFSSERVER_OUT,">nfsserver_all") or die "Can NOT write file \"nfsserver_all\" \n";
  open(YPCONF_SERVER,">yp.conf") or die "Can NOT write file \"yp.conf\" \n";
  open(HOSTS_LIST_OUT,">$hosts_list") or die "Can NOT write file \"$hosts_list\" \n";
  open(SWAPCONF_OUT,">mkswapfile") or die "Can NOT write file \"mkswapfile\" \n";
  open(GLOBAL_SETTING,">drbl_deploy.conf") or die "Can NOT write file \"drbl_deploy.conf\" \n";

  # get the etherboot zpxe filename, we use sort and head to choose only one.
  chomp(my $etherboot_zpxe=`LC_ALL=C unalias ls 2> /dev/null; basename \`ls -f /tftpboot/etherboot-*/eb-*-etherboot-pci.zpxe 2>/dev/null | sort -r | head -n1\``);
  chomp(my $sis900_zpxe=`LC_ALL=C unalias ls 2> /dev/null; basename \`ls -f /tftpboot/etherboot-*/sis900.zpxe 2>/dev/null | sort -r | head -n1\``);
  # some general option in dhcpd.conf, hosts, $main_sh
  print DHCPD_OUT <<EOF;
# Generated by DRBL. 
# Do NOT modify this file unless you know what you are doing!

default-lease-time			7776000;
max-lease-time				7776000;
option subnet-mask			255.255.255.0;
option domain-name-servers  		$nameserver;
option domain-name			"$domain";	
ddns-update-style                       none;
server-name 				drbl;

filename = "pxelinux.0";

## Uncomment the following "if block" when you have some buggy PXE NIC card (such as annoying sis900 NIC). Remember to modify the MAC vendor prefix and restart dhcpd service!!!
## This is a workround for some network card with BAD PXE code in firmware.
## It will only affect those clients with MAC vendor prefix you assigned.
## Ref: http://syslinux.zytor.com/archives/2005-August/005640.html

#if substring (option vendor-class-identifier, 0, 3) = "PXE" {
#     # **************************************************************
#     # ***MODIFY*** the MAC vendor prefix of client network card here.
#     # **************************************************************
#     # For annoying sis900 network card, maybe it's 00:07:95, 00:0C:6E...
#     if substring (hardware, 1, 3) = 00:0C:6E {
#         # $etherboot_zpxe is a all-in-one pxe image, works for most NIC.
#         # $sis900_zpxe is specially for sis900 NIC.
#         # Try either one.
#         #filename = "$etherboot_zpxe";
#         filename = "$sis900_zpxe";
#     }
#}

EOF

  # set the config file for mkswapfile
  print SWAPCONF_OUT "maxswapsize=$maxswapsize\n";

  #print HOSTS_OUT "127.0.0.1 localhost localhost.localdomain\n";

  print NETGROUP_OUT "# Added by DRBL, begin\n";

  print NETGROUP_OUT "nodes ";

# write the nis client config file for server, i.e. ypbind will also run in
# DRBL server, so that user can use yppasswd to change his passwd in server.
# The yp server is the DRBL server, too, so we use localhost.
  print YPCONF_SERVER <<YPCONF_SERVER_EOF;
domain $nisdomain server localhost
YPCONF_SERVER_EOF

# output the global setting for drbl_deploy
  print GLOBAL_SETTING <<GLOBAL_EOF;
##################################
# drbl_deploy global setting
# File automatically created by drblpush.
# It is better not to manually modify this file.
##################################
config_file="$config_file"
purge_client="$purge_client"
client_root_passwd="$client_root_passwd"
client_pxelinux_passwd="$client_pxelinux_passwd"
language="$language"
set_client_system_select="$set_client_system_select"
set_DBN_client_audio_plugdev="$set_DBN_client_audio_plugdev"
open_thin_client_option=$open_thin_client_option
client_system_boot_timeout="$client_system_boot_timeout"
collect_mac=$collect_mac
total_client_no=$total_client_no
nfs_protocol="$nfs_protocol"
client_init="$CLIENT_INIT"
mkswapfile="$mkswapfile"
nfsserver_default="$nfsserver_default"
nameserver="$nameserver"
nameserver_="$nameserver_"
domain="$domain"
nisdomain="$nisdomain"
public_ip_list="$public_ip_list"
login_gdm_opt="$login_gdm_opt"
client_autologin_passwd="$client_autologin_passwd"
timed_login_time="$TIMED_LOGIN_TIME"
clonezilla_box_mode="$clonezilla_box_mode"
drbl_ssi_mode="$drbl_ssi_mode"
##################################
# End of global setting
##################################

GLOBAL_EOF

close(GLOBAL_EOF);
system("chmod 600 drbl_deploy.conf");
system("mkdir -p $drbl_syscfg; cp -f drbl_deploy.conf $drbl_syscfg/");

  print DISKLESS_OUT <<EOF;
#!/bin/bash $sh_debug
# **********************************************************************
# File automatically created by drblpush, 
# better not to modify this file manually.
# "drblpush" is written by K. L. Huang, klhaung _at_ gmail com,
# especially for Debian, then modified to use with Redhat by
# Steven Shiau, steven _at_ nchc org tw.
# **********************************************************************

# Load DRBL setting and functions
if [ ! -f "/opt/drbl/sbin/drbl-conf-functions" ]; then
  echo "Unable to find /opt/drbl/sbin/drbl-conf-functions! Program terminated!" 
  exit 1
fi
. /opt/drbl/sbin/drbl-conf-functions
. /etc/drbl/drbl_deploy.conf

# get the l10n message
if [ -f "$DRBL_SCRIPT_PATH/lang/bash/$language" ] ; then
 . $DRBL_SCRIPT_PATH/lang/bash/$language
else
   echo "Not such language option!!!"
   exit 1
fi
 
# store the orig LC_ALL, then set it as C
LC_ALL_org=\$LC_ALL
export LC_ALL=C

EOF

print DISKLESS_OUT q{
# check if the space is enough to setup DRBL
echo -n "Checking the necessary disk space... "
if [ "$clonezilla_box_mode" = "yes" -o "$drbl_ssi_mode" = "yes" ]; then
  total_client_no_for_checking="1"
else
  total_client_no_for_checking="$total_client_no"
fi
space_check=$($DRBL_SCRIPT_PATH/sbin/check_drbl_setup_space -n $total_client_no_for_checking)
rc=$?
if [ "$rc" -gt 0 ]; then
  total_avail_space=$(echo $space_check | awk '{print $1}')
  drbl_need_space=$(echo $space_check | awk '{print $2}')
  [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
  echo "$msg_total_avail_space: $total_avail_space (MB)"
  echo "$msg_necessary_space_setup_drbl: $drbl_need_space (MB)"
  echo "$msg_total_client_no: $total_client_no"
  echo "$msg_system_maybe_not_enough_space"
  echo "$msg_press_ctrl_c_stop!"
  echo "$msg_press_enter_to_continue"
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
  read
fi
echo "done!"

# copy the config files to $drbl_syscfg...
echo -n "Copying the config file to $drbl_syscfg... "
mkdir -m 700 -p $drbl_syscfg
cp -f $config_file $drbl_syscfg/
[ -f $public_ip_list ] && cp -f $public_ip_list $drbl_syscfg/
echo "done!"

# Do some checks...
if [ "$(dirname $drbl_common_root)" = "/" ]; then
  [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
  echo "You can NOT assign the drbl_common_root as / in drbl.conf!!!"
  echo "Program terminated!!!"
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
  exit 1
fi

# varlib_NOT_2_be_copied and varcache_2_be_copied are loaded from drbl.conf
# varlib_NOT_2_be_copied -> varlib_opts_common_to_each is processed in 
# sbin/gen_client_files.sh

# If purge_client = no, which means we will NOT overwrite the old files.
# we had better to add "-u" for rsync, and we assign keep_old_files_flag=yes
if [ "$purge_client" = "no" ]; then
  RSYNC_OPT_EXTRA="-u"
  keep_old_files_flag="yes"
else
  RSYNC_OPT_EXTRA=""
  keep_old_files_flag="no"
fi

# check if drbl is installed or not, which is necessary
if ! rpm -q --quiet drbl &>/dev/null && ! chk_deb_installed drbl &>/dev/null; then
  echo "You did NOT install drbl!!! Program terminated!"
  exit 1
fi

# backup the original setting files in DRBL server
[ -f $DHCPDCONF_DIR/dhcpd.conf ] && mv -f $DHCPDCONF_DIR/dhcpd.conf $DHCPDCONF_DIR/dhcpd.conf.orig
[ -f /etc/netgroup ] && mv -f /etc/netgroup /etc/netgroup.drblsave
[ -f /var/yp/securenets ] && mv -f /var/yp/securenets /var/yp/securenets.drblsave
[ -f /etc/ypserv.securenets ] && mv -f /etc/ypserv.securenets /etc/ypserv.securenets.drblsave

# copy some config files (dhcpd.conf, yp.conf...) created
# in the drblpush DRBL server.

cp -f dhcpd.conf $DHCPDCONF_DIR/
cp -f mkswapfile $SYSCONF_PATH/mkswapfile

for icfg in yp.conf netgroup; do
  cp -f $icfg /etc/
done

# create /etc/hosts based on drblpush.conf and dhcpd.conf, so must be after dhcpd.conf is copied to system.
$DRBL_SCRIPT_PATH/sbin/drbl-etc-hosts

echo -n "Cleaning the stale files of the diskless nodes if they exist... "
# clean the config or setting files in /tftpboot/node_root/etc/diskless-image
# and /tftpboot/nodes/*/etc/diskless-image.
# This action is important, otherwise the stalled files will always exist.
find $drbl_common_root/etc/diskless-image $drblroot/*/etc/diskless-image -name "config" -exec rm -f {} \; &> /dev/null
find $drbl_common_root $drblroot -name "$public_ip_list" -exec rm -f {} \; &> /dev/null
echo "done!"

# Get the gdm or kdm config filename
get_gdm_kdm_conf_filename

# set gdm.conf (althought we already set that in drbl rpm postrun script
# but it seems that sometimes it will fail). Set it again here.
if [ -f $GDM_CFG ]; then
  # force to use graphic greeting (gdmgreeter is available in sarge, not in woody. In woody, it is gdmlogin)
  # gdmgreeter: /usr/bin/gdmgreeter (sarge) or /usr/lib/gdm/gdmgreeter (breezy)
  # gnome 2.14: /usr/libexec/gdmgreeter
  GDM_GREETER="$($query_pkglist_cmd gdm 2>/dev/null | grep -E "\/gdmgreeter$")"
  if [ -n "$GDM_GREETER" ]; then
   # Set Greeter=$GDM_GREETER
   lines="$(get_block_line_in_gdm_kdm daemon $GDM_CFG)"
   begin_line=$(echo $lines | awk -F" " '{print $1}')
   end_line=$(echo $lines | awk -F" " '{print $2}')
   chk_cmd="if ($begin_line..$end_line) {print}"
   if [ -n "$(perl -n -e "$chk_cmd" $GDM_CFG | grep -i "^Greeter=")" ]; then
     sub_cmd="if ($begin_line..$end_line) {s|^Greeter=.*|Greeter=$GDM_GREETER|}"
     perl -pi -e "$sub_cmd" $GDM_CFG
   else
     # insert 1 blank line
     sub_cmd="if ($((end_line))..$((end_line))) {s|^(.*)$|\$1\n|gi}"
     perl -pi -e "$sub_cmd" $GDM_CFG
     # replace the one we want in the added blank line
     sub_cmd="if ($((end_line+1))..$((end_line+1))) {s|^$|Greeter=$GDM_GREETER|gi}"
     perl -pi -e "$sub_cmd" $GDM_CFG
   fi
   # Set GraphicalTheme=drbl-gdm
   lines="$(get_block_line_in_gdm_kdm greeter $GDM_CFG)"
   begin_line=$(echo $lines | awk -F" " '{print $1}')
   end_line=$(echo $lines | awk -F" " '{print $2}')
   chk_cmd="if ($begin_line..$end_line) {print}"
   if [ -n "$(perl -n -e "$chk_cmd" $GDM_CFG | grep -i "^GraphicalTheme=")" ]; then
     sub_cmd="if ($begin_line..$end_line) {s|^GraphicalTheme=.*|GraphicalTheme=drbl-gdm|}"
     perl -pi -e "$sub_cmd" $GDM_CFG
   else
     # insert 1 blank line
     sub_cmd="if ($((end_line))..$((end_line))) {s|^(.*)$|\$1\n|gi}"
     perl -pi -e "$sub_cmd" $GDM_CFG
     # replace the one we want in the added blank line
     sub_cmd="if ($((end_line+1))..$((end_line+1))) {s|^$|GraphicalTheme=drbl-gdm|gi}"
     perl -pi -e "$sub_cmd" $GDM_CFG
   fi
  fi
fi

#
# backup the old MAC address files if the collect MAC is on
if [ "$collect_mac" = "yes" ]; then
  echo -n "Backuping the old MAC address files... "
  now=$(date +%F-%k-%M)
  find $drbl_syscfg -name "macadr-eth*.txt" -exec mv {} {}.saved_$now \;
  echo "done!"
fi

# Part 2,
# generate file system for clients, like what is done in Debian diskless-newimage
#

# Setting
echo "$msg_delimiter_star_line"
# get the distribution name and type: OS_Version and OS_type
check_distribution_name
echo "$msg_delimiter_star_line"
if [ -z "$OS_Version" ]; then
  [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
  echo "$msg_not_determine_OS"
  echo "$msg_is_not_supported"
  echo "$msg_press_ctrl_c_stop!"
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
  read
  exit 1 
fi
echo "The version number for your Linux: $OS_Version"

# First, common root files
[ ! -d /tftpboot ] && mkdir /tftpboot

case "$purge_client" in
   [yY][eE][sS])
      echo -n "Completely cleaning old common root files if they exist... " 
      # Clean the stalled files...
      [ -d /tftpboot/node_root/etc ] && rm -rf /tftpboot/node_root/etc
      [ -d /tftpboot/node_root/var ] && rm -rf /tftpboot/node_root/var
      echo "done !"
      
      echo -n "Completely cleaning old nodes if they exist... " 
      # clean old nodes link, here we assume maybe they are all private IP
      for ip_prefix in 192.168 172.1[6-9] 172.2[0-9] 172.3[01] 10; do
        for iclient_link in /tftpboot/${ip_prefix}.*; do
          [ -L "$iclient_link" ] && rm -f $iclient_link
        done
        # then, clean old node files
        for iclient in /tftpboot/nodes/${ip_prefix}.*; do
          [ -d "$iclient" ] && rm -rf $iclient
        done
      done

      echo "done !"
      ;;
   *)
      echo "Keeping the old common root files if they exist... " 
      echo "Keeping old nodes if they exist... " 
      ;;
esac

echo -n "Creating common root files... This might take several minutes..."
echo -n "."
for d in home mnt proc tmp usr opt root dev var lib initrd sys; do
   mkdir -p /tftpboot/node_root/$d
done
# These dirs depend on distribution, so we will test it before create it.
# Add misc net srv on 6/14/2005 for FC4
# /selinux will be created automatically by kernel ? NOT by DRBL.
for d in media misc net srv; do
   [ -d "/$d" ] && mkdir -p /tftpboot/node_root/$d
done

# 1/7/2006, since B2D does not have /media, but it will create and use that 
# once you plug the usb devices, so now we mkdir media for DRBL B2D client 
echo -n "."
if [ -e /etc/b2d-release ]; then
   mkdir -p /tftpboot/node_root/media
fi

echo -n "."
# copy some rc files to root home directory
for ir in .bashrc .bash_profile .profile .viminfo; do
 [ -f /root/$ir ] && rsync -a $RSYNC_OPT_EXTRA /root/$ir /tftpboot/node_root/root/
done

# create the console so that client can output message when entering init. This is especially for Debian. 
echo -n "."
# force to clean the old ones
for i in console null; do
  [ -c /tftpboot/node_root/dev/$i ] && rm -f /tftpboot/node_root/dev/$i
done
mknod -m 600 /tftpboot/node_root/dev/console c 5 1
mknod -m 666 /tftpboot/node_root/dev/null c 1 3

#
echo -n "."
# copy /sbin, /bin to node_root
# Note!!! For rsync, do NOT to append "/" in the /sbin, .i.e. NO /sbin/
rsync -a $RSYNC_OPT_EXTRA /sbin /tftpboot/node_root/
# put the real init into common root as init.orig, DRBL client will have 
# an "init" to run before this init.orig
rsync -a $RSYNC_OPT_EXTRA /sbin/init /tftpboot/node_root/sbin/init.orig

#
echo -n "."
rsync -a $RSYNC_OPT_EXTRA /bin /tftpboot/node_root/
# We need awk and cut in init.drbl.
# For RH-like, awk and cut are in /bin, however, in Debian, they are in /usr/bin, which is not mounted when trying to get IP address of NFS server in running init.drbl. So we have to copy them.
# Note!!! In Debian, we need the gawk, not awk, so we already installed gawk
# in drblsrv, and it will replace awk as /etc/alternatives/awk -> /usr/bin/gawk
# But maybe it is better to cp gawk -> awk ?
must_prog_for_init_drbl="cut gawk"
for imust in $must_prog_for_init_drbl; do
  [ -e "$drbl_common_root/bin/$imust" ] && rm -f $drbl_common_root/bin/$imust
  if [ -e "/usr/bin/$imust" ]; then
     #echo "Copying $imust from /usr/bin/ to $drbl_common_root/bin/..."
     cp -af --dereference /usr/bin/$imust $drbl_common_root/bin/
  else
     [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
     echo "FATAL error!!! $imust is not found in /usr/bin!!! Client will NOT be able to boot or run correctly!!!"
     [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
  fi
done
# link gawk as awk for clients.
(cd $drbl_common_root/bin/; ln -fs gawk awk)

echo -n "."
# Creat a file /tftpboot/node_root/sbin/fsck.nfs to let rc.sysinit use 
# "fsck.nfs" always successfully
echo "#!/bin/bash
exit 0" > /tftpboot/node_root/sbin/fsck.nfs
chmod 755 /tftpboot/node_root/sbin/fsck.nfs

echo -n "."

# Steven todo, make sure it is right ?
# /tftpboot/node_root/lib/security is important for PAM, if we remove/update it,
# clients have to reboot, otherwise user can not login in the client.
# So it is better to keep /tftpboot/node_root/lib/security/ without updating.
if [ -d /tftpboot/node_root/lib/security ]; then
  rsync -a $RSYNC_OPT_EXTRA --exclude=modules/ --exclude=security/ /lib /tftpboot/node_root/
else
  rsync -a $RSYNC_OPT_EXTRA --exclude=modules/ /lib /tftpboot/node_root/
fi

# For x86_64
# For FC3 or later: /lib64 is a directory, not /lib32, only dir /lib
# For Ubuntu breezy amd64: /lib64 is a symbolic to /lib, /lib32 is a directory
for d in lib32 lib64; do
 [ -d "/$d" ] && rsync -a $RSYNC_OPT_EXTRA /$d /tftpboot/node_root/
 [ -L "/$d" ] && cp -a /$d /tftpboot/node_root/
done

echo " done!"

# Copy or update the kernel for client if necessary...
echo "Update the kernel for client if necessary... "
/opt/drbl/sbin/update_client_kernel_from_server.sh $RSYNC_OPT_EXTRA

# copy /etc to template node
# /etc/drbl/ is for server only.
echo "Copying the directory /etc/ to clients common root /tftpboot/node_root..."
rsync -a --exclude=/etc/drbl/ $RSYNC_OPT_EXTRA /etc /tftpboot/node_root

# clean the ssh key, so that client will create its own. 
key_file="ssh_host_dsa_key ssh_host_dsa_key.pub ssh_host_key ssh_host_key.pub ssh_host_rsa_key ssh_host_rsa_key.pub"
for ik in $key_file; do
  if diff /etc/ssh/$ik /tftpboot/node_root/etc/ssh/$ik &>/dev/null; then
     echo -n "Cleaning the ssh key file $ik copied from server... "
     rm -f /tftpboot/node_root/etc/ssh/$ik
     echo "done!"
  fi
done

# make sure the hostname of server in 127.0.0.1 in /etc/hosts 
# is not copied to clients.
# like
#-----------------------------------------------------------
#127.0.0.1               rh9 localhost.localdomain localhost
#-----------------------------------------------------------
# if it is copied to client, client will have some problem to connect to server
# such as yppasswd will complain the yppasswdd is NOT running on "rh9".
HOSTNAME_SRV=`/bin/hostname`
if [ -n "$(grep $HOSTNAME_SRV /tftpboot/node_root/etc/hosts |grep 127.0.0.1)" ]; then
 perl -p -i -e "s/127.0.0.1.*/127.0.0.1		localhost.localdomain localhost/g" /tftpboot/node_root/etc/hosts
fi

# create mkswapfile to /tftpboot/node_root/etc/init.d/
# This must before service to add
cp -f $drbl_setup_path/files/misc/{mkswapfile,drblthincli,arm-wol} /tftpboot/node_root/etc/init.d/
# For Debian, there is no gdm-safe-restart script, we just copy it from drbl
# package. We need gdm-safe-restart for terminal mode setup.
[ ! -x /usr/sbin/gdm-safe-restart ] && cp -f $drbl_setup_path/files/misc/gdm-safe-restart /usr/sbin/gdm-safe-restart
chown root.root /tftpboot/node_root/etc/init.d/{mkswapfile,drblthincli,arm-wol}

# For MDK/Debian/SuSE, we put the one we wrote "firstboot.XXX.drbl" to 
# common root /etc/init.d as firstboot.
# There is already firstboot comes with RH/FC/CentOS.
# We do NOT use the firstboot comes with yast2-firstboot in SuSE.
if [ "$OS_type" != "RH" ]; then
  if [ -f "$drbl_setup_path/files/${OS_Version}/firstboot.${OS_Version}.drbl" ]; then
    cp -f $drbl_setup_path/files/${OS_Version}/firstboot.${OS_Version}.drbl /tftpboot/node_root/etc/init.d/firstboot
  else
    [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
    echo "Warning! Unable to find the fine-tune file ${drbl_setup_path}/files/${OS_Version}/firstboot.${OS_Version}.drbl, use ${drbl_setup_path}/files/default/firstboot.default-${OS_type}.drbl as /etc/init.d/firstboot for DRBL clients!"
    echo "This may cause some problems to DRBL clients!"
    [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
    cp -f $drbl_setup_path/files/default/firstboot.default-${OS_type}.drbl /tftpboot/node_root/etc/init.d/firstboot
  fi
fi

# modify some bootup script or setting (System V is easier to do here.. all scripts are separated.)
if [ -e /etc/debian_version ]; then
  # Debian
  # For genuine Debian Sarge
  perl -pi -e 's/(^[[:space:]]*umount -ttmpfs.*)/#$1 # Modified by DRBL/g' $drbl_common_root/etc/init.d/umountfs
  perl -pi -e 's/(^[[:space:]]*umount -tnoproc)(,noprocfs.*)/$1,nonfs,notmpfs$2 # Modified by DRBL/g' $drbl_common_root/etc/init.d/umountfs
  # For genuine Debian Etch
  perl -pi -e 's/(^[[:space:]]*)(proc|procfs|linprocfs|devfs|sysfs|usbfs.*)/$1nfs|tmpfs|none|$2/g' $drbl_common_root/etc/init.d/umountfs
  # for B2D
  perl -pi -e 's/^[[:space:]]*umount \$FORCE -a -r.*/umount \$FORCE -tnoproc,nonfs,notmpfs,noprocfs,nodevfs,nosysfs,nousbfs,nousbdevfs,nodevpts -d -a -r # Modified by DRBL/g' $drbl_common_root/etc/init.d/umountfs

elif [ -e /etc/SuSE-release ]; then
  # For SuSE
  # SuSE is unique here, it uses parallel start service "startpar", we do not
  # want that, otherwise some services might fail due to NFS client does not
  # finish yet.
  echo -n "Turn off runlevel scripts in parallel in clients... "
  perl -pi -e "s/^[[:space:]]*[#]*[[:space:]]*RUN_PARALLEL=.*/RUN_PARALLEL=no/g" $drbl_common_root/etc/sysconfig/boot
  echo "done!"
  # modify some services
  # etc/init.d/boot, use -o remount so it will not complain when booting.
  perl -pi -e 's/^([[:space:]]*mount -n -t proc)(.*)/$1 -o remount $2 # Modified by DRBL/g' $drbl_common_root/etc/init.d/boot
  perl -pi -e 's/^([[:space:]]*mount -n -t sysfs)(.*)/$1 -o remount $2 # Modified by DRBL/g' $drbl_common_root/etc/init.d/boot
  # boot.udev, we have to turn on runlevel 1 so that clonezilla will be ok.
  perl -pi -e 's/^[[:space:]]*#+[[:space:]]*Default-Start:.*/# Default-Start:     B 1 2 3 4 5/g' $drbl_common_root/etc/init.d/boot.udev
  # boot.localfs, we add -l when umount in "boot.udev stop" (called by reboot/halt)
  perl -pi -e 's/^([[:space:]]*umount) -avt (noproc,nonfs,nosmbfs.*)/$1 -avtl nosysfs,$2 # Modified by DRBL/g' $drbl_common_root/etc/init.d/boot.localfs
  # nfs client, we do not want to recreate ld.so.cache, it is only provided
  # by DRBL server.
  # Note! recreate here will take a long time.
  # Note2: boot.ldconfig is run before nfs. 
  # It will not include some remote NFS directory 
  # (like /opt/kde/lib... /opt/gnome/lib...
  # we have to turn off boot.ldconfig in /etc/init.d/boot.d also.
  perl -pi -e 's|^([[:space:]]*#+)[[:space:]]*check if ld.so.cache needs to be refreshed.*|$1 DRBL comment this, we will not let boot.ldconfig run in DRBL client.|g' $drbl_common_root/etc/init.d/nfs
  perl -pi -e 's|/etc/init.d/(boot.ldconfig start.*)|#$1|g' $drbl_common_root/etc/init.d/nfs
  rm -f $drbl_common_root/etc/init.d/boot.d/[SK][0-9][0-9]boot.ldconfig 
fi

# remove the unnecessary service, 
# First, remove all the service
# TODO, Debian/RH
# prepare the necessary env for chkconfig, update-rc.d or insserv
if [ -e /etc/debian_version ]; then
  # For Debian
  prepare_update_rc_d_env $drbl_common_root/
elif [ -e /etc/SuSE-release ]; then
  # For SuSE
  create_insserv_env $drbl_common_root/
else
  # For RH-like
  create_chkconfig_env $drbl_common_root/
fi
for isrv in /etc/init.d/*; do
  # Skip directory
  [ -d "$isrv" ] && continue
  i="$(basename $isrv)"
  # skip those do not support chkconfig, or actually, they are not services.
  # reboot/halt are necessary for all dists.
  [ "$i" = "dualconf" ] && continue
  [ "$i" = "functions" ] && continue
  [ "$i" = "reboot" ] && continue
  [ "$i" = "halt" ] && continue
  [ "$i" = "killall" ] && continue
  [ "$i" = "single" ] && continue
  [ "$i" = "mandrake_consmap" ] && continue
  [ "$i" = "mandrake_everytime" ] && continue
  [ "$i" = "mandrake_firstime" ] && continue
  [ "$i" = "usb" ] && continue
  if [ -e /etc/debian_version ]; then
    # For Debian
    # We should keep the services in rcS.d, but "update-rc.d remove" does
    # not support this. It will also clean all the services in rcS.d.
    # So we will copy those services of rcS.d to client's common root 
    # after this. NOTE! This can only be done after all updata-rc.d 
    # finished. Otherwise it will affect the update-rc.d
    chroot $drbl_common_root/ /usr/sbin/update-rc.d -f $i remove &> /dev/null
  elif [ -e /etc/SuSE-release ]; then
    # For SuSE
    # There are a lot of boot.* services, we must exclude them also.
    # Special case: boot.udev, which only starts in boot, 2, 3, 5, but we need 
    # it to start in 1 also. So we remove boot.udev here, then modify it, then
    # add it later.
    [ "$i" = "boot.udev" ] && chroot $drbl_common_root/ /sbin/insserv -f -r $i
    [ -n "$(echo $i | grep "^boot.*")" ] && continue

    [ "$i" = "Makefile" ] && continue
    [ "$i" = "README" ] && continue
    [ "$i" = "rc" ] && continue
    chroot $drbl_common_root/ /sbin/insserv -f -r $i
  else
    # For RH-like
    chroot $drbl_common_root/ /sbin/chkconfig --del $i
  fi
done

# 2nd, add the service which DRBL client need
client_services=""
# list the possible services which are necessary for cleitns, 
# we will test all that in RedHat/Fedora/Mandrake/Debian...
# TODO, separate them as must and option... if must service is not on, exit.
# Note: "nfs" is server in RH, but it's client in SuSE. So we have to add it
# separately for SuSE.
# Note: hwscan for suse will be processed later, check the session "# Take care the hardware config files, clean old, make them be detected at boot"
# For Ubuntu, we add acpid and acpi-support for clients.
client_services_chklist="netfs portmap crond nfslock sshd crond xfs ypbind kudzu harddrake dm alsa sound keytable haldaemon messagebus nis nfs-common makedev ssh dbus-1 hal dbus kbd acpid acpi-support"

# check if the service listed exists
for iser in $client_services_chklist; do
   [ -e "/etc/init.d/$iser" ] && client_services="$client_services $iser"
done

# add the services only exist in DRBL client.
client_services="$client_services drblthincli $mkswapfile arm-wol"

# For some distribution, add special service if DRBL is configured to run
# some desktop application, such as iiimf, cups.

# add some special services for specific distribution
if [ -e /etc/debian_version ]; then
  # For Debian
  # The umountfs is already modified by drblpush
  client_services="$client_services sendsigs umountfs"
elif [ -e /etc/SuSE-release ]; then
  # For SuSE
  # Suse uses xdm to start kdm/gdm/xdm, they are all in the same service name.
  # We foced to use the modified boot.udev (it's on in runlevel 1,2,3,4,5
  # Note: "nfs" is server in RH, but it's client in SuSE. So we have to add it
  # separately for SuSE.
  client_services="$client_services nfs xdm boot.udev"
else
  # For RH-like
  # IIim in FC2, iiim in FC3, scim for MDK 10.1 (scim is not a service, so skip this). Try to find which one...
  for iinput in IIim iiim; do
     # TODO, Debian/RH
     if [ -n "$(LC_ALL=C [ -x /sbin/chkconfig ] && chkconfig --list $iinput 2>/dev/null | awk '/5:on/ {print $7}')" -o -n "$(LC_ALL=C [ -x /sbin/chkconfig ] && chkconfig --list $iinput 2>/dev/null | awk '/3:on/ {print $5}')" ]; then
        client_services="$client_services $iinput"
     fi
  done
  # Due to this bug, we force to turn on gpm in FC4.
  # https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=158620
  case "$OS_Version" in
    FC[4-9])
       # To avoid this bug, shit!
       # https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=158620
       client_services="$client_services gpm"
       # modify the gpm so that it will start in rc1, clonezilla is run in rc1.d
       perl -pi -e "s/^# chkconfig: 2345 85 15/# chkconfig: 12345 17 83/g" $drbl_common_root/etc/init.d/gpm
       ;;
  esac
fi
# Add those necessary services:
# firstboot is always necessary. Even for MDK, there is no firstboot in /etc/init.d, we will add it which is provided by DRBL. It will control the run level
# via chkconfig (i.e. for rc3, although the service is added, but it will
# not run.
client_services="$client_services firstboot"

# add the services specified by user
if [ -f /etc/drbl/client-extra-service ]; then
  . /etc/drbl/client-extra-service
  client_services="$client_services $service_extra_added"
else
  # create a template client-extra-service
  cat <<-EXTRA_SRV_END > /etc/drbl/client-extra-service
# You can put the extra service you want client to run, put them in one line.
# The necessary services (nfs, firstboot, xfs...) for DRBL client are already
# specified in the drblpush, so you do not have to add them.
# Example:
# service_extra_added="webmin apmd"
#
service_extra_added=""
EXTRA_SRV_END
fi
echo "The startup services for DRBL client are:"
# strip the leading space
[ "$BOOTUP" = "color" ] && $SETCOLOR_SUCCESS
echo $(echo $client_services | sed -e "s/^ //g")
[ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL

# prepare the necessary env for chkconfig, update-rc.d or insserv
if [ -e /etc/debian_version ]; then
  # For Debian
  prepare_update_rc_d_env $drbl_common_root/
elif [ -e /etc/SuSE-release ]; then
  # For SuSE
  create_insserv_env $drbl_common_root/
else
  # For RH-like
  create_chkconfig_env $drbl_common_root/
fi
for i in $client_services; do
  if [ -e /etc/debian_version ]; then
    case "$i" in
      portmap)
        chroot $drbl_common_root/ /usr/sbin/update-rc.d $i start 18 2 3 4 5 . start 32 0 6 . stop 32 1 . &> /dev/null
        ;;
      nis)
        chroot $drbl_common_root/ /usr/sbin/update-rc.d $i start 19 2 3 4 5 . stop 19 0 1 6 . &> /dev/null
        ;;
      sendsigs)
        chroot $drbl_common_root/ /usr/sbin/update-rc.d $i start 20 0 6 . &> /dev/null
        ;;
      umountfs)
        chroot $drbl_common_root/ /usr/sbin/update-rc.d $i start 40 0 6 . &> /dev/null
        ;;
      mkswapfile)
        chroot $drbl_common_root/ /usr/sbin/update-rc.d $i start 35 2 3 4 5 . stop 65 0 1 6 . &> /dev/null
        ;;
      firstboot)
        chroot $drbl_common_root/ /usr/sbin/update-rc.d $i start 95 2 3 4 5 . stop 05 0 1 6 . &> /dev/null
        ;;
      drblthincli)
        chroot $drbl_common_root/ /usr/sbin/update-rc.d $i start 98 2 3 4 5 . stop 02 0 1 6 . &> /dev/null
        ;;
      nfs-common)
        chroot $drbl_common_root/ /usr/sbin/update-rc.d $i start 21 2 3 4 5 . stop 79 0 1 6 . &> /dev/null
        ;;
      acpid)
        chroot $drbl_common_root/ /usr/sbin/update-rc.d $i start 10 2 3 4 5 . stop 21 0 1 6 . &> /dev/null
        ;;
      acpi-support)
        chroot $drbl_common_root/ /usr/sbin/update-rc.d $i start 99 2 3 4 5 . stop 20 0 1 6 . &> /dev/null
        ;;
      arm-wol)
        chroot $drbl_common_root/ /usr/sbin/update-rc.d $i start 99 2 3 4 5 . &> /dev/null
        ;;
      *)
        chroot $drbl_common_root/ /usr/sbin/update-rc.d $i defaults &> /dev/null
        ;;
    esac
  elif [ -e /etc/SuSE-release ]; then
    # SuSE
    chroot /tftpboot/node_root/ /sbin/insserv -f $i
  else
    # RH-like
    chroot /tftpboot/node_root/ /sbin/chkconfig --add $i
    if [ "$i" = "ypbind" ]; then
     # when using chkconfig --add ypbind, client do not put in rcx.d, since
     # it is:
     # chkconfig: - 27 73
     # Hence we use chkconfig ypbind to turn on it.
     chroot /tftpboot/node_root/ /sbin/chkconfig $i on
    fi
  fi
done

# copy those rcS.d services for Debian, this can only be done after all updata-rc.d finished. Otherwise it will affect the update-rc.d
if [ -e /etc/debian_version ]; then
   # exclude those not necessary:
   # bootmisc.sh will prevent client to login by showning
   # "System bootup in progress - please wait" > /etc/nologin
   # network is already done in initrd of client
   RCS_D_EXCLUDE=""
   unnecessary_rcsd_srv="bootmisc.sh networking linux-restricted-modules-common"
   for isv in $unnecessary_rcsd_srv; do
     RCS_D_EXCLUDE="$RCS_D_EXCLUDE --exclude=S*${isv} "
   done
   rsync -a $RCS_D_EXCLUDE /etc/rcS.d/* $drbl_common_root/etc/rcS.d/
   # force to link some necessary services, since Knoppix or B2D won't have
   # them, but in DRBL, it's a must!!!
   (
     cd $drbl_common_root/etc/rcS.d/
     [ -f ../init.d/mountvirtfsn ] && ln -fs ../init.d/mountvirtfsn S02mountvirtfsn
     [ -f ../init.d/discover ] && ln -fs ../init.d/discover S36discover
     # B2D pureGnome 20051212 does not have hotplug* in rcS.d, but pureKDE has.
     # Anyway, for to link them.
     [ -f ../init.d/hotplug ] && ln -fs ../init.d/hotplug S40hotplug
     [ -f ../init.d/hotplug-net ] && ln -fs ../init.d/hotplug-net S41hotplug-net
     # change the hdparm from S07 to S60 (which is far after S41force-load-ide so we can access IDE device after IDE-related modules are loaded and ready).
     if [ -f ../init.d/hdparm ]; then
       [ -e "S07hdparm" ] && rm -f S07hdparm
       ln -fs ../init.d/hdparm S60hdparm
     fi
     [ -f ../init.d/portmap ] && ln -fs ../init.d/portmap S43portmap
     [ -f ../init.d/mountnfs.sh ] && ln -fs ../init.d/mountnfs.sh S45mountnfs.sh
   )
   # modify some services which maybe not fit the requirement.
   # a. module-init-tools, since the method it detects rw is not quite well.
   if [ -e $drbl_common_root/etc/init.d/module-init-tools ]; then
     perl -pi -e 's|if \[ -w /lib/modules/\$KVER.*|if touch /lib/modules/\$KVER/modules.dep 2>/dev/null; then|g' $drbl_common_root/etc/init.d/module-init-tools
   fi

fi

vmware_as_server="$(grep "VMWare Inc" /proc/pci 2>/dev/null)"
# for VMWare, you have better to install the VMWare tools, 
if [ -n "$vmware_as_server" ]; then
  [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
  echo "It is VMWare as DRBL server ..., If you want to use X Window, make sure you already installed VMWare tools."
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
fi
# First, clean the XF86Config, 
# let configure (like redhat-cfg-xfree86) in /etc/init.d/firstboot
# to create the first one.
# Remove XF86Config and xorg.conf (Both for RH/MDK) in common root
# NOTE! We can NOT remove XF86Config-4/xorg.conf for Debian... it is a template, just rename it.
if [ -e /etc/debian_version ]; then
  # Debian
  for ix in XF86Config-4 xorg.conf; do
    [ -e "/tftpboot/node_root/etc/X11/$ix" ] && mv -f /tftpboot/node_root/etc/X11/${ix} /tftpboot/node_root/etc/X11/${ix}.drbl.template
  done
  # Debian Sarge does not sync the locale setting of gdm with system. do it 
  if [ -f /etc/default/gdm ]; then
    # use subshell to avoid the running shell
    (
      # For B2D, it uses /etc/sysconfig/i18n...
      [ -e /etc/sysconfig/i18n ] && . /etc/sysconfig/i18n
      # the environment priority is higher then /etc/sysconfig/i18n
      [ -e /etc/environment ] && . /etc/environment
      if [ -n "$LANG" ]; then
        if grep -q "^[[:space:]]*#*[[:space:]]*LANG=.*" /tftpboot/node_root/etc/default/gdm 2>/dev/null; then
           perl -pi -e "s/^[[:space:]]*#*[[:space:]]*LANG=.*/LANG=$LANG/g" /tftpboot/node_root/etc/default/gdm
        else
           echo "LANG=$LANG" >> /tftpboot/node_root/etc/default/gdm
        fi
      fi
    )
  fi
else
  # RH-like
  for ix in XF86Config xorg.conf; do
    [ -e "/tftpboot/node_root/etc/X11/$ix" ] && rm -f /tftpboot/node_root/etc/X11/${ix}*
  done
fi

# remove the firstboot setting to aviod it say NO
[ -f /tftpboot/node_root/etc/sysconfig/firstboot ] && rm -f /tftpboot/node_root/etc/sysconfig/firstboot 
# remove the /etc/reconfigSys to avoid firstboot run reconfig
[ -f /tftpboot/node_root/etc/reconfigSys ] && rm -f /tftpboot/node_root/etc/reconfigSys
# disable the /usr/sbin/firstboot in the firstboot service, we should not
# reconfig ntp, user accounts for clients...
perl -p -i -e 's|^(\s*)(/usr/sbin/firstboot)$|$1# $2 # comment by DRBL|g' /tftpboot/node_root/etc/init.d/firstboot

# remove the script in rc[0,6].d to let the client can halt and reboot
if [ -e /etc/debian_version ]; then
  # Debian
  # For Debian, we use update-rc.d to assign which level run which program, so
  # no networking & umountnfs.sh
  true
elif [ -e /etc/SuSE-release ]; then
  # SuSE
  client_must_remove_srv="nfs"
  for i in $client_must_remove_srv; do 
     rm -f /tftpboot/node_root/etc/init.d/rc[123456].d/K[0-9][0-9]$i
  done
else
  # RH-like
  client_must_remove_srv="netfs network killall"
  for i in $client_must_remove_srv; do 
     rm -f /tftpboot/node_root/etc/rc[06].d/[SK][0-9][0-9]$i
  done
fi

# Take care the hardware config files, clean old, make them be detected at boot.
if [ -e /etc/debian_version ]; then
  # Debian
  # In Debian, we need to keep the modules.conf* so that discover will work.
  # We can not force to put ide-cd ide-disk ide-generic  modules in /etc/modules (they are loaded by /etc/rcS.d/S20modutils), this will result chip driver (like piix and ide_core) is loaded afther them (by /etc/rcS.d/S40hotplut). This will cause a problem: unable to turn on IDE HD DMA ("HDIO_SET-DMA failed: Operation not permitted")
  # So we create a startup script after hotplug.
  if [ -f $drbl_common_root/etc/modules ]; then
    rm -f $drbl_common_root/etc/modules
    cat <<-MOD_END > $drbl_common_root/etc/modules
# /etc/modules: kernel modules to load at boot time.
#
# This file should contain the names of kernel modules that are
# to be loaded at boot time, one per line.  Comments begin with
# a "#", and everything on the line after them are ignored.

# Note from DRBL:
# These modules are cleaned by DRBL drblpush so that we have a clean file.
# You can add any module you need here. But do not force to put ide-cd ide-disk ide-generic modules here, this will result chip driver (like piix and ide_core) is loaded afther them (by /etc/rcS.d/S40hotplut). This will cause a problem: unable to turn on IDE HD DMA ("HDIO_SET-DMA failed: Operation not permitted")
# DRBL will load ide-* in /etc/rcS.d/S41force-load-ide 

MOD_END
  fi
  cp -f $drbl_setup_path/files/misc/force-load-ide $drbl_common_root/etc/init.d/force-load-ide
  prepare_update_rc_d_env $drbl_common_root/
  chroot $drbl_common_root/ /usr/sbin/update-rc.d force-load-ide start 41 S . &> /dev/null
elif [ -e /etc/SuSE-release ]; then
  # SuSE
  # No more force to put some almost-must modules (ide-disk...) in /etc/sysconfig/kernel, same reason with the Debian one.
  # Here we modify hwscan to let it run in boot.d and add a service "force-load-ide" in boot.d
  # hwscan only exists in SuSE 9.3, in 10.0 or later it's gone!
  create_insserv_env $drbl_common_root/
  for i in parse-load-mod-suse force-load-ide; do
    cp -f $drbl_setup_path/files/misc/$i $drbl_common_root/etc/init.d/
    chroot $drbl_common_root/ /sbin/insserv -f $i
  done
  # modify boot.idedma service
  chroot $drbl_common_root/ /sbin/insserv -f -r boot.idedma
  perl -pi -e 's/^#[[:space:]]*Required-Start:.*/# Required-Start: boot.loadmodules force-load-ide/g' $drbl_common_root/etc/init.d/boot.idedma
  chroot $drbl_common_root/ /sbin/insserv -f boot.idedma
  # process the hwscan for SuSE 9.3
  if [ -e "$drbl_common_root/etc/init.d/hwscan" ]; then
    perl -pi -e 's/^#[[:space:]]*Default-Start:.*/# Default-Start: B/g' $drbl_common_root/etc/init.d/hwscan
    chroot $drbl_common_root/ /sbin/insserv -f hwscan
  fi
else
  # RH-like
  # Only for RH-like distribution, we can remove the modules.conf*
  # remove the etc/modules.conf in template so that the kudzu in the client can create their own hardware config file.
  # In Debian, we need to keep the modules.conf* so that discover will work.
  find /tftpboot/node_root/etc/ -name "modules.conf*" -exec rm -f {} \;
fi

# force to disable selinux in the client.
for ise in /etc/selinux/config /etc/sysconfig/selinux; do
  if [ -f /tftpboot/node_root/$ise ]; then
    perl -pi -e "s/^SELINUX=.*/SELINUX=disabled/g" /tftpboot/node_root/$ise
  fi
done

# switch the link in $drblcommont_root/sbin, some distributions, 
# like B2D, will link poweroff to init, for we have make it link to init.orig
# lnkfiles="halt poweroff reboot telinit"
lnkfiles="$(find $drbl_common_root/sbin/ -type l -lname "init" -print)"
for ilnk in $lnkfiles; do
  ( cd $drbl_common_root/sbin/; ln -fs init.orig $ilnk )
done

# remove the template's etc/sysconfig/hwconf which kudzu will log
[ -f /tftpboot/node_root/etc/sysconfig/hwconf ] && rm -f /tftpboot/node_root/etc/sysconfig/hwconf

# The root over NFS mount is done in sbin/init which Steven modified,
# $nfsserver:/tftpboot/node_root
# so remove this file
[ -f /tftpboot/node_root/etc/fstab ] && rm -f /tftpboot/node_root/etc/fstab

# clean the rhn config, client should not do that.
[ -d /tftpboot/node_root/etc/sysconfig/rhn ] && rm -rf /tftpboot/node_root/etc/sysconfig/rhn 2> /dev/null

# create new init to mount separate client's fstab and ...
# Ref. Debian's diskless_newimage, /var/lib/diskless/default/root/sbin/init
# The original init has already renamed as init.orig

cp -f $drbl_setup_path/files/misc/init.drbl /tftpboot/node_root/sbin/init
chown root.root /tftpboot/node_root/sbin/init
chown 755 /tftpboot/node_root/sbin/init

# mkdir special directory etc/diskless-image for each diskless host to mount its fstab
#
mkdir -p /tftpboot/node_root/etc/diskless-image

# copy dev tarball to /tftpboot/node_root/etc/diskless-image
if [ -x "/tftpboot/node_root/sbin/udevd" ]; then
  echo -n "Using udev for clients... " 
elif [ -f "$drbl_pkgdir/dev.tgz" ]; then
  echo -n "Using old-style dev for clients... " 
  cp -f $drbl_pkgdir/dev.tgz /tftpboot/node_root/etc/diskless-image
else
  [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
  echo "Can NOT find udev or the dev.tgz, did you already setup the DRBL server ?"
  echo "Please press Ctrl-C to stop the program!"
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
  read
  exit 1 
fi

# Switch client graphic/text mode
case "$OS_type" in
RH|MDK|SUSE)
  # set the init to user specifies
  case "$client_init" in
    "text")
          CLIENT_INIT_RL=3
          ;;
    "graphic")
          CLIENT_INIT_RL=5
          ;;
  esac
  perl -p -i -e "s/^id:[1-5]:initdefault:/id:$CLIENT_INIT_RL:initdefault:/g" /tftpboot/node_root/etc/inittab
  ;;
DBN)
  default_dm="$($DRBL_SCRIPT_PATH/bin/check_dm 2> /dev/null)"
  case "$client_init" in
    "text")
        echo "Set text mode for Debian DRBL client..."
        prepare_update_rc_d_env $drbl_common_root/
        chroot $drbl_common_root/ /usr/sbin/update-rc.d -f $default_dm remove &> /dev/null
        #clean_update_rc_d_env $drbl_common_root/
        ;;
    "graphic")
      if [ -n "$default_dm" ]; then
        echo "Set graphic mode for Debian DRBL client..."
        prepare_update_rc_d_env $drbl_common_root/
        chroot $drbl_common_root/ /usr/sbin/update-rc.d $default_dm start 99 2 3 4 5 . stop 05 0 1 6 . &> /dev/null
        #clean_update_rc_d_env $drbl_common_root/
      fi
      ;;
  esac
  ;;
esac

# Turn off all the xinted/inted services in clients.
# Set the tftpd to on when xinetd/inted starts in server.
# (1) for client:
if [ -e /etc/debian_version ]; then
  # Debian
  if grep -q "^tftp[[:space:]]+" $drbl_common_root/etc/inetd.conf 2>/dev/null; then
    # TODO: /usr/sbin/update-inetd is perl, and require some perl modules.
    # It need /usr/share/perl5/DebianNet.pm, but it depends on perl version.
    #chroot $drbl_common_root /usr/sbin/update-inetd --remove tftp
    # Here we use easier method, just delete the tftp in /etc/inetd.conf
    # It looks like: 
    # tftp           dgram   udp     wait    root  /usr/sbin/in.tftpd /usr/sbin/in.tftpd -s /var/lib/tftpboot
    perl -pi -e "s/^tftp[[:space:]]+.*//g" $drbl_common_root/etc/inetd.conf
  fi
  if [ -e $drbl_common_root/etc/init.d/tftpd-hpa ]; then
    # it's a standalone daemon
    prepare_update_rc_d_env $drbl_common_root/
    chroot $drbl_common_root/ /usr/sbin/update-rc.d -f tftpd-hpa remove &> /dev/null
  fi
else
  # RH-like & SuSE
  perl -p -i -e "s/disable.*=.*/disable                 = yes/g" $drbl_common_root/etc/xinetd.d/tftp 
fi

# (2) for server
# set the tftp to on when xinetd/inted starts in server.
if [ -e /etc/debian_version ]; then
  # Debian
  # Force to remove tftp in inetd if it's set, and we will add it later 
  # and put our arguments "-s /tftpboot/nbi_img"
  if grep -q "^tftp" /etc/inetd.conf 2>/dev/null; then
    /usr/sbin/update-inetd --remove tftp
  fi
  if [ -e /etc/init.d/tftpd-hpa ]; then
    # it's a standalone daemon
    cat <<-TFTP_END > /etc/default/tftpd-hpa
RUN_DAEMON="yes"
OPTIONS="-l -s /tftpboot/nbi_img"
TFTP_END
  else
    # it's a daemon in inetd, set it in inetd.conf
    /usr/sbin/update-inetd --group BOOT --add 'tftp	dgram	udp	wait	root	/usr/sbin/in.tftpd	/usr/sbin/in.tftpd	-s /tftpboot/nbi_img' 
  fi
else
  # RH-like & SuSE
  perl -p -i -e "s/disable.*=.*/disable                 = no/g" /etc/xinetd.d/tftp 
  # set the tftp working directory to be /tftpboot/nbi_img 
  # to have higher security.
  perl -p -i -e "s/server_arg.*=.*/server_args		= -s \/tftpboot\/nbi_img/g"  /etc/xinetd.d/tftp
fi

# create a config file for each diskless host to mount its fstab
# Steven to do, what's master ?
cat <<-CONFIG_END > /tftpboot/node_root/etc/diskless-image/config

nfsserver_default=$nfsserver_default
nfsimagedir=$drbl_common_root
nfshostsdir=$drblroot
nameserver=$nameserver

CONFIG_END

# for clients' public IP 
# if the file $public_ip_list is created, copy it
[ -f "$public_ip_list" ] && cp -f $public_ip_list /tftpboot/node_root/etc/diskless-image/

# copy the collected MAC addresses to drbl sysconfig
if [ "$collect_mac" = "yes" ]; then
  cp -f macadr-eth*.txt $drbl_syscfg/ &> /dev/null
fi

# write the resolv.conf 
[ -f /tftpboot/node_root/etc/resolv.conf ] && rm -rf /tftpboot/node_root/etc/resolv.conf

for nameserver in $nameserver_; do 
  echo "nameserver $nameserver" >> /tftpboot/node_root/etc/resolv.conf
done

# rc.sysinit only in RH-like (BSD), no rc.sysinit in Debian/SuSE
case "$OS_type" in
  RH|MDK)
    # For distribution RH/FC/CO/MDK/MDV
    if [ -f "${drbl_setup_path}/files/${OS_Version}/rc.sysinit.${OS_Version}.drbl" ]; then
      cp -f ${drbl_setup_path}/files/${OS_Version}/rc.sysinit.${OS_Version}.drbl /tftpboot/node_root/etc/rc.d/rc.sysinit
    else
      # Can not find fine-tune file, show warning.
      [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
      echo "Warning! Unable to find the fine-tune file ${drbl_setup_path}/files/${OS_Version}/rc.sysinit.${OS_Version}.drbl, use ${drbl_setup_path}/files/default/rc.sysinit.default-${OS_type}.drbl as /etc/rc.d/rc.sysinit for DRBL clients!"
      echo "This may cause some problems to DRBL clients!"
      [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
      cp -f ${drbl_setup_path}/files/default/rc.sysinit.default-${OS_type}.drbl /tftpboot/node_root/etc/rc.d/rc.sysinit
    fi
    ;;
esac

# "ln -fs tmp/boot/ boot" in template 
# insert "mkdir tmp/boot" in rc.sysinit of other clients, because it's tmpfs
# so that /sbin/mkkerneldoth in rc.sysinit can creat file "/boot/boot.h"
(cd /tftpboot/node_root; ln -fs tmp/boot boot)

# create the CLEAN rc.boot/boot.local/rc.local to avoid some commands copied from server
if [ -e /etc/debian_version ]; then
  # Debian
  [ -d "$drbl_common_root/etc/rc.boot" ] && rm -f $drbl_common_root/etc/rc.boot/*
elif [ -e /etc/SuSE-release ]; then
  # SuSE
  if [ -f "$drbl_common_root/etc/init.d/boot.local" ]; then
    perl -pi -e "s/^[[:space:]]*[^#]+//g" $drbl_common_root/etc/init.d/boot.local
  fi
else
  # RH-like
  # 1st, clean rc.local 
  [ -f /tftpboot/node_root/etc/rc.d/rc.local ] && rm -f /tftpboot/node_root/etc/rc.d/rc.local
  
  # 2nd, create a clean rc.local 
  cat <<-RC_LOCAL > /tftpboot/node_root/etc/rc.d/rc.local
#!/bin/bash
#
# This script will be executed *after* all the other init scripts.
# You can put your own initialization stuff in here if you don't
# want to do the full Sys V style init stuff.

touch /var/lock/subsys/local

# For Mandrake, harddrake will not create cdrom link automatically... so
# detect it and create it.
# While for Redhat, kudzu will do that. Anyway, we just do it.
if [ ! -e "/dev/cdrom" ]; then
  cddev="\$($DRBL_SCRIPT_PATH/bin/detect_cdrom)"
  [ -n "\$cddev" ] && ln -fs /dev/\$cddev /dev/cdrom
fi

# For Mandrake, it use /mnt (tmpfs) instead of /media for cdrom, floppy, create the mount point in tmpfs, since mandrake does not create them automatically.
# Although the problem is only in mandrake, but we still create them for all RH-like dists, since user maybe want to use these mount points.
for d in floppy cdrom loop disk usb; do
  [ ! -d "/mnt/\$d" ] && mkdir -p /mnt/\$d
done

# run the time sync when client boots.
[ -x "/etc/cron.daily/timesync" ] && /etc/cron.daily/timesync &

RC_LOCAL

  #change its mode
  chown root.root /tftpboot/node_root/etc/rc.d/rc.local
  chmod 775 /tftpboot/node_root/etc/rc.d/rc.local
fi

# Modify some rc programs.
# For RH-like, use the modified template etc/init.d/halt, which remove all the umount command
# For Debian and SuSE, just use perl to modify them.
if [ -e /etc/debian_version ]; then
  # Debian
  # For genuine Debian
  # remove -i in "reboot -d -f -i" so it won't stop network before reboot
  # remove -i in "halt -d -f -i -p" so it won't stop network before halt
  perl -pi -e 's/^([[:space:]]*reboot .*)-i(.*)/$1 $2 # Modified by DRBL/' $drbl_common_root/etc/init.d/reboot
  perl -pi -e 's/^([[:space:]]*halt .*)-i(.*)/$1 $2 # Modified by DRBL/' $drbl_common_root/etc/init.d/halt
  # For B2D, the reboot and halt is a little different, except the above,
  # we have to comment umount -a 
  perl -pi -e 's/^([[:space:]]*umount -a.*)/#$1 # Modified by DRBL/' $drbl_common_root/etc/init.d/reboot
  perl -pi -e 's/^([[:space:]]*umount -a.*)/#$1 # Modified by DRBL/' $drbl_common_root/etc/init.d/halt

  # Do not clean or remove etc/mtab when boots
  perl -pi -e 's|^([[:space:]]*:> $MTAB_PATH.*)|#$1 # Modified by DRBL|' $drbl_common_root/etc/init.d/checkroot.sh
  perl -pi -e 's|^([[:space:]]*rm -f \${MTAB_PATH}~.*)|#$1 # Modified by DRBL|' $drbl_common_root/etc/init.d/checkroot.sh
  # Do not remove /fastboot, DRBL client is always fastboot
  perl -pi -e 's|^([[:space:]]*rm -f )(/fastboot)(.*)|$1 $3 # modified by DRBL|' $drbl_common_root/etc/init.d/checkfs.sh

elif [ -e /etc/SuSE-release ]; then
  # SuSE
  # in SuSE, /etc/init.d/reboot is link to halt, so we just have to modify
  # halt.
  perl -pi -e 's|^(> /success.*)|#$1 # Modified by DRBL|' $drbl_common_root/etc/init.d/halt
  perl -pi -e 's|^(umount -anvt proc.*)|#$1 # Modified by DRBL|' $drbl_common_root/etc/init.d/halt
  # do not clean or remove etc/mtab when boots
  perl -pi -e 's|^([[:space:]]*)(rm -f /etc/mtab.*)|$1# $2 # Modified by DRBL|' $drbl_common_root/etc/init.d/boot.rootfsck
  # Not only etc/mtab, do not remove /fastboot, too. DRBL client is always fastboot
  perl -pi -e 's|^([[:space:]]*rm -f )/etc/mtab\* (.*)/fastboot(.*)|$1 $2 $3 # Modified by DRBL|' $drbl_common_root/etc/init.d/boot.localfs
  # boot.rootfsck, we comment the mount -f / to avoid / be mounted twice.
  perl -pi -e 's|^([[:space:]]*)(mount -f /)|$1# $2 # Modified by DRBL|g' $drbl_common_root/etc/init.d/boot.rootfsck
else
  # RH-like
  if [ -f "$drbl_setup_path/files/$OS_Version/halt.$OS_Version.drbl" ]; then
    cp -f $drbl_setup_path/files/$OS_Version/halt.$OS_Version.drbl $drbl_common_root/etc/init.d/halt
  else
    # not Debian, it's RH-like (BSD style), so show warning.
    [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
    echo "Warning! Unable to find the fine-tune file ${drbl_setup_path}/files/$OS_Version/halt.${OS_Version}.drbl, use ${drbl_setup_path}/files/default/halt.default-${OS_type}.drbl as /etc/init.d/halt for DRBL clients!"
    echo "This may cause some problems to DRBL clients!"
    [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
    cp -f $drbl_setup_path/files/default/halt.default-${OS_type}.drbl $drbl_common_root/etc/init.d/halt
  fi
fi

# This is done in init.drbl, where we do not use link.
# Force to use the /proc/mounts, not use the /etc/mtab, otherwise they will
# NOT sync to each other
#[ -f /tftpboot/node_root/etc/mtab~ ] && rm -rf /tftpboot/node_root/etc/mtab~
#ln -fs /proc/mounts /tftpboot/node_root/etc/mtab

# delete the users in template, i.e. we will use the YP, not local account 
# in clients
echo -n "Deleting the accounts (except root) in the clients common root template... "
newroot="/tftpboot/node_root/"
usrdel_file_need="/usr/sbin/userdel"
cp --parents $usrdel_file_need $newroot
#usrdel_lib_need=$(ldd /usr/sbin/userdel | cut -d" " -f3)
#cp --parents $usrdel_lib_need $newroot
if ldd $usrdel_file_need &>/dev/null; then
  usrdel_lib_need=$(ldd /usr/sbin/userdel | sed -e "s/.*=> //g" -e "s/(0x.*)//g" | awk '{print $1}')
  for imod in $usrdel_lib_need; do
      cp --parents $imod $newroot
  done
fi
# UGLY... For SuSE, we need to copy /usr/lib/pwdutils/ to $newroot, 
# but why ? Here it's just a lots of try-and-errors...
[ -d /usr/lib/pwdutils/ ] && cp --parents -r /usr/lib/pwdutils $newroot
[ -x /usr/sbin/userdel-pre.local ] && cp --parents /usr/sbin/userdel-pre.local $newroot 
[ -x /usr/sbin/userdel-post.local ] && cp --parents /usr/sbin/userdel-post.local $newroot 
# /usr/bin/crontab exists in /usr/sbin/userdel-pre.local in SuSE
[ -x /usr/bin/crontab ] && cp --parents /usr/bin/crontab $newroot 

user_to_del="$($DRBL_SCRIPT_PATH/bin/get_common_usersname 2>/dev/null)"
for u in $user_to_del; do
  if grep -q "^$u:" $newroot/etc/passwd; then
    chroot $newroot /usr/sbin/userdel $u 2>/dev/null
  fi
done
echo "done!"

# Enable the NIS client for this template
# For Mandrake/Debian, there is no authconfig, 
# Mandrake use drakauth, but not interactive ?
echo -n "Enabling the NIS client in the common root template... "
# For RH-like, used to use /usr/sbin/authconfig, but in FC5, it's python... not easy to create the "create_authconfig_env /tftpboot/node_root/"
# turn on the nis in common root's /etc/nsswitch.conf, this is necessary for MDK/DBN since MDK/DBN does NOT have /usr/sbin/authconfig 
perl -pi -e "s/^passwd:.*/passwd:     files nis/" /tftpboot/node_root/etc/nsswitch.conf 
perl -pi -e "s/^shadow:.*/shadow:     files nis/" /tftpboot/node_root/etc/nsswitch.conf 
perl -pi -e "s/^group:.*/group:     files nis/" /tftpboot/node_root/etc/nsswitch.conf 
perl -pi -e "s/^hosts:.*/hosts:     files nis dns/" /tftpboot/node_root/etc/nsswitch.conf 

# For Debian
if [ -e /etc/debian_version ]; then
  if [ -f $drbl_common_root/etc/default/nis ]; then
    perl -p -i -e "s/^NISSERVER=.*/NISSERVER=false/" $drbl_common_root/etc/default/nis
    perl -p -i -e "s/^NISCLIENT=.*/NISCLIENT=true/" $drbl_common_root/etc/default/nis
  fi
fi
echo "done!"

echo -n "Creating some necessary files in the clients common root template..."
# set the arguments "-q" in kudzu to let system do configuration that
# doesn't require user input
newroot="/tftpboot/node_root/"
#perl -p -i -e "s/^KUDZU_ARGS=.*/KUDZU_ARGS=-q/" $newroot/etc/init.d/kudzu 
[ -d "$newroot/etc/sysconfig" ] && echo "KUDZU_ARGS=-q" >> $newroot/etc/sysconfig/kudzu

echo -n "."
# write the ntp server setting
if ! grep -q "^server pool.ntp.org" /etc/ntp.conf 2>/dev/null; then
  echo "server pool.ntp.org" >> /etc/ntp.conf
fi
if ! grep -q "^server stdtime.sinica.edu.tw" /etc/ntp.conf 2>/dev/null; then
  echo "server stdtime.sinica.edu.tw" >> /etc/ntp.conf
fi

# set the restrict for ntp clients
if ! grep -q "^restrict default ignore" /etc/ntp.conf 2>/dev/null; then
  echo "restrict default ignore" >> /etc/ntp.conf
fi

if ! grep -q "^restrict 127.0.0.1" /etc/ntp.conf 2>/dev/null; then
  echo "restrict 127.0.0.1" >> /etc/ntp.conf
fi

echo -n "."
# create the /var in template, only directory 
# Other directory in /var/lib/ is important for some applications.
# but /var/lib/rpm/* is necessary for rpm database,
# /var/spool/mail is necessary for each user.
# It's better to export /var/lib all.

# use rsync will be easier....Thanks to Wayne Davison wayned@samba.org
rsync -a $RSYNC_OPT_EXTRA --include="*/" --exclude="*" /var /tftpboot/node_root/

echo -n "."

# For SuSE, we need to copy /var/X11R6 to clients also. How about /var/adm ?
[ -d /var/X11R6 ] && rsync -a $RSYNC_OPT_EXTRA /var/X11R6/* /tftpboot/node_root/var/X11R6/
# Copy all /var/lib/* to the common root
[ -d /var/lib ] && rsync -a $RSYNC_OPT_EXTRA /var/lib/* /tftpboot/node_root/var/lib/

# Copy selected /var/cache/* to the common root
for icache in $varcache_2_be_copied; do
  [ -d "/var/cache/$icache" ] && rsync -a $RSYNC_OPT_EXTRA /var/cache/$icache /tftpboot/node_root/var/cache/
done

};

# print all the nfsserver to /tftpboot/node_root/etc/diskless-image/config
print NFSSERVER_OUT "NFSSERVER_LIST=\"";
foreach my $k1 ( sort(keys %$rHoH) ) {
  if( $k1=~/general/ ) { next; } # skip general block
  my $nfsserver=$rHoH->{$k1}{"NFSSERVER"};
  #---------------
  my $interface=$rHoH->{$k1}{"INTERFACE"};
  # Try to get setting from system also
  # use the NIC "eth1, eth2..." of DRBL server as default nfsserver_sys...
  my $nfsserver_sys;
  chomp($nfsserver_sys=`$DRBL_SCRIPT_PATH/bin/get_ip $interface`);
  # set nfsserver, the priority: use the config file first, if unset, then use the value in system
  if ( ! $nfsserver ) { 
   $nfsserver = $nfsserver_sys; 
   print "* nfsserver is not set in config file, \nthe one \"$nfsserver\" got from system will be used.\n" if $verbosity >= 2;   
  }
  
  # check if the values are set in config file or system  
  unless ( $nfsserver ) {
     print "Error! NFSSERVER is unset!\n";
     print "Please set nfsserver in config file \"$_[0]\" or IPADDR in system config file.\n";
     exit;
  }
    #---------------
    #print "nfsserver: $nfsserver\n";
    print NFSSERVER_OUT "$nfsserver ";

    # next one
    $i++;
  };
print NFSSERVER_OUT "\"\n";

print DISKLESS_OUT q{
echo -n ". "
# append all the nfsserver to /tftpboot/node_root/etc/diskless-image/config
cat nfsserver_all >> /tftpboot/node_root/etc/diskless-image/config

echo "done!"
};

# Part 3,
# create every client node, like Debian's diskless-newhost
#
  print DISKLESS_OUT q{
# create every client node, like Debian's diskless-newhost
};

  foreach my $k1 ( sort(keys %$rHoH) ) {
    if( $k1=~/general/ ) { next; } # skip general block
    my $interface=$rHoH->{$k1}{"INTERFACE"};
    my $network=$rHoH->{$k1}{"NETWORK"};
    my $nfsserver=$rHoH->{$k1}{"NFSSERVER"};
    my $bootserver=$rHoH->{$k1}{"BOOTSERVER"};
    my $nisserver=$rHoH->{$k1}{"NISSERVER"};
    my $nbi=$rHoH->{$k1}{"NBI"};
    my $mac=$rHoH->{$k1}{"MAC"};
    my $ip_start=$rHoH->{$k1}{"IP_START"};
    my $range=$rHoH->{$k1}{"RANGE"};

    if( length($bootserver)==0 ) { $bootserver=$nfsserver; }
    if( length($nisserver)==0 ) { $nisserver=$nfsserver; }
    if( length($nbi)==0 ) { $nbi=$rHoH->{"general"}{"NBI"}; }
    # Try to get setting from system also
    # use the NIC "eth1, eth2..." of DRBL server as default nfsserver_sys...
    chomp($hostname_sys=`$DRBL_SCRIPT_PATH/bin/parse_net_conf all hostname`);
    chomp($netmask_sys=`$DRBL_SCRIPT_PATH/bin/get_netmask $interface`);
    chomp($ipaddr_sys=`$DRBL_SCRIPT_PATH/bin/get_ip $interface`);
    # the IP address for server is the NFS server for client
    my $nfsserver_sys=$ipaddr_sys;
    my $bootserver_sys=$nfsserver_sys;
    my $nisserver_sys=$nfsserver_sys;
    # set nfsserver, bootserver, nisserver address, the priority: use the config file first, if unset, then use the value in system
   
    # If hostname_prefix unset, try to set it as that of server
    if ( ! $hostname_prefix ) { 
      @hostname_sp_sys=split(/\./,$hostname_sys);
      $hostname_prefix="$hostname_sp_sys[0]"; 
    }
    # Get the interface number (i.e eth1 -> extract "1")
    # and set it as a part of hostname, it will be like node-1...
    # For interface like vmnet1, we will not extract that so that the
    # hostname won't conflict.
    my $grp_no = $interface;
    $grp_no =~ s/eth//g;
    # If IP alias, eth0:1 will be 0:1, which is not a legal name in dhcpd.
    # so we change 0:1 to 0_1
    $grp_no =~ s/:/-/g;
    $hostname = "$hostname_prefix"."$grp_no"; 
    print "The hostname set for client is: \"$hostname\".\n" if $verbosity >= 2;

    unless ( $netmask_sys ) {
       print "Error! NETMASK is unset!\n";
       print "Please set NETMASK in system config file.\n";
       exit;
    }

    if ( ! $network ) { 
      # Since there are two versions of ipcalc, we use the perl one, which is
      # from http://jodies.de/ipcalc
      $network = `$DRBL_SCRIPT_PATH/bin/ipcalc $ipaddr_sys $netmask_sys | awk -F' ' '/Network:/ {print \$2}' | sed -e "s|/.*||g"`;
      chomp($network);
      print colored ("The calculated NETWORK for $interface is $network.\n", 'red');
    }

    if ( ! $nfsserver ) { 
     $nfsserver = $nfsserver_sys; 
     print "* nfsserver is not set in config file, \nthe one \"$nfsserver\" got from system will be used.\n" if $verbosity >= 2;   
    }
    if ( ! $bootserver ) { 
     $bootserver = $bootserver_sys; 
     print "* bootserver is not set in config file, \nthe one \"$bootserver\" got from system will be used.\n" if $verbosity >= 2;   
    }
    if ( ! $nisserver ) { 
     $nisserver = $nisserver_sys; 
     print "* nisserver is not set in config file, \nthe one \"$nisserver\" got from system will be used.\n" if $verbosity >= 2;   
    }
    
    # Last check if the values are set in config file or system  
    unless ( $hostname ) {
       print "Error! HOSTNAME is unset!\n";
       print "Please set hostname in config file \"$_[0]\" or HOSTNAME in system config file.\n";
       exit;
    }
    unless ( $nfsserver ) {
       print "Error! NFSSERVER is unset!\n";
       print "Please set nfsserver in config file \"$_[0]\"\n";
       exit;
    }
    unless ( $bootserver ) {
       print "Error! BOOTSERVER is unset!\n";
       print "Please set bootserver in config file \"$_[0]\"\n";
       exit;
    }
    unless ( $nisserver ) {
       print "Error! NISSERVER is unset!\n";
       print "Please set nisserver in config file \"$_[0]\"\n";
       exit;
    }
    
    # go 
    @nfsserverIp=split(/\./,$nfsserver);
    @networkIp=split(/\./,$network);

    print DHCPD_OUT <<EOF;
subnet $network netmask 255.255.255.0 {
    option broadcast-address	$networkIp[0].$networkIp[1].$networkIp[2].255;
    option routers $bootserver;
    next-server $bootserver;

EOF

    # range option, we have to create the IP table file
    if( length($mac)==0 && length($range)!=0 ) {
      chomp ( $temprange = `LC_ALL=C mktemp /tmp/drbl_range.XXXXXX` );
      open(RANGE_OUT,">$temprange");
      my($rs,$re)=split(/-/,$range,2);
      # get the initial value in the last set of digits in the IP address 
      # from range starting no.
      $ip_start=$rs;
      for($i=$rs;$i<=$re;$i++) {
        my $rg_ip="$networkIp[0].$networkIp[1].$networkIp[2].$i";
	print "checking IP is same with nfsserver or not, nfsserver is $nfsserver, ip is $rg_ip!\n" if $verbosity >= 2;
	if ( "$rg_ip" ne "$nfsserver" ) {
          print RANGE_OUT "$networkIp[0].$networkIp[1].$networkIp[2].$i\n";
	}
	else {
	  # skip the IP same with nfsserver.
          my $next_ip=$i;
	  $next_ip++;
          $next_ip="$networkIp[0].$networkIp[1].$networkIp[2].$next_ip";
	  print "* The client IP address you assigned is same with nfsserver: $rg_ip, \n ---> the next IP address ($next_ip) will be used for that client!\n";
	  # increase the end of range by 1 
	  $re++;
	}
      }
      close(RANGE_OUT);
    }

    # open mac or range file
    # set the initial IP address in the subnet for fixed IP client (MAC) or range option
    $i=$ip_start;
    if( length($mac)!=0 ) { open(MAC_IN,$mac) or die "Can NOT find MAC address file \"$mac\"! \n"; }
    elsif( length($range)!= 0 ) { open(MAC_IN,"$temprange") or die "Can NOT find IP address range temp file \"$temprange\"! \n"; 
    }

    # MAC_IN is both for MAC and RANGE readin number
    while(<MAC_IN>) {
      chop;
      if($nfsserverIp[0]==$networkIp[0] &&
         $nfsserverIp[1]==$networkIp[1] &&
         $nfsserverIp[2]==$networkIp[2] &&
         $nfsserverIp[3]==$i) { 
         $i++; 
      }

      # hostname for client
      # the name will like fc2-101, fc2-201...,i.e. like
      # prefix-{ethx}{client no}, it's impossible we will have more than 100
      # DRBL clients connectted to each ethernet card of the server.
      # So forget about something like fc2-1-001, fc2-1-002...
      $label="";
      if($i<10) { $label=$hostname."0".$i; }
      elsif($i<=254) { $label=$hostname.$i; }
      elsif($i>254) { last; } # minus 2 ip: $network.0 $network.255

      # ip
      if( length($mac)!=0 ) { 
	# mac 
        if($nfsserverIp[0]==$networkIp[0] &&
           $nfsserverIp[1]==$networkIp[1] &&
           $nfsserverIp[2]==$networkIp[2] &&
           $nfsserverIp[3]==$i) { 
           $i++; 
        }
        $ip="$networkIp[0].$networkIp[1].$networkIp[2].$i";

        # generate dhcpd.conf      
	# without nbi set in config file
        print DHCPD_OUT <<EOF;
    host $label {
        hardware ethernet  $_;
        fixed-address $ip;
        option host-name "$label";
    }
EOF
      } elsif( length($range)!=0 ) { 
	# range
        $ip=$_;
      }
      
      # clean the temp range file
      unlink ($temprange) if -f $temprange;

      # generate netgroup
      print NETGROUP_OUT "($label,,) ";

      # append the hosts to hosts_list
      print HOSTS_LIST_OUT <<EOF;
$ip
EOF


#
      print DISKLESS_OUT q{
      [ "$clonezilla_box_mode" = "yes" -o "$drbl_ssi_mode" = "yes" ] && [ "$pseudo_flag" = "on" ] && pseudo_opt="-p"
      };
      print DISKLESS_OUT <<EOF;
      # $keep_old_files_flag is assigned in shell, not from perl.
$DRBL_SCRIPT_PATH/sbin/gen_client_files.sh -l $language -h $ip -k \$keep_old_files_flag -n $nfsserver -a $label -i $nisserver \$pseudo_opt
      [ -z "\$template_client" ] && template_client="$ip"
EOF
      print DISKLESS_OUT q{
      pseudo_flag=on
      };

      # next one
      $i++;
    }

    # generate dhcpd.conf 
    if( length($mac)!=0 ) { # mac - just close it 
      print DHCPD_OUT "}\n";
    } 
    elsif( length($range)!=0 ) { # range - generate range & filename
        # without nbi set in config file
        my($rs,$re)=split(/-/,$range,2);
        print DHCPD_OUT <<EOF;
    range $networkIp[0].$networkIp[1].$networkIp[2].$rs $networkIp[0].$networkIp[1].$networkIp[2].$re;
}

EOF
    }
    close(MAC_IN);
  }

# generate in $main_sh
# TODO, Debian/RH
print DISKLESS_OUT q{
# Generate the files for DRBL single system image SSI
echo "Template client for DRBL SSI is $template_client"
$DRBL_SCRIPT_PATH/sbin/gen_ssi_files -n -t $template_client

# output dhcpd arguments or interfaces to sysconfig file
dhcp_eths="$(awk -F"=" '/^interface=.*/ {print $2}' $config_file)"
# if the itnerface is alias, print the original interface
# i.e. if eth0:1, we print eth0
dhcp_eths="$(echo $dhcp_eths | sed -e "s/:[0-9]*//g")"
if [ -e "/etc/debian_version" ]; then
   # Debian, use the parameter "INTERFACES"
   echo "INTERFACES=\"$dhcp_eths\"" > $SYSCONF_PATH/$DHCP_SRV_NAME
elif [ -e "/etc/SuSE-release" ]; then
   perl -pi -e "s/^[#]*[[:space:]]*[#]*DHCPD_INTERFACE=.*/DHCPD_INTERFACE=\"$dhcp_eths\"/g" $SYSCONF_PATH/$DHCP_SRV_NAME
else
   # RH-like, use the parameter "DHCPDARGS"
   echo "DHCPDARGS=\"$dhcp_eths\"" > $SYSCONF_PATH/$DHCP_SRV_NAME
fi

# turn on pxelinux passwd if set
if [ -n "$client_pxelinux_passwd" ]; then
  $DRBL_SCRIPT_PATH/sbin/drbl-pxelinux-passwd -e --stdin $client_pxelinux_passwd
fi

# write the NISDOMAIN to system config file in DRBL server
NET_sys_RH="/etc/sysconfig/network"
NIS_Debian="/etc/defaultdomain"
NIS_SuSE="/etc/defaultdomain"
if [ -e /etc/debian_version ]; then
  echo "$nisdomain" > $NIS_Debian
  perl -p -i -e "s/^NISSERVER=.*/NISSERVER=master/" /etc/default/nis
  perl -p -i -e "s/^NISCLIENT=.*/NISCLIENT=true/"   /etc/default/nis
elif [ -e /etc/SuSE-release ]; then
  # SuSE
  echo "$nisdomain" > $NIS_SuSE
else
  # RH-like
  NIS_sys=$(grep NISDOMAIN $NET_sys_RH 2>/dev/null)
  if [ -z "$NIS_sys" ]; then
    echo "NISDOMAIN=$nisdomain" >> $NET_sys_RH
  else
    perl -p -i -e "s/^NISDOMAIN=.*/NISDOMAIN=$nisdomain/" $NET_sys_RH
  fi
fi

# before restart NIS, force the variable NISDOMAIN now is that set in config file
nisdomainname $nisdomain

# Since we set tcp as the default NFS protocol, if tcp over NFS is not supported in the server running kernel, make a switch for client to use udp. 
# Ex:for RH9, tcp over NFS is not supported in the runnking kernel 2.4.20-8
if [ "$nfs_protocol" = "udp" ]; then
  [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
  echo 'Switch "tcp over NFS" to "udp over NFS" for the DRBL clients...'
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
  $DRBL_SCRIPT_PATH/sbin/drbl-nfs-conf --no-gen-ssi --protocol udp
fi

# force to turn on portmap for rc3.d and rc5.d as default, without portmap
# nfs will go wrong...
[ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
echo "Now set the necessary services for DRBL server - dhcp, tftp, nfs, and nis to be on when the machine start up."
[ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL

# set the restrict in ntp.conf, only the subnet of DRBL clients can access.
drbl_subnet=
for ihost in /tftpboot/nodes/*; do
  ip="`basename $ihost`"
  subnet=$(echo $ip | cut -d"." -f1-3)
  if [ -z "$(echo $drbl_subnet | grep $subnet 2> /dev/null)" ]; then
    drbl_subnet="$drbl_subnet $subnet"
  fi
done
for i_subnet in $drbl_subnet; do
  if ! grep -q "^restrict $i_subnet.*" /etc/ntp.conf ; then
    echo "restrict $i_subnet.0 mask 255.255.255.0 notrust nomodify notrap" >> /etc/ntp.conf
  fi
done

# create NFS exports
$DRBL_SCRIPT_PATH/sbin/drbl-nfs-exports --no-restart generate

# start the iptables NAT
$DRBL_SCRIPT_PATH/sbin/drbl-nat-rules generate

# set the YP securenets
$DRBL_SCRIPT_PATH/sbin/drbl-yp-securenets --no-restart generate

# $drbl_server_service_chklist is loaded from conf/drbl.conf
for serv in $drbl_server_service_chklist; do 
  # TODO, Debian/RH
  if [ -e "/etc/init.d/$serv" ]; then
    if [ -e /etc/debian_version ]; then
       # Debian
       echo "Force to turn on $serv in this Debian DRBL server..."
	case "$serv" in
	  portmap)
            /usr/sbin/update-rc.d $serv start 18 2 3 4 5 . start 32 0 6 . stop 32 1 . &> /dev/null
	    ;;
	  nis)
            /usr/sbin/update-rc.d $serv start 19 2 3 4 5 . stop 19 0 1 6 . &> /dev/null
	    ;;
	  nfs-common)
            /usr/sbin/update-rc.d $serv start 21 2 3 4 5 . stop 79 0 1 6 . &> /dev/null
	    ;;
	  nfs-kernel-server)
            /usr/sbin/update-rc.d $serv start 20 2 3 4 5 . stop 80 0 1 6 . &> /dev/null
	    ;;
	  *)
	    # such as dhcp3-server, tftpd-hpa
            /usr/sbin/update-rc.d $serv defaults &> /dev/null
	    ;;
	esac
    elif [ -e /etc/SuSE-release ]; then
      # SuSE
      echo "Force to turn on $serv in this SuSE DRBL server..."
      /sbin/insserv $serv
    else
       # RH-like
      echo "Force to turn on $serv in this RH-like DRBL server..."
      /sbin/chkconfig $serv on
    fi
  fi
done

# TODO, Debian/RH
# add the drbl-clients-nat service for DRBL server.
if [ -e /etc/debian_version ]; then
   cp -f $drbl_setup_path/files/misc/drbl-clients-nat /etc/init.d
   # before we do it, clean it to avoid the stalled files.
   update-rc.d -f drbl-clients-nat remove &>/dev/null
   # do it
   update-rc.d drbl-clients-nat start 40 2 3 4 5 . stop 89 0 6 . &>/dev/null
fi

# flush the YP
echo "Update YP..."
if [ -e /etc/debian_version ]; then
  # For Debian woody, it seems that /etc/networks is not automaticaly created.
  # If we can not find it, just touch it
  [ ! -e /etc/networks ] && touch /etc/networks
fi
make -C /var/yp &> /dev/null

# Clean those pseudo clients (empty directories)
rmdir $drblroot/* 2>/dev/null

# if it is drbl_ssi_mode or clonezilla_box_mode, add clientdir=node_root ini pxelinux.cfg/default
if [ "$drbl_ssi_mode" = "yes" -o "$clonezilla_box_mode" = "yes" ]; then
  $DRBL_SCRIPT_PATH/sbin/turn-drbl-ssi-mode --no-create-ssi-template on 
else
  $DRBL_SCRIPT_PATH/sbin/turn-drbl-ssi-mode --no-create-ssi-template off 
fi

# (re)start all the service which DRBL server need
$DRBL_SCRIPT_PATH/sbin/drbl-all-service start

# set the boot prompt for clients if set
case "$set_client_system_select" in
   y|Y|[yY][eE][sS])
     # process if we wan to turn on/off the thin client option in PXE boot menu
     case "$open_thin_client_option" in
         y|Y|[yY][eE][sS])
	    # set the option for processing PXE boot menu
	    client_select_opt="-e"
	    # Turn on the thin client server (gdm/kdm...)
	    $DRBL_SCRIPT_PATH/sbin/drbl-powerful-thin-client --no-gen-ssi --thin -ln $language
	    ;;
         n|N|[nN][oO])
	    # set the option for processing PXE boot menu
	    client_select_opt="-d"
	    # Turn on the thin client server (gdm/kdm...)
	    $DRBL_SCRIPT_PATH/sbin/drbl-powerful-thin-client --no-gen-ssi --powerful -ln $language
	    ;;
     esac
     $DRBL_SCRIPT_PATH/sbin/drbl-client-system-select $client_select_opt -t $client_system_boot_timeout on
     ;;
   n|N|[nN][oO])
      $DRBL_SCRIPT_PATH/sbin/drbl-client-system-select off
      ;;
esac

#
case "$purge_client" in
   n|N|[nN][oO])
     # Do not prompt user to restart client if no existing client exists
     tune_DBN_audio_plugdev_extra_opt="-r"
     ;;
esac
# set the DBN clients audio and plugdev if set
if [ -e /etc/debian_version ]; then
  case "$set_DBN_client_audio_plugdev" in
     y|Y|[yY][eE][sS])
       #$DRBL_SCRIPT_PATH/sbin/tune-debian-audio-plugdev-perm -l $language -a -p $tune_DBN_audio_plugdev_extra_opt
       $DRBL_SCRIPT_PATH/sbin/tune-debian-dev-group-perm -l $language -g "audio cdrom plugdev floppy video" -e $tune_DBN_audio_plugdev_extra_opt
       ;;
  esac
fi

#
# echo warning message if TCPwrapper is set.
host_allow_set=$(grep -v "^[[:space:]]*#" /etc/hosts.allow)
host_deny_set=$(grep -v "^[[:space:]]*#" /etc/hosts.deny)
if [ -n "$host_allow_set" -o -n "$host_deny_set" ]; then
   client_ips="$($DRBL_SCRIPT_PATH/bin/get-client-ip-list)"
   [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
   echo "$msg_hosts_allow_deny_is_set"
   echo "$msg_you_must_make_sure_these_clients"
   # format the output, 4 IP addresses in one line
   # --------------------
   i=0
   for ip in $client_ips; do
    i=$(($i+1))
    echo -n "$ip "
    [ "$(expr $i % 4)" -eq 0 ] && echo
   done
   echo
   # --------------------
   echo "$msg_can_access_this_DRBL_server"
   echo "$msg_otherwise_client_fail_to_boot"
   [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
   echo "TFTP open timeout"
   echo "TFTP......."
   [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
   echo "$msg_or"
   [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
   echo "mount: RPC: Unable to receive; errno = Connection refused"
   [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
fi

# Check the NFSD no, it's very important when heavy client traffic.
RUNNING_NFSDCOUNT="$(ps -ef | grep nfsd | grep -v grep | wc -l)"
total_necessary_nfsd="$($DRBL_SCRIPT_PATH/bin/get-necessary-nfsd-no)"
if [ -z "$total_necessary_nfsd" ]; then
  [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
  echo "Warning! Unable to get the total necessary NFS daemon number!!!"
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
fi
if [ "$RUNNING_NFSDCOUNT" -lt "$total_necessary_nfsd" ]; then
  [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
  echo "The number of running NFS services in this DRBL number ($RUNNING_NFSDCOUNT) is not enough for clients, $total_necessary_nfsd nsfd is expected! The performance will NOT be good! Check the NFS setting in /etc/sysconfig/ or /etc/default/!!!"
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
fi

#
#echo "$msg_delimiter_star_line"
#echo "Now syncing - flush filesystem buffers..." 
sync;sync;sync
#
export LC_ALL=$LC_ALL_org

echo "$msg_delimiter_star_line"
echo "Enjoy DRBL!!!"
echo "http://drbl.nchc.org.tw; http://drbl.sf.net"
echo "NCHC Free Software Labs, Taiwan. http://free.nchc.org.tw"
echo "$msg_delimiter_star_line"

# ask user to reboot after first time upgrade the nfs-utils in
# drblsrv_desktop.sh or get_drbl_kernel.sh
# if not, user will see a lot of 
# "kernel: lockd: rejected NSM callback from 7f000001:1027" 
# in the server console and /var/log/messages
echo "$msg_if_you_like_you_can_reboot_to_make_sure_everthing"
echo "$msg_delimiter_star_line"
[ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
echo "$msg_drbl_server_is_ready $msg_all_set_you_can_turn_on_clients"
[ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
echo "$msg_etherboot_5_4_is_required"
[ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
};

  print NETGROUP_OUT "\n";
  print NETGROUP_OUT "# Added by DRBL, end\n";

  close(DHCPD_OUT);
#  close(HOSTS_OUT);
  close(NETGROUP_OUT);
  close(DISKLESS_OUT);
  close(NFSSERVER_OUT);
  close(HOSTS_LIST_OUT);
  close(SWAPCONF_OUT);
  #chnage its mode
  system("LC_ALL=C chmod 700 $main_sh");

  # set public IP if options is yes
  if ("$set_client_public_ip_opt" eq "yes" && "$mode" eq "create_config_file"){
       # then user run drblpush with -i, create the $public_ip_list
       print "$delimiter{\"star_line\"}\n".
             "$lang_deploy{\"ok_let_do_it\"}\n".
             "$delimiter{\"dash_line\"}\n";
       # create the $public_ip_list file
       set_client_public_ip("$hosts_list","$public_ip_list");
  }

} # end of the drbl_server_parse

#
sub usage_details{
  die "$usage\n".
  "-c, --config      The DRBL config file, text format\n".
  "-i, --interactive Interactive mode, setup step by step.\n".
  "-k, --keep_clients Y/n Keep previously saved files for clients.\n".
  "-m, --client_startup_mode [1|2] Assign client mode, 1 for graphic mode, 2 for text mode.\n".
  "-n, --no_deploy   Just create files, do NOT deploy the files into system\n".
  "-p, --port_client_no number The client no. in each NIC port.\n".
  "-s, --swap_create y/N Switch to create and use local swap in clients.\n".
  "-z, --clonezilla_box y/N Clonezilla box mode, suppress some DRBL functions.\n".
  "-l, --language NO Set the language to be shown\n".
  "                  [0]: English\n".
  "                  [1]: Chinese Traditional (Big5) - Taiwan\n".
  "                  [2] Chinese Traditional (UTF-8, Unicode) - Taiwan\n".
  "--ln IDX          Set the language to be shown\n".
  "                  [en]: English\n".
  "                  [tw.BIG5]: Chinese Traditional (Big5) - Taiwan\n".
  "                  [tw.UTF-8] Chinese Traditional (UTF-8, Unicode) - Taiwan\n".
  "-q, --quiet       Be less verbose\n".
  "-v, --verbose     Be more verbose\n".
  "-d, --debug       Turn on debug mode when run shell script\n";
} # end of usage_details
#
sub check_MAC_file{
  my $macfile_dir="$_[0]";
  my $macfile_prefix="$_[1]";
  # note! maybe there are multiple MAC files when run drblpush with "-c"
  my $macfile_exist=system("LC_ALL=C ls $macfile_dir/$macfile_prefix* &>/dev/null");
  if ($macfile_exist == 256) {
    # unable to find the $macfile_prefix*
    print "$delimiter{\"star_line\"}\n".
          colored ("$lang_word{\"unable_to_find_the\"} $macfile_dir/$macfile_prefix; $lang_deploy{\"hint_for_detect_MAC\"} $macfile_prefix\n", 'red').
          "$lang_deploy{\"press_enter_to_continue\"}";
          chomp($line=<STDIN>);
    print "$delimiter{\"dash_line\"}\n";
  }else{
   # MAC file exists, check if it contains illeagle character.
   # empty those comment line, and delete the empty line and those comment line
   system("perl -p -i -e \"s/^[[:space:]]*#.*\$//g\" $macfile_dir/$macfile_prefix*");
   system("perl -p -i -e \"s/^[[:space:]]*\$//g\" $macfile_dir/$macfile_prefix*");
   my $macfile_check=`for ifile in $macfile_dir/$macfile_prefix*; do grep -v -E '([[:alnum:]]|:|^[[:space:]]*\$)' \$ifile; done`;
   chomp($macfile_check);
   if ( $macfile_check ) {
      print "$lang_deploy{\"illeagle_char_in_MAC\"},". 
            colored ("\"$macfile_check\"\n", 'red').
            "$lang_deploy{\"fix_wrong_MAC_file\"} \n".
            "$lang_word{\"program_stop\"}!!!\n";
      exit(1);
   }
  }
} # end of check_MAC_file

#########################################
# Main program
my $no_deploy = 0;
my $config_file = "";
our $verbosity = 1;
our $usage="Usage: $0 [-l|--language index_number] [-i|--interactive] [-n|--no_deploy] [-q|--quiet] [-v|--verbose] [-h|--help] [-c|--config config_file] [-p|--port_client_no number] [ -k|--keep_clients Y/n ] [ -m|--client_startup_mode 1/2 ] [ -r|--drbl_ssi_mode y/N ] [ -s|--swap_create y/N ] [ -z|--clonezilla_box_mode y/N ] [ -d|--debug ]";

# must have argument
die "$usage\n" if $#ARGV<0;

# Parse command-line options
while ($#ARGV != -1) {
   my $arg;
   $arg = shift(@ARGV);
   if (lc($arg) =~ /^(-)?(-)?l(anguage)?$/) {
     $lang_opt = shift(@ARGV);
   } elsif (lc($arg) =~ /^(-)?(-)?ln$/) {
     $language = shift(@ARGV);
   } elsif (lc($arg) =~ /^(-)?(-)?n(o_deploy)?$/) {
     $no_deploy = 1; 
   } elsif (lc($arg) =~ /^(-)?(-)?c(config)?$/) {
     $config_file = shift(@ARGV);
     $mode="load_config_file";
   } elsif (lc($arg) =~ /^(-)?(-)?v(erbose)?$/) {
     $verbosity++;
   } elsif (lc($arg) =~ /^(-)?(-)?q(uiet)?$/) {
     $verbosity--;
   } elsif (lc($arg) =~ /^(-)?(-)?p(ort_client_no)?$/) {
     $assign_client_no_each_port = shift(@ARGV);
   } elsif (lc($arg) =~ /^(-)?(-)?h(elp)?$/) {
     usage_details();
   } elsif (lc($arg) =~ /^(-)?(-)?i(nteractive)?$/) {
     $mode = "create_config_file";
   } elsif (lc($arg) =~ /^(-)?(-)?k(eep_clients)?$/) {
     $keep_client = shift(@ARGV);
   } elsif (lc($arg) =~ /^(-)?(-)?m(ode)?$/) {
     $client_startup_mode = shift(@ARGV);
   } elsif (lc($arg) =~ /^(-)?(-)?s(wap_mode)?$/) {
     $swap_create = shift(@ARGV);
   } elsif (lc($arg) =~ /^-z$|^--clonezilla_box_mode$/) {
     $clonezilla_box_mode = shift(@ARGV);
   } elsif (lc($arg) =~ /^-r$|^--drbl_ssi_mode$/) {
     $drbl_ssi_mode = shift(@ARGV);
   } elsif (lc($arg) =~ /^(-)?(-)?d(ebug)?$/) {
     $sh_debug = "-x"; 
   } else {
     usage_details();
   }
}

# get the language
$language=lang_set($lang_opt) if ( ! $language );
require "$DRBL_SCRIPT_PATH/lang/perl/$language";

# hint for user to answer y/n
print "$delimiter{\"star_line\"}\n".
      colored ("$lang_deploy{\"hint_for_answer\"}\n", 'yellow');

# check if drbl server package is installed or not
print "$delimiter{\"star_line\"}\n";
print "$lang_deploy{\"searching_installed_drbl_packages\"}\n";
# just pick package drbl to test

# return code is number divided by 256
my $drbl_rpm = system("LC_ALL=C rpm -q drbl &> /dev/null") / 256;
my $drbl_deb = system("LC_ALL=C dpkg -s drbl &> /dev/null") / 256;
my $drbl = $drbl_rpm * $drbl_deb;
if ($drbl eq 0) {
        print "$lang_deploy{\"finished_searching_installed_drbl_packages\"}\n";
	print "$delimiter{\"star_line\"}\n";
}else{
	print "$delimiter{\"star_line\"}\n".
	       colored ("$delimiter{\"warning_line\"}\n", 'yellow').
	      "$lang_deploy{\"no_drbl_server_package_found\"}\n".
	      "[y/N] ";
	chomp($line=<STDIN>);
	SWITCH: for ($line) {
		/"^y"|"^yes"/i && do {
	          print "$delimiter{\"star_line\"}\n".
                        "$lang_deploy{\"ok_let_continue\"}\n".
                        "$lang_deploy{\"but_you_will_see_errors\"}\n";
                  last SWITCH;
                };
		/.*/ && do {
	          print "!!!!!!!!!!!!!!!!!!!!!!!!!\n".
                        "$lang_deploy{\"smart_decision\"}\n";
	          exit(1);
                  last SWITCH;
                };
        }
}

if ("$mode" eq "create_config_file") {
        print "$delimiter{\"dash_line\"}\n".
	      "$lang_deploy{\"interactive_mode_prompt\"}\n".
              "$delimiter{\"dash_line\"}\n";
        interactive_mode;
	$config_file=$DRBLPUSH_CONF;
} elsif ("$mode" eq "load_config_file") {
       # copy the pre-saved setting file to this working directory
       # config_file
       system("[ -f $config_file ] && cp -f $config_file .");
       # public IP setting
       system("[ -f $drbl_syscfg/$public_ip_list ] && cp -f $drbl_syscfg/$public_ip_list $public_ip_list");
       # MAC address files
       system("cp -f $drbl_syscfg/macadr-eth*.txt . &> /dev/null");

}
unless ( $config_file ) { die "$usage\n"; }

# parse the config file, then create the exe script file $main.sh
drbl_server_parse($config_file);

print "$delimiter{\"star_line\"}\n";
print "purge_client: $purge_client\n" if $verbosity >=2;
if ( $client_exist_flag = "0" && $purge_client eq "no" ) { 
   # old clients exist and we want to keep them, show warning messages
   print colored ("$lang_deploy{\"note_for_keep_client_setting\"}\n", 'red').
         "$lang_deploy{\"press_enter_to_continue\"}";
         chomp($line=<STDIN>);
}

# ready to go
if ( $no_deploy ) { 
	print "$delimiter{\"warning_line\"}\n".
	      "$lang_deploy{\"no_deploy_prompt\"}\n";
}
else {
	print "$delimiter{\"star_line\"}\n".
	      "$lang_deploy{\"ready_to_deploy\"}\n".
	      colored ("$lang_deploy{\"overwrite_firewall_rule\"}\n", 'red').
	      colored ("$lang_deploy{\"backup_firewall_rule\"}\n", 'red').
	      "[Y/n] ";
	chomp($line=<STDIN>);
	if ($line eq "n" || $line eq "N" || $line eq "no" || $line eq "NO") {
	 print "$delimiter{\"exclamation_line\"}\n".
	       "$lang_deploy{\"oh_quit_now\"}\n";
         unlink ($main_sh) if -f $main_sh;
	} else {
	 print "$delimiter{\"star_line\"}\n".
               "$lang_deploy{\"ok_let_do_it\"}\n".
               "$delimiter{\"dash_line\"}\n";
         my $whoiam = `LC_ALL=C id -nu`;
	 chomp($whoiam);
         # Also copy the $DRBLPUSH_CONF to system so that we can re-run the
         # program by "drblpush -c $drbl_syscfg/$DRBLPUSH_CONF"
         my $run_main="LC_ALL=C ./$main_sh";
	 if ("$whoiam" eq "root") { 
	     system("$run_main");
         }else{
             print "$lang_deploy{\"you_are_not_root\"},\n". 
	           "$lang_word{\"please_enter\"} ". colored("$lang_word{\"root_passwd\"} ",'red') ."$lang_word{\"to_deploy_them\"}...\n"; 
	     my $su_rlt=system("su -c '$run_main' root");
	     while ($su_rlt == 256) { 
	            $su_rlt=system("su -c '$run_main' root");
	     }
	     # copy the config file to DRBL server
         } 
        }
}
# clean the temp working directory
rmtree ($drblpush_wd) if -d $drblpush_wd;

#########################################
