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:55 +0100
commit534731e7a7956c3d82c09c9aa01080b19aa818d1 (patch)
tree1f7bdb0e36d1034fdca2ebd1c60bb89f835ecc49 /meta/recipes-core/systemd
parent7e5124a44c8d589b2dffc1d083653dc3b084d082 (diff)
downloadpoky-534731e7a7956c3d82c09c9aa01080b19aa818d1.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" (From OE-Core rev: 9ef6f326ad323b2687440b81b0a983cb3d86a3ab) 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")
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.")