summaryrefslogtreecommitdiffstats
path: root/meta/recipes-core/systemd
diff options
context:
space:
mode:
authorAlex Kiernan <alex.kiernan@gmail.com>2019-05-08 16:57:27 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2019-05-09 16:31:06 +0100
commit9ef6f326ad323b2687440b81b0a983cb3d86a3ab (patch)
tree7cbbd38fad1c51195470f9efb65f52609c7a99d5 /meta/recipes-core/systemd
parentc5fb399f5894c16cf8eeadd507dc38c29b0fd657 (diff)
downloadopenembedded-core-9ef6f326ad323b2687440b81b0a983cb3d86a3ab.tar.gz
systemd-systemctl: Restore support for enable command
Refactor so that SystemdUnit is its own class, then add support for the enable command. This restores the ability of systemd.bbclass to create instances using syntax such as: SYSTEMD_SERVICE_${PN} = "serial-getty@ttyAMA0.service" Signed-off-by: Alex Kiernan <alex.kiernan@gmail.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta/recipes-core/systemd')
-rwxr-xr-xmeta/recipes-core/systemd/systemd-systemctl/systemctl179
1 files changed, 102 insertions, 77 deletions
diff --git a/meta/recipes-core/systemd/systemd-systemctl/systemctl b/meta/recipes-core/systemd/systemd-systemctl/systemctl
index 7fdaf8ce03..8d7b3ba32d 100755
--- a/meta/recipes-core/systemd/systemd-systemctl/systemctl
+++ b/meta/recipes-core/systemd/systemd-systemctl/systemctl
@@ -20,6 +20,8 @@ SYSCONFDIR = Path("etc")
BASE_LIBDIR = Path("lib")
LIBDIR = Path("usr", "lib")
+locations = list()
+
class SystemdFile():
"""Class representing a single systemd configuration file"""
@@ -111,12 +113,6 @@ class Presets():
def _collect_presets(self, scope, root):
"""Collect list of preset files"""
- locations = [SYSCONFDIR / "systemd"]
- # Handle the usrmerge case by ignoring /lib when it's a symlink
- if not BASE_LIBDIR.is_symlink():
- locations.append(BASE_LIBDIR / "systemd")
- locations.append(LIBDIR / "systemd")
-
presets = dict()
for location in locations:
paths = (root / location / scope).glob("*.preset")
@@ -146,27 +142,6 @@ class Presets():
return None
-def collect_services(root):
- """Collect list of service files"""
- locations = [SYSCONFDIR / "systemd"]
- # Handle the usrmerge case by ignoring /lib when it's a symlink
- if not BASE_LIBDIR.is_symlink():
- locations.append(BASE_LIBDIR / "systemd")
- locations.append(LIBDIR / "systemd")
-
- services = dict()
- for location in locations:
- paths = (root / location / "system").glob("*")
- for path in paths:
- if path.is_dir():
- continue
- # implement earlier names override later ones
- if path.name not in services:
- services[path.name] = path
-
- return services
-
-
def add_link(path, target):
try:
path.parent.mkdir(parents=True)
@@ -177,69 +152,113 @@ def add_link(path, target):
path.symlink_to(target)
-def process_deps(root, config, service, location, prop, dirstem):
- systemdir = SYSCONFDIR / "systemd" / "system"
+class SystemdUnitNotFoundError(Exception):
+ pass
- target = ROOT / location.relative_to(root)
- try:
- for dependent in config.get('Install', prop):
- wants = root / systemdir / "{}.{}".format(dependent, dirstem) / service
- add_link(wants, target)
- except KeyError:
- pass
+class SystemdUnit():
+ def __init__(self, root, unit):
+ self.root = root
+ self.unit = unit
+ self.config = None
+
+ def _path_for_unit(self, unit):
+ for location in locations:
+ path = self.root / location / "system" / unit
+ if path.exists():
+ return path
+ raise SystemdUnitNotFoundError(self.root, unit)
-def enable(root, service, location, services):
- if location.is_symlink():
- # ignore aliases
- return
+ def _process_deps(self, config, service, location, prop, dirstem):
+ systemdir = self.root / SYSCONFDIR / "systemd" / "system"
+
+ target = ROOT / location.relative_to(self.root)
+ try:
+ for dependent in config.get('Install', prop):
+ wants = systemdir / "{}.{}".format(dependent, dirstem) / service
+ add_link(wants, target)
+
+ except KeyError:
+ pass
+
+ def enable(self):
+ # if we're enabling an instance, first extract the actual instance
+ # then figure out what the template unit is
+ template = re.match(r"[^@]+@(?P<instance>[^\.]*)\.", self.unit)
+ if template:
+ instance = template.group('instance')
+ unit = re.sub(r"@[^\.]*\.", "@.", self.unit, 1)
+ else:
+ instance = None
+ unit = self.unit
+
+ path = self._path_for_unit(unit)
+
+ if path.is_symlink():
+ # ignore aliases
+ return
- config = SystemdFile(root, location)
- template = re.match(r"[^@]+@(?P<instance>[^\.]*)\.", service)
- if template:
- instance = template.group('instance')
- if not instance:
+ config = SystemdFile(self.root, path)
+ if instance == "":
try:
- instance = config.get('Install', 'DefaultInstance')[0]
- service = service.replace("@.", "@{}.".format(instance))
+ default_instance = config.get('Install', 'DefaultInstance')[0]
except KeyError:
- pass
- if instance is None:
- return
- else:
- instance = None
+ # no default instance, so nothing to enable
+ return
- process_deps(root, config, service, location, 'WantedBy', 'wants')
- process_deps(root, config, service, location, 'RequiredBy', 'requires')
+ service = self.unit.replace("@.",
+ "@{}.".format(default_instance))
+ else:
+ service = self.unit
- try:
- for also in config.get('Install', 'Also'):
- enable(root, also, services[also], services)
+ self._process_deps(config, service, path, 'WantedBy', 'wants')
+ self._process_deps(config, service, path, 'RequiredBy', 'requires')
- except KeyError:
- pass
+ try:
+ for also in config.get('Install', 'Also'):
+ SystemdUnit(self.root, also).enable()
- systemdir = root / SYSCONFDIR / "systemd" / "system"
- target = ROOT / location.relative_to(root)
- try:
- for dest in config.get('Install', 'Alias'):
- alias = systemdir / dest
- add_link(alias, target)
+ except KeyError:
+ pass
- except KeyError:
- pass
+ systemdir = self.root / SYSCONFDIR / "systemd" / "system"
+ target = ROOT / path.relative_to(self.root)
+ try:
+ for dest in config.get('Install', 'Alias'):
+ alias = systemdir / dest
+ add_link(alias, target)
+
+ except KeyError:
+ pass
+
+ def mask(self):
+ systemdir = self.root / SYSCONFDIR / "systemd" / "system"
+ add_link(systemdir / self.unit, "/dev/null")
+
+
+def collect_services(root):
+ """Collect list of service files"""
+ services = set()
+ for location in locations:
+ paths = (root / location / "system").glob("*")
+ for path in paths:
+ if path.is_dir():
+ continue
+ services.add(path.name)
+
+ return services
def preset_all(root):
presets = Presets('system-preset', root)
services = collect_services(root)
- for service, location in services.items():
+ for service in services:
state = presets.state(service)
if state == "enable" or state is None:
- enable(root, service, location, services)
+ SystemdUnit(root, service).enable()
# If we populate the systemd links we also create /etc/machine-id, which
# allows systemd to boot with the filesystem read-only before generating
@@ -251,18 +270,13 @@ def preset_all(root):
(root / SYSCONFDIR / "machine-id").touch()
-def mask(root, *services):
- systemdir = root / SYSCONFDIR / "systemd" / "system"
- for service in services:
- add_link(systemdir / service, "/dev/null")
-
-
def main():
if sys.version_info < (3, 4, 0):
sys.exit("Python 3.4 or greater is required")
parser = argparse.ArgumentParser()
- parser.add_argument('command', nargs=1, choices=['mask', 'preset-all'])
+ parser.add_argument('command', nargs=1, choices=['enable', 'mask',
+ 'preset-all'])
parser.add_argument('service', nargs=argparse.REMAINDER)
parser.add_argument('--root')
parser.add_argument('--preset-mode',
@@ -272,9 +286,20 @@ def main():
args = parser.parse_args()
root = Path(args.root) if args.root else ROOT
+
+ locations.append(SYSCONFDIR / "systemd")
+ # Handle the usrmerge case by ignoring /lib when it's a symlink
+ if not (root / BASE_LIBDIR).is_symlink():
+ locations.append(BASE_LIBDIR / "systemd")
+ locations.append(LIBDIR / "systemd")
+
command = args.command[0]
if command == "mask":
- mask(root, *args.service)
+ for service in args.service:
+ SystemdUnit(root, service).mask()
+ elif command == "enable":
+ for service in args.service:
+ SystemdUnit(root, service).enable()
elif command == "preset-all":
if len(args.service) != 0:
sys.exit("Too many arguments.")