#! /usr/bin/perl
# Copyright (c) 2017 Bruker BioSpin GmbH";

use strict;
use English;
use Getopt::Long;
use Pod::Usage;
use File::Find ();
use File::Basename;
use File::Path;
use File::Copy;
use Sys::Syslog qw(:standard :macros);  # standard functions & macros
use IO::Socket::INET;

my $program = basename($0);

# for the convenience of &wanted calls, including -eval statements:
use vars qw/*name *dir *prune/;
*name   = *File::Find::name;
*dir    = *File::Find::dir;
*prune  = *File::Find::prune;

###
# main sub function prototypes
sub get_os_version;
sub get_local_version;
sub get_files_to_remove(\@\@);
sub clean_up_config_files;
sub enable_required_services;
sub create_rpm_package;
sub create_image_info();
###
# helper functions used by the main sub functions
###
sub clear_dhcp_lease;
sub restore_ntp_conf;
sub clear_etc_host;
sub disable_bruker_repos;
sub GetSmbiosSerialNumber;
sub getCodemeterSerialNumber;
sub editIfcfgFiles();
sub remove_dot_topspin;
sub remove_broken_bruker_links;
sub all_ifcg_eth_files(\@);
sub search_user_history_files(\@);
sub search_mozilla_history(\@);
sub search_old_var_log_files(\@);
sub search_user_mail;
sub mozilla_cache(\@);
sub doexec ($@);
sub ls($);

# small helper function 
sub boolean($) {my $var=shift; return $var ? 'true' : 'false'; }


####
# Supported options with defaults
###

my $help = 0;
my $img_name;
my $usr_ts_vers;
my $man = 0;
my $verbose = 0;
my $test = 0;
my $rpmpkg = 0;
my $sshkeys = 1;
my $archive = 1;
my $restore = 0;


###
# Define options for pod2usage
###
GetOptions(
	   'help|?' => \$help,
	   'name:s' => \$img_name,
	   'tsvers:s' => \$usr_ts_vers,
	   'man'  => \$man,
	   'verbose+'  => \$verbose,
	   'test'  => \$test,
	   'rpmpkg!'  => \$rpmpkg,
	   'sshkeys!'  => \$sshkeys,
	   'archive!'  => \$archive,
	   'restore'  => \$restore,

	  ) || pod2usage(2);

pod2usage(1) if $help;
pod2usage(-exitstatus => 0, -verbose => 2) if $man;


# Path to dmidecode
my $dmi ='/usr/sbin/dmidecode';

# Backup Network file archive
my $archived_network_files = '/tmp/prepare_master_network_files.tar.bz2';

###
# Tar options for creation and extraction of network file archive
##
my $tar_c_options = '--create --bzip2 --selinux --absolute-names --ignore-failed-read --file';
my $tar_x_options = '--extract --bzip2 --preserve-permissions --absolute-names  --file';

# Get OS and bruker-setup version
my $OS_Version = get_os_version();
my $version = get_local_version();

###
# Starting point 
###
print "$program (version ",$version,")\n","Copyright (c) 2017 Bruker BioSpin GmbH\n";

# Test is User is root (UID == 0)
if ($EUID != 0) {
  $test = 1;
  $verbose = 1;
  print "\nStarted as non-root: verbose and testmode on!\n";
}

# Print all arguments if verbose
if ($verbose) {
  print "\nFlags:\n";
  print '  $help    '," = ",boolean($help),"\n";
  print '  $man     '," = ",boolean($man),"\n";
  print '  $verbose '," = ",boolean($verbose),"\n";
  print '  $test    '," = ",boolean($test),"\n";
  print '  $rpmpkg  '," = ",boolean($rpmpkg),"\n";
  print '  $sshkeys '," = ",boolean($sshkeys),"\n";
  print '  $archive '," = ",boolean($archive),"\n";
  print '  $restore '," = ",boolean($restore),"\n";
  print '  $name    '," = ",$img_name,"\n";
  print '  $tsvers  '," = ",$usr_ts_vers,"\n\n";
}

# Restore all network files and exit script if restore 
if ($restore) {
  system("tar $tar_x_options $archived_network_files");
  exit 0;
}

###
# Use syslog for reports
##
openlog('bruker-setup', 'nofatal,pid', 'user');
syslog(LOG_INFO,"$program Version $version");


if($verbose) {
  print "Detected OS Version: $OS_Version\n";
  print "Detected Bruker-Setup Version: $version\n";
}

# Get all users and groups and define patterns
my @rwx = qw(--- --x -w- -wx r-- r-x rw- rwx);
my @moname = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
my (%uid, %user);
while (my ($name, $pw, $uid) = getpwent) {
  $user{$uid} = $name unless exists $user{$uid};
}

my (%gid, %group);
while (my ($name, $pw, $gid) = getgrent) {
  $group{$gid} = $name unless exists $group{$gid};
}

my @REMOVE;
my @TARFILES;

# Define list of unwanted files (tmp and user files)
get_files_to_remove(@REMOVE, @TARFILES);

if ($verbose) {
    print "Files to be removed:\n";
    foreach my $file (@REMOVE) {
	ls($file) if -f $file;
    }
}

###
# create archive of all files to be removed
###
system("tar $tar_c_options $archived_network_files @TARFILES 2> /dev/null") if $archive;
print "Backup of network files created '$archived_network_files'\n" if ($archive and $verbose);

# clean config files and configuration to "reset" the system
clean_up_config_files();

###
# Enable one time services for the necessary reboot after prepare-master
###
enable_required_services();

print "Removing files to prepare Master image " .
  ($test ? ' == test only ==' : '') . "\n";

# Remove unwanted files
foreach my $file (@REMOVE) {
  next unless -e $file;
  print " $file\n";
  if (-f $file) {
    unlink($file)  || warn "\t$file: $!\n" unless $test;    	
  } elsif (-d $file) {
    rmdir($file) || warn "\t$file: $!\n" unless $test;
  } else {
    warn "$file is not a directory or a file!\n" unless $test    	
  }
}

#create_rpm_package() if $rpmpkg;

create_image_info();

my @cmcontainerinfo = getCodemeterSerialNumber();
if(@cmcontainerinfo) {
  if($cmcontainerinfo[0] eq '1') {
    chomp $cmcontainerinfo[1];
    if ($cmcontainerinfo[1] ne "") {
	  my $cmd = "cmu --delete-cmact-license --serial $cmcontainerinfo[1]"; 
	  print "Execute: $cmd\n" if $verbose;
	  system($cmd);
    } else {
    	die "CmContainer serial number could not be determined\n";
    }
  } elsif ($cmcontainerinfo[0] eq '0') {
  	print "No CmContainer found, do nothing\n";
  } else {
  	die "More than one CmContainer found\n";
  }
} else {
  die "CmContainer serial number could not be determined\n";
}
 

####
# Disable Network on next boot (will be reenabled by bruker-setup service)
####
if ($OS_Version < 7 and not $test) {
  my $network = '/etc/sysconfig/network';
  open(NETWORK, ">$network") or die "Cannot open $network: $!";
  print NETWORK "NETWORKING=no\n";
  close(NETWORK) ;
}

#if (open(FD,"rpm -q --queryformat='%{RELEASE}' bruker-setup-release|")) {
#    my $bim_bersion = <FD>;
#    close FD;
#    print "\nRelease of this Bruker Image is:\n\t$bim_bersion\n\n";
#}
print "\nRelease of this Bruker Image is:\n\t";
system("bruker-image-info");
print "\n\n";

closelog();
exit;


################
#              #
# Soubroutines #
#              #
################
sub clean_up_config_files {
  # disable bruker repositories
  disable_bruker_repos();
  # clean dhcp lease to get new ip after reboot
  clear_dhcp_lease();
  # Restore default CentOS ntp_conf w/o modified by a dhcp client request from the bruker-setup rpm
  restore_ntp_conf();
  # clean etc/hosts file of ...
  clear_etc_host;
}

sub get_files_to_remove(\@\@) {
  my ($remove, $archive) = @_;
  my @SSH_FILES, my @SSL_FILES;
 
  ###
  # option 'nosshkeys' : @SSH_FILES and @SSL_FILES are empty
  ###
  if (not $sshkeys) {
    @SSH_FILES = ();
    @SSL_FILES = ();
  } else {
    my $SSH_DIR = '/etc/ssh';
    @SSH_FILES = glob ("$SSH_DIR/ssh_host_*");
    push (@SSH_FILES,"/root/.ssh/authorized_keys",
	  "/root/.ssh/known_hosts",
	  "/usr/NX/home/nx/.ssh/known_hosts");
	# Add user nmr users ssh folder
	push(@SSH_FILES, glob ("/home/nmrsu/.ssh/*"), glob ("/home/nmr/.ssh/*"), "/home/nmrsu/.ssh/","/home/nmr/.ssh");
	  
    my $SSL_DIR = '/usr/share/ssl/certs';
    @SSL_FILES = (
	"$SSL_DIR/ipop3d.pem",
	"$SSL_DIR/imapd.pem",
	);
  }

  my @TOPSPIN_FILES = (
    '/usr/local/flexlm/Bruker/licenses/license.dat',
    '/etc/profile.d/flexlm_license.sh',
    '/usr/local/flexlm/Bruker/licenses/flexlm.log',
  );

  my @NETWORK_FILES = (
    '/etc/resolv.conf',
    '/etc/dhclient-eth0.conf',
    '/etc/sysconfig/networking/profiles/default/network',
    '/etc/sysconfig/networking/profiles/default/resolv.conf',
  );

  if ($OS_Version < 7) {
    # append with all ifcfg-eth* files
    print "Search ifcg_eth? FILES\n" if  $verbose;
    File::Find::find({wanted => \&all_ifcg_eth_files},'/etc/sysconfig');
  } else {
    editIfcfgFiles();
  }

  ####
  # Files from bruker-setup services
  ###
  my @BRUKER_FILES = (
		      '/.default-hostname',
		      '/root/bin/mk-changes',
		      '/root/bin/mount_pub',
		      '/etc/sysconfig/bruker-setup',
		      '/etc/sysconfig/hwconf',
    );

  ####
  # and unwanted files in home directories
  ###
  print "Search history FILES\n" if  $verbose;
  my @HISTORY_FILES =();
  File::Find::find({wanted => \&search_mozilla_history}, '/home','/root');
  File::Find::find({wanted => \&search_user_history_files},'/home','/root');
  print "@HISTORY_FILES\n" if  $verbose;

  ####
  # and unwanted files in /var/log and subdirs
  print "Search old  FILES\n" if  $verbose;
  my @SYSTEM_FILES =();
  File::Find::find({wanted => \&search_old_var_log_files},'/var/log');
  my @USER_MAIL = search_user_mail();
  push(@SYSTEM_FILES,@USER_MAIL) if @USER_MAIL;
  print "@SYSTEM_FILES\n" if  $verbose;


  # Traverse desired filesystems and clean-up files
  File::Find::find({wanted => \&remove_dot_topspin}, '/home');
  File::Find::find({wanted => \&remove_broken_bruker_links}, '/usr/share/applications');

  ####
  # Find and remove mozilla cache
  my @MOZCACHE;
  File::Find::find({wanted => \&mozilla_cache}, '/home','/root');
  doexec('rm','-rf',@MOZCACHE) if (@MOZCACHE);

  push (@$remove,@BRUKER_FILES,@HISTORY_FILES,@SYSTEM_FILES,@SSH_FILES,@SSL_FILES,@TOPSPIN_FILES,@NETWORK_FILES);
  push (@$archive,@BRUKER_FILES,@SSH_FILES,@SSL_FILES,@TOPSPIN_FILES,@NETWORK_FILES);
}

sub get_local_version {
  my $querycmd = 'rpm -q --queryformat \'%{VERSION}.%{RELEASE}\' bruker-setup';
  my $rpm_version = `$querycmd`;
  chomp $rpm_version;
  return $rpm_version;
}

sub get_os_version {
  my $querycmd = 'rpm -qf --queryformat %{Name} /etc/redhat-release';
  my $redhat = `$querycmd`;
  chomp $redhat;
  $querycmd = 'rpm -q --queryformat %{version} ' . $redhat;
  my $redhat_release = `$querycmd`;
  my $rh_release  = (int $redhat_release);
  return $rh_release;
}

sub getCodemeterSerialNumber(\@) {
  my (@info) = @_; 
  my $serial;
  # Read output from cmu
  open(CM, "cmu -l|") || die "Can't pipe to cmu: $!\n";
  my @lines = <CM>;
  close(CM);
  if (@lines) {
    # Check number of serials
    my $numSerial = (split / /, $lines[$#lines])[1];
    $info[0] = $numSerial;
     
    if ($numSerial eq '1') {
      foreach my $line (@lines) {
        if ($line =~ /- CmContainer with Serial Number/) {
    	  $serial = (split / /, $line)[5];
    	  print "Found CmContainer serial: $serial\n" if $verbose;
    	  $info[1] = $serial;
    	  return @info; 
        }
      }
    } elsif ($$numSerial eq '0') {
    	my $msg = "Warning: No CmContainer found!\n";
    	print $msg;
        return @info;   	
    } else {
    	my $msg = "Warning: More than one CmContainer found!\n";
    	print $msg;
        return @info;
    }
  } else {
  	print "Warning: Output from cmu was empty\n" if $verbose;
	return;
  }
}

sub GetSmbiosSerialNumber {
  open(DMI,"$dmi -t1|") || die "can't pipe to $dmi: $!\n"; {
    my $ser_num;
    my $product;
    my $model;

    while (<DMI>) {
      print STDERR if $verbose > 1;

      if ( /Serial Number:\s(\w+)/ ) {
		$ser_num = $1;
		my $msg = '$'."ser_num = $ser_num";
		print STDERR $msg,"\n" if $verbose;
		syslog(LOG_INFO, $msg);
	  }
	  if ( /Serial Number: VMware-(.*)\n/ ) {
		$ser_num = 'VM' . substr(md5_hex($1),0,8);
		my $msg = '$'."ser_num = $ser_num";
		print STDERR $msg,"\n" if $verbose;
		syslog(LOG_INFO, $msg);
	  }

	  if ( /Product Name:\s(.*)/ ) {
		$product = $1;
		print STDERR '$',"product = $product\n" if $verbose;

		if ($product  =~ (/^hp workstation (xw4100|xw4200|xw5000)/)) {
		    $model = $1;
		}
		if ($product  =~ (/^HP\s*(xw4300|xw4400|Z400|Z420)\s*Workstation/))	{
		    $model = $1;
		}
		if ($product  =~ (/^VMware Virtual Platform/)) {
		    use Digest::MD5 qw(md5_hex);
		    if ( /Serial Number: VMware-(.*)\n/ ) {
			  $ser_num = 'VM' . substr(md5_hex($1),0,8);
		    }
		}
	  }
	  if ($product  =~ (/^VirtualBox/)) {
		if ( /UUID:\s*([\dA-Z]*)/ )	{
          $ser_num = 'VB' . $1;
		}
	  }
	}
	close(DMI);
	return $ser_num;
  }
  return;
}

sub editIfcfgFiles() {
    my $sysclass	= '/sys/class/net';
    opendir(NET,$sysclass) || die "can't open to $sysclass: $!\n";
    my @ethdevs = grep(!/^\./, readdir(NET));
    closedir(NET);

    print "Found Ether Devices: @ethdevs\n" if $verbose;

    my $netcfg	= '/etc/sysconfig/network-scripts/ifcfg';

    foreach my $dev (@ethdevs)
    {
	# check for physical devs
	my $linkname = readlink(join('/',$sysclass,$dev));
	next if ($linkname =~ /virtual\/net/); # skip virtual

	print "$linkname\n" if $verbose;
	my $addrpath = join('/',$sysclass,$dev, 'address');
	open(ADR,$addrpath) || die "can't open to $addrpath: $!\n";
	my $addr = <ADR>;
	close(ADR);
	chomp $addr;
	print "$addr\n" if $verbose;

	if ( $dev eq 'eno1')
	{
	    my $file = join('-',$netcfg,$dev);
	    open(CFG,"$file")  || die "$file: $!\n";
	    my @lines = <CFG>;
	    close(CFG);

	    my $netifnames = 0;
	    open(CFG,">$file")  || die "$file: $!\n";
	    foreach my $line (@lines)
	    {
		###
		# remove HWADDR if present
		next if ($line =~ /^HWADDR=/);

		if ($line =~ /^NAME=/)
		{
		    print CFG 'NAME="Spectrometer Network"'."\n";
		    print "\n" if $verbose;
		    next;
		}
		print CFG $line;
	    }
	    close(CFG);

	}
    }
    #manuel edit of ens1
    my $dev = "ens1";
    my $file = join('-',$netcfg,$dev);
    open(CFG,"$file")  || die "$file: $!\n";
    my @lines = <CFG>;
    close(CFG);

    open(CFG,">$file")  || die "$file: $!\n";
    foreach my $line (@lines)
    {
		###
		# remove HWADDR if present
		next if ($line =~ /^HWADDR=/);
		print CFG $line;
    }
    close(CFG);
}

sub remove_dot_topspin {
    my ($dev,$ino,$mode,$nlink,$uid,$gid);
    my $search = '\.topspin-.*\z';
    (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
    -d _ &&
    /^$search/s &&
    doexec('rm','-rf','{}');

}

sub remove_teamviewer {
    print "Clean and reset Teamviewer\n";
    my $teamviewerd = "/etc/init.d/teamviewerd";
    if(-e $teamviewerd){
    	system("/etc/init.d/teamviewerd stop");
		sleep(3);
    } else {
		print "Teamviewer "
    }
    system("rm -rf /home/*/.config/teamviewer*");
    system("rm -rf /opt/teamviewer*/config");
    system("/etc/init.d/teamviewerd start");	
    sleep(3);
}

