diff options
Diffstat (limited to 'meta/recipes-core/systemd')
-rwxr-xr-x | meta/recipes-core/systemd/systemd-systemctl/systemctl | 179 |
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.") |