#!/usr/bin/perl

########## Confixx(R) 3.0 Professional ############
####### Copyright SWsoft, Inc. 2004-2005 ##########
#### http://www.sw-soft.com - info@sw-soft.com ####


use strict;

use File::Basename;
use File::Copy;
use File::Find;

## UNTERPROGRAMME FÜR CONFIXX INSTALLATION & KONFIGURATION
sub BackUpFile{
	my ($from,$to,$force) = @_;
	if (-e $from){
		if ((!( -e $to)) || ($force)){
			my $dir = dirname($to);
			if (!( -e $dir)){
				&RecCreateDir($dir, 0700);
			}
			print &ltext('install_do_file_copy', $from, $to);
			copy($from, $to);
		}
	}
}


sub RecCreateDir{
  my ($dir, $permissions) = @_;
  my ($dir2);
  unless ( -e $dir ) {
    $dir = &ChopDir($dir);
    $dir2 = dirname($dir);
    unless( ( $dir eq $dir2 ) || ( -e $dir2 ) ) {
      &RecCreateDir($dir2, $permissions);
    }
    mkdir ($dir, $permissions);
    chmod ($permissions, $dir);
  }
	return (-d $dir)?1:0;
}


sub ChopDir{
  my ($dir) = @_;
  $dir =~ s/(?=[^\/])\/+$//;  ## if ends with <not slash><slash>+ remove <slash>+
  return($dir);
}





# -------------------- getBin -------------------- #
#
# Finds binary file
# Parameters:
# $binary - file name
# $nn - if false (default) and file is not found, ask user for another location/file name
# @search - list of directories where the file may be located
#
sub getBin {
  my ($binary, $nn, @search) = @_;

  push @search,( "/bin","/usr/bin","/usr/sbin","/sbin",
							 "/usr/local/bin","/usr/local/sbin");
  my ($path,$fullPath,$input);

	foreach $path ( @search ){
		$fullPath = "$path/$binary";
		if(-x $fullPath){
			return $fullPath;
		}
	}

	my $reBinary = qr/\Q$binary\E$/;

	until($nn){
		print &ltext('install_bin_manual', $binary);
		$input = <STDIN>;
		unless (defined($input)){  ## ctrl+D (EOF)
			return undef;
		}

		chop($input);

		if ( -x $input &&
				 ( $input =~ /$reBinary/ ||
					 YesNoQuestion( "'$input' does not look like name of '$binary'.".
													' Should Confixx use it anyway?', 'j' ) ) ) {
			print &ltext('install_selected', $input);
			return $input;
		}else{
			print &ltext('install_bin_name', $input, $binary);
		}
	}
	return undef;
}
# -------------------- end getBin -------------------- */





sub writeConfig {
  my ($file, $content) = @_;

  open FILE, ">$file.tmp" or
    die("Unable to open '$file.tmp' for writing: $!\n");
  print FILE $content;
  close(FILE) or
    die("Unable to close '$file.tmp' after writing: $!\n");
	
  if (-e $file) {
    &move($file, "$file.sav") or
      die("Unable to move '$file' to '$file.sav':$!\n");
  }
  &move("$file.tmp", $file) or
    die("Unable to move '$file.tmp' to '$file':$!\n");
}

sub readFile {
  my ($file) = @_;
  
  unless (open(FILE, "<$file")) {
    warn("Unable to open file '$file' for reading: $!\n");
    return undef;
  }
	
  my $content = '';
  while (<FILE>) {
    $content .= $_;
  }
  close(FILE);
  return $content;
}

#
# get the argument to call the start-stop script of the service
#
# arguments:
#     $script - path to the script
#     @restart - list of arguments to search. 
#                Default list:  'reload','restart','reread'
#
# return:
#    $key - the allowed argumnet to call the script
#
 
sub getReloadKey {
  my $script = shift;
	my ( @restarts );
	if (@_) {
		@restarts = @_;
	} else {
		@restarts = ('reload','restart','reread');
	}

  my @keys = &getKeys($script); ## get list of allowed keys
  my %inKeys = map {$_=>1} @keys; ## translate to hash
	
  foreach my $key (@restarts) {
		if ( $inKeys{$key} ) {
			return $key;
		}
  }
}

