diff options
Diffstat (limited to 'meta/recipes-core/systemd/systemd-systemctl/systemctl')
-rwxr-xr-x | meta/recipes-core/systemd/systemd-systemctl/systemctl | 61 |
1 files changed, 49 insertions, 12 deletions
diff --git a/meta/recipes-core/systemd/systemd-systemctl/systemctl b/meta/recipes-core/systemd/systemd-systemctl/systemctl index de733e255b..2229bc7b6d 100755 --- a/meta/recipes-core/systemd/systemd-systemctl/systemctl +++ b/meta/recipes-core/systemd/systemd-systemctl/systemctl | |||
@@ -11,6 +11,7 @@ import re | |||
11 | import sys | 11 | import sys |
12 | 12 | ||
13 | from collections import namedtuple | 13 | from collections import namedtuple |
14 | from itertools import chain | ||
14 | from pathlib import Path | 15 | from pathlib import Path |
15 | 16 | ||
16 | version = 1.0 | 17 | version = 1.0 |
@@ -25,12 +26,19 @@ locations = list() | |||
25 | 26 | ||
26 | class SystemdFile(): | 27 | class SystemdFile(): |
27 | """Class representing a single systemd configuration file""" | 28 | """Class representing a single systemd configuration file""" |
28 | def __init__(self, root, path): | 29 | |
30 | _clearable_keys = ['WantedBy'] | ||
31 | |||
32 | def __init__(self, root, path, instance_unit_name): | ||
29 | self.sections = dict() | 33 | self.sections = dict() |
30 | self._parse(root, path) | 34 | self._parse(root, path) |
31 | dirname = os.path.basename(path.name) + ".d" | 35 | dirname = os.path.basename(path.name) + ".d" |
32 | for location in locations: | 36 | for location in locations: |
33 | for path2 in sorted((root / location / "system" / dirname).glob("*.conf")): | 37 | files = (root / location / "system" / dirname).glob("*.conf") |
38 | if instance_unit_name: | ||
39 | inst_dirname = instance_unit_name + ".d" | ||
40 | files = chain(files, (root / location / "system" / inst_dirname).glob("*.conf")) | ||
41 | for path2 in sorted(files): | ||
34 | self._parse(root, path2) | 42 | self._parse(root, path2) |
35 | 43 | ||
36 | def _parse(self, root, path): | 44 | def _parse(self, root, path): |
@@ -75,6 +83,14 @@ class SystemdFile(): | |||
75 | v = m.group('value') | 83 | v = m.group('value') |
76 | if k not in section: | 84 | if k not in section: |
77 | section[k] = list() | 85 | section[k] = list() |
86 | |||
87 | # If we come across a "key=" line for a "clearable key", then | ||
88 | # forget all preceding assignments. This works because we are | ||
89 | # processing files in correct parse order. | ||
90 | if k in self._clearable_keys and not v: | ||
91 | del section[k] | ||
92 | continue | ||
93 | |||
78 | section[k].extend(v.split()) | 94 | section[k].extend(v.split()) |
79 | 95 | ||
80 | def get(self, section, prop): | 96 | def get(self, section, prop): |
@@ -160,7 +176,9 @@ def add_link(path, target): | |||
160 | 176 | ||
161 | 177 | ||
162 | class SystemdUnitNotFoundError(Exception): | 178 | class SystemdUnitNotFoundError(Exception): |
163 | pass | 179 | def __init__(self, path, unit): |
180 | self.path = path | ||
181 | self.unit = unit | ||
164 | 182 | ||
165 | 183 | ||
166 | class SystemdUnit(): | 184 | class SystemdUnit(): |
@@ -177,24 +195,29 @@ class SystemdUnit(): | |||
177 | 195 | ||
178 | raise SystemdUnitNotFoundError(self.root, unit) | 196 | raise SystemdUnitNotFoundError(self.root, unit) |
179 | 197 | ||
180 | def _process_deps(self, config, service, location, prop, dirstem): | 198 | def _process_deps(self, config, service, location, prop, dirstem, instance): |
181 | systemdir = self.root / SYSCONFDIR / "systemd" / "system" | 199 | systemdir = self.root / SYSCONFDIR / "systemd" / "system" |
182 | 200 | ||
183 | target = ROOT / location.relative_to(self.root) | 201 | target = ROOT / location.relative_to(self.root) |
184 | try: | 202 | try: |
185 | for dependent in config.get('Install', prop): | 203 | for dependent in config.get('Install', prop): |
204 | # expand any %i to instance (ignoring escape sequence %%) | ||
205 | dependent = re.sub("([^%](%%)*)%i", "\\g<1>{}".format(instance), dependent) | ||
186 | wants = systemdir / "{}.{}".format(dependent, dirstem) / service | 206 | wants = systemdir / "{}.{}".format(dependent, dirstem) / service |
187 | add_link(wants, target) | 207 | add_link(wants, target) |
188 | 208 | ||
189 | except KeyError: | 209 | except KeyError: |
190 | pass | 210 | pass |
191 | 211 | ||
192 | def enable(self): | 212 | def enable(self, units_enabled=[]): |
193 | # if we're enabling an instance, first extract the actual instance | 213 | # if we're enabling an instance, first extract the actual instance |
194 | # then figure out what the template unit is | 214 | # then figure out what the template unit is |
195 | template = re.match(r"[^@]+@(?P<instance>[^\.]*)\.", self.unit) | 215 | template = re.match(r"[^@]+@(?P<instance>[^\.]*)\.", self.unit) |
216 | instance_unit_name = None | ||
196 | if template: | 217 | if template: |
197 | instance = template.group('instance') | 218 | instance = template.group('instance') |
219 | if instance != "": | ||
220 | instance_unit_name = self.unit | ||
198 | unit = re.sub(r"@[^\.]*\.", "@.", self.unit, 1) | 221 | unit = re.sub(r"@[^\.]*\.", "@.", self.unit, 1) |
199 | else: | 222 | else: |
200 | instance = None | 223 | instance = None |
@@ -206,7 +229,7 @@ class SystemdUnit(): | |||
206 | # ignore aliases | 229 | # ignore aliases |
207 | return | 230 | return |
208 | 231 | ||
209 | config = SystemdFile(self.root, path) | 232 | config = SystemdFile(self.root, path, instance_unit_name) |
210 | if instance == "": | 233 | if instance == "": |
211 | try: | 234 | try: |
212 | default_instance = config.get('Install', 'DefaultInstance')[0] | 235 | default_instance = config.get('Install', 'DefaultInstance')[0] |
@@ -219,12 +242,17 @@ class SystemdUnit(): | |||
219 | else: | 242 | else: |
220 | service = self.unit | 243 | service = self.unit |
221 | 244 | ||
222 | self._process_deps(config, service, path, 'WantedBy', 'wants') | 245 | self._process_deps(config, service, path, 'WantedBy', 'wants', instance) |
223 | self._process_deps(config, service, path, 'RequiredBy', 'requires') | 246 | self._process_deps(config, service, path, 'RequiredBy', 'requires', instance) |
224 | 247 | ||
225 | try: | 248 | try: |
226 | for also in config.get('Install', 'Also'): | 249 | for also in config.get('Install', 'Also'): |
227 | SystemdUnit(self.root, also).enable() | 250 | try: |
251 | units_enabled.append(unit) | ||
252 | if also not in units_enabled: | ||
253 | SystemdUnit(self.root, also).enable(units_enabled) | ||
254 | except SystemdUnitNotFoundError as e: | ||
255 | sys.exit("Error: Systemctl also enable issue with %s (%s)" % (service, e.unit)) | ||
228 | 256 | ||
229 | except KeyError: | 257 | except KeyError: |
230 | pass | 258 | pass |
@@ -265,7 +293,10 @@ def preset_all(root): | |||
265 | state = presets.state(service) | 293 | state = presets.state(service) |
266 | 294 | ||
267 | if state == "enable" or state is None: | 295 | if state == "enable" or state is None: |
268 | SystemdUnit(root, service).enable() | 296 | try: |
297 | SystemdUnit(root, service).enable() | ||
298 | except SystemdUnitNotFoundError: | ||
299 | sys.exit("Error: Systemctl preset_all issue in %s" % service) | ||
269 | 300 | ||
270 | # If we populate the systemd links we also create /etc/machine-id, which | 301 | # If we populate the systemd links we also create /etc/machine-id, which |
271 | # allows systemd to boot with the filesystem read-only before generating | 302 | # allows systemd to boot with the filesystem read-only before generating |
@@ -307,10 +338,16 @@ def main(): | |||
307 | 338 | ||
308 | if command == "mask": | 339 | if command == "mask": |
309 | for service in args.service: | 340 | for service in args.service: |
310 | SystemdUnit(root, service).mask() | 341 | try: |
342 | SystemdUnit(root, service).mask() | ||
343 | except SystemdUnitNotFoundError as e: | ||
344 | sys.exit("Error: Systemctl main mask issue in %s (%s)" % (service, e.unit)) | ||
311 | elif command == "enable": | 345 | elif command == "enable": |
312 | for service in args.service: | 346 | for service in args.service: |
313 | SystemdUnit(root, service).enable() | 347 | try: |
348 | SystemdUnit(root, service).enable() | ||
349 | except SystemdUnitNotFoundError as e: | ||
350 | sys.exit("Error: Systemctl main enable issue in %s (%s)" % (service, e.unit)) | ||
314 | elif command == "preset-all": | 351 | elif command == "preset-all": |
315 | if len(args.service) != 0: | 352 | if len(args.service) != 0: |
316 | sys.exit("Too many arguments.") | 353 | sys.exit("Too many arguments.") |