bdisk/bdisk/bchroot.py

74 lines
3.6 KiB
Python
Executable File

# NOTE: this is almost taken verbatim from https://github.com/pkgcore/pychroot's
# pychroot/scripts/pychroot.py because the pychroot.Chroot method isn't really
# documented very well
#from __future__ import absolute_import, unicode_literals
#from functools import partial
import os
import sys
import psutil
#from pychroot.base import Chroot
import pychroot
import subprocess
import ctypes
def chrootMount(source, target, fs, options=''):
ret = ctypes.CDLL('libc.so.6', use_errno=True).mount(source, target, fs, 0, options)
if ret < 0:
errno = ctypes.get_errno()
raise RuntimeError("Error mounting {} ({}) on {} with options '{}': {}".
format(source, fs, target, options, os.strerror(errno)))
def chroot(chrootdir, chroot_hostname, cmd = '/root/pre-build.sh'):
# MOUNT the chroot
mountpoints = psutil.disk_partitions(all = True)
mounts = []
for m in mountpoints:
mounts.append(m.mountpoint)
# mount the chrootdir... onto itself. as a bind mount. it's so stupid, i know. see https://bugs.archlinux.org/task/46169
if chrootdir not in mounts:
subprocess.call(['/bin/mount', '--bind', chrootdir, chrootdir])
### The following mountpoints don't seem to mount properly with pychroot. save it for v3.n+1. TODO. ###
# bind-mount so we can resolve things inside
if (chrootdir + '/etc/resolv.conf') not in mounts:
subprocess.call(['/bin/mount', '--bind', '-o', 'ro', '/etc/resolv.conf', chrootdir + '/etc/resolv.conf'])
# mount -t proc to chrootdir + '/proc' here
if (chrootdir + '/proc') not in mounts:
subprocess.call(['/bin/mount', '-t', 'proc', '-o', 'nosuid,noexec,nodev', 'proc', chrootdir + '/proc'])
# rbind mount /sys to chrootdir + '/sys' here
if (chrootdir + '/sys') not in mounts:
subprocess.call(['/bin/mount', '-t', 'sysfs', '-o', 'nosuid,noexec,nodev,ro', 'sys', chrootdir + '/sys'])
# mount the efivars in the chroot if it exists on the host. i mean, why not?
if '/sys/firmware/efi/efivars' in mounts:
if (chrootdir + '/sys/firmware/efi/efivars') not in mounts:
subprocess.call(['/bin/mount', '-t', 'efivarfs', '-o', 'nosuid,noexec,nodev', 'efivarfs', chrootdir + '/sys/firmware/efi/efivars'])
# rbind mount /dev to chrootdir + '/dev' here
if (chrootdir + '/dev') not in mounts:
subprocess.call(['/bin/mount', '-t', 'devtmpfs', '-o', 'mode=0755,nosuid', 'udev', chrootdir + '/dev'])
if (chrootdir + '/dev/pts') not in mounts:
subprocess.call(['/bin/mount', '-t', 'devpts', '-o', 'mode=0620,gid=5,nosuid,noexec', 'devpts', chrootdir + '/dev/pts'])
if '/dev/shm' in mounts:
if (chrootdir + '/dev/shm') not in mounts:
subprocess.call(['/bin/mount', '-t', 'tmpfs', '-o', 'mode=1777,nosuid,nodev', 'shm', chrootdir + '/dev/shm'])
if '/run' in mounts:
if (chrootdir + '/run') not in mounts:
subprocess.call(['/bin/mount', '-t', 'tmpfs', '-o', 'nosuid,nodev,mode=0755', 'run', chrootdir + '/run'])
if '/tmp' in mounts:
if (chrootdir + '/tmp') not in mounts:
subprocess.call(['/bin/mount', '-t', 'tmpfs', '-o', 'mode=1777,strictatime,nodev,nosuid', 'tmp', chrootdir + '/tmp'])
print("Now performing '{0}' in chroot for {1}...".format(cmd, chrootdir))
print("You can view the progress via:\n\n\ttail -f {0}/var/log/chroot_install.log\n".format(chrootdir))
real_root = os.open("/", os.O_RDONLY)
os.chroot(chrootdir)
os.system('/root/pre-build.sh')
os.fchdir(real_root)
os.chroot('.')
os.close(real_root)
return(chrootdir)
def chrootUnmount(chrootdir):
subprocess.call(['umount', '-lR', chrootdir])