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:
Oliver Smith 2018-04-29 22:17:57 +00:00 committed by GitHub
parent f49da75998
commit 4e665a2190
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 51 additions and 48 deletions

View File

@ -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"])

View File

@ -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 <http://www.gnu.org/licenses/>.
"""
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

View File

@ -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"],