From 3619db5267492217dce4ae47d9c8e08be6f75837 Mon Sep 17 00:00:00 2001 From: Colin Guthrie Date: Tue, 24 Apr 2012 20:10:47 +0000 Subject: services: Read systemd service information. This adds support for two different methods of working with systemd. The first, and more complete method is to query systemd for information about whether a service is enabled at boot. This mode requires that we are running under systemd and thus only works for machines in interactive mode post-install. For the installer, we also support a more rudamentary method which scans for unit files which contain simple install rules (i.e. only those services which are part of the typical multi-user or graphical targets (corresponding to runlevels 3 and 5 in the old days). This method will not show all services but it should be enough for the installer. https://bugs.mageia.org/show_bug.cgi?id=3253 https://bugs.mageia.org/show_bug.cgi?id=3740 https://bugs.mageia.org/show_bug.cgi?id=4910 https://bugs.mageia.org/show_bug.cgi?id=5122 --- perl-install/services.pm | 98 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 82 insertions(+), 16 deletions(-) (limited to 'perl-install/services.pm') diff --git a/perl-install/services.pm b/perl-install/services.pm index f7efdc5e3..1210077b1 100644 --- a/perl-install/services.pm +++ b/perl-install/services.pm @@ -369,31 +369,97 @@ sub xinetd_services() { @xinetd_services; } -sub services_raw() { +sub _systemd_services() { local $ENV{LANGUAGE} = 'C'; - my (@services, @xinetd_services); - foreach (run_program::rooted_get_stdout($::prefix, '/sbin/chkconfig', '--list')) { - if (my ($xinetd_name, $on_off) = m!^\t(\S+):\s*(on|off)!) { - push @xinetd_services, [ $xinetd_name, $on_off eq 'on' ]; - } elsif (my ($name, $l) = m!^(\S+)\s+(0:(on|off).*)!) { - push @services, [ $name, [ $l =~ /(\d+):on/g ] ]; - } + my @services; + # Running system using systemd + log::explanations("Detected systemd running. Using systemctl introspection."); + foreach (run_program::rooted_get_stdout($::prefix, '/bin/systemctl', '--full', '--all', 'list-units')) { + if (my ($name) = m!^(\S+)\.service\s+loaded!) { + # We only look at non-template, non-linked service files in /lib + # We also check for any non-masked sysvinit files as these are + # also handled by systemd + if ($name !~ /.*\@$/g && (-e "$::prefix/lib/systemd/system/$name.service" or -e "$::prefix/etc/rc.d/init.d/$name") && ! -l "$::prefix/lib/systemd/system/$name.service") { + push @services, [ $name, !!run_program::rooted($::prefix, '/bin/systemctl', '--quiet', 'is-enabled', "$name.service") ]; + } + } + } + @services; +} + +sub _legacy_services() { + local $ENV{LANGUAGE} = 'C'; + my @services; + my $has_systemd = has_systemd(); + if ($has_systemd) { + # The system not using systemd but will be at next boot. This is + # is typically the case in the installer. In this mode we must read + # as much as is practicable from the native systemd unit files and + # combine that with information from chkconfig regarding legacy sysvinit + # scripts (which systemd will parse and include when running) + log::explanations("Detected systemd installed. Using fake service+chkconfig introspection."); + foreach (glob_("$::prefix/lib/systemd/system/*.service")) { + my ($name) = m!([^/]*).service$!; + + # We only look at non-template, non-symlinked service files + if (!(/.*\@\.service$/g) && ! -l $_) { + # Limit ourselves to "standard" targets + my $wantedby = cat_($_) =~ /^WantedBy=(graphical|multi-user).target$/sm ? $1 : ''; + if ($wantedby) { + # Exclude if enabled statically + # Note DO NOT use -e when testing for files that could + # be symbolic links as this will fail under a chroot + # setup where -e will fail if the symlink target does + # exist which is typically the case when viewed outside + # of the chroot. + if (!-l "$::prefix/lib/systemd/system/$wantedby.target.wants/$name.service") { + push @services, [ $name, !!-l "$::prefix/etc/systemd/system/$wantedby.target.wants/$name.service" ]; + } + } + } + } + } else { + log::explanations("Could not detect systemd. Using chkconfig service introspection."); + } + + # Regardless of whether we expect to use systemd on next boot, we still + # need to instrospect information about non-systemd native services. + my $runlevel; + my $on_off; + if (!$::isInstall) { + $runlevel = (split " ", `/sbin/runlevel`)[1]; } - \@services, \@xinetd_services; + foreach (run_program::rooted_get_stdout($::prefix, '/sbin/chkconfig', '--list', '--type', 'sysv')) { + if (my ($name, $l) = m!^(\S+)\s+(0:(on|off).*)!) { + # If we expect to use systemd (i.e. installer) only show those + # sysvinit scripts which are not masked by a native systemd unit. + my $has_systemd_unit = (-e "$::prefix/lib/systemd/system/$name.service" or -l "$::prefix/lib/systemd/system/$name.service"); + if (!$has_systemd || !$has_systemd_unit) { + if ($::isInstall) { + $on_off = $l =~ /\d+:on/g; + } else { + $on_off = $l =~ /$runlevel:on/g; + } + push @services, [ $name, $on_off ]; + } + } + } + @services; } -#- returns: +#- returns: #--- the listref of installed services #--- the listref of "on" services sub services() { - my ($services, $xinetd_services) = services_raw(); - my @l = @$xinetd_services; - if ($::isInstall) { - push @l, map { [ $_->[0], @{$_->[1]} > 0 ] } @$services; + my @services; + if (running_systemd()) { + @services = _systemd_services(); } else { - my $runlevel = (split " ", `/sbin/runlevel`)[1]; - push @l, map { [ $_->[0], member($runlevel, @{$_->[1]}) ] } @$services; + @services = _legacy_services(); } + + my @l = xinetd_services(); + push @l, @services; @l = sort { $a->[0] cmp $b->[0] } @l; [ map { $_->[0] } @l ], [ map { $_->[0] } grep { $_->[1] } @l ]; } -- cgit v1.2.1