From 7a025f125cbe7c0b0acebca8be8a99e8758a6ef9 Mon Sep 17 00:00:00 2001 From: Colin Guthrie Date: Thu, 16 Feb 2012 14:14:41 +0000 Subject: Migrate service enabled/disabled status from sysvinit to systemd on upgrade --- Makefile | 6 ++- NEWS | 6 ++- README.systemd | 8 +++ add-service | 155 ++++++++++++++++++++++++++++++++++++++++++++++++--------- 4 files changed, 148 insertions(+), 27 deletions(-) create mode 100644 README.systemd diff --git a/Makefile b/Makefile index d1cce64..5838e45 100644 --- a/Makefile +++ b/Makefile @@ -12,12 +12,14 @@ MACROS_FILES = rpm-helper.macros CONF_FILES = ssl TEST_FILES = t/*.t FILES = AUTHORS README COPYING NEWS Makefile \ - $(SCRIPT_FILES) $(MACROS_FILES:=.in) $(CONF_FILES) \ + $(SCRIPT_FILES) $(MACROS_FILES:=.in) $(CONF_FILES) \ $(TEST_FILES) +SYSTEMDMIGRATION_FILES = README.systemd pkgdatadir = /usr/share/$(PACKAGE) rpmmacrosdir = /etc/rpm/macros.d sysconfigdir = /etc/sysconfig +systemdmigrationdir = /var/lib/rpm-helper/systemd-migration all: @echo "use make install or make dist" @@ -29,6 +31,8 @@ install: $(MACROS_FILES) install -m 644 $(MACROS_FILES) $(DESTDIR)/$(rpmmacrosdir) install -d -m 755 $(DESTDIR)$(sysconfigdir) install -m 644 $(CONF_FILES) $(DESTDIR)/$(sysconfigdir) + install -d -m 755 $(DESTDIR)$(systemdmigrationdir) + install -m 644 $(SYSTEMDMIGRATION_FILES) $(DESTDIR)/$(systemdmigrationdir) rpm-helper.macros: rpm-helper.macros.in sed -e 's:@pkgdatadir@:$(pkgdatadir):' < $< > $@ diff --git a/NEWS b/NEWS index e74ba07..8d96916 100644 --- a/NEWS +++ b/NEWS @@ -1,7 +1,9 @@ - * Silent enable/disable services + * Silent enable/disable services + * Migrate service enabled/disabled status from sysvinit to systemd + on upgrade 2011-11-03 D Morgan 0.24.5 - * Add support for systemd .path files + * Add support for systemd .path files 2011-11-03 Colin Guthrie 0.24.4 * fix up missing file in the Makefile diff --git a/README.systemd b/README.systemd new file mode 100644 index 0000000..db76ef8 --- /dev/null +++ b/README.systemd @@ -0,0 +1,8 @@ +This folder is used to track systemd migration. + +When you install an updated package that contains a native systemd unit which +supersedes the legacy sysvinit script, the fact that the service is enabled or +not must be migrated to the systemd way of doing things. + +This folder is simply a place to store a note of which services have been +migrated, such that the process is not repeated on subsequent package updates. diff --git a/add-service b/add-service index fb17a43..bd51d86 100755 --- a/add-service +++ b/add-service @@ -40,31 +40,55 @@ else fi units="$*" # systemd units units_to_enable= # units enabled by msec +systemd_migration_dir=/var/lib/rpm-helper/systemd-migration +mkdir -p "${systemd_migration_dir}" + +SYSTEMUNITDIR=/lib/systemd/system +USERUNITDIR=/etc/systemd/system +RUNTIMEUNITDIR=/run/systemd/system + +find_unit() { + unit=$(basename $1) + + # We need to normalise the systemd unit name as the native unit may not have + # the same filename (sans it's .service suffix) as sysvinit script. + # In this case, symlinks are used to mask the sysvinit file, but for enabling + # and disabling units we must use the official name. + + searchunit= + if [ -f "$SYSTEMUNITDIR/$unit" ]; then + if [ -L "$SYSTEMUNITDIR/$unit" ]; then + searchunit=$(/usr/bin/readlink "$SYSTEMUNITDIR/$unit") + else + searchunit="$SYSTEMUNITDIR/$unit" + fi + elif [ -f "$USERUNITDIR/$unit" ]; then + if [ -L "$USERUNITDIR/$unit" ]; then + searchunit=$(/usr/bin/readlink "$USERUNITDIR/$unit") + else + searchunit="$USERUNITDIR/$unit" + fi + elif [ -f "$RUNTIMEUNITDIR/$unit" ]; then + if [ -L "$RUNTIMEUNITDIR/$unit" ]; then + searchunit=$(/usr/bin/readlink "$RUNTIMEUNITDIR/$unit") + else + searchunit="$RUNTIMEUNITDIR/$unit" + fi + fi + if [ -n "$searchunit" ]; then + echo -n $searchunit + fi +} + # If only a sysvinit service is given, then deal with a systemd unit of the same # name. Specific specs can enable specific unit names as needed but this should # catch the most common usage. if [ -z "$units" ]; then units="$srv.service" - - # We need to normalise the systemd unit name as the native unit may not have - # the same filename (sans it's .service suffix) as sysvinit script. - # In this case, symlinks are used to mask the sysvinit file, but for enabling - # and disabling units we must use the official name. - SYSTEMUNITDIR=/lib/systemd/system - USERUNITDIR=/etc/systemd/system - RUNTIMEUNITDIR=/run/systemd/system - - searchunit= - if [ -f "$SYSTEMUNITDIR/$units" ]; then - searchunit=$(/usr/bin/readlink "$SYSTEMUNITDIR/$units") - elif [ -f "$USERUNITDIR/$units" ]; then - searchunit=$(/usr/bin/readlink "$USERUNITDIR/$units") - elif [ -f "$RUNTIMEUNITDIR/$units" ]; then - searchunit=$(/usr/bin/readlink "$RUNTIMEUNITDIR/$units") - fi + searchunit=$(find_unit $units) if [ -n "$searchunit" ]; then - units=$searchunit + units=$(basename $searchunit) fi fi @@ -112,6 +136,12 @@ add_service() { if [ -n "$units_to_enable" ]; then /bin/systemctl --quiet enable $units_to_enable >/dev/null fi + + # When no native systemd unit exists, the above command will actually + # just end up running chkconfig anyway, but if a native systemd unit exists + # the legacy init script will not be enabled. + # In order to enable switching back ot sysvinit, we should enable the + # sysvinit scripts too. if [ -n "$srv" -a -f /etc/rc.d/init.d/$srv ]; then /sbin/chkconfig --add $srv @@ -131,20 +161,97 @@ add_service() { fi } +check_sysvinit_service() { + rl=$1 + srv=$2 + + set -- /etc/rc${rl}.d/S??$srv + if [ $# -gt 1 ]; then + echo 1>&2 "add-service: Error: $srv appears multiple times at runlevel $rl: $*" + fi + + echo -n $1 +} if [ $num = 1 ]; then # First install mode add_service else # Upgrade mode. + + # Handle migration to systemd. + # If a previously installed package only had a sysvinit script, but an + # updated package has a native systemd unit, we need to make sure we migrate + # any service enablement for various targets (née runlevels) + if [ -n "$srv" -a -n "$units" ]; then + if [ ! -f "${systemd_migration_dir}/$srv" ]; then + full_path_units= + for unit in $units; do + # We need a full path for the symlink. Also it's possible + # that $unit contains "foo.service" where foo is actually + # a sysvinit script and thus we'll not have anything native. + # We only consider a "migration" to have taken place when + # we genuinely have a native systemd unit. + unit=$(find_unit $unit) + if [ -n "$unit" ]; then + full_path_units="$full_path_units $unit" + fi + done + + if [ -n "$full_path_units" ]; then + enable_targets= + # We have not yet migrated this service + # First we check in which runlevels the legacy service is enabled + # Only bother checking runlevels 1 3 and 5 + script=$(check_sysvinit_service 1 $srv) + + # NB We only check that the link exists as the old sysvinit + # script may have been removed during migration to systemd + # native unit. + if [ -L "$script" ]; then + enable_targets="$enable_targets rescue.target" + fi + + script=$(check_sysvinit_service 3 $srv) + if [ -L "$script" ]; then + enable_targets="$enable_targets multi-user.target" + else + # As graphical.target includes everything in multi-user.target, + # we only need to check 5 when 3 does NOT give us a result. + script=$(check_sysvinit_service 5 $srv) + if [ -L "$script" ]; then + enable_targets="$enable_targets graphical.target" + fi + fi + + if [ -n "$enable_targets" ]; then + for enable_target in $enable_targets; do + wantsdir=$USERUNITDIR/${enable_target}.wants + mkdir -p $wantsdir + for unit in $full_path_units; do + if [ ! -f $wantsdir/$(basename $unit) ]; then + echo 1>&2 "Migrating sysvinit service '$srv' to systemd native unit '$(basename $unit)' for target '${enable_target}'" + ln -s $unit $wantsdir/$(basename $unit) + fi + done + done + if [ x$init = xsystemd ]; then + /bin/systemctl --system daemon-reload + fi + fi + + # It could be that a package is installed but not enabled. + # If that is the case, we should still consider it "migrated" + # even when we do not enable anything. + touch "${systemd_migration_dir}/$srv" + fi + fi + fi + if [ x$init = xsystemd ]; then /bin/systemctl --quiet try-restart $units elif [ -f /etc/rc.d/init.d/$srv ]; then - set -- /etc/rc3.d/S??$srv - if [ $# -gt 1 ]; then - echo 1>&2 "add-service: Error: $srv appears multiple times: $*" - fi - - if [ -f "$1" ]; then + script=$(check_sysvinit_service 3 $srv); + if [ -f "$script" ]; then /sbin/chkconfig --add $srv fi -- cgit v1.2.1