]> git.ipfire.org Git - pakfire.git/commitdiff
jail: Move the environment into an extra object
authorMichael Tremer <michael.tremer@ipfire.org>
Sun, 29 Dec 2024 14:59:17 +0000 (14:59 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sun, 29 Dec 2024 14:59:17 +0000 (14:59 +0000)
This allows us to pass a custom environment to each command that we are
running. This helps us to keep the environment a lot cleaner.

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
12 files changed:
Makefile.am
src/libpakfire/archive.c
src/libpakfire/build.c
src/libpakfire/env.c [new file with mode: 0644]
src/libpakfire/include/pakfire/env.h [new file with mode: 0644]
src/libpakfire/include/pakfire/jail.h
src/libpakfire/include/pakfire/parser.h
src/libpakfire/jail.c
src/libpakfire/parser.c
src/libpakfire/scriptlet.c
tests/libpakfire/cgroup.c
tests/libpakfire/jail.c

index 706b3c8198da8a673ea8c0dfbbcf41c1e6ea74b4..78f100844779c71f347f94469598b0a504be61cd 100644 (file)
@@ -199,6 +199,7 @@ libpakfire_la_SOURCES = \
        src/libpakfire/deps.c \
        src/libpakfire/digest.c \
        src/libpakfire/dist.c \
+       src/libpakfire/env.c \
        src/libpakfire/fhs.c \
        src/libpakfire/file.c \
        src/libpakfire/filelist.c \
@@ -254,6 +255,7 @@ pkginclude_HEADERS += \
        src/libpakfire/include/pakfire/deps.h \
        src/libpakfire/include/pakfire/digest.h \
        src/libpakfire/include/pakfire/dist.h \
+       src/libpakfire/include/pakfire/env.h \
        src/libpakfire/include/pakfire/fhs.h \
        src/libpakfire/include/pakfire/file.h \
        src/libpakfire/include/pakfire/filelist.h \
index c71732e9cc73ac65ae659c9b9c7e72f155aeff2a..2421e1c1bbbbeaba38153e611bd87d01ed2a88c9 100644 (file)
@@ -1817,7 +1817,7 @@ static int pakfire_archive_handle_systemd_sysusers(struct pakfire_archive* archi
                goto ERROR;
 
        // Run!
-       r = pakfire_jail_communicate(jail, argv, PAKFIRE_JAIL_NOENT_OK,
+       r = pakfire_jail_communicate(jail, argv, NULL, PAKFIRE_JAIL_NOENT_OK,
                pakfire_archive_stream_payload, a, NULL, NULL);
 
 ERROR:
index f53e35ed55b9016625ccfd4ab312071051497cad..aec2064de705e39d619e4513ae2bf44777d5df3b 100644 (file)
@@ -34,6 +34,7 @@
 #include <pakfire/ctx.h>
 #include <pakfire/deps.h>
 #include <pakfire/dist.h>
+#include <pakfire/env.h>
 #include <pakfire/file.h>
 #include <pakfire/i18n.h>
 #include <pakfire/jail.h>
@@ -90,6 +91,9 @@ struct pakfire_build {
        // Jail
        struct pakfire_jail* jail;
 
+       // Environment
+       struct pakfire_env* env;
+
        // The build repository
        struct pakfire_repo* repo;
 
@@ -293,7 +297,7 @@ static int pakfire_build_run_script(
        }
 
        // Execute the script
-       r = pakfire_jail_exec_script(build->jail, script, length, args,
+       r = pakfire_jail_exec_script(build->jail, script, length, args, build->env,
                        stdin_callback, stdin_data, stdout_callback, stdout_data);
        if (r)
                ERROR(build->ctx, "Script '%s' failed with status %d\n", filename, r);
@@ -1026,18 +1030,23 @@ ERROR:
 
 static int pakfire_build_stage(struct pakfire_build* build,
                struct pakfire_parser* makefile, const char* stage) {
+       struct pakfire_env* env = NULL;
+       char* script = NULL;
        char template[1024];
+       int r;
 
        // Prepare template for this stage
-       int r = pakfire_string_format(template, TEMPLATE, stage);
-       if (r)
+       r = pakfire_string_format(template, TEMPLATE, stage);
+       if (r < 0)
                return r;
 
        // Fetch the environment
-       char** envp = pakfire_parser_make_environ(makefile);
+       env = pakfire_parser_make_environ(makefile);
+       if (!env)
+               goto ERROR;
 
        // Create the build script
-       char* script = pakfire_parser_expand(makefile, "build", template);
+       script = pakfire_parser_expand(makefile, "build", template);
        if (!script) {
                ERROR(build->ctx, "Could not generate the build script for stage '%s': %m\n", stage);
                goto ERROR;
@@ -1045,26 +1054,17 @@ static int pakfire_build_stage(struct pakfire_build* build,
 
        INFO(build->ctx, "Running build stage '%s'\n", stage);
 
-       // Import environment
-       // XXX is this a good idea?
-       r = pakfire_jail_import_env(build->jail, (const char**)envp);
-       if (r) {
-               ERROR(build->ctx, "Could not import environment: %m\n");
-               goto ERROR;
-       }
+       // XXX merge the basic environment
 
        // Run the script
-       r = pakfire_jail_exec_script(build->jail, script, strlen(script), NULL,
+       r = pakfire_jail_exec_script(build->jail, script, strlen(script), NULL, env,
                        NULL, NULL, pakfire_build_output_callback, build);
        if (r)
                ERROR(build->ctx, "Build stage '%s' failed with status %d\n", stage, r);
 
 ERROR:
-       if (envp) {
-               for (char** e = envp; *e; e++)
-                       free(*e);
-               free(envp);
-       }
+       if (env)
+               pakfire_env_unref(env);
        if (script)
                free(script);
 
@@ -1320,6 +1320,8 @@ static void pakfire_build_free(struct pakfire_build* build) {
 
        if (build->jail)
                pakfire_jail_unref(build->jail);
+       if (build->env)
+               pakfire_env_unref(build->env);
 
        if (build->cgroup) {
                // Destroy the cgroup
@@ -1521,7 +1523,7 @@ static int pakfire_build_setup_ccache(struct pakfire_build* build) {
                DEBUG(build->ctx, "ccache usage has been disabled for this build\n");
 
                // Set CCACHE_DISABLE=1 so that if ccache is installed, it will disable itself
-               r = pakfire_jail_set_env(build->jail, "CCACHE_DISABLE", "1");
+               r = pakfire_env_set(build->env, "CCACHE_DISABLE", "1");
                if (r) {
                        ERROR(build->ctx, "Could not disable ccache: %m\n");
                        return r;
@@ -1531,14 +1533,14 @@ static int pakfire_build_setup_ccache(struct pakfire_build* build) {
        }
 
        // Set CCACHE_DIR
-       r = pakfire_jail_set_env(build->jail, "CCACHE_DIR", CCACHE_DIR);
+       r = pakfire_env_set(build->env, "CCACHE_DIR", CCACHE_DIR);
        if (r) {
                ERROR(build->ctx, "Could not set ccache directory: %m\n");
                return r;
        }
 
        // Set CCACHE_TEMPDIR
-       r = pakfire_jail_set_env(build->jail, "CCACHE_TEMPDIR", "/tmp");
+       r = pakfire_env_set(build->env, "CCACHE_TEMPDIR", "/tmp");
        if (r) {
                ERROR(build->ctx, "Could not set ccache tempdir: %m\n");
                return r;
@@ -1617,6 +1619,11 @@ PAKFIRE_EXPORT int pakfire_build_create(struct pakfire_build** build,
        // Copy flags
        b->flags = flags;
 
+       // Create an environment
+       r = pakfire_env_create(&b->env, b->ctx);
+       if (r < 0)
+               goto ERROR;
+
        // Store start time
        r = pakfire_build_set_time_start(b);
        if (r)
@@ -2537,7 +2544,7 @@ PAKFIRE_EXPORT int pakfire_build_shell(struct pakfire_build* build, const char*
 
        // Run the command (if given)
        if (argv)
-               return pakfire_jail_exec(build->jail, argv, 0);
+               return pakfire_jail_exec(build->jail, argv, build->env, 0);
 
        // Otherwise run the shell
        return pakfire_jail_shell(build->jail);
diff --git a/src/libpakfire/env.c b/src/libpakfire/env.c
new file mode 100644 (file)
index 0000000..9d1dcfd
--- /dev/null
@@ -0,0 +1,189 @@
+/*#############################################################################
+#                                                                             #
+# Pakfire - The IPFire package management system                              #
+# Copyright (C) 2024 Pakfire development team                                 #
+#                                                                             #
+# This program is free software: you can redistribute it and/or modify        #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# This program is distributed in the hope that it will be useful,             #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+#############################################################################*/
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include <pakfire/ctx.h>
+#include <pakfire/env.h>
+#include <pakfire/string.h>
+
+#define ENVIRON_SIZE     128
+
+struct pakfire_env {
+       struct pakfire_ctx* ctx;
+       int nrefs;
+
+       char* env[ENVIRON_SIZE];
+};
+
+static void pakfire_env_free(struct pakfire_env* env) {
+       // Free environment
+       for (unsigned int i = 0; env->env[i]; i++)
+               free(env->env[i]);
+
+       if (env->ctx)
+               pakfire_ctx_unref(env->ctx);
+       free(env);
+}
+
+int pakfire_env_create(struct pakfire_env** env, struct pakfire_ctx* ctx) {
+       struct pakfire_env* e = NULL;
+
+       // Allocate a new environment
+       e = calloc(1, sizeof(*e));
+       if (!e)
+               return -errno;
+
+       // Store a reference to the context
+       e->ctx = pakfire_ctx_ref(ctx);
+
+       // Initialize the reference counter
+       e->nrefs = 1;
+
+       // Return the pointer
+       *env = e;
+
+       return 0;
+}
+
+struct pakfire_env* pakfire_env_ref(struct pakfire_env* env) {
+       ++env->nrefs;
+
+       return env;
+}
+
+struct pakfire_env* pakfire_env_unref(struct pakfire_env* env) {
+       if (--env->nrefs > 0)
+               return env;
+
+       pakfire_env_free(env);
+       return NULL;
+}
+
+char** pakfire_env_get_envp(struct pakfire_env* env) {
+       if (!env->env[0])
+               return NULL;
+
+       return env->env;
+}
+
+// Returns the length of the environment
+static unsigned int pakfire_env_length(struct pakfire_env* env) {
+       unsigned int i = 0;
+
+       // Count everything in the environment
+       for (char** e = env->env; *e; e++)
+               i++;
+
+       return i;
+}
+
+// Finds an existing environment variable and returns its index or -1 if not found
+static int pakfire_env_find(struct pakfire_env* env, const char* key) {
+       if (!key)
+               return -EINVAL;
+
+       const size_t length = strlen(key);
+
+       for (unsigned int i = 0; env->env[i]; i++) {
+               if ((pakfire_string_startswith(env->env[i], key)
+                               && *(env->env[i] + length) == '=')) {
+                       return i;
+               }
+       }
+
+       // Nothing found
+       return -1;
+}
+
+// Returns the value of an environment variable or NULL
+const char* pakfire_env_get(struct pakfire_env* env, const char* key) {
+       int i = pakfire_env_find(env, key);
+       if (i < 0)
+               return NULL;
+
+       return env->env[i] + strlen(key) + 1;
+}
+
+// Sets an environment variable
+int pakfire_env_set(struct pakfire_env* env, const char* key, const char* value) {
+       int r;
+
+       // Find the index where to write this value to
+       int i = pakfire_env_find(env, key);
+       if (i < 0)
+               i = pakfire_env_length(env);
+
+       // Return ENOBUFS when the environment is full
+       if (i >= ENVIRON_SIZE)
+               return -ENOBUFS;
+
+       // Free any previous value
+       if (env->env[i])
+               free(env->env[i]);
+
+       // Format and set environment variable
+       r = asprintf(&env->env[i], "%s=%s", key, value);
+       if (r < 0) {
+               ERROR(env->ctx, "Could not set environment variable %s: %m\n", key);
+               return -errno;
+       }
+
+       DEBUG(env->ctx, "Set environment variable: %s\n", env->env[i]);
+
+       return 0;
+}
+
+// Imports an environment
+int pakfire_env_import(struct pakfire_env* env, const char** e) {
+       char* key = NULL;
+       char* val = NULL;
+       int r;
+
+       // Is there anything to import?
+       if (!e)
+               return 0;
+
+       // Copy environment variables
+       for (unsigned int i = 0; e[i]; i++) {
+               r = pakfire_string_partition(e[i], "=", &key, &val);
+               if (r < 0)
+                       continue;
+
+               // Set value
+               r = pakfire_env_set(env, key, val);
+
+               if (key)
+                       free(key);
+               if (val)
+                       free(val);
+
+               // Break on error
+               if (r)
+                       return r;
+       }
+
+       return 0;
+}
+
+int pakfire_env_merge(struct pakfire_env* env1, struct pakfire_env* env2) {
+       return pakfire_env_import(env1, (const char**)env2->env);
+}
diff --git a/src/libpakfire/include/pakfire/env.h b/src/libpakfire/include/pakfire/env.h
new file mode 100644 (file)
index 0000000..882984e
--- /dev/null
@@ -0,0 +1,45 @@
+/*#############################################################################
+#                                                                             #
+# Pakfire - The IPFire package management system                              #
+# Copyright (C) 2024 Pakfire development team                                 #
+#                                                                             #
+# This program is free software: you can redistribute it and/or modify        #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# This program is distributed in the hope that it will be useful,             #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+#############################################################################*/
+
+#ifndef PAKFIRE_ENV_H
+#define PAKFIRE_ENV_H
+
+#ifdef PAKFIRE_PRIVATE
+
+#include <pakfire/ctx.h>
+
+struct pakfire_env;
+
+int pakfire_env_create(struct pakfire_env** env, struct pakfire_ctx* ctx);
+
+struct pakfire_env* pakfire_env_ref(struct pakfire_env* env);
+struct pakfire_env* pakfire_env_unref(struct pakfire_env* env);
+
+char** pakfire_env_get_envp(struct pakfire_env* env);
+
+const char* pakfire_env_get(struct pakfire_env* env, const char* key);
+int pakfire_env_set(struct pakfire_env* env, const char* key, const char* value);
+
+int pakfire_env_import(struct pakfire_env* env, const char** e);
+
+int pakfire_env_merge(struct pakfire_env* env1, struct pakfire_env* env2);
+
+#endif /* PAKFIRE_PRIVATE */
+#endif /* PAKFIRE_ENV_H */
index 6aac94bdadb37eb12182e6ccdf47122ac73f7dbe..b6ac0015e0448c53018965101c715411dae90b79 100644 (file)
@@ -24,6 +24,7 @@
 #ifdef PAKFIRE_PRIVATE
 
 #include <pakfire/cgroup.h>
+#include <pakfire/env.h>
 #include <pakfire/pakfire.h>
 #include <pakfire/pty.h>
 
@@ -44,11 +45,6 @@ int pakfire_jail_nice(struct pakfire_jail* jail, int nice);
 // Timeout
 int pakfire_jail_set_timeout(struct pakfire_jail* jail, unsigned int timeout);
 
-// Environment
-const char* pakfire_jail_get_env(struct pakfire_jail* jail, const char* key);
-int pakfire_jail_set_env(struct pakfire_jail* jail, const char* key, const char* value);
-int pakfire_jail_import_env(struct pakfire_jail* jail, const char* env[]);
-
 typedef int (*pakfire_jail_callback)(struct pakfire_jail* jail, void* data);
 
 // Standard Input
@@ -70,27 +66,28 @@ enum pakfire_jail_exec_flags {
        PAKFIRE_JAIL_HAS_LOOP_DEVICES = (1 << 3),
 };
 
-int pakfire_jail_exec(struct pakfire_jail* jail, const char* argv[], int flags);
+int pakfire_jail_exec(struct pakfire_jail* jail,
+       const char* argv[], struct pakfire_env* env, int flags);
 
 int pakfire_jail_exec_capture_output(struct pakfire_jail* jail,
-       const char* argv[], int flags, char** output, size_t* length);
+       const char* argv[], struct pakfire_env* env, int flags, char** output, size_t* length);
 
 // Resource limits
 int pakfire_jail_set_cgroup(struct pakfire_jail* jail, struct pakfire_cgroup* cgroup);
 
 int pakfire_jail_communicate(
-       struct pakfire_jail* jail, const char* argv[], int flags,
+       struct pakfire_jail* jail, const char* argv[], struct pakfire_env* env, int flags,
        pakfire_pty_stdin_callback stdin_callback, void* stdin_data,
        pakfire_pty_stdout_callback stdout_callback, void* stdout_data);
 
 // Convenience functions
 int pakfire_jail_run(struct pakfire* pakfire,
-       const char* argv[], int flags, char** output, size_t* output_length);
+       const char* argv[], struct pakfire_env* env, int flags, char** output, size_t* output_length);
 int pakfire_jail_run_script(struct pakfire* pakfire,
-       const char* script, const size_t length, const char* argv[], int flags);
+       const char* script, const size_t length, const char* argv[], struct pakfire_env* env, int flags);
 
 int pakfire_jail_exec_script(struct pakfire_jail* jail,
-       const char* script, const size_t size, const char* args[],
+       const char* script, const size_t size, const char* args[], struct pakfire_env* env,
        pakfire_pty_stdin_callback stdin_callback, void* stdin_data,
        pakfire_pty_stdout_callback stdout_callback, void* stdout_data);
 
index 881ccd5be97b34c1fb6646d21bb89973c53b78f5..f6b2143eaf71f96941eec14e2c8c5d1ec3462f1d 100644 (file)
@@ -28,6 +28,7 @@
 
 struct pakfire_parser;
 
+#include <pakfire/env.h>
 #include <pakfire/package.h>
 #include <pakfire/parser.h>
 #include <pakfire/repo.h>
@@ -113,7 +114,7 @@ int pakfire_parser_apply_declaration(
 int pakfire_parser_parse_data(struct pakfire_parser* parent, const char* data, size_t len,
        struct pakfire_parser_error** error);
 
-char** pakfire_parser_make_environ(struct pakfire_parser* parser);
+struct pakfire_env* pakfire_parser_make_environ(struct pakfire_parser* parser);
 
 #endif /* PAKFIRE_PRIVATE */
 
index ff620e2e22eea31cbbd319061ebdf273e9fa88ec..9f551bd62f8897bd3fd0f8d4bc3f834d39126f71 100644 (file)
@@ -49,6 +49,7 @@
 
 #include <pakfire/arch.h>
 #include <pakfire/cgroup.h>
+#include <pakfire/env.h>
 #include <pakfire/jail.h>
 #include <pakfire/log_stream.h>
 #include <pakfire/logging.h>
@@ -62,7 +63,6 @@
 #include <pakfire/util.h>
 
 #define BUFFER_SIZE      1024 * 64
-#define ENVIRON_SIZE     128
 #define MAX_MOUNTPOINTS  8
 
 // The default environment that will be set for every command
@@ -106,7 +106,7 @@ struct pakfire_jail {
        struct pakfire_cgroup* cgroup;
 
        // Environment
-       char* env[ENVIRON_SIZE];
+       struct pakfire_env* env;
 
        // Mountpoints
        struct pakfire_jail_mountpoint mountpoints[MAX_MOUNTPOINTS];
@@ -166,14 +166,12 @@ static int pakfire_jail_exec_has_flag(
 static void pakfire_jail_free(struct pakfire_jail* jail) {
        DEBUG(jail->ctx, "Freeing jail at %p\n", jail);
 
-       // Free environment
-       for (unsigned int i = 0; jail->env[i]; i++)
-               free(jail->env[i]);
-
        if (jail->cgroup)
                pakfire_cgroup_unref(jail->cgroup);
        if (jail->pakfire)
                pakfire_unref(jail->pakfire);
+       if (jail->env)
+               pakfire_env_unref(jail->env);
        if (jail->ctx)
                pakfire_ctx_unref(jail->ctx);
        free(jail);
@@ -210,29 +208,34 @@ int pakfire_jail_create(struct pakfire_jail** jail, struct pakfire* pakfire) {
 
        DEBUG(j->ctx, "Allocated new jail at %p\n", j);
 
+       // Create environment
+       r = pakfire_env_create(&j->env, j->ctx);
+       if (r < 0)
+               goto ERROR;
+
        // Set default environment
        for (const struct environ* e = ENV; e->key; e++) {
-               r = pakfire_jail_set_env(j, e->key, e->val);
-               if (r)
+               r = pakfire_env_set(j->env, e->key, e->val);
+               if (r < 0)
                        goto ERROR;
        }
 
        // Enable all CPU features that CPU has to offer
        if (!pakfire_arch_is_supported_by_host(arch)) {
-               r = pakfire_jail_set_env(j, "QEMU_CPU", "max");
-               if (r)
+               r = pakfire_env_set(j->env, "QEMU_CPU", "max");
+               if (r < 0)
                        goto ERROR;
        }
 
        // Set container UUID
-       r = pakfire_jail_set_env(j, "container_uuid", pakfire_jail_uuid(j));
-       if (r)
+       r = pakfire_env_set(j->env, "container_uuid", pakfire_jail_uuid(j));
+       if (r < 0)
                goto ERROR;
 
        // Disable systemctl to talk to systemd
        if (!pakfire_on_root(j->pakfire)) {
-               r = pakfire_jail_set_env(j, "SYSTEMD_OFFLINE", "1");
-               if (r)
+               r = pakfire_env_set(j->env, "SYSTEMD_OFFLINE", "1");
+               if (r < 0)
                        goto ERROR;
        }
 
@@ -293,106 +296,6 @@ int pakfire_jail_set_cgroup(struct pakfire_jail* jail, struct pakfire_cgroup* cg
        return 0;
 }
 
-// Environment
-
-// Returns the length of the environment
-static unsigned int pakfire_jail_env_length(struct pakfire_jail* jail) {
-       unsigned int i = 0;
-
-       // Count everything in the environment
-       for (char** e = jail->env; *e; e++)
-               i++;
-
-       return i;
-}
-
-// Finds an existing environment variable and returns its index or -1 if not found
-static int pakfire_jail_find_env(struct pakfire_jail* jail, const char* key) {
-       if (!key) {
-               errno = EINVAL;
-               return -1;
-       }
-
-       const size_t length = strlen(key);
-
-       for (unsigned int i = 0; jail->env[i]; i++) {
-               if ((pakfire_string_startswith(jail->env[i], key)
-                               && *(jail->env[i] + length) == '=')) {
-                       return i;
-               }
-       }
-
-       // Nothing found
-       return -1;
-}
-
-// Returns the value of an environment variable or NULL
-const char* pakfire_jail_get_env(struct pakfire_jail* jail,
-               const char* key) {
-       int i = pakfire_jail_find_env(jail, key);
-       if (i < 0)
-               return NULL;
-
-       return jail->env[i] + strlen(key) + 1;
-}
-
-// Sets an environment variable
-int pakfire_jail_set_env(struct pakfire_jail* jail,
-               const char* key, const char* value) {
-       // Find the index where to write this value to
-       int i = pakfire_jail_find_env(jail, key);
-       if (i < 0)
-               i = pakfire_jail_env_length(jail);
-
-       // Return -ENOSPC when the environment is full
-       if (i >= ENVIRON_SIZE) {
-               errno = ENOSPC;
-               return -1;
-       }
-
-       // Free any previous value
-       if (jail->env[i])
-               free(jail->env[i]);
-
-       // Format and set environment variable
-       asprintf(&jail->env[i], "%s=%s", key, value);
-
-       DEBUG(jail->ctx, "Set environment variable: %s\n", jail->env[i]);
-
-       return 0;
-}
-
-// Imports an environment
-int pakfire_jail_import_env(struct pakfire_jail* jail, const char* env[]) {
-       if (!env)
-               return 0;
-
-       char* key;
-       char* val;
-       int r;
-
-       // Copy environment variables
-       for (unsigned int i = 0; env[i]; i++) {
-               r = pakfire_string_partition(env[i], "=", &key, &val);
-               if (r)
-                       continue;
-
-               // Set value
-               r = pakfire_jail_set_env(jail, key, val);
-
-               if (key)
-                       free(key);
-               if (val)
-                       free(val);
-
-               // Break on error
-               if (r)
-                       return r;
-       }
-
-       return 0;
-}
-
 // Timeout
 
 int pakfire_jail_set_timeout(
@@ -1069,11 +972,12 @@ static int pakfire_jail_exited(sd_event_source* source, const siginfo_t* si, voi
 
 struct pakfire_jail_command {
        const char** argv;
-       const char** envp;
+       struct pakfire_env* env;
 };
 
 static int pakfire_jail_launch_command(struct pakfire_jail* jail, void* data) {
        struct pakfire_jail_command* command = data;
+       char** envp = NULL;
        int r;
 
        // Check if argv is valid
@@ -1086,8 +990,15 @@ static int pakfire_jail_launch_command(struct pakfire_jail* jail, void* data) {
        for (unsigned int i = 0; command->argv[i]; i++)
                DEBUG(jail->ctx, "  argv[%u] = %s\n", i, command->argv[i]);
 
+       // Fetch the environment
+       if (command->env) {
+               envp = pakfire_env_get_envp(command->env);
+               if (!envp)
+                       return -ENOTSUP;
+       }
+
        // exec() command
-       r = execvpe(command->argv[0], (char**)command->argv, (char**)command->envp);
+       r = execvpe(command->argv[0], (char**)command->argv, envp);
        if (r < 0) {
                // Translate errno into regular exit code
                switch (errno) {
@@ -1624,9 +1535,11 @@ ERROR:
        return r;
 }
 
-int pakfire_jail_exec(struct pakfire_jail* jail, const char* argv[], int flags) {
+int pakfire_jail_exec(struct pakfire_jail* jail,
+               const char* argv[], struct pakfire_env* env, int flags) {
        struct pakfire_jail_command command = {
                .argv = argv,
+               .env  = env,
        };
 
        return __pakfire_jail_exec(jail, pakfire_jail_launch_command, &command, flags,
@@ -1634,9 +1547,10 @@ int pakfire_jail_exec(struct pakfire_jail* jail, const char* argv[], int flags)
 }
 
 int pakfire_jail_exec_capture_output(struct pakfire_jail* jail,
-               const char* argv[], int flags, char** output, size_t* length) {
+               const char* argv[], struct pakfire_env* env, int flags, char** output, size_t* length) {
        struct pakfire_jail_command command = {
                .argv = argv,
+               .env  = env,
        };
 
        return __pakfire_jail_exec(jail, pakfire_jail_launch_command, &command, flags,
@@ -1644,11 +1558,12 @@ int pakfire_jail_exec_capture_output(struct pakfire_jail* jail,
 }
 
 int pakfire_jail_communicate(
-               struct pakfire_jail* jail, const char* argv[], int flags,
+               struct pakfire_jail* jail, const char* argv[], struct pakfire_env* env, int flags,
                pakfire_pty_stdin_callback stdin_callback, void* stdin_data,
                pakfire_pty_stdout_callback stdout_callback, void* stdout_data) {
        struct pakfire_jail_command command = {
                .argv = argv,
+               .env  = env,
        };
 
        return __pakfire_jail_exec(jail, pakfire_jail_launch_command, &command, flags,
@@ -1656,7 +1571,7 @@ int pakfire_jail_communicate(
 }
 
 int pakfire_jail_exec_script(struct pakfire_jail* jail,
-               const char* script, const size_t size, const char* args[],
+               const char* script, const size_t size, const char* args[], struct pakfire_env* env,
                pakfire_pty_stdin_callback stdin_callback, void* stdin_data,
                pakfire_pty_stdout_callback stdout_callback, void* stdout_data) {
        char path[PATH_MAX];
@@ -1717,7 +1632,7 @@ int pakfire_jail_exec_script(struct pakfire_jail* jail,
                argv[i] = args[i-1];
 
        // Run the script
-       r = pakfire_jail_communicate(jail, argv, 0,
+       r = pakfire_jail_communicate(jail, argv, env, 0,
                stdin_callback, stdin_data, stdout_callback, stdout_data);
 
 ERROR:
@@ -1737,8 +1652,8 @@ ERROR:
        A convenience function that creates a new jail, runs the given command and destroys
        the jail again.
 */
-int pakfire_jail_run(struct pakfire* pakfire,
-               const char* argv[], int flags, char** output, size_t* output_length) {
+int pakfire_jail_run(struct pakfire* pakfire, const char* argv[], struct pakfire_env* env,
+               int flags, char** output, size_t* output_length) {
        struct pakfire_jail* jail = NULL;
        int r;
 
@@ -1748,7 +1663,7 @@ int pakfire_jail_run(struct pakfire* pakfire,
                goto ERROR;
 
        // Execute the command
-       r = pakfire_jail_exec_capture_output(jail, argv, flags, output, output_length);
+       r = pakfire_jail_exec_capture_output(jail, argv, env, flags, output, output_length);
 
 ERROR:
        if (jail)
@@ -1757,8 +1672,8 @@ ERROR:
        return r;
 }
 
-int pakfire_jail_run_script(struct pakfire* pakfire,
-               const char* script, const size_t length, const char* argv[], int flags) {
+int pakfire_jail_run_script(struct pakfire* pakfire, const char* script, const size_t length,
+               const char* argv[], struct pakfire_env* env, int flags) {
        struct pakfire_jail* jail = NULL;
        int r;
 
@@ -1768,7 +1683,7 @@ int pakfire_jail_run_script(struct pakfire* pakfire,
                goto ERROR;
 
        // Execute the command
-       r = pakfire_jail_exec_script(jail, script, length, argv, NULL, NULL, NULL, NULL);
+       r = pakfire_jail_exec_script(jail, script, length, argv, env, NULL, NULL, NULL, NULL);
 
 ERROR:
        if (jail)
@@ -1778,37 +1693,47 @@ ERROR:
 }
 
 int pakfire_jail_shell(struct pakfire_jail* jail) {
+       struct pakfire_env* env = NULL;
        int r;
 
        const char* argv[] = {
                "/bin/bash", "--login", NULL,
        };
 
+       // Create a new environment
+       r = pakfire_env_create(&env, jail->ctx);
+       if (r < 0)
+               goto ERROR;
+
        // Copy TERM
        char* TERM = secure_getenv("TERM");
        if (TERM) {
-               r = pakfire_jail_set_env(jail, "TERM", TERM);
-               if (r)
-                       return r;
+               r = pakfire_env_set(env, "TERM", TERM);
+               if (r < 0)
+                       goto ERROR;
        }
 
        // Copy LANG
        char* LANG = secure_getenv("LANG");
        if (LANG) {
-               r = pakfire_jail_set_env(jail, "LANG", LANG);
-               if (r)
-                       return r;
+               r = pakfire_env_set(env, "LANG", LANG);
+               if (r < 0)
+                       goto ERROR;
        }
 
        // Execute /bin/bash
-       r = pakfire_jail_exec(jail, argv, PAKFIRE_JAIL_INTERACTIVE);
-
-       // Raise any errors
+       r = pakfire_jail_exec(jail, argv, env, PAKFIRE_JAIL_INTERACTIVE);
        if (r < 0)
-               return r;
+               goto ERROR;
 
        // Ignore any return codes from the shell
-       return 0;
+       r = 0;
+
+ERROR:
+       if (env)
+               pakfire_env_unref(env);
+
+       return r;
 }
 
 static int pakfire_jail_run_if_possible(struct pakfire* pakfire, const char** argv) {
@@ -1829,7 +1754,7 @@ static int pakfire_jail_run_if_possible(struct pakfire* pakfire, const char** ar
                goto ERROR;
        }
 
-       r = pakfire_jail_run(pakfire, argv, 0, NULL, NULL);
+       r = pakfire_jail_run(pakfire, argv, NULL, 0, NULL, NULL);
 
 ERROR:
        if (ctx)
index ec59ca7fabd739b6b96af1468e14a2ea4b8b0557..0bb42efc32d6e08976f8e15cb7481adfd0b291bb 100644 (file)
@@ -32,6 +32,7 @@
 
 #include <pakfire/ctx.h>
 #include <pakfire/deps.h>
+#include <pakfire/env.h>
 #include <pakfire/jail.h>
 #include <pakfire/logging.h>
 #include <pakfire/package.h>
@@ -479,7 +480,7 @@ static int pakfire_parser_expand_commands(struct pakfire_parser* parser, char**
                size_t length = 0;
 
                // Execute the command inside the Pakfire environment
-               r = pakfire_jail_run(parser->pakfire, argv, 0, &output, &length);
+               r = pakfire_jail_run(parser->pakfire, argv, NULL, 0, &output, &length);
                if (r) {
                        // Just log this and continue
                        DEBUG(parser->ctx, "Command '%s' failed with return code %d\n", command, r);
@@ -954,47 +955,40 @@ int pakfire_parser_set_namespace(struct pakfire_parser* parser, const char* name
        return 0;
 }
 
-char** pakfire_parser_make_environ(struct pakfire_parser* parser) {
-       char** envp = NULL;
-       unsigned int num = 0;
+struct pakfire_env* pakfire_parser_make_environ(struct pakfire_parser* parser) {
+       struct pakfire_parser_declaration* d = NULL;
+       struct pakfire_env* env = NULL;
+       char* value = NULL;
+       int r;
+
+       // Create a new empty environment
+       r = pakfire_env_create(&env, parser->ctx);
+       if (r < 0)
+               goto ERROR;
 
        for (unsigned int i = 0; i < parser->num_declarations; i++) {
-               struct pakfire_parser_declaration* d = parser->declarations[i];
+               d = parser->declarations[i];
                if (!d)
                        continue;
 
                // Is the export flag set?
                if (d->flags & PAKFIRE_PARSER_DECLARATION_EXPORT) {
-                       char* buffer = NULL;
-
-                       char* value = pakfire_parser_expand(parser, d->namespace, d->value);
+                       value = pakfire_parser_expand(parser, d->namespace, d->value);
                        if (!value)
                                goto ERROR;
 
-                       // Build line
-                       int r = asprintf(&buffer, "%s=%s", d->name, value);
-                       free(value);
+                       // Store the value
+                       r = pakfire_env_set(env, d->name, value);
                        if (r < 0)
                                goto ERROR;
-
-                       // Extend the array
-                       envp = reallocarray(envp, num + 2, sizeof(*envp));
-                       if (!envp)
-                               goto ERROR;
-
-                       envp[num++] = buffer;
-                       envp[num] = NULL;
                }
        }
 
-       return envp;
+       return env;
 
 ERROR:
-       if (envp) {
-               for (char** e = envp; *e; e++)
-                       free(*e);
-               free(envp);
-       }
+       if (env)
+               pakfire_env_unref(env);
 
        return NULL;
 }
index a28891d8aab321ce0693cfe321d57f369f0b4873..a29707e6a4463733fd7add24566e2e168f44abc9 100644 (file)
@@ -181,7 +181,7 @@ static int pakfire_scriptlet_is_shell_script(struct pakfire_scriptlet* scriptlet
 int pakfire_scriptlet_execute(struct pakfire_scriptlet* scriptlet, struct pakfire* pakfire) {
        // Detect what kind of script this is and run it
        if (pakfire_scriptlet_is_shell_script(scriptlet))
-               return pakfire_jail_run_script(pakfire, scriptlet->data, scriptlet->size, NULL, 0);
+               return pakfire_jail_run_script(pakfire, scriptlet->data, scriptlet->size, NULL, NULL, 0);
 
        ERROR(scriptlet->ctx, "Scriptlet is of an unknown kind\n");
        return -ENOTSUP;
index 11ae3a4f32e1018d57cf550a7963dbee0dfd16ef..47429149a4e29c7556ced577339f64014fe37109 100644 (file)
@@ -124,7 +124,7 @@ static int test_stats(const struct test* t) {
 
        // Run a few things
        for (unsigned int i = 0; i < 3; i++) {
-               ASSERT_SUCCESS(pakfire_jail_exec(jail, argv, 0));
+               ASSERT_SUCCESS(pakfire_jail_exec(jail, argv, NULL, 0));
        }
 
        // Try reading the stats into some invalid space
index 819794ffc0ba08a08854206b3a47ebf03afcb374..d93e20f4e8766bcc44efa9e9cb367343b2f61ba1 100644 (file)
@@ -68,7 +68,7 @@ static int test_exit_code(const struct test* t) {
        ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire));
 
        // Check if we receive the correct exit code
-       ASSERT(pakfire_jail_exec(jail, argv, 0) == 123);
+       ASSERT(pakfire_jail_exec(jail, argv, NULL, 0) == 123);
 
        // Success
        r = EXIT_SUCCESS;
@@ -92,7 +92,7 @@ static int test_segv(const struct test* t) {
        ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire));
 
        // Check if we receive the correct exit code
-       ASSERT(pakfire_jail_exec(jail, argv, 0) == 139);
+       ASSERT(pakfire_jail_exec(jail, argv, NULL, 0) == 139);
 
        // Success
        r = EXIT_SUCCESS;
@@ -104,34 +104,6 @@ FAIL:
        return r;
 }
 
-static int test_env(const struct test* t) {
-       struct pakfire_jail* jail = NULL;
-
-       // Create a new jail
-       ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire));
-
-       // Check if the default variables are set
-       ASSERT(pakfire_jail_get_env(jail, "LANG"));
-       ASSERT(pakfire_jail_get_env(jail, "TERM"));
-
-       // Fetch a non-existing environment variable
-       ASSERT_NULL(pakfire_jail_get_env(jail, "VARIABLE"));
-
-       // Set a variable
-       ASSERT_SUCCESS(pakfire_jail_set_env(jail, "VARIABLE", "VALUE"));
-
-       // Read the value back
-       ASSERT_STRING_EQUALS(pakfire_jail_get_env(jail, "VARIABLE"), "VALUE");
-
-       // Destroy it
-       ASSERT_NULL(pakfire_jail_unref(jail));
-
-       return EXIT_SUCCESS;
-
-FAIL:
-       return EXIT_FAILURE;
-}
-
 static int test_exec(const struct test* t) {
        struct pakfire_jail* jail = NULL;
        char* output = NULL;
@@ -141,7 +113,7 @@ static int test_exec(const struct test* t) {
        ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire));
 
        // Try to execute something
-       ASSERT_SUCCESS(pakfire_jail_exec_capture_output(jail, cmd_hello_world, 0, &output, &length));
+       ASSERT_SUCCESS(pakfire_jail_exec_capture_output(jail, cmd_hello_world, NULL, 0, &output, &length));
 
        // We should have some output
        ASSERT_STRING_EQUALS(output, "Hello World!\n");
@@ -171,7 +143,7 @@ static int test_launch_into_cgroup(const struct test* t) {
        ASSERT_SUCCESS(pakfire_jail_set_cgroup(jail, cgroup));
 
        // Run command
-       ASSERT(pakfire_jail_exec(jail, cmd_hello_world, 0) == 0);
+       ASSERT(pakfire_jail_exec(jail, cmd_hello_world, NULL, 0) == 0);
 
        r = EXIT_SUCCESS;
 
@@ -206,7 +178,7 @@ static int test_nice(const struct test* t) {
        ASSERT_SUCCESS(pakfire_jail_nice(jail, 5));
 
        // Check if the nice level has been set
-       ASSERT_SUCCESS(pakfire_jail_exec_capture_output(jail, argv, 0, &output, NULL));
+       ASSERT_SUCCESS(pakfire_jail_exec_capture_output(jail, argv, NULL, 0, &output, NULL));
        ASSERT_STRING_EQUALS(output, "5\n");
 
        // Success
@@ -240,10 +212,10 @@ static int test_memory_limit(const struct test* t) {
        ASSERT_SUCCESS(pakfire_cgroup_set_memory_limit(cgroup, 100 * 1024 * 1024));
 
        // Try to exhaust all memory
-       ASSERT_FAILURE(pakfire_jail_exec(jail, cmd_exhaust_memory, 0));
+       ASSERT_FAILURE(pakfire_jail_exec(jail, cmd_exhaust_memory, NULL, 0));
 
        // A fork bomb should also exhaust all memory
-       ASSERT_FAILURE(pakfire_jail_exec(jail, cmd_fork_bomb, 0));
+       ASSERT_FAILURE(pakfire_jail_exec(jail, cmd_fork_bomb, NULL, 0));
 
        // Success
        r = EXIT_SUCCESS;
@@ -277,7 +249,7 @@ static int test_pid_limit(const struct test* t) {
        ASSERT_SUCCESS(pakfire_cgroup_set_pid_limit(cgroup, 100));
 
        // Try to fork as many processes as possible
-       ASSERT_FAILURE(pakfire_jail_exec(jail, cmd_fork_bomb, 0));
+       ASSERT_FAILURE(pakfire_jail_exec(jail, cmd_fork_bomb, NULL, 0));
 
        // Success
        r = EXIT_SUCCESS;
@@ -298,7 +270,7 @@ static int test_file_ownership(const struct test* t) {
        char* output = NULL;
 
        // Execute a simple command
-       ASSERT_SUCCESS(pakfire_jail_run(t->pakfire, cmd_stat_ownership, 0, &output, NULL));
+       ASSERT_SUCCESS(pakfire_jail_run(t->pakfire, cmd_stat_ownership, NULL, 0, &output, NULL));
 
        // Check if the file has been mapped to root/root
        ASSERT_STRING_EQUALS(output, "uid=0 gid=0\n");
@@ -335,7 +307,7 @@ static int test_bind(const struct test* t) {
        ASSERT_SUCCESS(pakfire_jail_bind(jail, source, target, MS_RDONLY));
 
        // Check if the mount actually works
-       ASSERT_SUCCESS(pakfire_jail_exec(jail, argv, 0));
+       ASSERT_SUCCESS(pakfire_jail_exec(jail, argv, NULL, 0));
 
        // Success
        r = EXIT_SUCCESS;
@@ -384,7 +356,7 @@ static int test_communicate(const struct test* t) {
        ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire));
 
        // Check if the mount actually works
-       ASSERT_SUCCESS(pakfire_jail_communicate(jail, argv, 0,
+       ASSERT_SUCCESS(pakfire_jail_communicate(jail, argv, NULL, 0,
                callback_stdin, &lines, NULL, NULL));
 
        // Success
@@ -404,7 +376,7 @@ static int test_send_one_signal(const struct test* t,
        };
 
        // Perform the command
-       return pakfire_jail_exec(jail, argv, 0);
+       return pakfire_jail_exec(jail, argv, NULL, 0);
 }
 
 static int test_send_signal(const struct test* t) {
@@ -448,7 +420,7 @@ static int test_timeout(const struct test* t) {
        ASSERT_SUCCESS(pakfire_jail_set_timeout(jail, 1));
 
        // Check if we receive the correct exit code
-       ASSERT(pakfire_jail_exec(jail, argv, 0) == 139);
+       ASSERT(pakfire_jail_exec(jail, argv, NULL, 0) == 139);
 
        // Success
        r = EXIT_SUCCESS;
@@ -464,7 +436,6 @@ int main(int argc, const char* argv[]) {
        testsuite_add_test(test_create, TEST_WANTS_PAKFIRE);
        testsuite_add_test(test_exit_code, TEST_WANTS_PAKFIRE);
        testsuite_add_test(test_segv, TEST_WANTS_PAKFIRE);
-       testsuite_add_test(test_env, TEST_WANTS_PAKFIRE);
        testsuite_add_test(test_exec, TEST_WANTS_PAKFIRE);
 #if 0
        testsuite_add_test(test_launch_into_cgroup, TEST_WANTS_PAKFIRE);