#!/usr/bin/perl -w

use strict;
use Errno;
use esmith::ConfigDB;
use File::Temp;
use esmith::templates;
use File::Basename;
use Cwd 'abs_path';

my $conf = esmith::ConfigDB->open_ro;


my $event = $ARGV [0];
my $second = $ARGV [1];

my @servicedirpaths = ("/usr/lib/systemd/system/","/etc/systemd/system/");
my @presetdirpaths = ("/usr/lib/systemd/system-preset/","/etc/systemd/system-preset/");
my $filename = "/etc/systemd/system-preset/49-koozali.preset";
my $filename2 = "/usr/lib/systemd/system/sme-server.target.d/50koozali.conf";
my %services;
my %files;
my @WantedBy;my %wantedBy;

# expand preset file
esmith::templates::processTemplate({
                MORE_DATA => { },
                TEMPLATE_PATH => $filename,
                OUTPUT_FILENAME => $filename,
            });
# expand content of sme-server.target.d
esmith::templates::processTemplate({
                MORE_DATA => { },
                TEMPLATE_PATH => $filename2,
                OUTPUT_FILENAME => $filename2,
            });

# make sure our target is enabled
system("/usr/bin/systemctl  enable sme-server.target 2>/dev/null");
# force the main default target in /usr/lib
#ln -fs sme-server.target /lib/systemd/system/default.target
my $old_qfn = "sme-server.target";
my $new_qfn = "/lib/systemd/system/default.target";
if (!symlink($old_qfn, $new_qfn)) {
   if ($!{EEXIST}) {
      unlink($new_qfn)
         or die("Can't remove \"$new_qfn\": $!\n");
      symlink($old_qfn, $new_qfn)
         or die("Can't create symlink \"$new_qfn\": $!\n");
   } else {
      die("Can't create symlink \"$new_qfn\": $!\n");
   }
}

# we let the dedicated systemd command tryin to do what we will do later in this script
# as up to systemd 236 it is bugged see:
#  https://github.com/systemd/systemd/pull/7158 and https://github.com/systemd/systemd/pull/7289
system("/usr/bin/systemctl  preset-all");
# in case preset-all messed up  with our default target
system("/usr/bin/systemctl  set-default sme-server.target");

# list both preset directories
# seek files to be removed from usr/lib if same basename exist 
foreach my $d (@presetdirpaths) {
	opendir my $dir, "$d" or die "Cannot open directory: $!";
	my @dirfiles = readdir $dir;
	closedir $dir;
	foreach my $fi (@dirfiles) {
	        next unless ($fi =~ /.preset$/);
		$files{$fi}="$d$fi"
	}
}

# list wanted services in the sme-server.target
#Wants=acpid.service atd.service auditd.service avahi-daemon.service brandbot.path crond.service irqbalance.service nfs-client.target remote-fs.target rhel-configure.service rsyslog.service smartd.service yum-cron.service
my $smewants = `grep -P '^Wants=' /usr/lib/systemd/system/sme-server.target -rs`;
chomp $smewants;
my @smematches = ( $smewants =~ /([a-zA-Z0-9\-_]+\.service)/g );
my %smewants = map { $_ => 1 } @smematches; 

