From 69d50fa9f99d77b16f99f5a68797e7a745241931 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dan=20Vr=C3=A1til?= Date: Wed, 6 May 2015 15:52:23 +0200 Subject: [PATCH 1/5] Allow runtime and apps to override environment variables Sometimes it's necessary to override environment variables coming from outside the sandbox in order to point to the right places in the sandbox (like QT_PLUGIN_PATH pointing to /self/lib/qt5/plugins). To do so, runtimes and applications can add ENV=VALUE entries into [Vars] section in their metadata files. Specifying an empty value is also possible, which will effectively unset the variable. --- xdg-app-builtins-build-finish.c | 17 +++++++++++ xdg-app-builtins-run.c | 52 +++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/xdg-app-builtins-build-finish.c b/xdg-app-builtins-build-finish.c index 563cd326..3d6a6a0e 100644 --- a/xdg-app-builtins-build-finish.c +++ b/xdg-app-builtins-build-finish.c @@ -34,10 +34,12 @@ static char *opt_command; static char **opt_allow; +static char **opt_env_override; static GOptionEntry options[] = { { "command", 0, 0, G_OPTION_ARG_STRING, &opt_command, "Command to set", "COMMAND" }, { "allow", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_allow, "Environment options to set to true", "KEY" }, + { "env", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_env_override, "Override an environment variable", "VARIABLE=[VALUE]" }, { NULL } }; @@ -315,6 +317,21 @@ update_metadata (GFile *base, GCancellable *cancellable, GError **error) } } + /* We don't care about error here (when the group does not exist for instance) */ + g_key_file_remove_group (keyfile, "Vars", NULL); + if (opt_env_override) + { + for (i = 0; opt_env_override[i]; i++) + { + glnx_strfreev char **split = g_strsplit (opt_env_override[i], "=", 2); + if (split && split[0]) + { + g_key_file_set_string (keyfile, "Vars", split[0], split[1] ? split[1] : ""); + } + } + } + + if (!g_key_file_save_to_file (keyfile, path, error)) goto out; diff --git a/xdg-app-builtins-run.c b/xdg-app-builtins-run.c index a0949154..1f24a29e 100644 --- a/xdg-app-builtins-run.c +++ b/xdg-app-builtins-run.c @@ -54,6 +54,20 @@ static GOptionEntry options[] = { { NULL } }; +typedef struct { + char *name; + char *value; +} EnvVar; + +static void +free_envvar (void *p) +{ + EnvVar *v = (EnvVar *) p; + g_free (v->name); + g_free (v->value); + g_free (v); +} + static void add_extension_arg (const char *directory, const char *type, const char *extension, const char *arch, const char *branch, @@ -139,6 +153,30 @@ add_extension_args (GKeyFile *metakey, const char *full_ref, return ret; } +static void +add_env_overrides (GKeyFile *metakey, GPtrArray *env_array, GError **error) +{ + gsize i, keys_count; + /* Only free the array of keys, not the actual values */ + g_autofree char **keys; + + if (!g_key_file_has_group (metakey, "Vars")) + return; + + keys = g_key_file_get_keys (metakey, "Vars", &keys_count, error); + if (!keys) + return; + + for (i = 0; i < keys_count; i++) + { + EnvVar *var = malloc (sizeof (EnvVar)); + var->name = keys[i]; + var->value = g_key_file_get_string (metakey, "Vars", keys[i], error); + + g_ptr_array_add (env_array, var); + } +} + gboolean xdg_app_builtin_run (int argc, char **argv, GCancellable *cancellable, GError **error) { @@ -169,6 +207,7 @@ xdg_app_builtin_run (int argc, char **argv, GCancellable *cancellable, GError ** g_autoptr (GError) my_error = NULL; g_autoptr (GError) my_error2 = NULL; g_autoptr(GPtrArray) argv_array = NULL; + g_autoptr(GPtrArray) env_array = NULL; g_autofree char *monitor_path = NULL; gsize metadata_size, runtime_metadata_size; const char *app; @@ -261,6 +300,8 @@ xdg_app_builtin_run (int argc, char **argv, GCancellable *cancellable, GError ** path = g_file_get_path (runtime_deploy); g_debug ("Using runtime in %s", path); + env_array = g_ptr_array_new_with_free_func (free_envvar); + runtime_metadata = g_file_get_child (runtime_deploy, "metadata"); if (g_file_load_contents (runtime_metadata, cancellable, &runtime_metadata_contents, &runtime_metadata_size, NULL, NULL)) { @@ -271,8 +312,13 @@ xdg_app_builtin_run (int argc, char **argv, GCancellable *cancellable, GError ** if (!add_extension_args (runtime_metakey, runtime_ref, argv_array, cancellable, error)) goto out; + + add_env_overrides (runtime_metakey, env_array, error); } + /* Load application environment overrides *after* runtime */ + add_env_overrides (metakey, env_array, error); + if ((app_id_dir = xdg_app_ensure_data_dir (app, cancellable, error)) == NULL) goto out; @@ -339,6 +385,12 @@ xdg_app_builtin_run (int argc, char **argv, GCancellable *cancellable, GError ** g_setenv ("XDG_CONFIG_HOME", gs_file_get_path_cached (app_id_dir_config), TRUE); g_setenv ("XDG_CACHE_HOME", gs_file_get_path_cached (app_id_dir_cache), TRUE); + for (i = 0; i < env_array->len; i++) + { + EnvVar *var = g_ptr_array_index (env_array, i); + g_setenv (var->name, var->value, TRUE); + } + xdg_app_run_in_transient_unit (app); if (execv (HELPER, (char **)argv_array->pdata) == -1) From f035cbef489e87cd6ee091a952586b2d9bd5df91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dan=20Vr=C3=A1til?= Date: Wed, 6 May 2015 17:37:52 +0200 Subject: [PATCH 2/5] Don't clear the [Vars] group in build-finish command and improve error reporting --- xdg-app-builtins-build-finish.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/xdg-app-builtins-build-finish.c b/xdg-app-builtins-build-finish.c index 3d6a6a0e..d0179b1b 100644 --- a/xdg-app-builtins-build-finish.c +++ b/xdg-app-builtins-build-finish.c @@ -317,8 +317,6 @@ update_metadata (GFile *base, GCancellable *cancellable, GError **error) } } - /* We don't care about error here (when the group does not exist for instance) */ - g_key_file_remove_group (keyfile, "Vars", NULL); if (opt_env_override) { for (i = 0; opt_env_override[i]; i++) @@ -328,6 +326,11 @@ update_metadata (GFile *base, GCancellable *cancellable, GError **error) { g_key_file_set_string (keyfile, "Vars", split[0], split[1] ? split[1] : ""); } + else + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Cannot parse variable %s", opt_env_override[i]); + goto out; + } } } From 23259c2582377efd24a787951b563ebd24ac8e12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dan=20Vr=C3=A1til?= Date: Wed, 6 May 2015 17:40:14 +0200 Subject: [PATCH 3/5] Ignore errors in add_env_overrides() --- xdg-app-builtins-run.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/xdg-app-builtins-run.c b/xdg-app-builtins-run.c index 1f24a29e..47f071dd 100644 --- a/xdg-app-builtins-run.c +++ b/xdg-app-builtins-run.c @@ -154,7 +154,7 @@ add_extension_args (GKeyFile *metakey, const char *full_ref, } static void -add_env_overrides (GKeyFile *metakey, GPtrArray *env_array, GError **error) +add_env_overrides (GKeyFile *metakey, GPtrArray *env_array) { gsize i, keys_count; /* Only free the array of keys, not the actual values */ @@ -163,7 +163,7 @@ add_env_overrides (GKeyFile *metakey, GPtrArray *env_array, GError **error) if (!g_key_file_has_group (metakey, "Vars")) return; - keys = g_key_file_get_keys (metakey, "Vars", &keys_count, error); + keys = g_key_file_get_keys (metakey, "Vars", &keys_count, NULL); if (!keys) return; @@ -171,7 +171,7 @@ add_env_overrides (GKeyFile *metakey, GPtrArray *env_array, GError **error) { EnvVar *var = malloc (sizeof (EnvVar)); var->name = keys[i]; - var->value = g_key_file_get_string (metakey, "Vars", keys[i], error); + var->value = g_key_file_get_string (metakey, "Vars", keys[i], NULL); g_ptr_array_add (env_array, var); } @@ -313,11 +313,11 @@ xdg_app_builtin_run (int argc, char **argv, GCancellable *cancellable, GError ** if (!add_extension_args (runtime_metakey, runtime_ref, argv_array, cancellable, error)) goto out; - add_env_overrides (runtime_metakey, env_array, error); + add_env_overrides (runtime_metakey, env_array); } /* Load application environment overrides *after* runtime */ - add_env_overrides (metakey, env_array, error); + add_env_overrides (metakey, env_array); if ((app_id_dir = xdg_app_ensure_data_dir (app, cancellable, error)) == NULL) goto out; From 63e4e822f20e4cc020bff47fc7e1f6da2087a3fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dan=20Vr=C3=A1til?= Date: Wed, 6 May 2015 17:41:22 +0200 Subject: [PATCH 4/5] Actually unset the env variable when the value is empty --- xdg-app-builtins-run.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xdg-app-builtins-run.c b/xdg-app-builtins-run.c index 47f071dd..7f34f18e 100644 --- a/xdg-app-builtins-run.c +++ b/xdg-app-builtins-run.c @@ -388,7 +388,10 @@ xdg_app_builtin_run (int argc, char **argv, GCancellable *cancellable, GError ** for (i = 0; i < env_array->len; i++) { EnvVar *var = g_ptr_array_index (env_array, i); - g_setenv (var->name, var->value, TRUE); + if (!var->value || !var->value[0]) + g_unsetenv (var->name); + else + g_setenv (var->name, var->value, TRUE); } xdg_app_run_in_transient_unit (app); From 0a76e872df441ed0b55bef2b30edb16e7dacb8c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dan=20Vr=C3=A1til?= Date: Wed, 6 May 2015 17:45:19 +0200 Subject: [PATCH 5/5] Report error when --var option is missing '=' --- xdg-app-builtins-build-finish.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xdg-app-builtins-build-finish.c b/xdg-app-builtins-build-finish.c index d0179b1b..557d32b3 100644 --- a/xdg-app-builtins-build-finish.c +++ b/xdg-app-builtins-build-finish.c @@ -322,9 +322,9 @@ update_metadata (GFile *base, GCancellable *cancellable, GError **error) for (i = 0; opt_env_override[i]; i++) { glnx_strfreev char **split = g_strsplit (opt_env_override[i], "=", 2); - if (split && split[0]) + if (split && split[0] && split[1]) { - g_key_file_set_string (keyfile, "Vars", split[0], split[1] ? split[1] : ""); + g_key_file_set_string (keyfile, "Vars", split[0], split[1]); } else {