From 4e665a2190550068ee74b4c6c44ac9c913e1a781 Mon Sep 17 00:00:00 2001 From: Oliver Smith Date: Sun, 29 Apr 2018 22:17:57 +0000 Subject: [PATCH] Recreate device nodes in chroot after shutdown (#1447) Device nodes in the chroots get created in a tmpfs, so they can be created even if the filesystem where the chroot resides does not support device nodes (#1317). In "pmbootstrap shutdown" we umount the `dev` folder, which means all device nodes that were created inside this folder are gone. This commit changes the code to actually recreate the device nodes when using the chroot again. Details: * move `pmb.chroot.init.create_device_nodes` to `pmb.chroot.mount.crete_device_nodes` * don't call it in `pmb.chroot.init()` anymore, but in `pmb.chroot.mount_dev_tmpfs()` * Create the `null` device as well (`apk --initdb` also creates it on `init`, but we don't call it after `shutdown`) --- pmb/chroot/init.py | 43 +----------------------------------- pmb/chroot/mount.py | 50 +++++++++++++++++++++++++++++++++++++++--- pmb/config/__init__.py | 6 ++--- 3 files changed, 51 insertions(+), 48 deletions(-) diff --git a/pmb/chroot/init.py b/pmb/chroot/init.py index 4b9b711e..0d843dfb 100644 --- a/pmb/chroot/init.py +++ b/pmb/chroot/init.py @@ -45,46 +45,6 @@ def copy_resolv_conf(args, suffix="native"): pmb.helpers.run.root(args, ["touch", chroot]) -def create_device_nodes(args, suffix): - error = "Failed to create device nodes in the '" + suffix + "' chroot." - - # Folder sturcture - chroot = args.work + "/chroot_" + suffix - pmb.helpers.run.root(args, ["mkdir", "-p", chroot + "/dev"]) - - try: - # Create all device nodes as specified in the config - for dev in pmb.config.chroot_device_nodes: - path = chroot + "/dev/" + str(dev[4]) - if not os.path.exists(path): - pmb.helpers.run.root(args, ["mknod", - "-m", str(dev[0]), # permissions - path, # name - str(dev[1]), # type - str(dev[2]), # major - str(dev[3]), # minor - ]) - - # Verify major and minor numbers of created nodes - for dev in pmb.config.chroot_device_nodes: - path = chroot + "/dev/" + str(dev[4]) - stat_result = os.stat(path) - rdev = stat_result.st_rdev - assert os.major(rdev) == dev[2], "Wrong major in " + path - assert os.minor(rdev) == dev[3], "Wrong minor in " + path - - # Verify /dev/zero reading and writing - path = chroot + "/dev/zero" - with open(path, "r+b", 0) as handle: - assert handle.write(bytes([0xff])), "Write failed for " + path - assert handle.read(1) == bytes([0x00]), "Read failed for " + path - - # On failure: Show filesystem-related error - except Exception as e: - logging.info(str(e) + "!") - raise RuntimeError(error) - - def init(args, suffix="native"): # When already initialized: just prepare the chroot chroot = args.work + "/chroot_" + suffix @@ -110,8 +70,7 @@ def init(args, suffix="native"): logging.info("(" + suffix + ") install alpine-base") - # Initialize device nodes and cache - create_device_nodes(args, suffix) + # Initialize cache apk_cache = args.work + "/cache_apk_" + arch pmb.helpers.run.root(args, ["ln", "-s", "-f", "/var/cache/apk", chroot + "/etc/apk/cache"]) diff --git a/pmb/chroot/mount.py b/pmb/chroot/mount.py index 929ebfa0..762d9937 100644 --- a/pmb/chroot/mount.py +++ b/pmb/chroot/mount.py @@ -16,12 +16,53 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with pmbootstrap. If not, see . """ +import logging import os import pmb.config import pmb.parse import pmb.helpers.mount +def create_device_nodes(args, suffix): + """ + Create device nodes for null, zero, full, random, urandom in the chroot. + """ + try: + chroot = args.work + "/chroot_" + suffix + + # Create all device nodes as specified in the config + for dev in pmb.config.chroot_device_nodes: + path = chroot + "/dev/" + str(dev[4]) + if not os.path.exists(path): + pmb.helpers.run.root(args, ["mknod", + "-m", str(dev[0]), # permissions + path, # name + str(dev[1]), # type + str(dev[2]), # major + str(dev[3]), # minor + ]) + + # Verify major and minor numbers of created nodes + for dev in pmb.config.chroot_device_nodes: + path = chroot + "/dev/" + str(dev[4]) + stat_result = os.stat(path) + rdev = stat_result.st_rdev + assert os.major(rdev) == dev[2], "Wrong major in " + path + assert os.minor(rdev) == dev[3], "Wrong minor in " + path + + # Verify /dev/zero reading and writing + path = chroot + "/dev/zero" + with open(path, "r+b", 0) as handle: + assert handle.write(bytes([0xff])), "Write failed for " + path + assert handle.read(1) == bytes([0x00]), "Read failed for " + path + + # On failure: Show filesystem-related error + except Exception as e: + logging.info(str(e) + "!") + raise RuntimeError("Failed to create device nodes in the '" + + suffix + "' chroot.") + + def mount_dev_tmpfs(args, suffix="native"): """ Mount tmpfs inside the chroot's dev folder to make sure we can create @@ -33,13 +74,16 @@ def mount_dev_tmpfs(args, suffix="native"): if pmb.helpers.mount.ismount(dev): return - # Create the folder structure and mount it - if not os.path.exists(dev): - pmb.helpers.run.root(args, ["mkdir", "-p", dev]) + # Create the $chroot/dev folder and mount tmpfs there + pmb.helpers.run.root(args, ["mkdir", "-p", dev]) pmb.helpers.run.root(args, ["mount", "-t", "tmpfs", "-o", "size=1M,noexec,dev", "tmpfs", dev]) + # Create pts, shm folders and device nodes + pmb.helpers.run.root(args, ["mkdir", "-p", dev + "/pts", dev + "/shm"]) + create_device_nodes(args, suffix) + def mount(args, suffix="native"): # Mount tmpfs as the chroot's /dev diff --git a/pmb/config/__init__.py b/pmb/config/__init__.py index 1bc22c72..76e8a4c3 100644 --- a/pmb/config/__init__.py +++ b/pmb/config/__init__.py @@ -132,10 +132,10 @@ chroot_home_symlinks = { "/mnt/pmbootstrap-packages": "/home/pmos/packages/pmos", } -# The package alpine-base only creates some device nodes. Specify here, which -# additional nodes will get created during initialization of the chroot. -# Syntax for each entry: [permissions, type, major, minor, name] +# Device nodes to be created in each chroot. Syntax for each entry: +# [permissions, type, major, minor, name] chroot_device_nodes = [ + [666, "c", 1, 3, "null"], [666, "c", 1, 5, "zero"], [666, "c", 1, 7, "full"], [644, "c", 1, 8, "random"],