From 27d27dd1214fb5ae4dd96aca74887ba7c4a290fe Mon Sep 17 00:00:00 2001 From: slonkazoid Date: Tue, 3 Sep 2024 17:02:47 +0300 Subject: [PATCH 01/11] add cmd_env to set environment variables at config and runtime --- include/sway/commands.h | 1 + sway/commands.c | 1 + sway/commands/env.c | 14 ++++++++++++++ sway/meson.build | 1 + 4 files changed, 17 insertions(+) create mode 100644 sway/commands/env.c diff --git a/include/sway/commands.h b/include/sway/commands.h index 5210d3ba7..b77f49221 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -125,6 +125,7 @@ sway_cmd cmd_create_output; sway_cmd cmd_default_border; sway_cmd cmd_default_floating_border; sway_cmd cmd_default_orientation; +sway_cmd cmd_env; sway_cmd cmd_exec; sway_cmd cmd_exec_always; sway_cmd cmd_exit; diff --git a/sway/commands.c b/sway/commands.c index c2c12ee65..b07a6a8cf 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -57,6 +57,7 @@ static const struct cmd_handler handlers[] = { { "client.urgent", cmd_client_urgent }, { "default_border", cmd_default_border }, { "default_floating_border", cmd_default_floating_border }, + { "env", cmd_env }, { "exec", cmd_exec }, { "exec_always", cmd_exec_always }, { "floating_maximum_size", cmd_floating_maximum_size }, diff --git a/sway/commands/env.c b/sway/commands/env.c new file mode 100644 index 000000000..2603f257a --- /dev/null +++ b/sway/commands/env.c @@ -0,0 +1,14 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include "sway/commands.h" + +struct cmd_results *cmd_env(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "env", EXPECTED_EQUAL_TO, 2))) { + return error; + } + + setenv(argv[0], argv[1], 1); + + return cmd_results_new(CMD_SUCCESS, NULL); +} diff --git a/sway/meson.build b/sway/meson.build index 8042c89be..ea03e2ef0 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -52,6 +52,7 @@ sway_sources = files( 'commands/default_border.c', 'commands/default_floating_border.c', 'commands/default_orientation.c', + 'commands/env.c', 'commands/exit.c', 'commands/exec.c', 'commands/exec_always.c', From 8830b1f992c4cd6fe34ac3507ae9f71211fb3c8b Mon Sep 17 00:00:00 2001 From: slonkazoid Date: Sun, 8 Sep 2024 18:20:31 +0300 Subject: [PATCH 02/11] depend directly on glib-2.0 note: there were already implicit dependencies on glib-2.0, namely by pango --- meson.build | 1 + sway/meson.build | 1 + 2 files changed, 2 insertions(+) diff --git a/meson.build b/meson.build index 71e75fd9b..84350c694 100644 --- a/meson.build +++ b/meson.build @@ -69,6 +69,7 @@ xkbcommon = dependency('xkbcommon', version: '>=1.5.0') cairo = dependency('cairo') pango = dependency('pango') pangocairo = dependency('pangocairo') +glib = dependency('glib-2.0') gdk_pixbuf = dependency('gdk-pixbuf-2.0', required: get_option('gdk-pixbuf')) pixman = dependency('pixman-1') libevdev = dependency('libevdev') diff --git a/sway/meson.build b/sway/meson.build index ea03e2ef0..c02063650 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -221,6 +221,7 @@ sway_sources = files( sway_deps = [ cairo, drm, + glib, jsonc, libevdev, libinput, From f7d611af7bca45253f775b2ddc2dd5299b03f3fe Mon Sep 17 00:00:00 2001 From: slonkazoid Date: Sun, 8 Sep 2024 18:22:00 +0300 Subject: [PATCH 03/11] create an environment pointer for child processes --- sway/main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sway/main.c b/sway/main.c index 1c4939aa0..d855de5b5 100644 --- a/sway/main.c +++ b/sway/main.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -30,6 +31,7 @@ static int exit_value = 0; static struct rlimit original_nofile_rlimit = {0}; struct sway_server server = {0}; struct sway_debug debug = {0}; +char **child_envp; void sway_terminate(int exit_code) { if (!server.wl_display) { @@ -348,6 +350,8 @@ int main(int argc, char **argv) { ipc_init(&server); setenv("WAYLAND_DISPLAY", server.socket, true); + // g_get_environ creates a newly-allocated environment buffer + child_envp = g_get_environ(); if (!load_main_config(config_path, false, false)) { sway_terminate(EXIT_FAILURE); goto shutdown; @@ -381,6 +385,7 @@ shutdown: free(config_path); free_config(config); + g_strfreev(child_envp); pango_cairo_font_map_set_default(NULL); From 124b1f1248365cc8d191c085eac251a4a9548a5a Mon Sep 17 00:00:00 2001 From: slonkazoid Date: Sun, 8 Sep 2024 18:22:06 +0300 Subject: [PATCH 04/11] act on child_envp instead of global environment variables --- sway/commands/env.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sway/commands/env.c b/sway/commands/env.c index 2603f257a..e221fab76 100644 --- a/sway/commands/env.c +++ b/sway/commands/env.c @@ -1,14 +1,17 @@ #define _POSIX_C_SOURCE 200809L #include +#include #include "sway/commands.h" +extern char **child_envp; + struct cmd_results *cmd_env(int argc, char **argv) { struct cmd_results *error = NULL; if ((error = checkarg(argc, "env", EXPECTED_EQUAL_TO, 2))) { return error; } - setenv(argv[0], argv[1], 1); + child_envp = g_environ_setenv(child_envp, argv[0], argv[1], 1); return cmd_results_new(CMD_SUCCESS, NULL); } From d211b7d4a9a0ee3d0420a8aade39e9b96fe8c6ce Mon Sep 17 00:00:00 2001 From: slonkazoid Date: Sun, 8 Sep 2024 18:22:14 +0300 Subject: [PATCH 05/11] switch to execle and supply child_envp as the environment pointer --- sway/commands/exec_always.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sway/commands/exec_always.c b/sway/commands/exec_always.c index 8bc1048cd..2773238bf 100644 --- a/sway/commands/exec_always.c +++ b/sway/commands/exec_always.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "sway/commands.h" #include "sway/config.h" #include "sway/server.h" @@ -14,6 +15,8 @@ #include "log.h" #include "stringop.h" +extern char** child_envp; + struct cmd_results *cmd_exec_validate(int argc, char **argv) { struct cmd_results *error = NULL; if ((error = checkarg(argc, argv[-1], EXPECTED_AT_LEAST, 1))) { @@ -81,7 +84,7 @@ struct cmd_results *cmd_exec_process(int argc, char **argv) { if (ctx && !no_startup_id) { export_startup_id(ctx); } - execlp("sh", "sh", "-c", cmd, (void *)NULL); + execle("/bin/sh", "sh", "-c", cmd, (void *)NULL, child_envp); sway_log_errno(SWAY_ERROR, "execlp failed"); _exit(1); } From 2e56296ccc6f1b195b65ae54984c81d2e706f815 Mon Sep 17 00:00:00 2001 From: slonkazoid Date: Sun, 8 Sep 2024 18:28:53 +0300 Subject: [PATCH 06/11] add comment detailing why there is no error handling --- sway/commands/env.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sway/commands/env.c b/sway/commands/env.c index e221fab76..a382cb382 100644 --- a/sway/commands/env.c +++ b/sway/commands/env.c @@ -11,6 +11,8 @@ struct cmd_results *cmd_env(int argc, char **argv) { return error; } + // g_environ_setenv never returns NULL + // https://github.com/GNOME/glib/blob/8810cf7a/glib/genviron.c#L129 child_envp = g_environ_setenv(child_envp, argv[0], argv[1], 1); return cmd_results_new(CMD_SUCCESS, NULL); From 5740bcb961a16a134e459c09ccf80fdaa7ff88ce Mon Sep 17 00:00:00 2001 From: slonkazoid Date: Wed, 11 Sep 2024 19:55:30 +0300 Subject: [PATCH 07/11] Revert "depend directly on glib-2.0" This reverts commit 8830b1f992c4cd6fe34ac3507ae9f71211fb3c8b. --- meson.build | 1 - sway/meson.build | 1 - 2 files changed, 2 deletions(-) diff --git a/meson.build b/meson.build index 84350c694..71e75fd9b 100644 --- a/meson.build +++ b/meson.build @@ -69,7 +69,6 @@ xkbcommon = dependency('xkbcommon', version: '>=1.5.0') cairo = dependency('cairo') pango = dependency('pango') pangocairo = dependency('pangocairo') -glib = dependency('glib-2.0') gdk_pixbuf = dependency('gdk-pixbuf-2.0', required: get_option('gdk-pixbuf')) pixman = dependency('pixman-1') libevdev = dependency('libevdev') diff --git a/sway/meson.build b/sway/meson.build index c02063650..ea03e2ef0 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -221,7 +221,6 @@ sway_sources = files( sway_deps = [ cairo, drm, - glib, jsonc, libevdev, libinput, From 4f90f084918ddb5ef79c10b77450a673bc73c170 Mon Sep 17 00:00:00 2001 From: slonkazoid Date: Wed, 11 Sep 2024 22:56:53 +0300 Subject: [PATCH 08/11] reimplement glib functions --- include/env.h | 10 ++++ sway/commands/env.c | 4 +- sway/commands/exec_always.c | 1 - sway/env.c | 110 ++++++++++++++++++++++++++++++++++++ sway/main.c | 6 +- sway/meson.build | 1 + 6 files changed, 126 insertions(+), 6 deletions(-) create mode 100644 include/env.h create mode 100644 sway/env.c diff --git a/include/env.h b/include/env.h new file mode 100644 index 000000000..2d6e996f8 --- /dev/null +++ b/include/env.h @@ -0,0 +1,10 @@ +#ifndef _SWAY_ENV_H +#define _SWAY_ENV_H + +void env_free(char **envp); + +char **env_get_envp(); + +char **env_setenv(char **envp, char *name, char *value); + +#endif diff --git a/sway/commands/env.c b/sway/commands/env.c index a382cb382..93e45be0d 100644 --- a/sway/commands/env.c +++ b/sway/commands/env.c @@ -1,7 +1,7 @@ #define _POSIX_C_SOURCE 200809L #include -#include #include "sway/commands.h" +#include "env.h" extern char **child_envp; @@ -13,7 +13,7 @@ struct cmd_results *cmd_env(int argc, char **argv) { // g_environ_setenv never returns NULL // https://github.com/GNOME/glib/blob/8810cf7a/glib/genviron.c#L129 - child_envp = g_environ_setenv(child_envp, argv[0], argv[1], 1); + child_envp = env_setenv(child_envp, argv[0], argv[1]); return cmd_results_new(CMD_SUCCESS, NULL); } diff --git a/sway/commands/exec_always.c b/sway/commands/exec_always.c index 2773238bf..502beeb30 100644 --- a/sway/commands/exec_always.c +++ b/sway/commands/exec_always.c @@ -4,7 +4,6 @@ #include #include #include -#include #include "sway/commands.h" #include "sway/config.h" #include "sway/server.h" diff --git a/sway/env.c b/sway/env.c new file mode 100644 index 000000000..75e1d3f2f --- /dev/null +++ b/sway/env.c @@ -0,0 +1,110 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include + +extern char **environ; + +int _env_var_name_eq(char *env_name, char *cmp) { + size_t i = 0; + int reached_eq; + while (1) { + char current_char = env_name[i]; + char cmp_char = cmp[i]; + + int is_eq = current_char == '='; + int is_null = current_char == '\0'; + + if (is_eq) reached_eq = 1; + if (is_null && !reached_eq) return 0; + if (is_eq && cmp_char == '\0') return 1; + if (is_eq || cmp_char == '\0') return 0; + if (current_char != cmp_char) return 0; + + i++; + } +} + +typedef struct { + char *ptr; + size_t idx; +} _env_info; + +_env_info _env_get(char **envp, char *name) { + char *strp; + size_t i = 0; + while ((strp = envp[i]) != NULL) { + if (_env_var_name_eq(strp, name)) return (_env_info){strp, i}; + i++; + } + + return (_env_info){NULL, 0}; +} + +size_t _env_len(char **envp) { + char *strp; + size_t i = 0; + + while ((strp = envp[i]) != NULL) { + i++; + } + + return i; +} + +char **_env_clone(char **envp, size_t reserve) { + char **new_envp = calloc(_env_len(envp) + 1 + reserve, sizeof(char *)); + + char *strp; + size_t i = 0; + + while ((strp = envp[i]) != NULL) { + size_t n = strlen(strp) + 1; + char *new_strp = malloc(n); + memcpy(new_strp, strp, n); + new_envp[i] = new_strp; + i++; + } + + return new_envp; +} + +void env_free(char **envp) { + char *strp; + size_t i = 0; + while ((strp = envp[i]) != NULL) { + free(strp); + i++; + } + + free(envp); +} + +// copy the global environment array into a newly-allocated one +// you are responsible for deallocating it after use +char **env_get_envp() { return _env_clone(environ, 0); } + +// use env_get_envp() to acquire an envp +// might clone and deallocate the given envp +char **env_setenv(char **envp, char *name, char *value) { + size_t name_len = strlen(name); + size_t value_len = strlen(value); + char *newp = malloc(name_len + value_len + 2); + memcpy(newp, name, name_len); + memcpy(newp + name_len + 1, value, value_len); + newp[name_len] = '='; + newp[name_len + value_len + 1] = '\0'; + + _env_info existing = _env_get(envp, name); + if (existing.ptr != NULL) { + free(existing.ptr); + envp[existing.idx] = newp; + return envp; + } else { + char **new_envp = _env_clone(envp, 1); + new_envp[_env_len(envp)] = newp; + env_free(envp); + return new_envp; + } +} diff --git a/sway/main.c b/sway/main.c index d855de5b5..51c012e9f 100644 --- a/sway/main.c +++ b/sway/main.c @@ -1,6 +1,5 @@ #include #include -#include #include #include #include @@ -25,6 +24,7 @@ #include "log.h" #include "stringop.h" #include "util.h" +#include "env.h" static bool terminate_request = false; static int exit_value = 0; @@ -350,8 +350,8 @@ int main(int argc, char **argv) { ipc_init(&server); setenv("WAYLAND_DISPLAY", server.socket, true); - // g_get_environ creates a newly-allocated environment buffer - child_envp = g_get_environ(); + // env_get_envp creates a newly-allocated environment buffer + child_envp = env_get_envp(); if (!load_main_config(config_path, false, false)) { sway_terminate(EXIT_FAILURE); goto shutdown; diff --git a/sway/meson.build b/sway/meson.build index ea03e2ef0..75c2410ab 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -3,6 +3,7 @@ sway_sources = files( 'config.c', 'criteria.c', 'decoration.c', + 'env.c', 'ipc-json.c', 'ipc-server.c', 'lock.c', From 9b3def6f618010687547d7b356ea92d55bca98b9 Mon Sep 17 00:00:00 2001 From: slonkazoid Date: Wed, 11 Sep 2024 23:06:38 +0300 Subject: [PATCH 09/11] remove unnecessary headers --- sway/env.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sway/env.c b/sway/env.c index 75e1d3f2f..2083fa6a3 100644 --- a/sway/env.c +++ b/sway/env.c @@ -1,6 +1,4 @@ #define _POSIX_C_SOURCE 200809L -#include -#include #include #include From 8ca45f25381e8e7616a5cab8b0e07155ab2cfc9d Mon Sep 17 00:00:00 2001 From: slonkazoid Date: Thu, 12 Sep 2024 14:37:29 +0300 Subject: [PATCH 10/11] style changes --- include/env.h | 16 ++++++++++++++-- sway/commands/env.c | 2 -- sway/env.c | 36 ++++++++++++++++++------------------ sway/main.c | 2 +- 4 files changed, 33 insertions(+), 23 deletions(-) diff --git a/include/env.h b/include/env.h index 2d6e996f8..e91328327 100644 --- a/include/env.h +++ b/include/env.h @@ -1,10 +1,22 @@ #ifndef _SWAY_ENV_H #define _SWAY_ENV_H -void env_free(char **envp); +/** + * Deallocates an environment array created by + * sway_env_get_envp or sway_env_setenv. + */ +void env_destroy(char **envp); -char **env_get_envp(); +/** + * Gets a newly-allocated environment array pointer + * from the global environment. + */ +char **env_create(); +/** + * Sets or overwrites an environment variable in the given environment. + * Setting a new variable will reallocate the entire array. + */ char **env_setenv(char **envp, char *name, char *value); #endif diff --git a/sway/commands/env.c b/sway/commands/env.c index 93e45be0d..7032a59e2 100644 --- a/sway/commands/env.c +++ b/sway/commands/env.c @@ -11,8 +11,6 @@ struct cmd_results *cmd_env(int argc, char **argv) { return error; } - // g_environ_setenv never returns NULL - // https://github.com/GNOME/glib/blob/8810cf7a/glib/genviron.c#L129 child_envp = env_setenv(child_envp, argv[0], argv[1]); return cmd_results_new(CMD_SUCCESS, NULL); diff --git a/sway/env.c b/sway/env.c index 2083fa6a3..12843fe33 100644 --- a/sway/env.c +++ b/sway/env.c @@ -2,9 +2,14 @@ #include #include +typedef struct { + char *ptr; + size_t idx; +} env_info; + extern char **environ; -int _env_var_name_eq(char *env_name, char *cmp) { +int env_name_eq(char *env_name, char *cmp) { size_t i = 0; int reached_eq; while (1) { @@ -24,23 +29,18 @@ int _env_var_name_eq(char *env_name, char *cmp) { } } -typedef struct { - char *ptr; - size_t idx; -} _env_info; - -_env_info _env_get(char **envp, char *name) { +env_info env_get(char **envp, char *name) { char *strp; size_t i = 0; while ((strp = envp[i]) != NULL) { - if (_env_var_name_eq(strp, name)) return (_env_info){strp, i}; + if (env_name_eq(strp, name)) return (env_info){strp, i}; i++; } - return (_env_info){NULL, 0}; + return (env_info){NULL, 0}; } -size_t _env_len(char **envp) { +size_t env_len(char **envp) { char *strp; size_t i = 0; @@ -51,8 +51,8 @@ size_t _env_len(char **envp) { return i; } -char **_env_clone(char **envp, size_t reserve) { - char **new_envp = calloc(_env_len(envp) + 1 + reserve, sizeof(char *)); +char **env_clone(char **envp, size_t reserve) { + char **new_envp = calloc(env_len(envp) + 1 + reserve, sizeof(char *)); char *strp; size_t i = 0; @@ -68,7 +68,7 @@ char **_env_clone(char **envp, size_t reserve) { return new_envp; } -void env_free(char **envp) { +void env_destroy(char **envp) { char *strp; size_t i = 0; while ((strp = envp[i]) != NULL) { @@ -81,7 +81,7 @@ void env_free(char **envp) { // copy the global environment array into a newly-allocated one // you are responsible for deallocating it after use -char **env_get_envp() { return _env_clone(environ, 0); } +char **env_create() { return env_clone(environ, 0); } // use env_get_envp() to acquire an envp // might clone and deallocate the given envp @@ -94,15 +94,15 @@ char **env_setenv(char **envp, char *name, char *value) { newp[name_len] = '='; newp[name_len + value_len + 1] = '\0'; - _env_info existing = _env_get(envp, name); + env_info existing = env_get(envp, name); if (existing.ptr != NULL) { free(existing.ptr); envp[existing.idx] = newp; return envp; } else { - char **new_envp = _env_clone(envp, 1); - new_envp[_env_len(envp)] = newp; - env_free(envp); + char **new_envp = env_clone(envp, 1); + new_envp[env_len(envp)] = newp; + env_destroy(envp); return new_envp; } } diff --git a/sway/main.c b/sway/main.c index 51c012e9f..631eb11bb 100644 --- a/sway/main.c +++ b/sway/main.c @@ -351,7 +351,7 @@ int main(int argc, char **argv) { setenv("WAYLAND_DISPLAY", server.socket, true); // env_get_envp creates a newly-allocated environment buffer - child_envp = env_get_envp(); + child_envp = env_create(); if (!load_main_config(config_path, false, false)) { sway_terminate(EXIT_FAILURE); goto shutdown; From ca53b3e4ebdce25efbf781b92aadbdbdb1062aeb Mon Sep 17 00:00:00 2001 From: slonkazoid Date: Thu, 12 Sep 2024 15:04:14 +0300 Subject: [PATCH 11/11] add cmd_env_unset to remove environment variables --- include/env.h | 6 ++++++ include/sway/commands.h | 1 + sway/commands.c | 1 + sway/commands/env.c | 11 +++++++++++ sway/env.c | 27 ++++++++++++++++++++++----- 5 files changed, 41 insertions(+), 5 deletions(-) diff --git a/include/env.h b/include/env.h index e91328327..16a811a4c 100644 --- a/include/env.h +++ b/include/env.h @@ -19,4 +19,10 @@ char **env_create(); */ char **env_setenv(char **envp, char *name, char *value); +/** + * Unsets an environment variable in the given environment. + * If successful, this will reallocate the entire array. + */ +char **env_unsetenv(char **envp, char *name); + #endif diff --git a/include/sway/commands.h b/include/sway/commands.h index b77f49221..e933b3728 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -126,6 +126,7 @@ sway_cmd cmd_default_border; sway_cmd cmd_default_floating_border; sway_cmd cmd_default_orientation; sway_cmd cmd_env; +sway_cmd cmd_env_unset; sway_cmd cmd_exec; sway_cmd cmd_exec_always; sway_cmd cmd_exit; diff --git a/sway/commands.c b/sway/commands.c index b07a6a8cf..e19f86867 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -58,6 +58,7 @@ static const struct cmd_handler handlers[] = { { "default_border", cmd_default_border }, { "default_floating_border", cmd_default_floating_border }, { "env", cmd_env }, + { "env_unset", cmd_env_unset }, { "exec", cmd_exec }, { "exec_always", cmd_exec_always }, { "floating_maximum_size", cmd_floating_maximum_size }, diff --git a/sway/commands/env.c b/sway/commands/env.c index 7032a59e2..aba4e33b2 100644 --- a/sway/commands/env.c +++ b/sway/commands/env.c @@ -15,3 +15,14 @@ struct cmd_results *cmd_env(int argc, char **argv) { return cmd_results_new(CMD_SUCCESS, NULL); } + +struct cmd_results *cmd_env_unset(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "env_unset", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + child_envp = env_unsetenv(child_envp, argv[0]); + + return cmd_results_new(CMD_SUCCESS, NULL); +} diff --git a/sway/env.c b/sway/env.c index 12843fe33..8c7d63c24 100644 --- a/sway/env.c +++ b/sway/env.c @@ -51,18 +51,25 @@ size_t env_len(char **envp) { return i; } -char **env_clone(char **envp, size_t reserve) { - char **new_envp = calloc(env_len(envp) + 1 + reserve, sizeof(char *)); +char **env_clone(char **envp, size_t reserve, env_info exclude) { + size_t elem_count = env_len(envp) + 1 + reserve - (exclude.ptr != NULL); + char **new_envp = calloc(elem_count, sizeof(char *)); char *strp; size_t i = 0; + size_t new_i = 0; while ((strp = envp[i]) != NULL) { + if (exclude.ptr == strp) { + i++; + continue; + } size_t n = strlen(strp) + 1; char *new_strp = malloc(n); memcpy(new_strp, strp, n); - new_envp[i] = new_strp; + new_envp[new_i] = new_strp; i++; + new_i++; } return new_envp; @@ -81,7 +88,7 @@ void env_destroy(char **envp) { // copy the global environment array into a newly-allocated one // you are responsible for deallocating it after use -char **env_create() { return env_clone(environ, 0); } +char **env_create() { return env_clone(environ, 0, (env_info){NULL, 0}); } // use env_get_envp() to acquire an envp // might clone and deallocate the given envp @@ -100,9 +107,19 @@ char **env_setenv(char **envp, char *name, char *value) { envp[existing.idx] = newp; return envp; } else { - char **new_envp = env_clone(envp, 1); + char **new_envp = env_clone(envp, 1, (env_info){NULL, 0}); new_envp[env_len(envp)] = newp; env_destroy(envp); return new_envp; } } + +char **env_unsetenv(char **envp, char *name) { + env_info existing = env_get(envp, name); + if (existing.ptr == NULL) // dont do anything if + return envp; // the variable is not set + + char **new_envp = env_clone(envp, 0, existing); + env_destroy(envp); + return new_envp; +}