diff options
Diffstat (limited to '')
-rw-r--r-- | libexec_putenv.c | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/libexec_putenv.c b/libexec_putenv.c new file mode 100644 index 0000000..366f5fb --- /dev/null +++ b/libexec_putenv.c @@ -0,0 +1,144 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + + +int +libexec_putenv(struct libexec_command *cmd, enum libexec_insert_mode how, const char *string) +{ + char **env; + char *copy, *eqsign; + size_t i, n, len; + int environ_copied = 0; + void *new; + + if (!cmd || !string) { + errno = EINVAL; + return -1; + } + + env = cmd->environ ? cmd->environ : environ; + + if (how == LIBEXEC_APPEND || how == LIBEXEC_PREPEND) { + n = 0; + while (env[n]) + n++; + + just_add: + copy = strdup(string); + if (!copy) + return -1; + + if (!cmd->environ) { + if (libexec_copy_environ(cmd, NULL)) { + free(copy); + return -1; + } + environ_copied = 1; + } + + new = realloc(cmd->environ, (n + 2) * sizeof(*cmd->environ)); + if (!new) { + if (environ_copied) { + while (n) + free(cmd->environ[--n]); + free(cmd->environ); + cmd->environ = NULL; + } + free(copy); + return -1; + } + cmd->environ = new; + + if (how == LIBEXEC_APPEND) { + cmd->environ[n] = copy; + cmd->environ[n + 1] = NULL; + } else { + memmove(&cmd->environ[1], cmd->environ, (n + 1) * sizeof(*cmd->environ)); + cmd->environ[0] = copy; + } + + + } else { + eqsign = strchr(string, '='); + + if (!eqsign || (how != LIBEXEC_REPLACE && how != LIBEXEC_NOCLOBBER && how != LIBEXEC_NOREPLACE)) { + errno = EINVAL; + return -1; + } + + len = (size_t)(eqsign - string) + 1; + for (i = 0; env[i]; i++) + if (!strncmp(env[i], string, len)) + break; + + if (!env[i]) { + n = i; + how = LIBEXEC_APPEND; + goto just_add; + } + + if (how == LIBEXEC_NOREPLACE || !strcmp(env[i], string)) { + if (!cmd->environ) { + if (libexec_copy_environ(cmd, NULL)) { + free(copy); + return -1; + } + } + return 0; + } + if (how == LIBEXEC_NOCLOBBER) + return -1; /* do not change errno */ + + copy = strdup(string); + if (!copy) + return -1; + + if (!cmd->environ) { + if (libexec_copy_environ(cmd, NULL)) { + free(copy); + return -1; + } + } + + free(cmd->environ[i]); + cmd->environ[i] = copy; + + } + return 0; +} + + +#else + + +int +main(void) +{ + /* Correct usage is tested via + * libexec_putenv_append.c, + * libexec_putenv_noclobber.c, + * libexec_putenv_noreplace.c, + * libexec_putenv_prepend.c, and + * libexec_putenv_replace.c */ + + struct libexec_command cmd, ref; + + libexec_init_command(&cmd); + memcpy(&ref, &cmd, sizeof(cmd)); + + errno = 0; + ASSERT_EQ_INT(libexec_putenv(&cmd, (enum libexec_insert_mode)-1, "A=B"), -1); + ASSERT_EQ_INT(errno, EINVAL); + ASSERT_IS_TRUE(!memcmp(&cmd, &ref, sizeof(cmd))); + + errno = 0; + ASSERT_EQ_INT(libexec_putenv(&cmd, (enum libexec_insert_mode)LIBEXEC_INSERT_MODE__COUNT__, "A=B"), -1); + ASSERT_EQ_INT(errno, EINVAL); + ASSERT_IS_TRUE(!memcmp(&cmd, &ref, sizeof(cmd))); + + return 0; +} + + +#endif |