# 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])