#!/usr/bin/perl
#
#
#  Copyright (c) 2004, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
#  All rights reserved.
#
#  Redistribution and use in source and binary forms, with or without
#  modification, are permitted provided that the following conditions are met:
#
#   * Redistributions of source code must retain the above copyright notice,
#     this list of conditions and the following disclaimer.
#   * Redistributions in binary form must reproduce the above copyright notice,
#     this list of conditions and the following disclaimer in the documentation
#     and/or other materials provided with the distribution.
#   * Neither the name of SWITCH nor the names of its contributors may be
#     used to endorse or promote products derived from this software without
#     specific prior written permission.
#
#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
#  POSSIBILITY OF SUCH DAMAGE.
#
#  $Author: peter $
#
#  $Id: install.pl 76 2007-03-13 12:20:11Z peter $
#
#  $LastChangedRevision: 76 $

require 5.6.0;

use lib "./installer-items";
use lib "./libexec";
use strict;

# from libexec - the new modules
use NfSen;
use NfProfile;
use NfSenRRD;
use Nfsources;

# from installer-items - helper modules
use CopyRecursive;
use File::Copy;
use RRDconvertv1;

my $VERSION = '$Id: install.pl 76 2007-03-13 12:20:11Z peter $';
my $nfsen_version = "snapshot-20070312";

my @ProfileTag = ( 
	"# \n",
	"# Profile live.\n",
	"# \n",
);

my @RequiredDirs = ( 'PREFIX', 'BINDIR', 'LIBEXECDIR', 'CONFDIR', 'DOCDIR', 
					 'VARDIR', 'PROFILESTATDIR', 'PROFILEDATADIR', 
					 'BACKEND_PLUGINDIR', 'FRONTEND_PLUGINDIR', 'HTMLDIR' );
#
sub FindCommand {
	my $command = shift;

	my $fullpath = undef;
	my @path = split /:/, $ENV{'PATH'};
	foreach my $dir ( @path ) {
		if ( -x "$dir/$command" ) {
			$fullpath = "$dir/$command";
			last;
		}
	}
	return $fullpath;
	
} # End of FindCommand

# 
# Get Perl
sub GetPerl {

	my $whichperl;
	my $ans;
	$whichperl = FindCommand("perl");
	if ( defined $whichperl ) {
		print "Perl to use: [$whichperl] ";
		chomp($ans = <STDIN>);
		if ( length $ans ) {
			$whichperl = $ans;
		}
	} else {
		print "No Perl found in your PATH. Please specify where to find perl [] ";
		chomp($whichperl = <STDIN>);
	}

	while (1) {
		if ( -x $whichperl ) {
			my $err = system("$whichperl -e 'require 5.6.0;'") >> 8;
			last if $err == 0;
			print "Found errors while testing Perl\n";
		} else {
			print "No executable: '$whichperl'\n";
		}
		print "Perl to use: [] ";
		chomp($whichperl = <STDIN>);
	}

	return $whichperl;

} # End of GetPerl

sub CopyDir {
	my $orig = shift;
	my $dest = shift;

	my $DIR;
	mkdir $dest unless -d $dest;
	opendir($DIR, $orig) || die "can't open dir $orig: $!\n";
	while ( my $direntry = readdir $DIR ) {
		next if $direntry eq '.';
		next if $direntry eq '..';
		next if $direntry eq '.svn';
		if ( -d "$orig/$direntry" ) {
			CopyDir("$orig/$direntry", "$dest/$direntry");
			next;
		} 
		if ( -f "$dest/$direntry" || -l "$dest/$direntry") {
			unlink "$dest/$direntry";
		}
		CopyRecursive::fcopy("$orig/$direntry", "$dest/$direntry");
	}

	closedir $DIR;

} # End of CopyDir

