/* 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)) 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; cmd = LIBEXEC_COMMAND_INIT; 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