]> git.ipfire.org Git - pakfire.git/commitdiff
python: execute: Implement bind-mounting mountpoints
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 26 Mar 2025 14:43:13 +0000 (14:43 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 26 Mar 2025 14:43:13 +0000 (14:43 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/python/pakfire.c
tests/python/execute.py

index 884020b607abd9d00b9779093dc2027bf1054ab2..3c393857a002246261bf8ca4820441ee5fc2c8e6 100644 (file)
@@ -566,7 +566,9 @@ static PyObject* Pakfire_execute(PakfireObject* self, PyObject* args, PyObject*
        struct pakfire_input_buffer input = {};
        struct pakfire_jail* jail = NULL;
        struct pakfire_env* env = NULL;
+       PyObject* mountpoint = NULL;
        const char** argv = NULL;
+       PyObject* bind = NULL;
        PyObject* ret = NULL;
        PyObject* k = NULL;
        PyObject* v = NULL;
@@ -585,6 +587,7 @@ static PyObject* Pakfire_execute(PakfireObject* self, PyObject* args, PyObject*
        const char* kwlist[] = {
                "command",
                "environ",
+               "bind",
                "nice",
                "return_output",
                "input",
@@ -592,8 +595,8 @@ static PyObject* Pakfire_execute(PakfireObject* self, PyObject* args, PyObject*
        };
 
        // Parse arguments
-       if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Oiby#", (char**)kwlist,
-                       &command, &environ, &nice, &return_output, &input.data, &input.length))
+       if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOiby#", (char**)kwlist,
+                       &command, &environ, &bind, &nice, &return_output, &input.data, &input.length))
                goto ERROR;
 
        // Check if command is a list
@@ -694,6 +697,42 @@ static PyObject* Pakfire_execute(PakfireObject* self, PyObject* args, PyObject*
                }
        }
 
+       // Bind all mountpoints
+       if (bind) {
+               // Check if bind is a sequence, but it cannot be a string itself
+               if (!PySequence_Check(bind) || PyUnicode_Check(bind)) {
+                       PyErr_SetString(PyExc_TypeError, "bind must be a sequence");
+                       goto ERROR;
+               }
+
+               // Add all mountpoints
+               for (int i = 0; i < PySequence_Length(bind); i++) {
+                       mountpoint = PySequence_GetItem(bind, i);
+                       if (!mountpoint)
+                               goto ERROR;
+
+                       // All elements must be strings
+                       if (!PyUnicode_Check(mountpoint)) {
+                               PyErr_SetString(PyExc_TypeError, "bind mountpoints must be strings");
+                               goto ERROR;
+                       }
+
+                       // Fetch the string
+                       const char* s = PyUnicode_AsUTF8(mountpoint);
+
+                       // Bind!
+                       r = pakfire_jail_bind(jail, s, s, 0);
+                       if (r < 0) {
+                               errno = -r;
+                               PyErr_SetFromErrno(PyExc_OSError);
+                               goto ERROR;
+                       }
+
+                       Py_DECREF(mountpoint);
+                       mountpoint = NULL;
+               }
+       }
+
        Py_BEGIN_ALLOW_THREADS
 
        // Execute command
@@ -740,6 +779,7 @@ ERROR:
 
        Py_XDECREF(output.stdout);
        Py_XDECREF(output.stderr);
+       Py_XDECREF(mountpoint);
 
        return ret;
 }
index c2ce2e89d533a6f2ac14b92538f8b0fbb88c57bc..30ddcebdf43c6b41657f66e9db45683c77cdc9b8 100755 (executable)
@@ -122,6 +122,23 @@ class ExecuteTests(tests.TestCase):
                with self.assertRaises(pakfire.CommandExecutionError):
                        self.pakfire.execute(["/does-not-exist"], input=b"1234")
 
+       def test_execute_bind(self):
+               """
+                       Tries to bind-mount something
+               """
+               # Try to mount the
+               mountpoint = self.path()
+
+               # Check if this is actually a mountpoint
+               self.pakfire.execute(["/command", "check-mountpoint", mountpoint], bind=[mountpoint])
+
+               # Try some invalid inputs
+               with self.assertRaises(TypeError):
+                       self.pakfire.execute(["/command", "exit-with-code", "0"], bind="/something")
+
+               with self.assertRaises(TypeError):
+                       self.pakfire.execute(["/command", "exit-with-code", "0"], bind=[123])
+
        def test_nice(self):
                """
                        Check if the jail is able to set the nice level