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`)
This commit is contained in:
parent
f49da75998
commit
4e665a2190
|
@ -45,46 +45,6 @@ def copy_resolv_conf(args, suffix="native"):
|
||||||
pmb.helpers.run.root(args, ["touch", chroot])
|
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"):
|
def init(args, suffix="native"):
|
||||||
# When already initialized: just prepare the chroot
|
# When already initialized: just prepare the chroot
|
||||||
chroot = args.work + "/chroot_" + suffix
|
chroot = args.work + "/chroot_" + suffix
|
||||||
|
@ -110,8 +70,7 @@ def init(args, suffix="native"):
|
||||||
|
|
||||||
logging.info("(" + suffix + ") install alpine-base")
|
logging.info("(" + suffix + ") install alpine-base")
|
||||||
|
|
||||||
# Initialize device nodes and cache
|
# Initialize cache
|
||||||
create_device_nodes(args, suffix)
|
|
||||||
apk_cache = args.work + "/cache_apk_" + arch
|
apk_cache = args.work + "/cache_apk_" + arch
|
||||||
pmb.helpers.run.root(args, ["ln", "-s", "-f", "/var/cache/apk", chroot +
|
pmb.helpers.run.root(args, ["ln", "-s", "-f", "/var/cache/apk", chroot +
|
||||||
"/etc/apk/cache"])
|
"/etc/apk/cache"])
|
||||||
|
|
|
@ -16,12 +16,53 @@ GNU General Public License for more details.
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with pmbootstrap. If not, see <http://www.gnu.org/licenses/>.
|
along with pmbootstrap. If not, see <http://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import pmb.config
|
import pmb.config
|
||||||
import pmb.parse
|
import pmb.parse
|
||||||
import pmb.helpers.mount
|
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"):
|
def mount_dev_tmpfs(args, suffix="native"):
|
||||||
"""
|
"""
|
||||||
Mount tmpfs inside the chroot's dev folder to make sure we can create
|
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):
|
if pmb.helpers.mount.ismount(dev):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Create the folder structure and mount it
|
# Create the $chroot/dev folder and mount tmpfs there
|
||||||
if not os.path.exists(dev):
|
pmb.helpers.run.root(args, ["mkdir", "-p", dev])
|
||||||
pmb.helpers.run.root(args, ["mkdir", "-p", dev])
|
|
||||||
pmb.helpers.run.root(args, ["mount", "-t", "tmpfs",
|
pmb.helpers.run.root(args, ["mount", "-t", "tmpfs",
|
||||||
"-o", "size=1M,noexec,dev",
|
"-o", "size=1M,noexec,dev",
|
||||||
"tmpfs", 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"):
|
def mount(args, suffix="native"):
|
||||||
# Mount tmpfs as the chroot's /dev
|
# Mount tmpfs as the chroot's /dev
|
||||||
|
|
|
@ -132,10 +132,10 @@ chroot_home_symlinks = {
|
||||||
"/mnt/pmbootstrap-packages": "/home/pmos/packages/pmos",
|
"/mnt/pmbootstrap-packages": "/home/pmos/packages/pmos",
|
||||||
}
|
}
|
||||||
|
|
||||||
# The package alpine-base only creates some device nodes. Specify here, which
|
# Device nodes to be created in each chroot. Syntax for each entry:
|
||||||
# additional nodes will get created during initialization of the chroot.
|
# [permissions, type, major, minor, name]
|
||||||
# Syntax for each entry: [permissions, type, major, minor, name]
|
|
||||||
chroot_device_nodes = [
|
chroot_device_nodes = [
|
||||||
|
[666, "c", 1, 3, "null"],
|
||||||
[666, "c", 1, 5, "zero"],
|
[666, "c", 1, 5, "zero"],
|
||||||
[666, "c", 1, 7, "full"],
|
[666, "c", 1, 7, "full"],
|
||||||
[644, "c", 1, 8, "random"],
|
[644, "c", 1, 8, "random"],
|
||||||
|
|
Loading…
Reference in New Issue