#include <pakfire/types.h>
#include <pakfire/util.h>
+#define ENVIRON_SIZE 128
#define BUFFER_SIZE 1024 * 64
#define EPOLL_MAX_EVENTS 2
#define LDCONFIG "/sbin/ldconfig"
-static char* envp_empty[1] = { NULL };
+// The default environment that will be set for every command
+static const struct environ {
+ const char* key;
+ const char* val;
+} default_environ[] = {
+ { "LANG", "en_US.utf-8" },
+ { "TERM", "vt100" },
+ { NULL, NULL },
+};
struct pakfire_execute {
Pakfire pakfire;
const char** argv;
- char** envp;
+ char* envp[ENVIRON_SIZE];
char cgroup[PATH_MAX];
return 0;
}
+static int find_environ(struct pakfire_execute* env, const char* key) {
+ if (!key) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ char buffer[strlen(key) + 2];
+ unsigned int i = 0;
+
+ pakfire_string_format(buffer, "%s=", key);
+
+ for (i = 0; env->envp[i]; i++) {
+ if (pakfire_string_startswith(env->envp[i], buffer))
+ return i;
+ }
+
+ // Return -ENOSPC when the environment is full
+ if (i >= ENVIRON_SIZE) {
+ errno = ENOSPC;
+ return -1;
+ }
+
+ // Return the index of the next free slot
+ return i;
+}
+
+static int set_environ(struct pakfire_execute* env, const char* key, const char* value) {
+ // Find the index where to write this value to
+ int idx = find_environ(env, key);
+ if (idx < 0)
+ return idx;
+
+ // Free any previous value
+ if (env->envp[idx])
+ free(env->envp[idx]);
+
+ // Format and set environment variable
+ asprintf(&env->envp[idx], "%s=%s", key, value);
+
+ DEBUG(env->pakfire, "Set environment variable: %s\n", env->envp[idx]);
+
+ return 0;
+}
+
static int pakfire_execute_fork(void* data) {
struct pakfire_execute* env = (struct pakfire_execute*)data;
PAKFIRE_EXPORT int pakfire_execute(Pakfire pakfire, const char* argv[], char* envp[],
int flags, pakfire_execute_logging_callback logging_callback, void* data) {
DIR* cgroupdir = NULL;
+ int r;
struct pakfire_execute env = {
.pakfire = pakfire,
.argv = argv,
- .envp = envp,
.cgroup = "pakfire/execute-XXXXXX",
};
if (!argv || !argv[0])
return -EINVAL;
- if (!env.envp)
- env.envp = envp_empty;
+ // Set default environment
+ for (const struct environ* e = default_environ; e->key; e++) {
+ r = set_environ(&env, e->key, e->val);
+ if (r)
+ goto ERROR;
+ }
if (!logging_callback)
logging_callback = &default_logging_callback;
if (!(flags & PAKFIRE_EXECUTE_ENABLE_NETWORK))
args.flags |= CLONE_NEWNET;
+ // Setup interactive environment
+ if (flags & PAKFIRE_EXECUTE_INTERACTIVE) {
+ // Set environment
+ r = set_environ(&env, "PS1", "pakfire-chroot \\w> ");
+ if (r)
+ goto ERROR;
+
+ // Copy TERM
+ char* TERM = secure_getenv("TERM");
+ if (TERM) {
+ r = set_environ(&env, "TERM", TERM);
+ if (r)
+ goto ERROR;
+ }
+
+ // Copy LANG
+ char* LANG = secure_getenv("LANG");
+ if (LANG) {
+ r = set_environ(&env, "LANG", LANG);
+ if (r)
+ goto ERROR;
+ }
+
// Make some file descriptors for stdout & stderr
- if (!(flags & PAKFIRE_EXECUTE_INTERACTIVE)) {
+ } else {
if (pipe(env.stdout) < 0) {
ERROR(pakfire, "Could not create file descriptors for stdout: %s\n",
strerror(errno));
-
- return -errno;
+ r = -1;
+ goto ERROR;
}
if (pipe(env.stderr) < 0) {
ERROR(pakfire, "Could not create file descriptors for stderr: %s\n",
strerror(errno));
+ r = -1;
+ goto ERROR;
+ }
+ }
- return -errno;
+ // Copy user environment
+ if (envp) {
+ char* key;
+ char* val;
+
+ // Copy environment variables
+ for (unsigned int i = 0; envp[i]; i++) {
+ r = pakfire_string_partition(envp[i], "=", &key, &val);
+ if (r)
+ continue;
+
+ // Set value
+ set_environ(&env, key, val);
+
+ if (key)
+ free(key);
+ if (val)
+ free(val);
}
}
// Make cgroup name
- int r = pakfire_cgroup_random_name(env.cgroup);
+ r = pakfire_cgroup_random_name(env.cgroup);
if (r)
goto ERROR;
if (env.stderr[0])
close(env.stderr[0]);
+ // Free environment
+ for (unsigned int i = 0; env.envp[i]; i++)
+ free(env.envp[i]);
+
return r;
}