sub clear_history {
    print "Clean history of current users";
    system("history -c");
}

sub remove_broken_bruker_links {
    my ($dev,$ino,$mode,$nlink,$uid,$gid);

    /^bruker-.*\z/s &&
    (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
    -l _
    && ! -f readlink($name) 
       && unlink($name) && syslog(LOG_INFO,"broken link $name removed");
}

sub all_ifcg_eth_files(\@) {
    my ($NETWORK_FILES) = @_;
    /^ifcfg-eth.*\z/s
    && push(@$NETWORK_FILES,$name);
}

sub doexec ($@) {
    my @command = @_; # copy so we don't try to s/// aliases to constants
    for my $word (@command){
      $word =~ s#{}#$name#g;
    }

    if ($verbose) {
	print "=> system(@command)\n"
    }
    else {
	print " $name\n";
    }
    return 1 if $test;
    system ("@command > /dev/null");
    return !$?;
}

sub search_user_history_files(\@) {
    my ($HISTORY_FILES) = @_;
    /^\.recently-used.*\z/s
    && push(@$HISTORY_FILES,$name);
    /^\.bash_history\z/s
    && push(@$HISTORY_FILES,$name);
    /^known_hosts\z/s
    && push(@$HISTORY_FILES,$name);
    /^nedit\.history\z/s
    && push(@$HISTORY_FILES,$name);
    /^konq_history\z/s 
    && push(@$HISTORY_FILES,$name);
}

sub search_mozilla_history(\@) {
    my ($HISTORY_FILES) = @_;
    /^sessionstore\..*\z/s
        && push(@$HISTORY_FILES,$name);

    /^places\.sqlite.*\z/s
        &&    push(@$HISTORY_FILES,$name);

    /^downloads\.sqlite\z/s
        &&    push(@$HISTORY_FILES,$name);

    /^cookies\.sqlite.*\z/s
        &&    push(@$HISTORY_FILES,$name);

    /^formhistory\.sqlite\z/s
        &&    push(@$HISTORY_FILES,$name);
}

sub search_old_var_log_files(\@) {
    my ($SYSTEM_FILES) = @_;
    /^boot\.log\..*\z/s && push(@$SYSTEM_FILES,$name);

    /^cron\..*\z/s && push(@$SYSTEM_FILES,$name);
    /^cron-\d{8}\z/s && push(@$SYSTEM_FILES,$name);

    /^maillog\..*\z/s && push(@$SYSTEM_FILES,$name);
    /^maillog-\d{8}\z/s && push(@$SYSTEM_FILES,$name);

    /^messages\..*\z/s && push(@$SYSTEM_FILES,$name);
    /^messages-\d{8}\z/s && push(@$SYSTEM_FILES,$name);

    /^rpmpkgs\..*\z/s && push(@$SYSTEM_FILES,$name);
    /^rpmpkgs-\d{8}\z/s && push(@$SYSTEM_FILES,$name);

    /^secure\..*\z/s && push(@$SYSTEM_FILES,$name);
    /^secure-\d{8}\z/s && push(@$SYSTEM_FILES,$name);

    /^spooler\..*\z/s && push(@$SYSTEM_FILES,$name);
    /^spooler-\d{8}\z/s && push(@$SYSTEM_FILES,$name);

    /^wtmp\..*\z/s && push(@$SYSTEM_FILES,$name);

    /^Xorg\..*\.log.*\z/s  && push(@$SYSTEM_FILES,$name);

    /^yum\.log\..*\z/s && push(@$SYSTEM_FILES,$name);

    ### cups log files
    /^access_log\..*\z/s && push(@$SYSTEM_FILES,$name);
    /^access_log-\d{8}\z/s && push(@$SYSTEM_FILES,$name);

    /^error_log\..*\z/s && push(@$SYSTEM_FILES,$name);
    /^error_log-\d{8}\z/s && push(@$SYSTEM_FILES,$name);

    /^page_log\..*\z/s && push(@$SYSTEM_FILES,$name);
    /^page_log-\d{8}\z/s && push(@$SYSTEM_FILES,$name);

    /^cups-pdf_log\..*\z/s && push(@$SYSTEM_FILES,$name);
    /^cups-pdf_log-\d{8}\z/s && push(@$SYSTEM_FILES,$name);

    ### gdm log files
    /^:[0-9]\.log\.[0-9]\z/s && push(@$SYSTEM_FILES,$name);
    /^:[0-9]\.log\z/s &&push(@$SYSTEM_FILES,$name);

    ### sysstat log files
    /^sa[0-9][0-9]\z/s && push(@$SYSTEM_FILES,$name);
    /^sar[0-9][0-9]\z/s && push(@$SYSTEM_FILES,$name);

}

sub mozilla_cache (\@) {
    my ($MOZCACHE) = @_;
    my ($dev,$ino,$mode,$nlink,$uid,$gid);

    (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
    -d _ &&
    /^Cache\z/s &&
      push(@$MOZCACHE,$name . '/*');
}

sub search_user_mail {
    my $MAIL_DIR = '/var/spool/mail';
    opendir(DIR,$MAIL_DIR) || return undef;
    
    my @subdir = grep( !/^\./, readdir(DIR));
    closedir(DIR);

    my @user_mail = ();
    foreach my $name (@subdir)
    {
	push(@user_mail,join('/',$MAIL_DIR,$name));
    }
    return @user_mail;
}

sub create_image_info() {
    chdir $ENV{'HOME'};

    my $local_ip_address;
    
    my $socket = IO::Socket::INET->new(
				       Proto       => 'udp',
				       PeerAddr    => '198.41.0.4', # a.root-servers.net
				       PeerPort    => '53', # DNS
				      );

    $local_ip_address = '127.0.0.1' unless $socket;
    # A side-effect of making a socket connection is that our IP address
    # is available from the 'sockhost' method
    $local_ip_address = $socket->sockhost;
    
    print "My-IP $local_ip_address\n" if $verbose;

    unless ($local_ip_address =~ /^149.236.\d*.\d*$/)
    {
	my $msg = "My-IP " . $local_ip_address . 
	    " is outside of Bruker.DE domain: no access to viola - " .
		" NO bruker-setup-release RPM created.";
	warn "$msg\n";
	return;
    }

    my $release_time = time();


    die "Missing $dmi\n" unless -x $dmi;

    ###
    # set some variables from hardware and current time
    #
    # Needed release string is: "bim_xw4200_L_1105678666")
    ###

    my @dmi_info;
    my $product;
    my $model;

    open(DMI,"$dmi -t1|") || die "can't pipe to $dmi: $!\n";
    while (<DMI>)
    {
	push(@dmi_info,$_);
	if ( /Product Name:\s(.*)/ )
	{
	    $product = $1;
	    print '$product =',"$product\n" if $verbose;


	    if ($product  =~ (/^hp workstation (xw\d+)/))
	    {
		$model = $1;
	    }
	    if ($product  =~ (/^HP\s*(\w*\d+)\s*Workstation/))
	    {
		$model = $1;
	    }
	    if ($product  =~ (/^VMware Virtual Platform/))
	    {
		$model = 'VMware';
	    }
	    if ($product  =~ (/^VirtualBox/))
	    {
		$model = 'VirtualBox';
	    }
	}
    }
    close(DMI);



    unless ($model)
    {
	print "***************************************************\n";
	print "*                                                 *\n";
	print "* Please notify carsten.kuhl\@bruker.com          *\n";
	print "* to fix this script.                             *\n";
	print "*                                                 *\n";
	print "***************************************************\n";

	print "The Workstation Model is not detected!\n\n";
	print "and send the following text:\n\n\n", @dmi_info ,"\n";
	die "\n";
    }
    
  my $name;
  
  if($img_name eq "") {
    $name = "bde";
  } else {
    $name = "$img_name";
  }

  my $querycmd = "cat /etc/redhat-release | grep -o \'[0-9]\\.[0-9]\'";
  my $centosVersion = `$querycmd`;
  chomp $centosVersion;
  my $centosVersionName;
  
  if ($centosVersion eq "") {
    $centosVersionName = "UnknownCentOS";
  } else {
    $centosVersionName = "c$centosVersion";
  }
  
  my @topspin_versions = installed_topspin_versions();
  my @topspin_vers;
  
  foreach my $tsvers (@topspin_versions) {
    my $cmd = "$tsvers -e topspinversion -dot";
    my $ts_vers = `$cmd`;
    chomp $ts_vers;
    push(@topspin_vers,$ts_vers);   
  }
  
  my $topspin_version_name;

  if($usr_ts_vers eq "") {
    if(@topspin_vers > 1) {
      print "Multiple TopSpins found (".join(', ',@topspin_vers)."). Using the first one found: $topspin_vers[0].\n";
      $topspin_version_name = "ts".$topspin_vers[0];
    } elsif (@topspin_vers < 1) {
      print "No TopSpin Version was found. Using empty TS version string.\n";
      $topspin_version_name = "_";
    } else {
      $topspin_version_name = "ts".$topspin_vers[0];
    }
    if($topspin_version_name ne ""){
      $topspin_version_name = "\_$topspin_version_name\_";
    }
  } else {
    $topspin_version_name = "\_$usr_ts_vers\_";
  }
  
  my $releaseVersion = "$name\_$model$topspin_version_name$centosVersionName\_$release_time";
    
  my $bruker_dir = "/etc/bruker-image";
  unless(-e $bruker_dir or mkdir($bruker_dir, 0755)) {
        die "Unable to create $bruker_dir\n";
  }
  my $bruker_info = "$bruker_dir/image-release";
  
  open(FH, ">$bruker_info") || die "Can't open file: $bruker_info";
  print FH "$releaseVersion\n";
  close(FH);
}

sub create_rpm_package {
    chdir $ENV{'HOME'};

    my $local_ip_address;
    
    my $socket = IO::Socket::INET->new(
				       Proto       => 'udp',
				       PeerAddr    => '198.41.0.4', # a.root-servers.net
				       PeerPort    => '53', # DNS
				      );

    $local_ip_address = '127.0.0.1' unless $socket;
    # A side-effect of making a socket connection is that our IP address
    # is available from the 'sockhost' method
    $local_ip_address = $socket->sockhost;
    
    print "My-IP $local_ip_address\n" if $verbose;

    unless ($local_ip_address =~ /^149.236.\d*.\d*$/)
    {
	my $msg = "My-IP " . $local_ip_address . 
	    " is outside of Bruker.DE domain: no access to viola - " .
		" NO bruker-setup-release RPM created.";
	warn "$msg\n";
	return;
    }

    my $release_time = time();


    die "Missing $dmi\n" unless -x $dmi;


    ###
    # set some variables from hardware and current time
    #
    # Needed release string is: "bim_xw4200_L_1105678666")
    ###

    my @dmi_info;
    my $product;
    my $model;

    open(DMI,"$dmi -t1|") || die "can't pipe to $dmi: $!\n";
    while (<DMI>)
    {
	push(@dmi_info,$_);
	if ( /Product Name:\s(.*)/ )
	{
	    $product = $1;
	    print '$product =',"$product\n" if $verbose;


	    if ($product  =~ (/^hp workstation (xw\d+)/))
	    {
		$model = $1;
	    }
	    if ($product  =~ (/^HP\s*(\w*\d+)\s*Workstation/))
	    {
		$model = $1;
	    }
	    if ($product  =~ (/^VMware Virtual Platform/))
	    {
		$model = 'VMware';
	    }
	    if ($product  =~ (/^VirtualBox/))
	    {
		$model = 'VirtualBox';
	    }
	}
    }
    close(DMI);



    unless ($model)
    {
	print "***************************************************\n";
	print "*                                                 *\n";
	print "* Please notify carsten.kuhl\@bruker.com          *\n";
	print "* to fix this script.                             *\n";
	print "*                                                 *\n";
	print "***************************************************\n";

	print "The Workstation Model is not detected!\n\n";
	print "and send the following text:\n\n\n", @dmi_info ,"\n";
	die "\n";
    }

    my $rpmmacros = $ENV{'HOME'} . '/.rpmmacros';
    my $specfile = 'bruker-setup-release.spec';
    my $bimcmd = 'bruker-image-info';
    my $macros = '--macros='. $rpmmacros;

    my $querycmd = 'rpm -qf --queryformat %{Name} /etc/redhat-release';
    my $redhat = `$querycmd`;

    chomp $redhat;
    $querycmd = 'rpm -q --queryformat %{version} ' . $redhat;

    my $redhat_release = `$querycmd`;

    my $rh_release  = (int $redhat_release);

    #my $version = $revision;
    $version =~ s/[\$:a-zA-Z ]//g;
    my $package = 'bruker-setup-release'. '-' . $version ;
    my $release = 'bim_' . $model . '_L_' . $release_time;

    my $RPMtopdir = $ENV{'HOME'} . '/rpmbuild';

    my $RPM_File = $RPMtopdir . "/RPMS/noarch/$package-$release.noarch.rpm";
    my $SRPM_File = $RPMtopdir . "/SRPMS/$package-$release.src.rpm";

    open(FD,">$rpmmacros") || die;
    print FD '%_topdir',"\t$RPMtopdir","\n";
    print FD '%_target        linux',"\n";
    print FD '%packager       Bruker BioSpin GmbH <nmr-software-support@bruker.de>',"\n";
    print FD '%version',"\t",$version,"\n";
    print FD '%release',"\t$release","\n";
    print FD '%distro',"\t\t",'rhel'. $rh_release,"\n" if ($redhat eq 'redhat-release');
    print FD '%distro'."\t\t".'centos'. $rh_release,"\n" if ($redhat eq 'centos-release');
    print FD '%debug_package %{nil}',"\n";
    print FD '',"\n";
    close FD;
    unlink $specfile unless $test;

    my @subdirs = qw(BUILD RPMS SOURCES SPECS SRPMS);
    my @rpm_build_tree;
    foreach my$dir (@subdirs)
    {
	push(@rpm_build_tree,join('/',$RPMtopdir,$dir));
    }

    mkpath([@rpm_build_tree],0,0711);
    use Net::FTP;

    my $host = "viola.software.bruker.de";
    my $FtpPath = "/pub/Bruker-Workstation-Releases/$rh_release";

    my $debug_mode = 0;
    $debug_mode = 1 if ($verbose);

    my $ftp = Net::FTP->new($host,
			    Debug => $debug_mode,
			    Passive => 1) or die "Cannot connect to $host: $@";

    $ftp->login("anonymous") or die "Cannot login ", $ftp->message;
    my $subDir = $FtpPath . "/SPECS";
    $ftp->cwd($subDir) or die "cwd $subDir ", $ftp->message;

    $ftp->binary;

    print "fetch $specfile from\n  $host:", $ftp->pwd(),"\n" if $verbose;

    $ftp->get($specfile) or die "get $specfile failed ", $ftp->message;

    $ftp->cwd("../SOURCES") or die "cwd ../SOURCES ",$ftp->message;
    $ftp->get($bimcmd) or die "get $bimcmd failed ", $ftp->message;

    my $build =  $RPMtopdir . '/BUILD/' . $package;
    mkdir $build;
    my $srctgz=  $RPMtopdir . '/SOURCES/'. $package . '.tar.gz' ;


    my $quiet = '--quiet';
    my $devnull = '2>/dev/null';

    print "\nCreating $package RPM package.\n\n ... please wait ....\n";

    if ($verbose)
    {
	$quiet = '-v';
	$devnull = '';
	print "\nCreate $RPM_File \n";
    }

    system "rpm -qa | sort > $build/InstalledRPMs";
    system "dmidecode  > $build/BuildHost";
    system "mv bruker-image-info $build/";
    my @topspin_versions = installed_topspin_versions();
    my @TopspinInfo = '';
    foreach my $tsvers (@topspin_versions)
    {
	system "$tsvers -e showconf >/dev/null";
	open(FD,$ENV{HOME}."/confspec") || next;
	my @lines =<FD>;
	close(FD);
	push(@TopspinInfo,@lines);
	push(@TopspinInfo,"\n\n************ EOF $tsvers -e showconf *******************\n\n\n");
    }
    open(FD,">$build/TopspinInfo") || die;
    print FD @TopspinInfo;
    close(FD);

    my @RepoList = repository_sorted_list();
    open(FD,">$build/DistributionSortedRPMS") || die;
    print FD @RepoList;
    close(FD);
    
    system "tar -czf $srctgz -C $RPMtopdir/BUILD $package";

    system "rm -rf $build/$package/";

    my $cmd = "rpmbuild -ba --rmsource --rmspec --clean $quiet $specfile $devnull";

    print "$cmd \n" if $verbose;


    open(FD,"$cmd|") || die;
    my @LOG = <FD>;
    close(FD);

    unlink $rpmmacros unless $verbose;


    if (-f $RPM_File )
    {
	print "\nInstalling bruker-setup-release RPM File\n";
	system "rpm -U $RPM_File";

	$subDir = $FtpPath . "/RPMS";

	$ftp->cwd($subDir) or die "cwd $subDir ", $ftp->message;
	$ftp->binary;

	$ftp->put($RPM_File)or die "put $RPM_File failed ", $ftp->message;

	unlink $RPM_File;
    }

    chdir $RPMtopdir .'/SRPMS/';

    $subDir = $FtpPath . "/SRPMS";

    $ftp->cwd($subDir) or die "cwd $subDir ", $ftp->message;
    my $SRPM_File = "$package-$release.src.rpm";
    $ftp->binary;
    $ftp->put("$SRPM_File")or die "put $SRPM_File failed ", $ftp->message;
    $ftp->quit;
    
    unlink("$SRPM_File");
    my $bruker_setup_release = basename($RPM_File);
    syslog(LOG_INFO,"$bruker_setup_release installed");
}

sub installed_topspin_versions {
    my $OPT_DIR = '/opt';
    opendir(DIR,$OPT_DIR) || return;
    
    my @subdir = grep( !/^\./, readdir(DIR));
    closedir(DIR);

    my @TOPSPIN = ();
    foreach my $name (@subdir)
    {
	my $topspin = join('/',$OPT_DIR,$name,'topspin');
	if (-x $topspin)
	{
	    push(@TOPSPIN,$topspin);
	}
    }

    return @TOPSPIN;
}

sub repository_sorted_list {
    ##
    # query RPM database
    my $cmd = 'rpm -qa --queryformat "%{N}-%{V}-%{R} %{DISTRIBUTION}\n"';

    my %Repo = ();

    print "Execute $cmd\n" if $verbose;

    ###
    # Build several lists
    open (FD,"$cmd|") || die "$!\n";
    while (<FD>)
    {
	chomp;
	my ($rpm,$repo) = split(/ /,$_,2);
	if ($Repo{$repo})
	{
	    $Repo{$repo} .= ' ' . $rpm;
	}
	else
	{
	    $Repo{$repo} = $rpm ;
	}
    }
    close(FD);

    my @REPOLIST = ();

    while (my($key,$val) = each(%Repo))
    {
	my @rpms = sort(split(/ /,$val));
	push(@REPOLIST,"\n$key\n");
	foreach my $pkg (@rpms)
	{
	     push(@REPOLIST,"\t$pkg\n");
	}
    }
    return @REPOLIST
}

sub restore_ntp_conf {
    my $ntp_conf = '/etc/ntp.conf';
    my $ntp_conf_pool = '/usr/share/bruker-setup/ntp.conf.centos.pool';
    copy($ntp_conf_pool,$ntp_conf) or warn "Copy $ntp_conf_pool to $ntp_conf failed: $!";
}

sub clear_dhcp_lease {
    print "clear_dhcp_lease:\n" if $verbose;

    my $cmd = 'rpm -ql dhcp';
    my $dhcpd_lease;
    my $leasefile = 'dhcpd.leases';
    my @lease_cmnt = ();

    open(FD,"$cmd|") || die "can't execute $cmd: $!\n";
    {
	while (<FD>)
	{
	    chomp;
	    $dhcpd_lease = $_ if /.*\/$leasefile$/;
	}
	close(FD);
    }

    print "\t$dhcpd_lease\n" if $verbose;
    return unless $dhcpd_lease;
    open(FD,$dhcpd_lease)  || die "can't open $dhcpd_lease: $!\n";
    {
	while (<FD>)
	{
	    push(@lease_cmnt,$_) if /^#/;
	}
	close(FD);
    }

    open(FD,">$dhcpd_lease")  || die "can't open $dhcpd_lease: $!\n";
    {
	print FD @lease_cmnt;
	close(FD);
	print "written:\n@lease_cmnt\n"  if $verbose;
    }
}

sub clear_etc_host {
    print "clear_etc_hosts:\n" if $verbose;

    my $etchosts = '/etc/hosts';
    my $serial_number = GetSmbiosSerialNumber();
    

    if (open(FDI,$etchosts))
    {
	my $newhosts = $etchosts . '.new';
	if (open(FDO,">$newhosts"))
	{
	    while (<FDI>)
	    {
		if (/^(127.0.0.1)\s*(localhost.localdomain)\s*($serial_number)\s*(localhost)/)
		{
		    print FDO "$1\t$2  $4\n";
		}
		else
		{
		    print FDO $_;
		}
	    }
	    close(FDO);
	    rename($newhosts,$etchosts);
	}
	close(FDI);
    }
}

sub disable_bruker_repos {
    print "disable_bruker_repos()\n" if $verbose;
    if ($OS_Version == 5) {
	my $repo = '/etc/yum.repos.d/Bruker-Addon.repo';
	open(my $fd,$repo) or return;
	my @lines = <$fd>;
	close($fd);
	my $curRepo ='undef';
	foreach (@lines) {
	    $curRepo = $1  if ( $_ =~ /^[\[](.*)[\]]/);
	    if ( $_ =~ /^enabled=(\d*)/) {
		my $status = $1;
		printf "$curRepo is %s\n",$status ? 'enabled':'disabled'  if $verbose;
		if ($status) {
		        $_ = "enabled=0\n";
		}
	    }
	}
	print @lines   if $verbose;
	open($fd, '>', $repo) or die "can't open $repo: $!\n";
	print $fd @lines;
	close($fd);
    } else {
	doexec('yum-config-manager','--disable',"bruker*") && syslog(LOG_INFO,"bruker* repos disabled");
    }
}

sub enable_required_services {
    print "enable_required_services($OS_Version):\n" if $verbose;
    enable_required_services_C5() if $OS_Version == 5;
    enable_required_services_C5() if $OS_Version == 6;
    enable_required_services_C7() if $OS_Version == 7;
}

sub enable_required_services_C5 {
    my $cmd = 'rpm -ql bruker-setup';
    my $rc_init = '/etc/rc.d/init.d';

    open(FD,"$cmd|") || die "can't execute $cmd: $!\n";
    {
	while (<FD>)
	{
	    chomp;
	    if ( /^$rc_init/)
	    {
		my $service = basename($_);
		doexec('chkconfig','--add',$service);
		doexec('chkconfig', $service,'on') && syslog(LOG_INFO,"service $service enabled");
	    }
	}
	close(FD);
    }
}

sub enable_required_services_C7 {
    my @service = qw(assign-network.service assign-hostname.service check-secureboot.service check-codemeter-license.service);
    doexec('systemctl','enable',@service) && syslog(LOG_INFO,"service @service enabled");
}

sub sizemm {
    my $rdev = shift;
    sprintf("%3d, %3d", ($rdev >> 8) & 0xff, $rdev & 0xff);
}

sub ls ($) {
    my $name = shift;

    my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
        $atime,$mtime,$ctime,$blksize,$blocks) = lstat($name);
    my $pname = $name;

    $blocks
        or $blocks = int(($size + 1023) / 1024);

    my $perms = $rwx[$mode & 7];
    $mode >>= 3;
    $perms = $rwx[$mode & 7] . $perms;
    $mode >>= 3;
    $perms = $rwx[$mode & 7] . $perms;
    substr($perms, 2, 1) =~ tr/-x/Ss/ if -u _;
    substr($perms, 5, 1) =~ tr/-x/Ss/ if -g _;
    substr($perms, 8, 1) =~ tr/-x/Tt/ if -k _;
    if    (-f _) { $perms = '-' . $perms; }
    elsif (-d _) { $perms = 'd' . $perms; }
    elsif (-l _) { $perms = 'l' . $perms; $pname .= ' -> ' . readlink($_); }
    elsif (-c _) { $perms = 'c' . $perms; $size = sizemm($rdev); }
    elsif (-b _) { $perms = 'b' . $perms; $size = sizemm($rdev); }
    elsif (-p _) { $perms = 'p' . $perms; }
    elsif (-S _) { $perms = 's' . $perms; }
    else         { $perms = '?' . $perms; }

    my $user = $user{$uid} || $uid;
    my $group = $group{$gid} || $gid;

    my ($sec,$min,$hour,$mday,$mon,$timeyear) = localtime($mtime);
    if (-M _ > 365.25 / 2) {
        $timeyear += 1900;
    } else {
        $timeyear = sprintf("%02d:%02d", $hour, $min);
    }

    printf "%5lu %-10s %3d %-8s %-8s %8s %s %2d %5s %s\n",
            $ino,
                      $perms,
                            $nlink,
                                $user,
                                     $group,
                                          $size,
                                              $moname[$mon],
                                                 $mday,
                                                     $timeyear,
                                                         $pname;

    #push(@Directories,$name) if -d $name;
    #push(@Files,$name) if -f $name;

    1;
}


__END__

=head1 NAME

prepare-master - Assign 'Hewlett Packard' Vendors  OUI to eth1

=head1 SYNOPSIS

prepare-master [options]

Options:

     -help            brief help message
     -man             prints the manual page
     -verbose         create verbose output
     -test            run script but do no changes
     -[no]rpmpkg      enable/disable build of bruker-setup-release rpm package
     -[no]sshkeys     enable/disable removal of  'ssh' related files
     -[no]archive     enable/disable backup creation of deleted network files
     -restore         restore network files from backup file
     -name            optional name of the image (default:bde)
     -tsvers          optional version string of topspin. The default is ts and the detected version (ts3.5.6)

=head1 OPTIONS

=over 8

=item B<-help>

    Print a brief help message and exits.

=item B<-man>

    Prints the manual page and exits.


=item B<-verbose>

    Print additional debug information

=item B<-test>

    Run prepare-master script but show only files that would be removed

=item B<-rpmpkg>

    Build only the bruker-setup-release package and send the files to
    ftp://viola.software.bruker.de/pub/Bruker-Workstation-Releases/[56]

=item B<-nosshkeys>

    Run prepare-master script but disable removing of ssh key files

=item B<-noarchive>

    Disable backup creation of deleted network files

=item B<-restore>

    Restore network files from backup file

=item B<-name>

    Define a image name. If not set the internal name bde is used

=item B<-tsvers>

    Define a image version. Otherwise ts and detected TS version is used

=back


=head1 DESCRIPTION

prepare-master - This script is required to remove all personalized information
before a master image is created.

=cut

