Ejemplo n.º 1
0
 def test_root(self):
     # test umount
     mount(self.source, self.target, None, MS_BIND)
     umount(self.target)
     # test umount2
     mount(self.source, self.target, None, MS_BIND)
     umount(self.target, MNT_FORCE)
Ejemplo n.º 2
0
 def test_no_perms(self):
     with self.assertRaises(OSError) as cm:
         mount(self.source, self.target, None, MS_BIND)
     self.assertTrue(cm.exception.errno in (errno.EPERM, errno.EACCES))
     with self.assertRaises(OSError) as cm:
         umount(self.target)
     self.assertTrue(cm.exception.errno in (errno.EPERM, errno.EINVAL))
Ejemplo n.º 3
0
    def test_lazy_unmount(self):
        src_file = pjoin(self.source, 'file')
        bind_file = pjoin(self.target, 'file')
        touch(src_file)
        with open(src_file, 'w') as f:
            f.write('foo')

        try:
            with Namespace(user=True, mount=True):
                mount(self.source, self.target, None, MS_BIND)
                assert os.path.exists(bind_file)

                with open(bind_file) as f:
                    # can't unmount the target due to the open file
                    with pytest.raises(OSError) as cm:
                        umount(self.target)
                    assert cm.value.errno == errno.EBUSY
                    # lazily unmount instead
                    umount(self.target, MNT_DETACH)
                    # confirm the file doesn't exist in the bind mount anymore
                    assert not os.path.exists(bind_file)
                    # but the file is still accessible to the process
                    assert f.read() == 'foo'

                # trying to reopen causes IOError
                with pytest.raises(IOError) as cm:
                    f = open(bind_file)
                assert cm.value.errno == errno.ENOENT
        except PermissionError:
            pytest.skip('No permission to use user and mount namespace')
Ejemplo n.º 4
0
    def test_lazy_unmount(self):
        src_file = pjoin(self.source, 'file')
        bind_file = pjoin(self.target, 'file')
        touch(src_file)
        with open(src_file, 'w') as f:
            f.write('foo')

        try:
            with Namespace(user=True, mount=True):
                mount(self.source, self.target, None, MS_BIND)
                assert os.path.exists(bind_file)

                with open(bind_file) as f:
                    # can't unmount the target due to the open file
                    with pytest.raises(OSError) as cm:
                        umount(self.target)
                    assert cm.value.errno == errno.EBUSY
                    # lazily unmount instead
                    umount(self.target, MNT_DETACH)
                    # confirm the file doesn't exist in the bind mount anymore
                    assert not os.path.exists(bind_file)
                    # but the file is still accessible to the process
                    assert f.read() == 'foo'

                # trying to reopen causes IOError
                with pytest.raises(IOError) as cm:
                    f = open(bind_file)
                assert cm.value.errno == errno.ENOENT
        except PermissionError:
            pytest.skip('No permission to use user and mount namespace')
Ejemplo n.º 5
0
 def test_no_perms(self):
     with pytest.raises(OSError) as cm:
         mount(self.source, self.target, None, MS_BIND)
     assert cm.value.errno in (errno.EPERM, errno.EACCES)
     with pytest.raises(OSError) as cm:
         umount(self.target)
     assert cm.value.errno in (errno.EPERM, errno.EINVAL)
Ejemplo n.º 6
0
 def test_no_perms(self):
     with self.assertRaises(OSError) as cm:
         mount(self.source, self.target, None, MS_BIND)
     self.assertTrue(cm.exception.errno in (errno.EPERM, errno.EACCES))
     with self.assertRaises(OSError) as cm:
         umount(self.target)
     self.assertTrue(cm.exception.errno in (errno.EPERM, errno.EINVAL))
Ejemplo n.º 7
0
 def test_root(self):
     # test umount
     mount(self.source, self.target, None, MS_BIND)
     umount(self.target)
     # test umount2
     mount(self.source, self.target, None, MS_BIND)
     umount(self.target, MNT_FORCE)
Ejemplo n.º 8
0
 def test_no_perms(self):
     with pytest.raises(OSError) as cm:
         mount(self.source, self.target, None, MS_BIND)
     assert cm.value.errno in (errno.EPERM, errno.EACCES)
     with pytest.raises(OSError) as cm:
         umount(self.target)
     assert cm.value.errno in (errno.EPERM, errno.EINVAL)
