summaryrefslogtreecommitdiffstats
path: root/meta/classes-recipe/systemd.bbclass
diff options
context:
space:
mode:
Diffstat (limited to 'meta/classes-recipe/systemd.bbclass')
-rw-r--r--meta/classes-recipe/systemd.bbclass204
1 files changed, 131 insertions, 73 deletions
diff --git a/meta/classes-recipe/systemd.bbclass b/meta/classes-recipe/systemd.bbclass
index 48b364c1d4..12c59647be 100644
--- a/meta/classes-recipe/systemd.bbclass
+++ b/meta/classes-recipe/systemd.bbclass
@@ -37,17 +37,29 @@ if systemctl >/dev/null 2>/dev/null; then
37 fi 37 fi
38 38
39 if [ "${SYSTEMD_AUTO_ENABLE}" = "enable" ]; then 39 if [ "${SYSTEMD_AUTO_ENABLE}" = "enable" ]; then
40 for service in ${SYSTEMD_SERVICE_ESCAPED}; do 40 for service in ${@systemd_filter_services("${SYSTEMD_SERVICE_ESCAPED}", False, d)}; do
41 systemctl ${OPTS} enable "$service" 41 systemctl ${OPTS} enable "$service"
42 done 42 done
43
44 for service in ${@systemd_filter_services("${SYSTEMD_SERVICE_ESCAPED}", True, d)}; do
45 systemctl --global ${OPTS} enable "$service"
46 done
43 fi 47 fi
44 48
45 if [ -z "$D" ]; then 49 if [ -z "$D" ]; then
50 # Reload only system service manager
51 # --global for daemon-reload is not supported: https://github.com/systemd/systemd/issues/19284
46 systemctl daemon-reload 52 systemctl daemon-reload
47 systemctl preset ${SYSTEMD_SERVICE_ESCAPED} 53 [ -n "${@systemd_filter_services("${SYSTEMD_SERVICE_ESCAPED}", False, d)}" ] && \
54 systemctl preset ${@systemd_filter_services("${SYSTEMD_SERVICE_ESCAPED}", False, d)}
55
56 [ -n "${@systemd_filter_services("${SYSTEMD_SERVICE_ESCAPED}", True, d)}" ] && \
57 systemctl --global preset ${@systemd_filter_services("${SYSTEMD_SERVICE_ESCAPED}", True, d)}
48 58
49 if [ "${SYSTEMD_AUTO_ENABLE}" = "enable" ]; then 59 if [ "${SYSTEMD_AUTO_ENABLE}" = "enable" ]; then
50 systemctl --no-block restart ${SYSTEMD_SERVICE_ESCAPED} 60 # --global flag for restart is not supported by systemd (see above)
61 [ -n "${@systemd_filter_services("${SYSTEMD_SERVICE_ESCAPED}", False, d)}" ] && \
62 systemctl --no-block restart ${@systemd_filter_services("${SYSTEMD_SERVICE_ESCAPED}", False, d)}
51 fi 63 fi
52 fi 64 fi
53fi 65fi
@@ -56,9 +68,14 @@ fi
56systemd_prerm() { 68systemd_prerm() {
57if systemctl >/dev/null 2>/dev/null; then 69if systemctl >/dev/null 2>/dev/null; then
58 if [ -z "$D" ]; then 70 if [ -z "$D" ]; then
59 systemctl stop ${SYSTEMD_SERVICE_ESCAPED} 71 if [ -n "${@systemd_filter_services("${SYSTEMD_SERVICE_ESCAPED}", False, d)}" ]; then
72 systemctl stop ${@systemd_filter_services("${SYSTEMD_SERVICE_ESCAPED}", False, d)}
73 systemctl disable ${@systemd_filter_services("${SYSTEMD_SERVICE_ESCAPED}", False, d)}
74 fi
60 75
61 systemctl disable ${SYSTEMD_SERVICE_ESCAPED} 76 # same as above, --global flag is not supported for stop so do disable only
77 [ -n "${@systemd_filter_services("${SYSTEMD_SERVICE_ESCAPED}", True, d)}" ] && \
78 systemctl --global disable ${@systemd_filter_services("${SYSTEMD_SERVICE_ESCAPED}", True, d)}
62 fi 79 fi
63fi 80fi
64} 81}
@@ -68,6 +85,49 @@ systemd_populate_packages[vardeps] += "systemd_prerm systemd_postinst"
68systemd_populate_packages[vardepsexclude] += "OVERRIDES" 85systemd_populate_packages[vardepsexclude] += "OVERRIDES"
69 86
70 87
88def systemd_service_path(service, searchpaths, d):
89 path_found = ''
90
91 # Deal with adding, for example, 'ifplugd@eth0.service' from
92 # 'ifplugd@.service'
93 base = None
94 at = service.find('@')
95 if at != -1:
96 ext = service.rfind('.')
97 base = service[:at] + '@' + service[ext:]
98
99 for path in searchpaths:
100 if os.path.lexists(oe.path.join(d.getVar("D"), path, service)):
101 path_found = path
102 break
103 elif base is not None:
104 if os.path.exists(oe.path.join(d.getVar("D"), path, base)):
105 path_found = path
106 break
107
108 return path_found, base
109
110def systemd_service_searchpaths(user, d):
111 if user:
112 return [
113 oe.path.join(d.getVar("sysconfdir"), "systemd", "user"),
114 d.getVar("systemd_user_unitdir"),
115 ]
116 else:
117 return [
118 oe.path.join(d.getVar("sysconfdir"), "systemd", "system"),
119 d.getVar("systemd_system_unitdir"),
120 ]
121
122def systemd_service_exists(service, user, d):
123 searchpaths = systemd_service_searchpaths(user, d)
124 path, _ = systemd_service_path(service, searchpaths, d)
125
126 return path != ''
127
128def systemd_filter_services(services, user, d):
129 return ' '.join(service for service in services.split() if systemd_service_exists(service, user, d))
130
71python systemd_populate_packages() { 131python systemd_populate_packages() {
72 import re 132 import re
73 import shlex 133 import shlex
@@ -85,7 +145,7 @@ python systemd_populate_packages() {
85 def systemd_check_package(pkg_systemd): 145 def systemd_check_package(pkg_systemd):
86 packages = d.getVar('PACKAGES') 146 packages = d.getVar('PACKAGES')
87 if not pkg_systemd in packages.split(): 147 if not pkg_systemd in packages.split():
88 bb.error('%s does not appear in package list, please add it' % pkg_systemd) 148 bb.error('%s is marked for packaging systemd scripts, but it does not appear in package list, please add it to PACKAGES or adjust SYSTEMD_PACKAGES accordingly' % pkg_systemd)
89 149
90 150
91 def systemd_generate_package_scripts(pkg): 151 def systemd_generate_package_scripts(pkg):
@@ -124,73 +184,75 @@ python systemd_populate_packages() {
124 return appended 184 return appended
125 185
126 # Add systemd files to FILES:*-systemd, parse for Also= and follow recursive 186 # Add systemd files to FILES:*-systemd, parse for Also= and follow recursive
127 def systemd_add_files_and_parse(pkg_systemd, path, service, keys): 187 def systemd_add_files_and_parse(pkg_systemd, path, service):
128 # avoid infinite recursion 188 # avoid infinite recursion
129 if systemd_append_file(pkg_systemd, oe.path.join(path, service)): 189 if systemd_append_file(pkg_systemd, oe.path.join(path, service)):
130 fullpath = oe.path.join(d.getVar("D"), path, service) 190 fullpath = oe.path.join(d.getVar("D"), path, service)
131 if service.find('.service') != -1: 191 if service.find('.service') != -1:
132 # for *.service add *@.service 192 # for *.service add *@.service
133 service_base = service.replace('.service', '') 193 service_base = service.replace('.service', '')
134 systemd_add_files_and_parse(pkg_systemd, path, service_base + '@.service', keys) 194 systemd_add_files_and_parse(pkg_systemd, path, service_base + '@.service')
195 # Add the socket unit which is referred by the Also= in this service file to the same package.
196 with open(fullpath, 'r') as unit_f:
197 for line in unit_f:
198 if line.startswith('Also'):
199 also_unit = line.split('=', 1)[1].strip()
200 if also_unit.find('.socket') != -1:
201 systemd_add_files_and_parse(pkg_systemd, path, also_unit)
135 if service.find('.socket') != -1: 202 if service.find('.socket') != -1:
136 # for *.socket add *.service and *@.service 203 # for *.socket add *.service and *@.service
137 service_base = service.replace('.socket', '') 204 service_base = service.replace('.socket', '')
138 systemd_add_files_and_parse(pkg_systemd, path, service_base + '.service', keys) 205 systemd_add_files_and_parse(pkg_systemd, path, service_base + '.service')
139 systemd_add_files_and_parse(pkg_systemd, path, service_base + '@.service', keys) 206 systemd_add_files_and_parse(pkg_systemd, path, service_base + '@.service')
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 207
151 # Check service-files and call systemd_add_files_and_parse for each entry 208 # Check service-files and call systemd_add_files_and_parse for each entry
152 def systemd_check_services(): 209 def systemd_check_services():
153 searchpaths = [oe.path.join(d.getVar("sysconfdir"), "systemd", "system"),] 210 searchpaths = systemd_service_searchpaths(False, d)
154 searchpaths.append(d.getVar("systemd_system_unitdir")) 211 searchpaths.extend(systemd_service_searchpaths(True, d))
155 searchpaths.append(d.getVar("systemd_user_unitdir")) 212
156 systemd_packages = d.getVar('SYSTEMD_PACKAGES') 213 systemd_packages = d.getVar('SYSTEMD_PACKAGES')
157 214
158 keys = 'Also'
159 # scan for all in SYSTEMD_SERVICE[] 215 # scan for all in SYSTEMD_SERVICE[]
160 for pkg_systemd in systemd_packages.split(): 216 for pkg_systemd in systemd_packages.split():
161 for service in get_package_var(d, 'SYSTEMD_SERVICE', pkg_systemd).split(): 217 for service in get_package_var(d, 'SYSTEMD_SERVICE', pkg_systemd).split():
162 path_found = '' 218 path_found, base = systemd_service_path(service, searchpaths, d)
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 219
181 if path_found != '': 220 if path_found != '':
182 systemd_add_files_and_parse(pkg_systemd, path_found, service, keys) 221 systemd_add_files_and_parse(pkg_systemd, path_found, service)
183 else: 222 else:
184 bb.fatal("Didn't find service unit '{0}', specified in SYSTEMD_SERVICE:{1}. {2}".format( 223 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 "")) 224 service, pkg_systemd, "Also looked for service unit '{0}'.".format(base) if base is not None else ""))
186 225
187 def systemd_create_presets(pkg, action): 226 def systemd_create_presets(pkg, action, user):
188 presetf = oe.path.join(d.getVar("PKGD"), d.getVar("systemd_unitdir"), "system-preset/98-%s.preset" % pkg) 227 import re
228
229 # Check there is at least one service of given type (system/user), don't
230 # create empty files.
231 needs_preset = False
232 for service in d.getVar('SYSTEMD_SERVICE:%s' % pkg).split():
233 if systemd_service_exists(service, user, d):
234 needs_preset = True
235 break
236
237 if not needs_preset:
238 return
239
240 prefix = "user" if user else "system"
241 presetf = oe.path.join(d.getVar("PKGD"), d.getVar("systemd_unitdir"), "%s-preset/98-%s.preset" % (prefix, pkg))
189 bb.utils.mkdirhier(os.path.dirname(presetf)) 242 bb.utils.mkdirhier(os.path.dirname(presetf))
190 with open(presetf, 'a') as fd: 243 with open(presetf, 'a') as fd:
244 template_services = {}
191 for service in d.getVar('SYSTEMD_SERVICE:%s' % pkg).split(): 245 for service in d.getVar('SYSTEMD_SERVICE:%s' % pkg).split():
192 fd.write("%s %s\n" % (action,service)) 246 if not systemd_service_exists(service, user, d):
193 d.appendVar("FILES:%s" % pkg, ' ' + oe.path.join(d.getVar("systemd_unitdir"), "system-preset/98-%s.preset" % pkg)) 247 continue
248 if '@' in service and '@.' not in service:
249 (servicename, instance, service_type) = re.split('[@.]', service)
250 template_services.setdefault(servicename + '@.' + service_type, []).append(instance)
251 else:
252 fd.write("%s %s\n" % (action,service))
253 for template, instances in template_services.items():
254 fd.write("%s %s %s\n" % (action, template, ' '.join(instances)))
255 d.appendVar("FILES:%s" % pkg, ' ' + oe.path.join(d.getVar("systemd_unitdir"), "%s-preset/98-%s.preset" % (prefix, pkg)))
194 256
195 # Run all modifications once when creating package 257 # Run all modifications once when creating package
196 if os.path.exists(d.getVar("D")): 258 if os.path.exists(d.getVar("D")):
@@ -200,7 +262,8 @@ python systemd_populate_packages() {
200 systemd_generate_package_scripts(pkg) 262 systemd_generate_package_scripts(pkg)
201 action = get_package_var(d, 'SYSTEMD_AUTO_ENABLE', pkg) 263 action = get_package_var(d, 'SYSTEMD_AUTO_ENABLE', pkg)
202 if action in ("enable", "disable"): 264 if action in ("enable", "disable"):
203 systemd_create_presets(pkg, action) 265 systemd_create_presets(pkg, action, False)
266 systemd_create_presets(pkg, action, True)
204 elif action not in ("mask", "preset"): 267 elif action not in ("mask", "preset"):
205 bb.fatal("SYSTEMD_AUTO_ENABLE:%s '%s' is not 'enable', 'disable', 'mask' or 'preset'" % (pkg, action)) 268 bb.fatal("SYSTEMD_AUTO_ENABLE:%s '%s' is not 'enable', 'disable', 'mask' or 'preset'" % (pkg, action))
206 systemd_check_services() 269 systemd_check_services()
@@ -208,33 +271,28 @@ python systemd_populate_packages() {
208 271
209PACKAGESPLITFUNCS =+ "systemd_populate_packages" 272PACKAGESPLITFUNCS =+ "systemd_populate_packages"
210 273
211python rm_systemd_unitdir (){ 274rm_systemd_unitdir() {
212 import shutil 275 rm -rf ${D}${systemd_unitdir}
213 if not bb.utils.contains('DISTRO_FEATURES', 'systemd', True, False, d): 276 # Change into ${D} and use a relative path with rmdir -p to avoid
214 systemd_unitdir = oe.path.join(d.getVar("D"), d.getVar('systemd_unitdir')) 277 # having it remove ${D} if it becomes empty.
215 if os.path.exists(systemd_unitdir): 278 (cd ${D} && rmdir -p $(dirname ${systemd_unitdir#/}) 2>/dev/null || :)
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} 279}
221 280
222python rm_sysvinit_initddir (){ 281rm_sysvinit_initddir() {
223 import shutil 282 local sysv_initddir=${INIT_D_DIR}
224 sysv_initddir = oe.path.join(d.getVar("D"), (d.getVar('INIT_D_DIR') or "/etc/init.d")) 283 : ${sysv_initddir:=${sysconfdir}/init.d}
225 284
226 if bb.utils.contains('DISTRO_FEATURES', 'systemd', True, False, d) and \ 285 # If systemd_system_unitdir contains anything, delete sysv_initddir
227 not bb.utils.contains('DISTRO_FEATURES', 'sysvinit', True, False, d) and \ 286 if [ "$(ls -A ${D}${systemd_system_unitdir} 2>/dev/null)" ]; then
228 os.path.exists(sysv_initddir): 287 rm -rf ${D}$sysv_initddir
229 systemd_system_unitdir = oe.path.join(d.getVar("D"), d.getVar('systemd_system_unitdir')) 288 rmdir -p $(dirname ${D}$sysv_initddir) 2>/dev/null || :
230 289 fi
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} 290}
235 291
236do_install[postfuncs] += "${RMINITDIR} " 292do_install[postfuncs] += "${RMINITDIR}"
237RMINITDIR:class-target = " rm_sysvinit_initddir rm_systemd_unitdir " 293RMINITDIR = " \
238RMINITDIR:class-nativesdk = " rm_sysvinit_initddir rm_systemd_unitdir " 294 ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', '', 'rm_systemd_unitdir', d)} \
239RMINITDIR = "" 295 ${@'rm_sysvinit_initddir' if bb.utils.contains('DISTRO_FEATURES', 'systemd', True, False, d) and \
240 296 not bb.utils.contains('DISTRO_FEATURES', 'sysvinit', True, False, d) else ''} \
297"
298RMINITDIR:class-native = ""