Chroot with contextmanager
This commit is contained in:
parent
1fa69d6bcc
commit
dd30ffe255
66
jlmkr.py
66
jlmkr.py
|
@ -125,8 +125,6 @@ SCRIPT_PATH = os.path.realpath(__file__)
|
||||||
SCRIPT_NAME = os.path.basename(SCRIPT_PATH)
|
SCRIPT_NAME = os.path.basename(SCRIPT_PATH)
|
||||||
SCRIPT_DIR_PATH = os.path.dirname(SCRIPT_PATH)
|
SCRIPT_DIR_PATH = os.path.dirname(SCRIPT_PATH)
|
||||||
COMMAND_NAME = os.path.basename(__file__)
|
COMMAND_NAME = os.path.basename(__file__)
|
||||||
INITIAL_ROOT = os.open("/", os.O_PATH)
|
|
||||||
CWD_BEFORE_CHROOT = None
|
|
||||||
SHORTNAME = "jlmkr"
|
SHORTNAME = "jlmkr"
|
||||||
|
|
||||||
# Only set a color if we have an interactive tty
|
# Only set a color if we have an interactive tty
|
||||||
|
@ -281,6 +279,25 @@ class CustomSubParser(argparse.ArgumentParser):
|
||||||
raise ExceptionWithParser(self, message)
|
raise ExceptionWithParser(self, message)
|
||||||
|
|
||||||
|
|
||||||
|
class Chroot:
|
||||||
|
def __init__(self, new_root):
|
||||||
|
self.new_root = new_root
|
||||||
|
self.old_root = None
|
||||||
|
self.initial_cwd = None
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
self.old_root = os.open("/", os.O_PATH)
|
||||||
|
self.initial_cwd = os.path.abspath(os.getcwd())
|
||||||
|
os.chdir(self.new_root)
|
||||||
|
os.chroot(".")
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_value, traceback):
|
||||||
|
os.chdir(self.old_root)
|
||||||
|
os.chroot(".")
|
||||||
|
os.close(self.old_root)
|
||||||
|
os.chdir(self.initial_cwd)
|
||||||
|
|
||||||
|
|
||||||
def eprint(*args, **kwargs):
|
def eprint(*args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Print to stderr.
|
Print to stderr.
|
||||||
|
@ -296,20 +313,6 @@ def fail(*args, **kwargs):
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def enter_chroot(new_root):
|
|
||||||
global CWD_BEFORE_CHROOT
|
|
||||||
CWD_BEFORE_CHROOT = os.path.abspath(os.getcwd())
|
|
||||||
os.chdir(new_root)
|
|
||||||
os.chroot(".")
|
|
||||||
|
|
||||||
|
|
||||||
# https://stackoverflow.com/a/61533559
|
|
||||||
def exit_chroot():
|
|
||||||
os.chdir(INITIAL_ROOT)
|
|
||||||
os.chroot(".")
|
|
||||||
os.chdir(CWD_BEFORE_CHROOT)
|
|
||||||
|
|
||||||
|
|
||||||
def get_jail_path(jail_name):
|
def get_jail_path(jail_name):
|
||||||
return os.path.join(JAILS_DIR_PATH, jail_name)
|
return os.path.join(JAILS_DIR_PATH, jail_name)
|
||||||
|
|
||||||
|
@ -787,6 +790,7 @@ def cleanup(jail_path):
|
||||||
"""
|
"""
|
||||||
Cleanup jail.
|
Cleanup jail.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if get_zfs_dataset(jail_path):
|
if get_zfs_dataset(jail_path):
|
||||||
eprint(f"Cleaning up: {jail_path}.")
|
eprint(f"Cleaning up: {jail_path}.")
|
||||||
remove_zfs_dataset(jail_path)
|
remove_zfs_dataset(jail_path)
|
||||||
|
@ -1373,9 +1377,9 @@ def create_jail(**kwargs):
|
||||||
# But alpine jails made with jailmaker have other issues
|
# But alpine jails made with jailmaker have other issues
|
||||||
# They don't shutdown cleanly via systemctl and machinectl...
|
# They don't shutdown cleanly via systemctl and machinectl...
|
||||||
|
|
||||||
enter_chroot(jail_rootfs_path)
|
with Chroot(jail_rootfs_path):
|
||||||
init_system_name = os.path.basename(os.path.realpath("/sbin/init"))
|
# Use chroot to correctly resolve absolute /sbin/init symlink
|
||||||
exit_chroot()
|
init_system_name = os.path.basename(os.path.realpath("/sbin/init"))
|
||||||
|
|
||||||
if (
|
if (
|
||||||
init_system_name != "systemd"
|
init_system_name != "systemd"
|
||||||
|
@ -1645,20 +1649,20 @@ def get_all_jail_names():
|
||||||
return jail_names
|
return jail_names
|
||||||
|
|
||||||
|
|
||||||
def parse_os_release(new_rootfs):
|
def parse_os_release(new_root):
|
||||||
enter_chroot(new_rootfs)
|
|
||||||
result = {}
|
result = {}
|
||||||
for candidate in ["/etc/os-release", "/usr/lib/os-release"]:
|
with Chroot(new_root):
|
||||||
try:
|
# Use chroot to correctly resolve os-release symlink (for nixos)
|
||||||
with open(candidate, encoding="utf-8") as f:
|
for candidate in ["/etc/os-release", "/usr/lib/os-release"]:
|
||||||
# TODO: can I create a solution which not depends on the internal _parse_os_release method?
|
try:
|
||||||
result = platform._parse_os_release(f)
|
with open(candidate, encoding="utf-8") as f:
|
||||||
break
|
# TODO: can I create a solution which not depends on the internal _parse_os_release method?
|
||||||
except OSError:
|
result = platform._parse_os_release(f)
|
||||||
# Silently ignore failing to read os release info
|
break
|
||||||
pass
|
except OSError:
|
||||||
|
# Silently ignore failing to read os release info
|
||||||
|
pass
|
||||||
|
|
||||||
exit_chroot()
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue