From b6ee4e77acd9257a8e2b9ad27ecac0274b1ed6d5 Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Sat, 13 Feb 2021 14:18:06 +0000 Subject: [PATCH] builder: Add mount/umount to _pakfire to avoid calling /bin/mount Signed-off-by: Michael Tremer --- src/_pakfire/_pakfiremodule.c | 72 +++++++++++++++++++++++++++ src/pakfire/builder.py | 91 ++++++++++------------------------- 2 files changed, 97 insertions(+), 66 deletions(-) diff --git a/src/_pakfire/_pakfiremodule.c b/src/_pakfire/_pakfiremodule.c index e3410f8fe..d8ff7b8e2 100644 --- a/src/_pakfire/_pakfiremodule.c +++ b/src/_pakfire/_pakfiremodule.c @@ -22,6 +22,7 @@ #include #include +#include #include @@ -66,6 +67,50 @@ static PyObject* _pakfire_arch_supported_by_host(PyObject* self, PyObject* args) Py_RETURN_FALSE; } +static PyObject* _pakfire_mount(PyObject* self, PyObject* args, PyObject* kwds) { + char* kwlist[] = { + "path", + "target", + "type", + "flags", + "options", + NULL, + }; + + const char* path = NULL; + const char* target = NULL; + const char* type = NULL; + int flags = 0; + const char* options = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss|zis", kwlist, + &path, &target, &type, &flags, &options)) + return NULL; + + int r = mount(path, target, type, flags, options); + if (r) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + Py_RETURN_NONE; +} + +static PyObject* _pakfire_umount(PyObject* self, PyObject* args) { + const char* path = NULL; + + if (!PyArg_ParseTuple(args, "s", &path)) + return NULL; + + int r = umount(path); + if (r) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + Py_RETURN_NONE; +} + static PyMethodDef pakfireModuleMethods[] = { {"performance_index", (PyCFunction)performance_index, METH_VARARGS, NULL}, {"version_compare", (PyCFunction)version_compare, METH_VARARGS, NULL}, @@ -73,6 +118,8 @@ static PyMethodDef pakfireModuleMethods[] = { {"sync", (PyCFunction)_sync, METH_NOARGS, NULL}, {"native_arch", (PyCFunction)_pakfire_native_arch, METH_NOARGS, NULL }, {"arch_supported_by_host", (PyCFunction)_pakfire_arch_supported_by_host, METH_VARARGS, NULL }, + {"mount", (PyCFunction)_pakfire_mount, METH_VARARGS|METH_KEYWORDS, NULL }, + {"umount", (PyCFunction)_pakfire_umount, METH_VARARGS, NULL }, { NULL, NULL, 0, NULL } }; @@ -257,5 +304,30 @@ PyMODINIT_FUNC PyInit__pakfire(void) { PyDict_SetItemString(d, "SOLVER_FLAG_SPLITPROVIDES", Py_BuildValue("i", SOLVER_FLAG_SPLITPROVIDES)); PyDict_SetItemString(d, "SOLVER_FLAG_IGNORE_RECOMMENDED", Py_BuildValue("i", SOLVER_FLAG_IGNORE_RECOMMENDED)); + // Mount Flags + if (PyModule_AddIntConstant(module, "MS_NOATIME", MS_NOATIME)) + return NULL; + + if (PyModule_AddIntConstant(module, "MS_NODEV", MS_NODEV)) + return NULL; + + if (PyModule_AddIntConstant(module, "MS_NOEXEC", MS_NOEXEC)) + return NULL; + + if (PyModule_AddIntConstant(module, "MS_RDONLY", MS_RDONLY)) + return NULL; + + if (PyModule_AddIntConstant(module, "MS_RELATIME", MS_RELATIME)) + return NULL; + + if (PyModule_AddIntConstant(module, "MS_STRICTATIME", MS_STRICTATIME)) + return NULL; + + if (PyModule_AddIntConstant(module, "MS_BIND", MS_BIND)) + return NULL; + + if (PyModule_AddIntConstant(module, "MS_REMOUNT", MS_REMOUNT)) + return NULL; + return module; } diff --git a/src/pakfire/builder.py b/src/pakfire/builder.py index b65018f69..37d09ea7a 100644 --- a/src/pakfire/builder.py +++ b/src/pakfire/builder.py @@ -38,7 +38,6 @@ from . import downloaders from . import logger from . import packages from . import repository -from . import shell from . import util import logging @@ -74,7 +73,7 @@ class Builder(object): # Settings array. self.settings = { "enable_ccache" : self.config.get_bool("builder", "use_ccache", True), - "buildroot_tmpfs" : self.config.get_bool("builder", "use_tmpfs", False), + "buildroot_tmpfs" : self.config.get_bool("builder", "use_tmpfs", True), } # Add settings from keyword arguments @@ -102,15 +101,8 @@ class Builder(object): def __enter__(self): self.log.debug("Entering %s" % self.path) - # Mount the directories - try: - self._mountall() - except OSError as e: - if e.errno == 30: # Read-only FS - raise BuildError("Buildroot is read-only: %s" % self.path) - - # Raise all other errors - raise + # Mount the build environment + self._mount() # Setup domain name resolution in chroot self.setup_dns() @@ -128,7 +120,7 @@ class Builder(object): self.cgroup = None # Umount the build environment - self._umountall() + self._umount() # Delete everything self._destroy() @@ -174,61 +166,37 @@ class Builder(object): if os.path.exists(self.path): util.rm(self.path) - @property - def mountpoints(self): - mountpoints = [] + def _mount(self): + """ + Mounts the build environment + """ + os.makedirs(self.path) - # Make root as a tmpfs if enabled. + # Mount ramdisk if enabled if self.settings.get("buildroot_tmpfs"): - mountpoints += [ - ("pakfire_root", "/", "tmpfs", "defaults"), - ] + _pakfire.mount("pakfire_root", self.path, "tmpfs") - # If ccache support is requested, we bind mount the cache. + # Bind-mount the ccache if enabled if self.settings.get("enable_ccache"): - # Create ccache cache directory if it does not exist. if not os.path.exists(CCACHE_CACHE_DIR): os.makedirs(CCACHE_CACHE_DIR) - mountpoints += [ - (CCACHE_CACHE_DIR, "/var/cache/ccache", "bind", "bind"), - ] - - return mountpoints - - def _mountall(self): - self.log.debug("Mounting environment") - - for src, dest, fs, options in self.mountpoints: - mountpoint = self.chrootPath(dest) - if options: - options = "-o %s" % options - - # Eventually create mountpoint directory - if not os.path.exists(mountpoint): - os.makedirs(mountpoint) - - self.execute_root("mount -n -t %s %s %s %s" % (fs, options, src, mountpoint), shell=True) + os.makedirs("%s/var/cache/ccache" % self.path) - def _umountall(self): - self.log.debug("Umounting environment") + _pakfire.mount(CCACHE_CACHE_DIR, "%s/var/cache/ccache" % self.path, + flags=_pakfire.MS_BIND) - mountpoints = [] - for src, dest, fs, options in reversed(self.mountpoints): - dest = self.chrootPath(dest) - - if not dest in mountpoints: - mountpoints.append(dest) - - while mountpoints: - for mp in mountpoints: - try: - self.execute_root("umount -n %s" % mp, shell=True) - except ShellEnvironmentError: - pass + def _umount(self): + """ + Umounts the build environment + """ + mountpoints = ( + "%s/var/cache/ccache" % self.path, + self.path, + ) - if not os.path.ismount(mp): - mountpoints.remove(mp) + for mp in mountpoints: + _pakfire.umount(mp) def copyin(self, file_out, file_in): if file_in.startswith("/"): @@ -288,15 +256,6 @@ class Builder(object): for i in ("/etc/resolv.conf", "/etc/hosts"): self.copyin(i, i) - def execute_root(self, command, **kwargs): - """ - Executes the given command outside the build chroot. - """ - shellenv = shell.ShellExecuteEnvironment(command, logger=self.log, **kwargs) - shellenv.execute() - - return shellenv - class BuilderContext(object): def __init__(self, builder): -- 2.47.2