#
# user $user needs to exist and must be a member of $WWWGROUP
sub VerifyUser {
	my $user = shift;

	my $www_gid = getgrnam($NfConf::WWWGROUP);

	my ($login,$pass,$uid,$user_gid) = getpwnam($user);
	if ( !defined $login ) {
		die "user '$user' not found on this system\n";
	}

	# Verify if $user has gid of $WWWGROUP
	if ( $user_gid == $www_gid ) {
		return $uid;
	}

	# Not yet found - check if $user is a member of $WWWGROUP
	my ($gid_name,$passwd,$group_gid,$group_members) = getgrgid($www_gid);
	if ( !defined $gid_name ) {
		die "Group '$user_gid' not found on this system\n";
	}
	# Check the members list
	foreach my $member ( split /\s+/, $group_members ) {
		if ( $member eq $user ) {
			# user found
			return $uid;
		}
	}
	die "User '$user' not a member of group '$NfConf::WWWGROUP'\n";

} # End of VerifyUser

sub VerifyConfig {

	# check if the vars of all required dirs are defined in the Config file
	my $missing = 0;
	foreach my $dir ( @RequiredDirs ) {
		my $var = "NfConf::${dir}";
		no strict 'refs';
		if ( !defined ${$var} ) {
			print STDERR "Missing Variable \$$dir in Config File\n";
			$missing++;
		}
		use strict 'refs';
	}
	if ( $missing ) {
		print STDERR "\nSome variables are missing in your config file.\n";
		print STDERR "If you upgrade from an older version of NfSen please check nfsen-dist.conf\n";
		print STDERR "for required variables.\n\n";
		exit;
	}

	die "Missing PREFIX directory of nfdump tools!\n" unless defined $NfConf::PREFIX;
	die "'$NfConf::PREFIX' not a directory!\n" unless -d  $NfConf::PREFIX;
	foreach my $binary ( 'nfcapd', 'nfdump', 'nfprofile' ) {
		die "nfdump tools installation error: '$binary' not found in '$NfConf::PREFIX'" unless -f "$NfConf::PREFIX/$binary";
	}

	my $www_gid = getgrnam($NfConf::WWWGROUP) || 
		die "WWW group '$NfConf::WWWGROUP' not found on this system\n";

	my $nfsen_uid = VerifyUser($NfConf::USER);

	die "NFSEN does not want to run as root!\n" if $NfConf::USER eq 'root';

	my $subdir = NfSen::SubdirHierarchy(time());
	if ( !defined $subdir ) {
		die "Selected subdir hierarchy %NfConf::SUBDIRLAYOUT out of range\n";
	}

	my %_seen;
	foreach my $source ( keys %NfConf::sources ) {
		my $len = length($source);
		if ( $len < 1 || $len > 19 ) {
			die "Error Ident: '$source': Source identifiers must be between 1 and 19 chars long!\n";
		}
		if ( $source =~ /[^a-z0-9_]+/i ) {
			die "Error Ident: '$source': Source identifiers must contain only characters [a-zA-Z0-9_] !\n";
		}
		my $port = $NfConf::sources{$source}{'port'};
		if ( $port > 0 && exists $_seen{$port} ) {
			die "Error Ident: '$source': Port $port already configured for source $_seen{$port}!\n";
		} else {
			$_seen{$port} = $source;
		}
		# 
		my $type = $NfConf::sources{$source}{'type'};
		if ( defined $type ) {
			$type = lc $type;
			my $collector = $NfSenRC::CollectorMap{$type};

			if ( !defined $collector ) {
				die "Source '$source': unknown collector for type '$type'";
			} elsif ( ! -f "$NfConf::PREFIX/$collector" ) {
				die "Source '$source': missing collector '$collector' for type '$type'";
			}
		}
	}

	return ($nfsen_uid, $www_gid );

} # End of VerifyConfig

