aboutsummaryrefslogblamecommitdiffstats
path: root/libexec_putenv.c
blob: c72a153e3f640c0e533c28c04839327fa1db10f3 (plain) (tree)
















































































                                                                                                                  

                                                                    
                                                  






































                                                              
                                   
















                                                                                                               
/* 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