# parse all files on reverse order : lower number take precedence
# we ignore joker lines *
# we ignore @ lines
# we ignore multiple in one line
# our default at the end is to disable if not listed
foreach my $filen (reverse sort keys %files) { 
#print "==============> $filen : ".$files{$filen} ."\n";
	# parsing $filename  content
	# should end with hash with 2 possible value : enable and disable
	# ignore lines starting with # or empty character
	open(FILE, '<', $files{$filen}) or die $!;
	while (<FILE>)	{
	    chomp; # remove newlines
	    next if (/^\s+$/);
	    next if (/^#/);
	    s/^\s+//;  # remove leading whitespace
	    s/\s+$//; # remove trailing whitespace
	    next unless length; # next rec unless anything left
#           print $_ ."\n";
	    next unless (/^(enable|disable)\s+([a-zA-Z0-9\-_.@]+\.service)/);
	    my $service=$2;
	    my $stats=$1;
#	    print $_ ."\n"; 
	    #ignore service that does not exists !
	    my $multiple = $service;
	    ($multiple = $service ) =~ s/([a-zA-Z0-9\-_.]+@)(.*)/$1.service/ if ( $service =~ /@/ );
	    #print "$stats $service $multiple\n";
	    next unless ( -e "/usr/lib/systemd/system/$service" or -e "/etc/systemd/system/$service" or -e "/usr/lib/systemd/system/$multiple");
	    # eliminate duplicates, this way we keep only the last entry of the lowest file as we do it in reverse order of file,
	    # but from top to bottom of file.
	    $services{$service}=$stats;

	    # list all Services explicitely listed in preset that are also in Wants= or with WantedBy= sme-server.target 
	    next if ( exists($wantedBy{$service}));
	    if (exists($smewants{$service}) ) { 
		$wantedBy{$service}=1; 
		#print "want $service \n";
            }
            else {
                my $wanted = `grep -P '^WantedBy=.*sme-server.target' /usr/lib/systemd/system/$service*  /etc/systemd/system/$service* -rsh` ;
                chomp $wanted;
		$wantedBy{$service}=1 unless ( $wanted eq "");
		#print "want $service \n" unless ( $wanted eq "") ;
            }

	}
}

# then check content of /etc/systemd/system/sme-server.target.wants/
# remove what is not in enable
my $d = "/etc/systemd/system/sme-server.target.wants/";
opendir my $dir, "$d" or die "Cannot open directory: $!";
my @dirfiles = readdir $dir;
closedir $dir;
foreach my $fi (@dirfiles) {
        # we ignore . and ..
        next if $fi =~ /\.+$/;
        # for the moment we only consider service  files and ignore target, mount, device, socket...
        next unless ($fi =~ /.service$/);
	# remove if file but not a link
	unless ( -l "$d$fi") {
		print "remove $d$fi : not a link\n";
		unlink "$d$fi";
		next;
	}
	# remove if also un /usr/lib .. not as preset-all does not care
	#if ( -l "/usr/lib/systemd/system/sme-server.target.wants/$fi") {
	#	print "remove $d$fi : also in /usr/lib/systemd/system/sme-server.target.wants/\n";
	#	unlink "$d$fi";
	#	next;
	#}
	# remove if link is not to an existing file # we should also check if pointing to an authorized path!
        my $multiple = $fi;
        ($multiple = $fi ) =~ s/([a-zA-Z0-9\-_.]+@)(.*)/$1.service/ if ( $fi =~ /@/ );
	my $absFilePath = abs_path("$d$fi") ;
	if ( ! -f "$absFilePath" or ( ! -f "/etc/systemd/system/$fi" and ! -f "/usr/lib/systemd/system/$fi" and ! -f "/usr/lib/systemd/system/$multiple") ) {
		print "remove $d$fi target '$absFilePath' does not exist or is not regular file in expected path\n";	
		unlink "$d$fi";
		next;
	}
        # is not enable in preset : remove
        #print "==$fi \n";
        if ( ! defined $services{$fi} or $services{$fi} ne "enable") {
                print "remove $d$fi as not enabled in preset\n";
                unlink "$d$fi";
		next;
        }
	# if not wanted remove
	unless ( exists($wantedBy{$fi})){
		print "remove $d$fi as not declared as WantedBy or in Wants for sme-server.target\n";
		unlink "$d$fi";
	}
}

# and we add wanted enabled services 
# we only do it for sme-server.target, ignoring the remaining of WantedBy
foreach my $service (sort keys %services) {
	my $wanted= "not";
	$wanted = "want" if ( exists($wantedBy{$service}));#(  /^$service$/ ~~ @WantedBy ); 
	my $status = $services{$service};
	my $linkedU = ( -e "/usr/lib/systemd/system/sme-server.target.wants/$service" ) ? "linked" : "not";
	my $linkedE = ( -e "/etc/systemd/system/sme-server.target.wants/$service" ) ? "linked" : "not"; 
	my $linkedD = ( -e "/etc/systemd/system/default.target.wants/$service" or -e "/usr/lib/systemd/system/default.target.wants/$service" ) ? "linked" : "not"; 
	## adding link if needed in /etc/systemd/system/sme-server.target.wants
	## readd event if present in usr/lib as preste-all does not care about that.
	if ( $status eq "enable" and $linkedE eq "not" and $linkedD eq "not"  and $wanted eq "want" and ( $service !~ /\@\.service$/ ) ){
		#print "systemctl add-wants sme-server.target $service\n";
		`/usr/bin/systemctl add-wants sme-server.target $service `;
	}
}

# do something about /usr/lib/systemd/system/sme-server.target.wants/
# we check for rpm owned and not rpm owned
# we only inform there, we do not do anything else
$d = "/usr/lib/systemd/system/sme-server.target.wants/";
opendir $dir, "$d" or die "Cannot open directory: $!";
@dirfiles = readdir $dir;
closedir $dir;
foreach my $fi (@dirfiles) {
        # we ignore . and ..
        next if $fi =~ /\.+$/;
        # for the moment we only consider service  files and ignore target, mount, device, socket...
        next unless ($fi =~ /.service$/);
        # remove if file but not a link
        print "$d$fi is not a link\n" unless ( -l "$d$fi");
        # remove if link is not to an existing file
        my $absFilePath = abs_path("$d$fi") ;
        print "$d$fi target '$absFilePath' does not exist or is not regular file\n" unless ( -f "$absFilePath");
        # check if owned by rpm
	my $rpmowned = `rpm -qf $d$fi`;
	chomp $rpmowned;
	if ($rpmowned ne "" ) {
		#print "$d$fi is owned by $rpmowned\n";
		#next;
	} else {
		print "$d$fi has been manually added\n";
	}
	if ( ! defined $services{$fi} or $services{$fi} ne "enable") {
                print "$d$fi is not enabled in preset\n";
        }
        # if not wanted remove
	# need to check its own files also here
	my $service = $fi;
	my $wanted = `grep -P '^WantedBy=.*sme-server.target' /usr/lib/systemd/system/$service*  /etc/systemd/system/$service* -rsh` ;
	chomp $wanted;
	unless ( exists($wantedBy{$fi})) {
                print "$d$fi is not declared as WantedBy or in Wants for sme-server.target\n";
        }
}