diff options
Diffstat (limited to 'meta/classes-recipe/systemd.bbclass')
-rw-r--r-- | meta/classes-recipe/systemd.bbclass | 204 |
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 |
53 | fi | 65 | fi |
@@ -56,9 +68,14 @@ fi | |||
56 | systemd_prerm() { | 68 | systemd_prerm() { |
57 | if systemctl >/dev/null 2>/dev/null; then | 69 | if 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 |
63 | fi | 80 | fi |
64 | } | 81 | } |
@@ -68,6 +85,49 @@ systemd_populate_packages[vardeps] += "systemd_prerm systemd_postinst" | |||
68 | systemd_populate_packages[vardepsexclude] += "OVERRIDES" | 85 | systemd_populate_packages[vardepsexclude] += "OVERRIDES" |
69 | 86 | ||
70 | 87 | ||
88 | def 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 | |||
110 | def 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 | |||
122 | def 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 | |||
128 | def systemd_filter_services(services, user, d): | ||
129 | return ' '.join(service for service in services.split() if systemd_service_exists(service, user, d)) | ||
130 | |||
71 | python systemd_populate_packages() { | 131 | python 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 | ||
209 | PACKAGESPLITFUNCS =+ "systemd_populate_packages" | 272 | PACKAGESPLITFUNCS =+ "systemd_populate_packages" |
210 | 273 | ||
211 | python rm_systemd_unitdir (){ | 274 | rm_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 | ||
222 | python rm_sysvinit_initddir (){ | 281 | rm_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 | ||
236 | do_install[postfuncs] += "${RMINITDIR} " | 292 | do_install[postfuncs] += "${RMINITDIR}" |
237 | RMINITDIR:class-target = " rm_sysvinit_initddir rm_systemd_unitdir " | 293 | RMINITDIR = " \ |
238 | RMINITDIR:class-nativesdk = " rm_sysvinit_initddir rm_systemd_unitdir " | 294 | ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', '', 'rm_systemd_unitdir', d)} \ |
239 | RMINITDIR = "" | 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 | " | ||
298 | RMINITDIR:class-native = "" | ||