#!/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 () { 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"; } }