#
# Patching: 
# Any string %%varname%% is replaced by the true value $NfCon::varname from 
# the config file
sub PatchVars {
	my $file = shift;

	open FILE, "$file" || die "Can't open file '$file' for reading: $!\n";
	my @lines = <FILE>;
	close FILE;

	open FILE, ">$file" || die "Can't open file '$file' for writing: $!\n";
	foreach my $line ( @lines ) {
		if ( $line =~ /%%(.+)%%/ ) {
			my $var = "NfConf::$1";
			no strict 'refs';
			$line =~ s#%%(.+)%%#${$var}#;
			use strict 'refs';
		}
		print FILE $line;
	}
	close FILE;

} # End of PatchVars

sub PatchAllScripts {

	my %GlobList = ( 
		"bin/*"		=> 	"$NfConf::BINDIR",
		"libexec/*"	=>	"$NfConf::LIBEXECDIR"
	);

	foreach my $glob_list ( keys %GlobList ) {
		my $dir 	= $GlobList{$glob_list};
    	my @Scripts	= glob($glob_list);
		print "In directory: $dir ...\n";
    	foreach my $script (@Scripts) {
        	$script =~ s#^.+/##;
        	if ( -f "$dir/$script" ) {
            	print "Update script: $script\n";
				PatchVars("$dir/$script");
        	} else {
            	print "ERROR: Failed to update script: '$script'. Installation incomplete!\n";
        	}
    	}
	}

	print "\n";

} # End of PatchAllScripts

sub RenameFiles {

	my @AllProfiles = NfProfile::ProfileList('.');
	if ( scalar @AllProfiles > 0 ) {
		my $found = 0;
		print "Rename pre nfsen 1.2 RRDfiles ... ";
		foreach my $profile ( @AllProfiles ) {
			foreach my $tmp (  '', '_other',  '_udp', '_tcp', '_icmp' ) {
				my $oldfile = "$NfConf::PROFILESTATDIR/$profile/bytes${tmp}.rrd";
				my $newfile = "$NfConf::PROFILESTATDIR/$profile/traffic${tmp}.rrd";
				if ( -f $oldfile ) {
					rename $oldfile, $newfile;
					$found = 1;
				}
			}
			foreach my $tmp (  'day', 'week', 'month',  'year' ) {
				my $oldfile = "$NfConf::PROFILESTATDIR/$profile/bytes-${tmp}.gif";
				my $newfile = "$NfConf::PROFILESTATDIR/$profile/traffic-${tmp}.gif";
				if ( -f $oldfile ) {
					rename $oldfile, $newfile;
					$found = 1;
				}
			}
		}
		if ( $found ) {
			print "pre 1.2 RRD files renamed\n";
		} else {
			print "No pre 1.2 RRD files found.\n";
		}
	}

} # End of RenameFiles

sub SetupHTML {
	my ( $nfsen_uid, $www_gid ) = @_;

	print "Setup php and html files.\n";
	mkdir "$NfConf::HTMLDIR" unless -d "$NfConf::HTMLDIR";
	die "Could not create HTMl directory '$NfConf::HTMLDIR': $!\n"  unless -d $NfConf::HTMLDIR;

	$CopyRecursive::CopyLink = 1;
	$CopyRecursive::MODE 	 = 0644;
	$CopyRecursive::UID 	 = 0;
	$CopyRecursive::GID 	 = $www_gid;
	CopyRecursive::dircopy("html", "$NfConf::HTMLDIR");
	open CONF, ">$NfConf::HTMLDIR/conf.php" || die "Can't open conf.php for writing: $!\n";
	print CONF "<?\n";
	print CONF "/* This file was automatically created by the NfSen install.pl script */\n\n";
	print CONF "\$COMMSOCKET = \"$NfConf::COMMSOCKET\";\n";
	print CONF "\n\$DEBUG=1;\n";
	print CONF "\n?>\n";
	close CONF;
	print "\n";
	
} # End of SetupHTML

