]> git.ipfire.org Git - pakfire.git/commitdiff
execute: Move setting default environment into libpakfire
authorMichael Tremer <michael.tremer@ipfire.org>
Fri, 21 May 2021 09:51:53 +0000 (09:51 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Fri, 21 May 2021 09:51:53 +0000 (09:51 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/execute.c
src/pakfire/builder.py

index 13ccce8f4353a13764ca0ab3e1c26610951a32eb..a75da8e67ad6e31aa7f9fda2c5e9bf9228465bc2 100644 (file)
 #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];
 
@@ -250,6 +259,50 @@ static int default_logging_callback(Pakfire pakfire, void* data, int priority,
        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;
 
@@ -338,11 +391,11 @@ static int pakfire_execute_fork(void* 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",
        };
 
@@ -350,8 +403,12 @@ PAKFIRE_EXPORT int pakfire_execute(Pakfire pakfire, const char* argv[], char* en
        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;
@@ -371,25 +428,69 @@ PAKFIRE_EXPORT int pakfire_execute(Pakfire pakfire, const char* argv[], char* en
        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;
 
@@ -473,6 +574,10 @@ 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;
 }
 
index aff755a7d389629e4e953ac259784a1c9ccd788b..20ae0f655eb7bd6a853b7eda0dc0640b14f0c100 100644 (file)
@@ -147,11 +147,7 @@ class BuilderContext(object):
        @property
        def environ(self):
                # Build a minimal environment for executing, but try to inherit TERM and LANG
-               env = {
-                       "PS1"  : "pakfire-chroot \w> ",
-                       "TERM" : os.environ.get("TERM", "vt100"),
-                       "LANG" : os.environ.get("LANG", "en_US.UTF-8"),
-               }
+               env = {}
 
                # Fake UTS_MACHINE, when we cannot use the personality syscall and
                # if the host architecture is not equal to the target architecture.