blob: 48b364c1d4d906d0ae6cb717e983122ec47d00a9 [file] [log] [blame]
Patrick Williams92b42cb2022-09-03 06:53:57 -05001#
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"))
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500155 searchpaths.append(d.getVar("systemd_user_unitdir"))
Patrick Williams92b42cb2022-09-03 06:53:57 -0500156 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:
Patrick Williams73bd93f2024-02-20 08:07:48 -0600173 if os.path.lexists(oe.path.join(d.getVar("D"), path, service)):
Patrick Williams92b42cb2022-09-03 06:53:57 -0500174 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
Andrew Geissler517393d2023-01-13 08:55:19 -0600209PACKAGESPLITFUNCS =+ "systemd_populate_packages"
Patrick Williams92b42cb2022-09-03 06:53:57 -0500210
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