sub SetupEnv {
	my $nfsen_uid	= shift;
	my $www_gid		= shift;
	
	# Make sure all required directories exist

	umask 0002;
	print "\nSetup diretories:\n";
	my @dirs = (
		"$NfConf::VARDIR",
		"$NfConf::VARDIR/run",
		"$NfConf::VARDIR/tmp",
		"$NfConf::VARDIR/filters",
		"$NfConf::VARDIR/fmt",
		"$NfConf::PROFILESTATDIR",
		"$NfConf::PROFILESTATDIR/live",
		"$NfConf::PROFILEDATADIR",
		"$NfConf::PROFILEDATADIR/live",
	);

	print "\nUse UID/GID $nfsen_uid $www_gid\n";

	foreach my $dir ( @dirs ) {
		if ( ! -d $dir ) {
			print "Creating: ";
			mkdir $dir || die "Can't mkdir '$dir': $!\n";
		} else {
			print "Exists: ";
		}
		chmod 0775, $dir || die "Can't chmod '$dir': $!\n";
		chown $nfsen_uid, $www_gid, $dir || die "Can't chown '$dir': $!\n";
		print "$dir\n";
	}

	print "\nProfile live: spool directories:\n";
	foreach my $ident ( keys %NfConf::sources ) {
		my $dir = "$NfConf::PROFILEDATADIR/live/$ident";
		if ( ! -d $dir ) {
			print "Creating: ";
			mkdir $dir || die "Can't mkdir '$dir': $!\n";
		} else {
			print "Exists: ";
		}
		chmod 0775, $dir || die "Can't chown '$dir': $!\n";
		chown $nfsen_uid, $www_gid, $dir || die "Can't chown '$dir': $!\n";
		print "$ident\n";
	}

	RenameFiles();

	my $now = time();
	my $tstart = $now - ( $now % 300 );
	foreach my $db ( keys %NfConf::sources ) {
		NfSenRRD::SetupRRD("$NfConf::PROFILESTATDIR/live", $db, $tstart - 300, 0);
	}
	if ( $Log::ERROR ) {
		die "Error setup RRD DBs: $Log::ERROR\n";
	}

	my %profileinfo = NfProfile::ReadProfile('live', '.');
	if ( $profileinfo{'status'} eq 'empty' ) {
		print "Create profile info for profile 'live'\n";
		# empty - new profile
		$profileinfo{'_comment_'} 	= \@ProfileTag;
		$profileinfo{'name'}		= 'live';
		$profileinfo{'tcreate'} 	= $tstart;
		$profileinfo{'tbegin'}		= $tstart;
		$profileinfo{'tstart'} 		= $tstart;
		$profileinfo{'tend'} 		= $tstart;
		$profileinfo{'updated'}		= $tstart - 300;
		$profileinfo{'expire'} 		= 0;
		$profileinfo{'maxsize'} 	= 0;
		$profileinfo{'size'} 		= 0;
		$profileinfo{'filter'}		= "";
		$profileinfo{'type'} 		= 0;
		$profileinfo{'locked'} 		= 0;
		$profileinfo{'status'} 		= 'rebuild';
		$profileinfo{'version'} 	= $NfProfile::PROFILE_VERSION;
		$profileinfo{'channel'}		= {};
		my $order = 1;
		foreach my $source ( keys %NfConf::sources ) {
			$profileinfo{'channel'}{$source}{'sign'}   = '+';
			$profileinfo{'channel'}{$source}{'colour'} = $NfConf::sources{$source}{'col'};
			$profileinfo{'channel'}{$source}{'order'}  = $order++;
			$profileinfo{'channel'}{$source}{'sourcelist'}  = $source;
		}
		NfProfile::WriteProfile(\%profileinfo);
	} else {
		print "Use existing profile info for profile 'live'\n";
	}

	my $filelist = "$NfConf::PROFILESTATDIR/live/*rrd $NfConf::PROFILESTATDIR/live/profile.dat";
	my @AllFIles = glob($filelist);
	chown $nfsen_uid, $www_gid, @AllFIles;

	print "\n";

} # End of SetupEnv

