pkgcore / pychroot

a python library and cli tool that simplify chroot handling
https://pkgcore.github.io/pychroot/
BSD 3-Clause "New" or "Revised" License
32 stars 7 forks source link

does not seem to unmount created mounts with custom mounts #22

Closed johnnybubonic closed 7 years ago

johnnybubonic commented 7 years ago

so i'm calling pychroot in a function, and i have a bunch of custom bind mounts (and don't want to use the defaults, as it doesn't allow for e.g. Arch's pacman, which requires the chroot to be bind mounted as /)...

...
def myChroot(chrootdir, chroot_hostname, cmd):
    mountpoints = psutil.disk_partitions(all = True)
    mounts = []
    for m in mountpoints:
        mounts.append(m.mountpoint)
    cmnts = {}
    # see https://bugs.archlinux.org/task/46169
    if chrootdir not in mounts:
        cmnts[chrootdir + ':/'] = {'recursive': False, 'readonly': False, 'create': False}
    if (chrootdir + '/proc') not in mounts:
        cmnts['proc:/proc'] = {'recursive': True, 'create': True}
    if (chrootdir + '/sys') not in mounts:
        cmnts['/sys'] = {'recursive': True, 'create': True}
    if (chrootdir + '/dev') not in mounts:
        cmnts['/dev'] = {'recursive': True, 'create': True}
    if '/sys/firmware/efi/efivars' in mounts:
        if (chrootdir + '/sys/firmware/efi/efivars') not in mounts:
            cmnts['/sys/firmware/efi/efivars'] = {'recursive': True}
    if '/run' in mounts:
        if (chrootdir + '/run') not in mounts:
            cmnts['/run'] = {'recursive': True}

    pychroot.base.Chroot.default_mounts = {}
    chrootcmd = pychroot.base.Chroot(chrootdir, mountpoints = cmnts, hostname = chroot_hostname)
    chrootcmd.mount()
    with chrootcmd:
        import os
        os.system(cmd)
    chrootcmd.cleanup()

so all well and good. the mounts create and the chrooted command executes. HOWEVER, the mounts created don't unmount after execution, not even with the chrootcmd.cleanup().

With the following, however:

import pychroot
chroot = pychroot.Chroot('/var/tmp/chroottest')
with chroot:
    import os
    os.system('ls /home')

It does indeed unmount the mounted dirs. (I should note that it also backgrounds on the command completion, which seems odd to me, but only from the python shell.)

am i doing something wrong or is this a bug? the documentation is admittedly a bit sparse, so apologies if i'm going about this the wrong way.

Arch Linux x86_64, fully up to date. python 3.5 pychroot 0.9.16 snakeoil 0.7.1

radhermit commented 7 years ago

Your initial code wasn't allowing the mount namespace to do its magic. Basically the code forks a child which setups up a mount namespace and then the mounts are performed inside that. Thus when the child exits, all the mounts get unmounted because the namespace also vanishes.

Really, you shouldn't explicitly call chroot.mount() unless you really want to do everything manually. Just creating the context manager and using it as such should be enough. I could probably help people realize this by documenting things a bit better and perhaps "privatizing" some function names for internal use only. :smile:

Closing this as it's not a bug and is working as intended. See the pychroot script as a simple example of how to use the Chroot context manager that operates as an extended chroot(1) equivalent. If you want more help, feel free to drop me an email.