#include <pakfire/build.h>
#include <pakfire/constants.h>
#include <pakfire/dist.h>
-#include <pakfire/execute.h>
+#include <pakfire/jail.h>
#include <pakfire/logging.h>
#include <pakfire/mount.h>
#include <pakfire/packagelist.h>
return PyLong_FromLong(cmp);
}
-static PyObject* Pakfire_execute_logging_callback = NULL;
-
-static int __Pakfire_execute_logging_callback(struct pakfire* pakfire, void* data,
+static int __Pakfire_logging_callback(struct pakfire* pakfire, void* data,
int priority, const char* line, size_t length) {
+ PyObject* callback = (PyObject*)data;
int r = 0;
// Do nothing if callback isn't set
- if (!Pakfire_execute_logging_callback)
+ if (!callback)
return 0;
// Translate priority to Python logging priorities
if (!args)
return 1;
- PyObject* result = PyObject_CallObject(Pakfire_execute_logging_callback, args);
+ PyObject* result = PyObject_CallObject(callback, args);
if (result && PyLong_Check(result)) {
r = PyLong_AsLong(result);
}
}
static PyObject* Pakfire_execute(PakfireObject* self, PyObject* args, PyObject* kwds) {
- char* kwlist[] = {"command", "environ", "enable_network", "interactive",
- "logging_callback", NULL};
+ char* kwlist[] = {
+ "command",
+ "environ",
+ "enable_network",
+ "interactive",
+ "logging_callback",
+ NULL
+ };
+
+ struct pakfire_jail* jail = NULL;
+ const char** argv = NULL;
+ int flags = 0;
+ int r;
+ PyObject* ret = NULL;
PyObject* command = NULL;
PyObject* environ = NULL;
// Check if command is a list
if (!PyList_Check(command)) {
PyErr_SetString(PyExc_TypeError, "command must be a list");
- return NULL;
+ goto ERROR;
}
- ssize_t command_length = PyList_Size(command);
+ const ssize_t command_length = PyList_Size(command);
// Check if command is not empty
if (command_length == 0) {
PyErr_SetString(PyExc_ValueError, "command is empty");
- return NULL;
+ goto ERROR;
}
+ // Allocate argv
+ argv = calloc(command_length + 1, sizeof(*argv));
+ if (!argv)
+ goto ERROR;
+
// All arguments in command must be strings
for (unsigned int i = 0; i < command_length; i++) {
PyObject* item = PyList_GET_ITEM(command, i);
PyErr_Format(PyExc_TypeError, "Item %u in command is not a string", i);
return NULL;
}
+
+ // Copy to argv
+ argv[i] = PyUnicode_AsUTF8(item);
}
- // Check if logging_callback is
- if (logging_callback && !PyCallable_Check(logging_callback)) {
- PyErr_SetString(PyExc_TypeError, "logging_callback must be callable\n");
- return NULL;
+#if 0
+ // Enable network?
+ if (enable_network)
+ flags |= PAKFIRE_JAIL_ENABLE_NETWORK;
+#endif
+
+ // Interactive?
+ if (interactive)
+ flags |= PAKFIRE_JAIL_INTERACTIVE;
+
+ // Create jail
+ r = pakfire_jail_create(&jail, self->pakfire, flags);
+ if (r) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ goto ERROR;
+ }
+
+ // Set logging callback
+ if (logging_callback) {
+ if (!PyCallable_Check(logging_callback)) {
+ PyErr_SetString(PyExc_TypeError, "logging_callback must be callable\n");
+ goto ERROR;
+ }
+
+ pakfire_jail_set_log_callback(jail, __Pakfire_logging_callback, logging_callback);
}
- ssize_t environ_length = 0;
- PyObject* key;
- PyObject* value;
+ PyObject* key = NULL;
+ PyObject* value = NULL;
Py_ssize_t p = 0;
+ // Parse the environment
if (environ) {
// Check if environ is a dictionary
if (!PyDict_Check(environ)) {
PyErr_SetString(PyExc_TypeError, "environ must be a dictionary");
- return NULL;
+ goto ERROR;
}
// All keys and values must be strings
while (PyDict_Next(environ, &p, &key, &value)) {
if (!PyUnicode_Check(key) || !PyUnicode_Check(value)) {
PyErr_SetString(PyExc_TypeError, "Environment contains a non-string object");
- return NULL;
+ goto ERROR;
}
- }
-
- environ_length = PyDict_Size(environ);
- }
-
- // All inputs look fine
- const char* argv[command_length + 1];
- char* envp[environ_length + 1];
- int flags = 0;
-
- // Parse arguments
- for (unsigned int i = 0; i < command_length; i++) {
- PyObject* item = PyList_GET_ITEM(command, i);
- argv[i] = PyUnicode_AsUTF8(item);
- }
-
- // Parse environ
- if (environ) {
- unsigned int i = 0;
- p = 0;
-
- while (PyDict_Next(environ, &p, &key, &value)) {
- int r = asprintf(&envp[i++], "%s=%s",
- PyUnicode_AsUTF8(key), PyUnicode_AsUTF8(value));
-
- // Handle errors
- if (r < 0) {
- // Cleanup
- for (i = 0; envp[i]; i++)
- free(envp[i]);
-
- return PyErr_NoMemory();
+ // Set environment value
+ r = pakfire_jail_set_env(jail, PyUnicode_AsUTF8(key), PyUnicode_AsUTF8(value));
+ if (r) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ goto ERROR;
}
}
}
- // Terminate argv and envp
- argv[command_length] = NULL;
- envp[environ_length] = NULL;
-
- // Enable network?
- if (enable_network)
- flags |= PAKFIRE_EXECUTE_ENABLE_NETWORK;
-
- // Interactive?
- if (interactive)
- flags |= PAKFIRE_EXECUTE_INTERACTIVE;
-
- // Set logging callback
- Pakfire_execute_logging_callback = logging_callback;
-
// Execute command
- int r = pakfire_execute(self->pakfire, argv, envp, flags,
- (logging_callback) ? __Pakfire_execute_logging_callback : NULL, NULL);
-
- // Cleanup
- for (unsigned int i = 0; envp[i]; i++)
- free(envp[i]);
+ r = pakfire_jail_exec(jail, argv, NULL);
- // Raise an OS error if r < 0
+ // If the return code was negative, we had some internal error
if (r < 0) {
- errno = -r;
-
PyErr_SetFromErrno(PyExc_OSError);
- return NULL;
+ goto ERROR;
- // Raise exception when the command failed
+ // Otherwise the executed command returned some error code
} else if (r > 0) {
PyObject* code = PyLong_FromLong(r);
+ // Raise CommandExecutionError
PyErr_SetObject(PyExc_CommandExecutionError, code);
Py_DECREF(code);
- return NULL;
+ goto ERROR;
}
- // Return nothing
- Py_RETURN_NONE;
+ // Return None if everything was successful
+ ret = Py_None;
+ Py_INCREF(ret);
+
+ERROR:
+ if (argv)
+ free(argv);
+
+ if (jail) {
+ // Dereference the logging callback
+ // It might happen that the jail is not being freed because something else is
+ // holding a reference to it. We will however lose the reference to the logging
+ // function here which is why we reset it.
+ pakfire_jail_set_log_callback(jail, NULL, NULL);
+
+ pakfire_jail_unref(jail);
+ }
+
+ return ret;
}
static PyObject* Pakfire_dist(PakfireObject* self, PyObject* args) {