sub UpgradeProfiles {
	my $nfsen_uid	= shift;
	my $www_gid		= shift;

	my @AllProfiles = NfProfile::ProfileList('.');
	if ( scalar @AllProfiles == 0 ) {
		print STDERR "$Log::ERROR\n" if defined $Log::ERROR;
		return;
	}

	$CopyRecursive::UID 	 = $nfsen_uid;
	$CopyRecursive::GID 	 = $www_gid;
	$CopyRecursive::MODE 	 = 0644;

	# fix permissions - all files/directories should ne $NfConf::USER and no longer WWW, as 
	# no php script will no longer write anything
	chown $nfsen_uid, $www_gid, "$NfConf::PROFILEDATADIR";
	chown $nfsen_uid, $www_gid, "$NfConf::PROFILESTATDIR";

	foreach my $profilename ( @AllProfiles ) {
		my %profileinfo = NfProfile::ReadProfile($profilename, '.');

		# Upgrade snapshots
		if ( $profileinfo{'version'} == $NfProfile::PROFILE_VERSION && $profileinfo{'tcreate'} == 0 ) {
			print "Upgrade profile '$profilename' from snapshot\n";
			# estimate create time of profile
			my $tcreate = (stat("$NfConf::PROFILESTATDIR/$profilename"))[9];
			$profileinfo{'tcreate'}	= $tcreate;
			$profileinfo{'tbegin'}	= $tcreate - ( $tcreate % 300 );

			NfProfile::WriteProfile(\%profileinfo);
		}

		# 1.3 introduces a version parameter for the profile
		next if $profileinfo{'version'} >= $NfProfile::PROFILE_VERSION;

		print "Upgrade profile '$profilename' to version '$NfProfile::PROFILE_VERSION'\n";
		$profileinfo{'version'} = $NfProfile::PROFILE_VERSION;
		$profileinfo{'group'} 	= '.';
		
		# fix permissions - all files/directories should ne $NfConf::USER and no longer WWW, as 
		# no php script will no longer write anything
		chown $nfsen_uid, $www_gid, "$NfConf::PROFILEDATADIR/$profilename";
		chown $nfsen_uid, $www_gid, "$NfConf::PROFILESTATDIR/$profilename";

		my @AllEntries = <$NfConf::PROFILESTATDIR/$profilename/*>;
		chown $nfsen_uid, $www_gid, @AllEntries;
		my @AllEntries = <$NfConf::PROFILEDATADIR/$profilename/*>;
		chown $nfsen_uid, $www_gid, @AllEntries;

		# 1.3 introduces channels and no longer has a sourcelist
		if ( exists $profileinfo{'legacy'} && exists $profileinfo{'legacy'}{'sourcelist'} ) {
			my $order = 1;
			my $oldfilter = undef;
			foreach my $channel ( split /:/, $profileinfo{'legacy'}{'sourcelist'} ) {
				$profileinfo{'channel'}{$channel}{'sign'}   = '+';
				$profileinfo{'channel'}{$channel}{'colour'} = $NfConf::sources{$channel}{'col'};
				$profileinfo{'channel'}{$channel}{'order'}  = $order;
				$profileinfo{'channel'}{$channel}{'sourcelist'}  = $channel;
				$order++;

				next if $profilename eq 'live';
				# copy filter files

				$oldfilter    = "$NfConf::PROFILEDATADIR/$profilename/$profileinfo{'filter'}";
				my $newfilter = "$NfConf::PROFILESTATDIR/$profilename/$channel-filter.txt";

				CopyRecursive::fcopy($oldfilter,$newfilter) or 
					$oldfilter = undef,
					print STDERR "Could not copy filter file: $!\n";
			}
			NfProfile::WriteProfile(\%profileinfo);
			unlink $oldfilter if defined $oldfilter;
		}
	}

} # End of UpgradeProfiles

sub CopyAllFiles {
	my $ConfigFile	= shift;
	my $nfsen_uid	= shift;
	my $www_gid		= shift;

	print "Copy NfSen dirs etc bin libexec plugins doc ...\n";

	$CopyRecursive::CopyLink = 1;
	$CopyRecursive::UID 	 = 0;
	$CopyRecursive::GID 	 = $www_gid;
	$CopyRecursive::MODE 	 = 0755;
	CopyRecursive::dircopy("bin", "$NfConf::BINDIR");
	CopyRecursive::dircopy("libexec", "$NfConf::LIBEXECDIR");
	$CopyRecursive::MODE 	 = 0644;
	CopyRecursive::dircopy("etc", "$NfConf::CONFDIR");
	CopyRecursive::dircopy("plugins/backend",  "$NfConf::BACKEND_PLUGINDIR");
	CopyRecursive::dircopy("plugins/frontend", "$NfConf::FRONTEND_PLUGINDIR");
	CopyRecursive::dircopy("doc", "$NfConf::DOCDIR");

	if ( $ConfigFile eq "$NfConf::CONFDIR/nfsen.conf" ) {
		print "Keep config file '$ConfigFile'\n";
	} else {
		print "Copy config file '$ConfigFile'\n";
		CopyRecursive::fcopy("$ConfigFile", "$NfConf::CONFDIR/nfsen.conf");
	}
	print "\n";

} # End of CopyAllFiles

sub Cleanup {
	
	print "Cleanup old files ...\n";

	my @OldFiles = ( "$NfConf::BINDIR/GenGraph.pl" ,
					 "$NfConf::BINDIR/pid_check.pl",
					 "$NfConf::BINDIR/nfsen-run",
					 "$NfConf::LIBEXECDIR/demoplugin.pm",
					 "$NfConf::LIBEXECDIR/PluginTemplate.pm",
					 "$NfConf::CONFDIR/nfsen-shell-param",
					);

	foreach my $file ( @OldFiles ) {
		unlink $file if -f $file;
	}

} # End of Cleanup

########################
#
# Main starts here
#
########################

$| = 1;

my $ConfigFile = shift @ARGV;


# Load the required NfSen modules 
unshift @INC, "libexec";
print "Check for required Perl modules: ";
eval {
	# other required modules
	require RRDs; 			import RRDs;
	require Mail::Header;	import Mail::Header;
	require Mail::Internet;	import Mail::Internet;
};
if ( $@ ) {
	print "Failed\nRequired nfsen modules not found\n";
	print "$@\n";
	exit;
} else {
	print "All modules found.\n";
}

# need to run as root
if ( !NfSen::root_process() ) {
	die "nfsen setup wants to run as root\n";
}

# need a config file
if ( !defined $ConfigFile ) {
	die "Config file required: $0 <nfsen.conf>\n";
}
if ( ! -f $ConfigFile ) {
	die "$ConfigFile: No such file.\n";
}

# Load the config
if ( !NfConf::LoadConfig($ConfigFile) ) {
	print "$Log::ERROR\n";
	exit 1;
}

my $hints = NfSen::LoadHints();
if ( $$$hints{'version'} == -1 ) {
	# initial NfSen install or upgrade from old version without hints
	$$$hints{'version'} 		= $nfsen_version;
	$$$hints{'subdirlayout'} 	= $NfConf::SUBDIRLAYOUT;
} else {
	print "Upgrade from version '$$$hints{'version'}' installed at " . scalar localtime $$$hints{'installed'};
	print "\n";
}
$$$hints{'installed'} 		= time();

my $rrd_version = $RRDs::VERSION;
die "Can't find out which version of RRD you are using!\n" unless defined $rrd_version;

$NfConf::RRDoffset = NfSenRRD::GetRRDoffset();
if ( !defined $NfConf::RRDoffset ) {
	die "$Log::ERROR\n";
}


# 
print "Setup NfSen:\n";
print "Version: $nfsen_version: $VERSION\n\n";

# Get Perl
# Put this into a NfCOnf Variablee, so we can use the standard Patch Procedure
$NfConf::PERL = GetPerl();


my ($nfsen_uid, $www_gid ) = VerifyConfig();
my $nfsen_run = 0;

# test for two files of old layout
my $need_rrdlayout_upgrade = -f "$NfConf::PROFILESTATDIR/live/flows.rrd" && -f "$NfConf::PROFILESTATDIR/live/packets_other.rrd";

my $rrdtool = undef;
if ( $need_rrdlayout_upgrade ) {
	$rrdtool = FindCommand("rrdtool");
	if ( !defined $rrdtool ) {
		print "\nERROR: command 'rrdtool' not found in your PATH: 'rrdtool' is needed to upgrade the DBs of your NfSen version\n";
		exit 1;
	}
}

my $pid_name = "nfsend.pid";
if ( -f "$NfConf::VARDIR/run/nfsen-run.pid" ) {
	# from NfSen <= 1.2
	$pid_name = "nfsen-run.pid";
}

if ( -f "$NfConf::VARDIR/run/$pid_name" ) {
	open PID, "$NfConf::VARDIR/run/$pid_name" || die "Can't open pid file: $!\n";
	my $pid = <PID>;
	chomp($pid);
	close PID;
	die "Can't extract PID out of '$NfConf::VARDIR/run/$pid_name'. Stop upgrade" if !defined $pid;
	if ( kill(0, $pid) == 1 ) {
		print "Stop nfsend while upgrading .";
		kill 15, $pid;
		my $cnt = 0;
		while ( -f "$NfConf::VARDIR/run/$pid_name" && $cnt < 300 ) {
			print ".";
			$cnt++;
			sleep(1);
		}
		if ( -f "$NfConf::VARDIR/run/$pid_name" ) {
			print "\nnfsend doesn't want to die! It's not save to upgrade NfSen!\n";
			exit;
		} else {
			print "done.\n";
			$nfsen_run = 1;
		}
	} else {
		print "nfsend pid file exists, but no process is running.\n";
		unlink "$NfConf::VARDIR/run/$pid_name";
	}
}

SetupHTML($nfsen_uid, $www_gid);
CopyAllFiles($ConfigFile, $nfsen_uid, $www_gid);
PatchAllScripts();
Cleanup();
SetupEnv($nfsen_uid, $www_gid);

UpgradeProfiles($nfsen_uid, $www_gid);

if ( $need_rrdlayout_upgrade ) {
	print "The profiles need be be updated to new RRD layout:\n";
	print "Use '$rrdtool' to dump current DBs\n";

	my @AllProfiles = NfProfile::ProfileList('.');
	if ( scalar @AllProfiles == 0 ) {
		print STDERR "$Log::ERROR\n" if defined $Log::ERROR;
		return;
	}
	foreach my $profilename ( @AllProfiles ) {
		if ( !RRDconvertv1::UpdateProfile($profilename, $rrdtool) ) {
			print "ERROR updating profile! NfSen installation incomplete\n";
			exit 0;
		}
	}
}


Nfsources::Reconfig();
NfSen::StoreHints();
chown $nfsen_uid, $www_gid, "$NfConf::PROFILESTATDIR/hints" || die "Can't chown hints db: $!\n";
print "Setup done.\n\n";

if ( $nfsen_run ) {
	print "Restart nfsend\n";
	system("$NfConf::BINDIR/nfsend");
}

print "* You may want to subscribe to the nfsen-discuss mailing list:\n";
print "* http://lists.sourceforge.net/lists/listinfo/nfsen-discuss\n";
print "* Please send bug reports back to me: peter.haag\@switch.ch\n";
exit 0;

