diff options
Diffstat (limited to 'meta')
-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") | |||
20 | BASE_LIBDIR = Path("lib") | 20 | BASE_LIBDIR = Path("lib") |
21 | LIBDIR = Path("usr", "lib") | 21 | LIBDIR = Path("usr", "lib") |
22 | 22 | ||
23 | locations = list() | ||
24 | |||
23 | 25 | ||
24 | class SystemdFile(): | 26 | class SystemdFile(): |
25 | """Class representing a single systemd configuration file""" | 27 | """Class representing a single systemd configuration file""" |
@@ -111,12 +113,6 @@ class Presets(): | |||
111 | 113 | ||
112 | def _collect_presets(self, scope, root): | 114 | def _collect_presets(self, scope, root): |
113 | """Collect list of preset files""" | 115 | """Collect list of preset files""" |
114 | locations = [SYSCONFDIR / "systemd"] | ||
115 | # Handle the usrmerge case by ignoring /lib when it's a symlink | ||
116 | if not BASE_LIBDIR.is_symlink(): | ||
117 | locations.append(BASE_LIBDIR / "systemd") | ||
118 | locations.append(LIBDIR / "systemd") | ||
119 | |||
120 | presets = dict() | 116 | presets = dict() |
121 | for location in locations: | 117 | for location in locations: |
122 | paths = (root / location / scope).glob("*.preset") | 118 | paths = (root / location / scope).glob("*.preset") |
@@ -146,27 +142,6 @@ class Presets(): | |||
146 | return None | 142 | return None |
147 | 143 | ||
148 | 144 | ||
149 | def collect_services(root): | ||
150 | """Collect list of service files""" | ||
151 | locations = [SYSCONFDIR / "systemd"] | ||
152 | # Handle the usrmerge case by ignoring /lib when it's a symlink | ||
153 | if not BASE_LIBDIR.is_symlink(): | ||
154 | locations.append(BASE_LIBDIR / "systemd") | ||
155 | locations.append(LIBDIR / "systemd") | ||
156 | |||
157 | services = dict() | ||
158 | for location in locations: | ||
159 | paths = (root / location / "system").glob("*") | ||
160 | for path in paths: | ||
161 | if path.is_dir(): | ||
162 | continue | ||
163 | # implement earlier names override later ones | ||
164 | if path.name not in services: | ||
165 | services[path.name] = path | ||
166 | |||
167 | return services | ||
168 | |||
169 | |||
170 | def add_link(path, target): | 145 | def add_link(path, target): |
171 | try: | 146 | try: |
172 | path.parent.mkdir(parents=True) | 147 | path.parent.mkdir(parents=True) |
@@ -177,69 +152,113 @@ def add_link(path, target): | |||
177 | path.symlink_to(target) | 152 | path.symlink_to(target) |
178 | 153 | ||
179 | 154 | ||
180 | def process_deps(root, config, service, location, prop, dirstem): | 155 | class SystemdUnitNotFoundError(Exception): |
181 | systemdir = SYSCONFDIR / "systemd" / "system" | 156 | pass |
182 | 157 | ||
183 | target = ROOT / location.relative_to(root) | ||
184 | try: | ||
185 | for dependent in config.get('Install', prop): | ||
186 | wants = root / systemdir / "{}.{}".format(dependent, dirstem) / service | ||
187 | add_link(wants, target) | ||
188 | 158 | ||
189 | except KeyError: | 159 | class SystemdUnit(): |
190 | pass | 160 | def __init__(self, root, unit): |
161 | self.root = root | ||
162 | self.unit = unit | ||
163 | self.config = None | ||
164 | |||
165 | def _path_for_unit(self, unit): | ||
166 | for location in locations: | ||
167 | path = self.root / location / "system" / unit | ||
168 | if path.exists(): | ||
169 | return path | ||
191 | 170 | ||
171 | raise SystemdUnitNotFoundError(self.root, unit) | ||
192 | 172 | ||
193 | def enable(root, service, location, services): | 173 | def _process_deps(self, config, service, location, prop, dirstem): |
194 | if location.is_symlink(): | 174 | systemdir = self.root / SYSCONFDIR / "systemd" / "system" |
195 | # ignore aliases | 175 | |
196 | return | 176 | target = ROOT / location.relative_to(self.root) |
177 | try: | ||
178 | for dependent in config.get('Install', prop): | ||
179 | wants = systemdir / "{}.{}".format(dependent, dirstem) / service | ||
180 | add_link(wants, target) | ||
181 | |||
182 | except KeyError: | ||
183 | pass | ||
184 | |||
185 | def enable(self): | ||
186 | # if we're enabling an instance, first extract the actual instance | ||
187 | # then figure out what the template unit is | ||
188 | template = re.match(r"[^@]+@(?P<instance>[^\.]*)\.", self.unit) | ||
189 | if template: | ||
190 | instance = template.group('instance') | ||
191 | unit = re.sub(r"@[^\.]*\.", "@.", self.unit, 1) | ||
192 | else: | ||
193 | instance = None | ||
194 | unit = self.unit | ||
195 | |||
196 | path = self._path_for_unit(unit) | ||
197 | |||
198 | if path.is_symlink(): | ||
199 | # ignore aliases | ||
200 | return | ||
197 | 201 | ||
198 | config = SystemdFile(root, location) | 202 | config = SystemdFile(self.root, path) |
199 | template = re.match(r"[^@]+@(?P<instance>[^\.]*)\.", service) | 203 | if instance == "": |
200 | if template: | ||
201 | instance = template.group('instance') | ||
202 | if not instance: | ||
203 | try: | 204 | try: |
204 | instance = config.get('Install', 'DefaultInstance')[0] | 205 | default_instance = config.get('Install', 'DefaultInstance')[0] |
205 | service = service.replace("@.", "@{}.".format(instance)) | ||
206 | except KeyError: | 206 | except KeyError: |
207 | pass | 207 | # no default instance, so nothing to enable |
208 | if instance is None: | 208 | return |
209 | return | ||
210 | else: | ||
211 | instance = None | ||
212 | 209 | ||
213 | process_deps(root, config, service, location, 'WantedBy', 'wants') | 210 | service = self.unit.replace("@.", |
214 | process_deps(root, config, service, location, 'RequiredBy', 'requires') | 211 | "@{}.".format(default_instance)) |
212 | else: | ||
213 | service = self.unit | ||
215 | 214 | ||
216 | try: | 215 | self._process_deps(config, service, path, 'WantedBy', 'wants') |
217 | for also in config.get('Install', 'Also'): | 216 | self._process_deps(config, service, path, 'RequiredBy', 'requires') |
218 | enable(root, also, services[also], services) | ||
219 | 217 | ||
220 | except KeyError: | 218 | try: |
221 | pass | 219 | for also in config.get('Install', 'Also'): |
220 | SystemdUnit(self.root, also).enable() | ||
222 | 221 | ||
223 | systemdir = root / SYSCONFDIR / "systemd" / "system" | 222 | except KeyError: |
224 | target = ROOT / location.relative_to(root) | 223 | pass |
225 | try: | ||
226 | for dest in config.get('Install', 'Alias'): | ||
227 | alias = systemdir / dest | ||
228 | add_link(alias, target) | ||
229 | 224 | ||
230 | except KeyError: | 225 | systemdir = self.root / SYSCONFDIR / "systemd" / "system" |
231 | pass | 226 | target = ROOT / path.relative_to(self.root) |
227 | try: | ||
228 | for dest in config.get('Install', 'Alias'): | ||
229 | alias = systemdir / dest | ||
230 | add_link(alias, target) | ||
231 | |||
232 | except KeyError: | ||
233 | pass | ||
234 | |||
235 | def mask(self): | ||
236 | systemdir = self.root / SYSCONFDIR / "systemd" / "system" | ||
237 | add_link(systemdir / self.unit, "/dev/null") | ||
238 | |||
239 | |||
240 | def collect_services(root): | ||
241 | """Collect list of service files""" | ||
242 | services = set() | ||
243 | for location in locations: | ||
244 | paths = (root / location / "system").glob("*") | ||
245 | for path in paths: | ||
246 | if path.is_dir(): | ||
247 | continue | ||
248 | services.add(path.name) | ||
249 | |||
250 | return services | ||
232 | 251 | ||
233 | 252 | ||
234 | def preset_all(root): | 253 | def preset_all(root): |
235 | presets = Presets('system-preset', root) | 254 | presets = Presets('system-preset', root) |
236 | services = collect_services(root) | 255 | services = collect_services(root) |
237 | 256 | ||
238 | for service, location in services.items(): | 257 | for service in services: |
239 | state = presets.state(service) | 258 | state = presets.state(service) |
240 | 259 | ||
241 | if state == "enable" or state is None: | 260 | if state == "enable" or state is None: |
242 | enable(root, service, location, services) | 261 | SystemdUnit(root, service).enable() |
243 | 262 | ||
244 | # If we populate the systemd links we also create /etc/machine-id, which | 263 | # If we populate the systemd links we also create /etc/machine-id, which |
245 | # allows systemd to boot with the filesystem read-only before generating | 264 | # allows systemd to boot with the filesystem read-only before generating |
@@ -251,18 +270,13 @@ def preset_all(root): | |||
251 | (root / SYSCONFDIR / "machine-id").touch() | 270 | (root / SYSCONFDIR / "machine-id").touch() |
252 | 271 | ||
253 | 272 | ||
254 | def mask(root, *services): | ||
255 | systemdir = root / SYSCONFDIR / "systemd" / "system" | ||
256 | for service in services: | ||
257 | add_link(systemdir / service, "/dev/null") | ||
258 | |||
259 | |||
260 | def main(): | 273 | def main(): |
261 | if sys.version_info < (3, 4, 0): | 274 | if sys.version_info < (3, 4, 0): |
262 | sys.exit("Python 3.4 or greater is required") | 275 | sys.exit("Python 3.4 or greater is required") |
263 | 276 | ||
264 | parser = argparse.ArgumentParser() | 277 | parser = argparse.ArgumentParser() |
265 | parser.add_argument('command', nargs=1, choices=['mask', 'preset-all']) | 278 | parser.add_argument('command', nargs=1, choices=['enable', 'mask', |
279 | 'preset-all']) | ||
266 | parser.add_argument('service', nargs=argparse.REMAINDER) | 280 | parser.add_argument('service', nargs=argparse.REMAINDER) |
267 | parser.add_argument('--root') | 281 | parser.add_argument('--root') |
268 | parser.add_argument('--preset-mode', | 282 | parser.add_argument('--preset-mode', |
@@ -272,9 +286,20 @@ def main(): | |||
272 | args = parser.parse_args() | 286 | args = parser.parse_args() |
273 | 287 | ||
274 | root = Path(args.root) if args.root else ROOT | 288 | root = Path(args.root) if args.root else ROOT |
289 | |||
290 | locations.append(SYSCONFDIR / "systemd") | ||
291 | # Handle the usrmerge case by ignoring /lib when it's a symlink | ||
292 | if not (root / BASE_LIBDIR).is_symlink(): | ||
293 | locations.append(BASE_LIBDIR / "systemd") | ||
294 | locations.append(LIBDIR / "systemd") | ||
295 | |||
275 | command = args.command[0] | 296 | command = args.command[0] |
276 | if command == "mask": | 297 | if command == "mask": |
277 | mask(root, *args.service) | 298 | for service in args.service: |
299 | SystemdUnit(root, service).mask() | ||
300 | elif command == "enable": | ||
301 | for service in args.service: | ||
302 | SystemdUnit(root, service).enable() | ||
278 | elif command == "preset-all": | 303 | elif command == "preset-all": |
279 | if len(args.service) != 0: | 304 | if len(args.service) != 0: |
280 | sys.exit("Too many arguments.") | 305 | sys.exit("Too many arguments.") |