Ejemplo n.º 9
0
 def test_args_bytes(self):
     # The initial source, target, and fstype arguments to mount(2) must be
     # byte strings; if they are unicode strings the arguments get mangled
     # leading to errors when the syscall is run. This confirms mount() from
     # snakeoil.osutils always converts the arguments into byte strings.
     for source, target, fstype in ((b'source', b'target', b'fstype'),
                                    ('source', 'target', 'fstype')):
         with mock.patch('snakeoil.osutils.mount.ctypes') as mock_ctypes:
             with pytest.raises(OSError):
                 mount(source, target, fstype, MS_BIND)
             mount_call = next(x for x in mock_ctypes.mock_calls if x[0] == 'CDLL().mount')
             for arg in mount_call[1][0:3]:
                 assert isinstance(arg, bytes)
Ejemplo n.º 10
0
    def test_bind_mount(self):
        src_file = pjoin(self.source, 'file')
        bind_file = pjoin(self.target, 'file')
        touch(src_file)

        try:
            with Namespace(user=True, mount=True):
                assert not os.path.exists(bind_file)
                mount(self.source, self.target, None, MS_BIND)
                assert os.path.exists(bind_file)
                umount(self.target)
                assert not os.path.exists(bind_file)
        except PermissionError:
            pytest.skip('No permission to use user and mount namespace')
Ejemplo n.º 11
0
 def test_args_bytes(self):
     # The initial source, target, and fstype arguments to mount(2) must be
     # byte strings; if they are unicode strings the arguments get mangled
     # leading to errors when the syscall is run. This confirms mount() from
     # snakeoil.osutils always converts the arguments into byte strings.
     for source, target, fstype in ((b'source', b'target', b'fstype'),
                                    ('source', 'target', 'fstype')):
         with mock.patch('snakeoil.osutils.mount.ctypes') as mock_ctypes:
             with pytest.raises(OSError):
                 mount(source, target, fstype, MS_BIND)
             mount_call = next(x for x in mock_ctypes.mock_calls
                               if x[0] == 'CDLL().mount')
             for arg in mount_call[1][0:3]:
                 assert isinstance(arg, bytes)
Ejemplo n.º 12
0
    def test_bind_mount(self):
        src_file = pjoin(self.source, 'file')
        bind_file = pjoin(self.target, 'file')
        touch(src_file)

        try:
            with Namespace(user=True, mount=True):
                assert not os.path.exists(bind_file)
                mount(self.source, self.target, None, MS_BIND)
                assert os.path.exists(bind_file)
                umount(self.target)
                assert not os.path.exists(bind_file)
        except PermissionError:
            pytest.skip('No permission to use user and mount namespace')
Ejemplo n.º 13
0
def bind(src, dest, chroot, create=False, log=None, readonly=False,
         recursive=False, **_kwargs):
    """Set up a bind mount.

    :param src: The source location to mount.
    :type src: str
    :param dest: The destination to mount on.
    :type dest: str
    :param chroot: The chroot base path.
    :type chroot: str
    :param create: Whether to create the destination.
    :type create: bool
    :param log: A logger to use for logging.
    :type log: logging.Logger
    :param readonly: Whether to remount read-only.
    :type readonly: bool
    :param recursive: Whether to use a recursive bind mount.
    :type recursive: bool
    """
    log = getlogger(log, __name__)
    fstypes = ('proc', 'sysfs', 'tmpfs')
    mount_flags = []
    mount_options = []

    if src not in fstypes:
        src = os.path.normpath(src)
    if os.path.islink(dest):
        dest = os.path.join(chroot, os.path.realpath(dest).lstrip('/'))
        if not os.path.exists(dest):
            create = True
    else:
        dest = os.path.normpath(dest)

    if create:
        try:
            if not os.path.isdir(src) and src not in fstypes:
                os.makedirs(os.path.dirname(dest))
            else:
                os.makedirs(dest)
        except OSError as e:
            if e.errno != errno.EEXIST:
                raise

        if not os.path.isdir(src) and src not in fstypes:
            try:
                touch(dest)
            except OSError as e:
                raise ChrootMountError(
                    "cannot bind mount to '{}'".format(dest), getattr(e, 'errno', None))

    if not os.path.exists(src) and src not in fstypes:
        raise ChrootMountError("cannot bind mount from '{}'".format(src), errno.ENOENT)
    elif not os.path.exists(dest):
        raise ChrootMountError("cannot bind mount to '{}'".format(dest), errno.ENOENT)

    if src in fstypes:
        fstype = src
        log.debug("  mounting '{}' filesystem on '{}'".format(src, dest))
    else:
        fstype = None
        mount_flags.append(MS_BIND)
        if recursive:
            mount_flags.append(MS_REC)
        log.debug("  bind mounting '{}' on '{}'".format(src, dest))

    try:
        mount(source=src, target=dest, fstype=fstype,
              flags=reduce(operator.or_, mount_flags, 0),
              data=','.join(mount_options))
        if readonly:
            mount_flags.extend([MS_REMOUNT, MS_RDONLY])
            mount(source=src, target=dest, fstype=fstype,
                  flags=reduce(operator.or_, mount_flags, 0),
                  data=','.join(mount_options))
    except OSError as e:
        raise ChrootMountError(
            'Failed mounting: mount -t {} {} {}'.format(fstype, src, dest), e.errno)
