1# 2# Copyright OpenEmbedded Contributors 3# 4# SPDX-License-Identifier: MIT 5# 6 7# The list of packages that should have systemd packaging scripts added. For 8# each entry, optionally have a SYSTEMD_SERVICE:[package] that lists the service 9# files in this package. If this variable isn't set, [package].service is used. 10SYSTEMD_PACKAGES ?= "${PN}" 11SYSTEMD_PACKAGES:class-native ?= "" 12SYSTEMD_PACKAGES:class-nativesdk ?= "" 13 14# Whether to enable or disable the services on installation. 15SYSTEMD_AUTO_ENABLE ??= "enable" 16 17# This class will be included in any recipe that supports systemd init scripts, 18# even if systemd is not in DISTRO_FEATURES. As such don't make any changes 19# directly but check the DISTRO_FEATURES first. 20python __anonymous() { 21 # If the distro features have systemd but not sysvinit, inhibit update-rcd 22 # from doing any work so that pure-systemd images don't have redundant init 23 # files. 24 if bb.utils.contains('DISTRO_FEATURES', 'systemd', True, False, d): 25 d.appendVar("DEPENDS", " systemd-systemctl-native") 26 d.appendVar("PACKAGE_WRITE_DEPS", " systemd-systemctl-native") 27 if not bb.utils.contains('DISTRO_FEATURES', 'sysvinit', True, False, d): 28 d.setVar("INHIBIT_UPDATERCD_BBCLASS", "1") 29} 30 31systemd_postinst() { 32if systemctl >/dev/null 2>/dev/null; then 33 OPTS="" 34 35 if [ -n "$D" ]; then 36 OPTS="--root=$D" 37 fi 38 39 if [ "${SYSTEMD_AUTO_ENABLE}" = "enable" ]; then 40 for service in ${SYSTEMD_SERVICE_ESCAPED}; do 41 systemctl ${OPTS} enable "$service" 42 done 43 fi 44 45 if [ -z "$D" ]; then 46 systemctl daemon-reload 47 systemctl preset ${SYSTEMD_SERVICE_ESCAPED} 48 49 if [ "${SYSTEMD_AUTO_ENABLE}" = "enable" ]; then 50 systemctl --no-block restart ${SYSTEMD_SERVICE_ESCAPED} 51 fi 52 fi 53fi 54} 55 56systemd_prerm() { 57if systemctl >/dev/null 2>/dev/null; then 58 if [ -z "$D" ]; then 59 systemctl stop ${SYSTEMD_SERVICE_ESCAPED} 60 61 systemctl disable ${SYSTEMD_SERVICE_ESCAPED} 62 fi 63fi 64} 65 66 67systemd_populate_packages[vardeps] += "systemd_prerm systemd_postinst" 68systemd_populate_packages[vardepsexclude] += "OVERRIDES" 69 70 71python systemd_populate_packages() { 72 import re 73 import shlex 74 75 if not bb.utils.contains('DISTRO_FEATURES', 'systemd', True, False, d): 76 return 77 78 def get_package_var(d, var, pkg): 79 val = (d.getVar('%s:%s' % (var, pkg)) or "").strip() 80 if val == "": 81 val = (d.getVar(var) or "").strip() 82 return val 83 84 # Check if systemd-packages already included in PACKAGES 85 def systemd_check_package(pkg_systemd): 86 packages = d.getVar('PACKAGES') 87 if not pkg_systemd in packages.split(): 88 bb.error('%s does not appear in package list, please add it' % pkg_systemd) 89 90 91 def systemd_generate_package_scripts(pkg): 92 bb.debug(1, 'adding systemd calls to postinst/postrm for %s' % pkg) 93 94 paths_escaped = ' '.join(shlex.quote(s) for s in d.getVar('SYSTEMD_SERVICE:' + pkg).split()) 95 d.setVar('SYSTEMD_SERVICE_ESCAPED:' + pkg, paths_escaped) 96 97 # Add pkg to the overrides so that it finds the SYSTEMD_SERVICE:pkg 98 # variable. 99 localdata = d.createCopy() 100 localdata.prependVar("OVERRIDES", pkg + ":") 101 102 postinst = d.getVar('pkg_postinst:%s' % pkg) 103 if not postinst: 104 postinst = '#!/bin/sh\n' 105 postinst += localdata.getVar('systemd_postinst') 106 d.setVar('pkg_postinst:%s' % pkg, postinst) 107 108 prerm = d.getVar('pkg_prerm:%s' % pkg) 109 if not prerm: 110 prerm = '#!/bin/sh\n' 111 prerm += localdata.getVar('systemd_prerm') 112 d.setVar('pkg_prerm:%s' % pkg, prerm) 113 114 115 # Add files to FILES:*-systemd if existent and not already done 116 def systemd_append_file(pkg_systemd, file_append): 117 appended = False 118 if os.path.exists(oe.path.join(d.getVar("D"), file_append)): 119 var_name = "FILES:" + pkg_systemd 120 files = d.getVar(var_name, False) or "" 121 if file_append not in files.split(): 122 d.appendVar(var_name, " " + file_append) 123 appended = True 124 return appended 125 126 # Add systemd files to FILES:*-systemd, parse for Also= and follow recursive 127 def systemd_add_files_and_parse(pkg_systemd, path, service, keys): 128 # avoid infinite recursion 129 if systemd_append_file(pkg_systemd, oe.path.join(path, service)): 130 fullpath = oe.path.join(d.getVar("D"), path, service) 131 if service.find('.service') != -1: 132 # for *.service add *@.service 133 service_base = service.replace('.service', '') 134 systemd_add_files_and_parse(pkg_systemd, path, service_base + '@.service', keys) 135 if service.find('.socket') != -1: 136 # for *.socket add *.service and *@.service 137 service_base = service.replace('.socket', '') 138 systemd_add_files_and_parse(pkg_systemd, path, service_base + '.service', keys) 139 systemd_add_files_and_parse(pkg_systemd, path, service_base + '@.service', keys) 140 for key in keys.split(): 141 # recurse all dependencies found in keys ('Also';'Conflicts';..) and add to files 142 cmd = "grep %s %s | sed 's,%s=,,g' | tr ',' '\\n'" % (key, shlex.quote(fullpath), key) 143 pipe = os.popen(cmd, 'r') 144 line = pipe.readline() 145 while line: 146 line = line.replace('\n', '') 147 systemd_add_files_and_parse(pkg_systemd, path, line, keys) 148 line = pipe.readline() 149 pipe.close() 150 151 # Check service-files and call systemd_add_files_and_parse for each entry 152 def systemd_check_services(): 153 searchpaths = [oe.path.join(d.getVar("sysconfdir"), "systemd", "system"),] 154 searchpaths.append(d.getVar("systemd_system_unitdir")) 155 searchpaths.append(d.getVar("systemd_user_unitdir")) 156 systemd_packages = d.getVar('SYSTEMD_PACKAGES') 157 158 keys = 'Also' 159 # scan for all in SYSTEMD_SERVICE[] 160 for pkg_systemd in systemd_packages.split(): 161 for service in get_package_var(d, 'SYSTEMD_SERVICE', pkg_systemd).split(): 162 path_found = '' 163 164 # Deal with adding, for example, 'ifplugd@eth0.service' from 165 # 'ifplugd@.service' 166 base = None 167 at = service.find('@') 168 if at != -1: 169 ext = service.rfind('.') 170 base = service[:at] + '@' + service[ext:] 171 172 for path in searchpaths: 173 if os.path.lexists(oe.path.join(d.getVar("D"), path, service)): 174 path_found = path 175 break 176 elif base is not None: 177 if os.path.exists(oe.path.join(d.getVar("D"), path, base)): 178 path_found = path 179 break 180 181 if path_found != '': 182 systemd_add_files_and_parse(pkg_systemd, path_found, service, keys) 183 else: 184 bb.fatal("Didn't find service unit '{0}', specified in SYSTEMD_SERVICE:{1}. {2}".format( 185 service, pkg_systemd, "Also looked for service unit '{0}'.".format(base) if base is not None else "")) 186 187 def systemd_create_presets(pkg, action): 188 presetf = oe.path.join(d.getVar("PKGD"), d.getVar("systemd_unitdir"), "system-preset/98-%s.preset" % pkg) 189 bb.utils.mkdirhier(os.path.dirname(presetf)) 190 with open(presetf, 'a') as fd: 191 for service in d.getVar('SYSTEMD_SERVICE:%s' % pkg).split(): 192 fd.write("%s %s\n" % (action,service)) 193 d.appendVar("FILES:%s" % pkg, ' ' + oe.path.join(d.getVar("systemd_unitdir"), "system-preset/98-%s.preset" % pkg)) 194 195 # Run all modifications once when creating package 196 if os.path.exists(d.getVar("D")): 197 for pkg in d.getVar('SYSTEMD_PACKAGES').split(): 198 systemd_check_package(pkg) 199 if d.getVar('SYSTEMD_SERVICE:' + pkg): 200 systemd_generate_package_scripts(pkg) 201 action = get_package_var(d, 'SYSTEMD_AUTO_ENABLE', pkg) 202 if action in ("enable", "disable"): 203 systemd_create_presets(pkg, action) 204 elif action not in ("mask", "preset"): 205 bb.fatal("SYSTEMD_AUTO_ENABLE:%s '%s' is not 'enable', 'disable', 'mask' or 'preset'" % (pkg, action)) 206 systemd_check_services() 207} 208 209PACKAGESPLITFUNCS =+ "systemd_populate_packages" 210 211python rm_systemd_unitdir (){ 212 import shutil 213 if not bb.utils.contains('DISTRO_FEATURES', 'systemd', True, False, d): 214 systemd_unitdir = oe.path.join(d.getVar("D"), d.getVar('systemd_unitdir')) 215 if os.path.exists(systemd_unitdir): 216 shutil.rmtree(systemd_unitdir) 217 systemd_libdir = os.path.dirname(systemd_unitdir) 218 if (os.path.exists(systemd_libdir) and not os.listdir(systemd_libdir)): 219 os.rmdir(systemd_libdir) 220} 221 222python rm_sysvinit_initddir (){ 223 import shutil 224 sysv_initddir = oe.path.join(d.getVar("D"), (d.getVar('INIT_D_DIR') or "/etc/init.d")) 225 226 if bb.utils.contains('DISTRO_FEATURES', 'systemd', True, False, d) and \ 227 not bb.utils.contains('DISTRO_FEATURES', 'sysvinit', True, False, d) and \ 228 os.path.exists(sysv_initddir): 229 systemd_system_unitdir = oe.path.join(d.getVar("D"), d.getVar('systemd_system_unitdir')) 230 231 # If systemd_system_unitdir contains anything, delete sysv_initddir 232 if (os.path.exists(systemd_system_unitdir) and os.listdir(systemd_system_unitdir)): 233 shutil.rmtree(sysv_initddir) 234} 235 236do_install[postfuncs] += "${RMINITDIR} " 237RMINITDIR:class-target = " rm_sysvinit_initddir rm_systemd_unitdir " 238RMINITDIR:class-nativesdk = " rm_sysvinit_initddir rm_systemd_unitdir " 239RMINITDIR = "" 240 241