summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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")
20BASE_LIBDIR = Path("lib") 20BASE_LIBDIR = Path("lib")
21LIBDIR = Path("usr", "lib") 21LIBDIR = Path("usr", "lib")
22 22
23locations = list()
24
23 25
24class SystemdFile(): 26class 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
149def 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
170def add_link(path, target): 145def 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
180def process_deps(root, config, service, location, prop, dirstem): 155class 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: 159class 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
193def 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
240def 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
234def preset_all(root): 253def 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
254def mask(root, *services):
255 systemdir = root / SYSCONFDIR / "systemd" / "system"
256 for service in services:
257 add_link(systemdir / service, "/dev/null")
258
259
260def main(): 273def 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.")