Ejemplo n.º 14
0
 def test_missing_dirs(self):
     with pytest.raises(OSError) as cm:
         mount('source', 'target', None, MS_BIND)
     assert cm.value.errno == errno.ENOENT
Ejemplo n.º 15
0
 def test_missing_dirs(self):
     with self.assertRaises(OSError) as cm:
         mount('source', 'target', None, MS_BIND)
     self.assertEqual(cm.exception.errno, errno.ENOENT)
Ejemplo n.º 16
0
 def test_missing_dirs(self):
     with self.assertRaises(OSError) as cm:
         mount('source', 'target', None, MS_BIND)
     self.assertEqual(cm.exception.errno, errno.ENOENT)
Ejemplo n.º 17
0
 def test_missing_dirs(self):
     with pytest.raises(OSError) as cm:
         mount('source', 'target', None, MS_BIND)
     assert cm.value.errno == errno.ENOENT
Ejemplo n.º 18
0
def bind(src,
         dest,
         chroot,
         create=False,
         log=None,
         readonly=False,
         recursive=False,
         **_kwargs):
    """Set up a bind mount.

    :param src: The source location to mount.
    :type src: str
    :param dest: The destination to mount on.
    :type dest: str
    :param chroot: The chroot base path.
    :type chroot: str
    :param create: Whether to create the destination.
    :type create: bool
    :param log: A logger to use for logging.
    :type log: logging.Logger
    :param readonly: Whether to remount read-only.
    :type readonly: bool
    :param recursive: Whether to use a recursive bind mount.
    :type recursive: bool
    """
    log = getlogger(log, __name__)
    fstypes = ('proc', 'sysfs', 'tmpfs')
    mount_flags = []
    mount_options = []

    if src not in fstypes:
        src = os.path.normpath(src)
    if os.path.islink(dest):
        dest = os.path.join(chroot, os.path.realpath(dest).lstrip('/'))
        if not os.path.exists(dest):
            create = True
    else:
        dest = os.path.normpath(dest)

    if create:
        try:
            if not os.path.isdir(src) and src not in fstypes:
                os.makedirs(os.path.dirname(dest))
            else:
                os.makedirs(dest)
        except OSError as e:
            if e.errno != errno.EEXIST:
                raise

        if not os.path.isdir(src) and src not in fstypes:
            try:
                touch(dest)
            except OSError as e:
                raise ChrootMountError(f'cannot bind mount to {dest!r}',
                                       getattr(e, 'errno', None))

    if not os.path.exists(src) and src not in fstypes:
        raise ChrootMountError(f'cannot bind mount from {src!r}', errno.ENOENT)
    elif not os.path.exists(dest):
        raise ChrootMountError(f'cannot bind mount to {dest!r}', errno.ENOENT)

    if src in fstypes:
        fstype = src
        log.debug('  mounting %r filesystem on %r', src, dest)
    else:
        fstype = None
        mount_flags.append(MS_BIND)
        if recursive:
            mount_flags.append(MS_REC)
        log.debug('  bind mounting %r on %r', src, dest)

    try:
        mount(source=src,
              target=dest,
              fstype=fstype,
              flags=reduce(operator.or_, mount_flags, 0),
              data=','.join(mount_options))
        if readonly:
            mount_flags.extend([MS_REMOUNT, MS_RDONLY])
            mount(source=src,
                  target=dest,
                  fstype=fstype,
                  flags=reduce(operator.or_, mount_flags, 0),
                  data=','.join(mount_options))
    except OSError as e:
        raise ChrootMountError(
            f'failed mounting: mount -t {fstype} {src} {dest}', e.errno)