sub getKeys {
  my $script = shift;
  my (@keys,$key);
  if (-x $script){
    if (-T $script && open (SCRIPT,"< $script")){
      my $state = 0;
      while (<SCRIPT>){  
 
		if ( /^\s*case\s+/ ) {  ## begin of case-block 
		  if ( $state == 0 ) {
			$state = 1;  ## case of first level
		  } else {
			$state = ( $state>4 )? $state++: 4;
		  }

		} elsif ( $state==1 && /^\s*([-_a-z|*]+)\)/ ) {  ## case value
		
		  push @keys,split(/\|/,$1);
		  
		} elsif ( /^\s*esac\s*($|;)/ ) { ## end of case-block
		  if ( $state > 4) {  
			$state--;
		  } elsif ( $state == 4) {
			$state = 1;	
		  } elsif ( $state == 1) {

			map { $state++ if /^(start|stop)/ } @keys;

			if ( $state == 3 ) { ## found 'start' & 'stop'  in keys
			  last;
			} else {  ## 'start' or 'stop' is not found
			  @keys = ();  ## wrong case
			}
			$state = 0;
		  }
		}
	  }	
	  close ( SCRIPT );
	}

    unless(@keys){  ## try get help string
      my $out=`$script 2>&1`;
      if ( $out =~ /\s(start\|[-_a-z|]+)/ ) {  ## parse output
				@keys = split(/\|/,$1);
	  } else {
		my $line;
		foreach $line ( split( /\n/, $out ) ) {
		  if ( $line =~/\s+([-_a-z|]+)\s+-\s+\S+/ ) {
			push @keys,split(/\|/,$1);
		  }	  
		}
	  }
	}
  }
  return @keys;

}

sub fixOwnership {
	my $path = shift;
	our $defaultUid = shift;
	our $defaultGid = shift;
	our %extraOwner = (@_);

	unless ( -d $path ) {
		warn "error: path '$path' is not dir\n";
		return 0;
	}

#
# check system accounts
#
	($defaultUid,$defaultGid) = &checkSysAccount( $defaultUid,$defaultGid );
	unless ( defined ( $defaultUid ) ) {
		return 0;
	}

	my ($inUid,$inGid,$outUid,$outGid);
	while ( ($inUid,$inGid) = each( %extraOwner ) ) {
		($outUid,$outGid) = &checkSysAccount( $inUid,$inGid );
		if ( defined ( $outUid ) ) {
			$extraOwner{$outUid} = $outGid;
		} else {
			delete $extraOwner{$inUid};
		}
	}

#
# end check system accounts
#
	find (\&prepareItem, $path);

	sub prepareItem {
		return if ( -l $File::Find::name );
		my ($uid,$gid) = (stat($File::Find::name))[4,5];
		my ($extraGid);
		if ( exists ($extraOwner{$uid} )  ) {
			$extraGid = $extraOwner{$uid};
			unless ( $gid == $extraGid ){
				chown ( $uid,$extraGid,$File::Find::name );
			}
		} else {
			if ( ( $uid != $defaultUid ) || ( $gid != $defaultGid ) ) {
				chown ( $defaultUid,$defaultGid,$File::Find::name );
			}
		}
	}

}


sub checkSysAccount {
	my ($inUid, $inGid) = @_;
	my ($gid,$uid);
	unless ( $inUid =~ /^\d+$/ ){
		unless ( ($uid,$gid) = (getpwnam($inUid))[2,3] ){
			warn "error: system account '$inUid' is not found: $!\n";
			return undef;
		}
		$inUid = $uid;
	}

	unless ( defined ($inGid) ) {
		unless ( $gid ) {
			$gid = (getpwuid( $inUid ))[3];
		}
		$inGid = $gid;

	} else {
		unless ( $inGid =~ /^\d+$/ ){
			unless ( $gid = (getgrnam( $inGid ))[3] ) {
				warn "error: system group '$inGid' is not found: $!\n";
				return undef;
			}
			$inGid = $gid;
		}
	}
	return ($inUid,$inGid);
}

sub getDistrib {
	my ($dist);

  if ( -e "/etc/redhat-release" ) {
    $dist = 'redhat';
 
  } elsif ( -e "/etc/mandrake-release" ) {
    $dist = 'mandrake';

  } elsif ( -e "/etc/SuSE-release" ) {
    $dist = 'suse';

  } elsif ( -e "/etc/debian_version" ) {
    $dist = 'debian';
  }

	return $dist;
}

1;
## /UNTERPROGRAMME FÜR CONFIXX INSTALLATION & KONFIGURATION
