mirror of
https://github.com/nchevsky/systemrescue-zfs.git
synced 2026-01-07 09:10:43 +01:00
Merge branch 'autoterminal' into 'main'
implement autoterminal: automatically started scripts that take over a virtual terminal for user interaction See merge request systemrescue/systemrescue-sources!196
This commit is contained in:
commit
ae8a15c2b2
|
|
@ -8,6 +8,29 @@ import glob
|
|||
import os
|
||||
import sys
|
||||
import re
|
||||
import tempfile
|
||||
|
||||
# pythons os.symlink bails when a file already exists, this function also handles overwrites
|
||||
def symlink_overwrite(target, link_file):
|
||||
link_dir = os.path.dirname(link_file)
|
||||
|
||||
while True:
|
||||
# get a tmp filename in the same dir as link_file
|
||||
tmp = tempfile.NamedTemporaryFile(delete=True, dir=link_dir)
|
||||
tmp.close()
|
||||
# tmp is now deleted
|
||||
|
||||
# os.symlink aborts when a file with the same name already exists
|
||||
# someone could have created a new file with the tmp name right in this moment
|
||||
# so we need to loop and try again in this case
|
||||
try:
|
||||
os.symlink(target,tmp.name)
|
||||
break
|
||||
except FileExistsError:
|
||||
pass
|
||||
|
||||
os.replace(tmp.name, link_file)
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Initialization
|
||||
|
|
@ -179,6 +202,64 @@ if (late_load_srm != None) and (late_load_srm != ""):
|
|||
# so we have to do this manually. Note: only affects multi-user.target, nothing else
|
||||
subprocess.run(["/usr/bin/systemctl", "--no-block", "start", "multi-user.target"])
|
||||
|
||||
# ==============================================================================
|
||||
# autoterminal: programs that take over a virtual terminal for user interaction
|
||||
# ==============================================================================
|
||||
|
||||
# expect a dict with terminal-name: command, like config['autoterminal']['tty2'] = "/usr/bin/setkmap"
|
||||
if ('autoterminal' in config) and (config['autoterminal'] is not None) and \
|
||||
(config['autoterminal'] is not False) and isinstance(config['autoterminal'], dict):
|
||||
print("====> Configuring autoterminal ...")
|
||||
with open('/usr/share/sysrescue/template/autoterminal.service', 'r') as template_file:
|
||||
conf_template = template_file.read()
|
||||
with open('/usr/share/sysrescue/template/serial-autoterminal.service', 'r') as template_file:
|
||||
serial_conf_template = template_file.read()
|
||||
start_services = []
|
||||
for terminal, command in sorted(config['autoterminal'].items()):
|
||||
if m := re.match(r"^serial:([a-zA-Z0-9_-]+)$", terminal):
|
||||
serial=True
|
||||
terminal = m.group(1)
|
||||
else:
|
||||
serial=False
|
||||
|
||||
if not re.match(r"^[a-zA-Z0-9_-]+$", terminal):
|
||||
print (f"Ignoring invalid terminal name '{terminal}'")
|
||||
errcnt+=1
|
||||
continue
|
||||
# do not check if terminal or command exists: an autorun could create them later on
|
||||
if serial:
|
||||
print (f"setting serial terminal '{terminal}' to '{command}'")
|
||||
else:
|
||||
print (f"setting terminal '{terminal}' to '{command}'")
|
||||
with open(f"/etc/systemd/system/autoterminal-{terminal}.service", "w") as terminal_conf:
|
||||
# write service config, based on the template config we loaded above
|
||||
# don't use getty@{terminal}.service name to not use autovt@{terminal}.service on-demand logic
|
||||
if serial:
|
||||
conf_data=serial_conf_template.replace("%TTY%",terminal)
|
||||
else:
|
||||
conf_data=conf_template.replace("%TTY%",terminal)
|
||||
|
||||
conf_data=conf_data.replace("%EXEC%",command)
|
||||
terminal_conf.write(conf_data)
|
||||
# enable service: always start it, do not wait for the user to switch to the terminal
|
||||
# means other programs (like X.org) can't allocate it away, also allows for longer running init sequences
|
||||
symlink_overwrite(f"/etc/systemd/system/autoterminal-{terminal}.service",
|
||||
f"/etc/systemd/system/getty.target.wants/autoterminal-{terminal}.service")
|
||||
|
||||
# mask the regular getty for this terminal
|
||||
if serial:
|
||||
symlink_overwrite("/dev/null",f"/etc/systemd/system/serial-getty@{terminal}.service")
|
||||
else:
|
||||
symlink_overwrite("/dev/null",f"/etc/systemd/system/getty@{terminal}.service")
|
||||
symlink_overwrite("/dev/null",f"/etc/systemd/system/autovt@{terminal}.service")
|
||||
|
||||
start_services.append(f"autoterminal-{terminal}.service")
|
||||
# reload systemd to allow the new config to take effect
|
||||
subprocess.run(["/usr/bin/systemctl", "daemon-reload"])
|
||||
# explicitly start new services (after daemon-reload): systemd can't update dependencies while starting
|
||||
for s in start_services:
|
||||
subprocess.run(["/usr/bin/systemctl", "--no-block", "start", s])
|
||||
|
||||
# ==============================================================================
|
||||
# End of the script
|
||||
# ==============================================================================
|
||||
|
|
|
|||
60
airootfs/usr/share/sysrescue/template/autoterminal.service
Normal file
60
airootfs/usr/share/sysrescue/template/autoterminal.service
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
#
|
||||
# This file is part of SystemRescue, based on getty@.service from systemd
|
||||
#
|
||||
# systemd is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
[Unit]
|
||||
Description=SystemRescue autoterminal %TTY%
|
||||
Documentation=https://www.system-rescue.org/manual/autoterminal/
|
||||
After=systemd-user-sessions.service plymouth-quit-wait.service getty-pre.target \
|
||||
getty@%TTY%.service autovt@%TTY%.service
|
||||
|
||||
# If additional gettys are spawned during boot then we should make
|
||||
# sure that this is synchronized before getty.target, even though
|
||||
# getty.target didn't actually pull it in.
|
||||
Before=getty.target
|
||||
IgnoreOnIsolate=yes
|
||||
|
||||
# IgnoreOnIsolate causes issues with sulogin, if someone isolates
|
||||
# rescue.target or starts rescue.service from multi-user.target or
|
||||
# graphical.target.
|
||||
Conflicts=rescue.service getty@%TTY%.service autovt@%TTY%.service
|
||||
Before=rescue.service
|
||||
|
||||
[Service]
|
||||
# the VT is cleared by TTYVTDisallocate
|
||||
ExecStart=-%EXEC%
|
||||
|
||||
# do not wait 5 seconds as for Type=idle before starting the service
|
||||
Type=simple
|
||||
|
||||
Restart=always
|
||||
RestartSec=1
|
||||
UtmpIdentifier=%TTY%
|
||||
StandardInput=tty
|
||||
StandardOutput=tty
|
||||
TTYPath=/dev/%TTY%
|
||||
TTYReset=yes
|
||||
TTYVHangup=yes
|
||||
TTYVTDisallocate=yes
|
||||
IgnoreSIGPIPE=no
|
||||
SendSIGHUP=yes
|
||||
|
||||
# make this a systemd-logind session without needing a getty
|
||||
User=root
|
||||
PAMName=login
|
||||
|
||||
# generate all utmp/wtmp entries and don't expect the program to do it
|
||||
UtmpMode=user
|
||||
|
||||
# Unset locale for the console getty since the console has problems
|
||||
# displaying some internationalized messages.
|
||||
UnsetEnvironment=LANG LANGUAGE LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY \
|
||||
LC_MESSAGES LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT LC_IDENTIFICATION
|
||||
|
||||
[Install]
|
||||
WantedBy=getty.target
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
#
|
||||
# This file is part of SystemRescue, based on serial-getty@.service from systemd
|
||||
#
|
||||
# systemd is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
[Unit]
|
||||
Description=SystemRescue serial autoterminal %TTY%
|
||||
Documentation=https://www.system-rescue.org/manual/autoterminal/
|
||||
BindsTo=dev-%TTY%.device
|
||||
After=dev-%TTY%.device systemd-user-sessions.service plymouth-quit-wait.service \
|
||||
getty-pre.target serial-getty@%TTY%.service
|
||||
|
||||
# If additional gettys are spawned during boot then we should make
|
||||
# sure that this is synchronized before getty.target, even though
|
||||
# getty.target didn't actually pull it in.
|
||||
Before=getty.target
|
||||
IgnoreOnIsolate=yes
|
||||
|
||||
# IgnoreOnIsolate causes issues with sulogin, if someone isolates
|
||||
# rescue.target or starts rescue.service from multi-user.target or
|
||||
# graphical.target.
|
||||
Conflicts=rescue.service serial-getty@%TTY%.service
|
||||
Before=rescue.service
|
||||
|
||||
[Service]
|
||||
ExecStart=-%EXEC%
|
||||
|
||||
# do not wait 5 seconds as for Type=idle before starting the service
|
||||
Type=simple
|
||||
|
||||
Restart=always
|
||||
RestartSec=1
|
||||
UtmpIdentifier=%TTY%
|
||||
StandardInput=tty
|
||||
StandardOutput=tty
|
||||
TTYPath=/dev/%TTY%
|
||||
TTYReset=yes
|
||||
TTYVHangup=yes
|
||||
IgnoreSIGPIPE=no
|
||||
SendSIGHUP=yes
|
||||
|
||||
# make this a systemd-logind session without needing a getty
|
||||
User=root
|
||||
PAMName=login
|
||||
|
||||
# generate all utmp/wtmp entries and don't expect the program to do it
|
||||
UtmpMode=user
|
||||
|
||||
[Install]
|
||||
WantedBy=getty.target
|
||||
Loading…
Reference in a new issue