diff --git a/libc/Android.mk b/libc/Android.mk
index f4f91416f..ca4692977 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -39,7 +39,6 @@ endif
 libc_common_src_files := \
     bionic/arc4random.c \
     bionic/bindresvport.c \
-    bionic/clearenv.c \
     bionic/daemon.c \
     bionic/err.c \
     bionic/ether_aton.c \
@@ -75,9 +74,6 @@ libc_common_src_files := \
     stdio/snprintf.c\
     stdio/sprintf.c \
     stdlib/atexit.c \
-    stdlib/getenv.c \
-    stdlib/putenv.c \
-    stdlib/setenv.c \
     unistd/syslog.c \
 
 # Fortify implementations of libc functions.
@@ -110,6 +106,7 @@ libc_bionic_src_files := \
     bionic/brk.cpp \
     bionic/chmod.cpp \
     bionic/chown.cpp \
+    bionic/clearenv.cpp \
     bionic/clock.cpp \
     bionic/clone.cpp \
     bionic/cmsg_nxthdr.cpp \
@@ -402,6 +399,8 @@ libc_upstream_openbsd_src_files := \
     upstream-openbsd/lib/libc/stdlib/atoi.c \
     upstream-openbsd/lib/libc/stdlib/atol.c \
     upstream-openbsd/lib/libc/stdlib/atoll.c \
+    upstream-openbsd/lib/libc/stdlib/getenv.c \
+    upstream-openbsd/lib/libc/stdlib/setenv.c \
     upstream-openbsd/lib/libc/stdlib/strtoimax.c \
     upstream-openbsd/lib/libc/stdlib/strtol.c \
     upstream-openbsd/lib/libc/stdlib/strtoll.c \
diff --git a/libc/bionic/clearenv.c b/libc/bionic/clearenv.cpp
similarity index 89%
rename from libc/bionic/clearenv.c
rename to libc/bionic/clearenv.cpp
index 0f6f066cc..c70cc3e1c 100644
--- a/libc/bionic/clearenv.c
+++ b/libc/bionic/clearenv.cpp
@@ -26,17 +26,15 @@
  * SUCH DAMAGE.
  */
 
-#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
 
-extern char** environ;
-
-int clearenv(void)
-{
-    char **P = environ;
-
-    if (P != NULL) {
-        for (; *P; ++P)
-            *P = NULL;
+int clearenv() {
+  char** e = environ;
+  if (e != NULL) {
+    for (; *e; ++e) {
+      *e = NULL;
     }
-    return 0;
+  }
+  return 0;
 }
diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h
index 58538ffc7..6c966f783 100644
--- a/libc/include/stdlib.h
+++ b/libc/include/stdlib.h
@@ -46,10 +46,10 @@ extern __noreturn void exit(int);
 extern __noreturn void _Exit(int);
 extern int atexit(void (*)(void));
 
-extern char *getenv(const char *);
-extern int putenv(const char *);
-extern int setenv(const char *, const char *, int);
-extern int unsetenv(const char *);
+extern char* getenv(const char*);
+extern int putenv(char*);
+extern int setenv(const char*, const char*, int);
+extern int unsetenv(const char*);
 extern int clearenv(void);
 
 extern char* mkdtemp(char*);
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index d21f23d3f..6cb36d8f9 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -47,7 +47,8 @@ __BEGIN_DECLS
 #define SEEK_CUR 1
 #define SEEK_END 2
 
-extern char **environ;
+extern char** environ;
+
 extern __noreturn void _exit(int);
 
 extern pid_t  fork(void);
diff --git a/libc/stdlib/putenv.c b/libc/stdlib/putenv.c
deleted file mode 100644
index 54482f6a1..000000000
--- a/libc/stdlib/putenv.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/*	$OpenBSD: putenv.c,v 1.5 2005/08/08 08:05:37 espie Exp $ */
-/*-
- * Copyright (c) 1988, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-int
-putenv(const char *str)
-{
-	char *p, *equal;
-	int rval;
-
-	if ((p = strdup(str)) == NULL)
-		return (-1);
-	if ((equal = strchr(p, '=')) == NULL) {
-		(void)free(p);
-		return (-1);
-	}
-	*equal = '\0';
-	rval = setenv(p, equal + 1, 1);
-	(void)free(p);
-	return (rval);
-}
diff --git a/libc/stdlib/getenv.c b/libc/upstream-openbsd/lib/libc/stdlib/getenv.c
similarity index 83%
rename from libc/stdlib/getenv.c
rename to libc/upstream-openbsd/lib/libc/stdlib/getenv.c
index 72367b34e..fd8482e9e 100644
--- a/libc/stdlib/getenv.c
+++ b/libc/upstream-openbsd/lib/libc/stdlib/getenv.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: getenv.c,v 1.8 2005/08/08 08:05:36 espie Exp $ */
+/*	$OpenBSD: getenv.c,v 1.10 2010/08/23 22:31:50 millert Exp $ */
 /*
  * Copyright (c) 1987, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -31,31 +31,29 @@
 #include <stdlib.h>
 #include <string.h>
 
-char *__findenv(const char *name, int *offset);
+char *__findenv(const char *name, int len, int *offset);
 
 /*
  * __findenv --
  *	Returns pointer to value associated with name, if any, else NULL.
+ *	Starts searching within the environmental array at offset.
  *	Sets offset to be the offset of the name/value combination in the
- *	environmental array, for use by setenv(3) and unsetenv(3).
+ *	environmental array, for use by putenv(3), setenv(3) and unsetenv(3).
  *	Explicitly removes '=' in argument name.
  *
  *	This routine *should* be a static; don't use it.
  */
 char *
-__findenv(const char *name, int *offset)
+__findenv(const char *name, int len, int *offset)
 {
 	extern char **environ;
-	int len, i;
+	int i;
 	const char *np;
 	char **p, *cp;
 
 	if (name == NULL || environ == NULL)
 		return (NULL);
-	for (np = name; *np && *np != '='; ++np)
-		;
-	len = np - name;
-	for (p = environ; (cp = *p) != NULL; ++p) {
+	for (p = environ + *offset; (cp = *p) != NULL; ++p) {
 		for (np = name, i = len; i && *cp; i--)
 			if (*cp++ != *np++)
 				break;
@@ -74,7 +72,10 @@ __findenv(const char *name, int *offset)
 char *
 getenv(const char *name)
 {
-	int offset;
+	int offset = 0;
+	const char *np;
 
-	return (__findenv(name, &offset));
+	for (np = name; *np && *np != '='; ++np)
+		;
+	return (__findenv(name, (int)(np - name), &offset));
 }
diff --git a/libc/stdlib/setenv.c b/libc/upstream-openbsd/lib/libc/stdlib/setenv.c
similarity index 54%
rename from libc/stdlib/setenv.c
rename to libc/upstream-openbsd/lib/libc/stdlib/setenv.c
index 856db5e93..9060fdba8 100644
--- a/libc/stdlib/setenv.c
+++ b/libc/upstream-openbsd/lib/libc/stdlib/setenv.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: setenv.c,v 1.9 2005/08/08 08:05:37 espie Exp $ */
+/*	$OpenBSD: setenv.c,v 1.14 2012/09/23 16:08:04 jeremy Exp $ */
 /*
  * Copyright (c) 1987 Regents of the University of California.
  * All rights reserved.
@@ -28,12 +28,59 @@
  * SUCH DAMAGE.
  */
 
+#include <errno.h>
 #include <stdlib.h>
 #include <string.h>
 
-char *__findenv(const char *name, int *offset);
+char *__findenv(const char *name, int len, int *offset);
 
 extern char **environ;
+static char **lastenv;				/* last value of environ */
+
+/*
+ * putenv --
+ *	Add a name=value string directly to the environmental, replacing
+ *	any current value.
+ */
+int
+putenv(char *str)
+{
+	char **P, *cp;
+	size_t cnt;
+	int offset = 0;
+
+	for (cp = str; *cp && *cp != '='; ++cp)
+		;
+	if (*cp != '=') {
+		errno = EINVAL;
+		return (-1);			/* missing `=' in string */
+	}
+
+	if (__findenv(str, (int)(cp - str), &offset) != NULL) {
+		environ[offset++] = str;
+		/* could be set multiple times */
+		while (__findenv(str, (int)(cp - str), &offset)) {
+			for (P = &environ[offset];; ++P)
+				if (!(*P = *(P + 1)))
+					break;
+		}
+		return (0);
+	}
+
+	/* create new slot for string */
+	for (P = environ; *P != NULL; P++)
+		;
+	cnt = P - environ;
+	P = (char **)realloc(lastenv, sizeof(char *) * (cnt + 2));
+	if (!P)
+		return (-1);
+	if (lastenv != environ)
+		memcpy(P, environ, cnt * sizeof(char *));
+	lastenv = environ = P;
+	environ[cnt] = str;
+	environ[cnt + 1] = NULL;
+	return (0);
+}
 
 /*
  * setenv --
@@ -43,29 +90,46 @@ extern char **environ;
 int
 setenv(const char *name, const char *value, int rewrite)
 {
-	static char **lastenv;			/* last value of environ */
-	char *C;
-	int l_value, offset;
+	char *C, **P;
+	const char *np;
+	int l_value, offset = 0;
+
+	if (!name || !*name) {
+		errno = EINVAL;
+		return (-1);
+	}
+	for (np = name; *np && *np != '='; ++np)
+		;
+	if (*np) {
+		errno = EINVAL;
+		return (-1);			/* has `=' in name */
+	}
 
-	if (*value == '=')			/* no `=' in value */
-		++value;
 	l_value = strlen(value);
-	if ((C = __findenv(name, &offset))) {	/* find if already exists */
+	if ((C = __findenv(name, (int)(np - name), &offset)) != NULL) {
+		int tmpoff = offset + 1;
 		if (!rewrite)
 			return (0);
-		if ((int)strlen(C) >= l_value) {	/* old larger; copy over */
+#if 0 /* XXX - existing entry may not be writable */
+		if (strlen(C) >= l_value) {	/* old larger; copy over */
 			while ((*C++ = *value++))
 				;
 			return (0);
 		}
+#endif
+		/* could be set multiple times */
+		while (__findenv(name, (int)(np - name), &tmpoff)) {
+			for (P = &environ[tmpoff];; ++P)
+				if (!(*P = *(P + 1)))
+					break;
+		}
 	} else {					/* create new slot */
 		size_t cnt;
-		char **P;
 
 		for (P = environ; *P != NULL; P++)
 			;
 		cnt = P - environ;
-        P = (char **)realloc(lastenv, sizeof(char *) * (cnt + 2));
+		P = (char **)realloc(lastenv, sizeof(char *) * (cnt + 2));
 		if (!P)
 			return (-1);
 		if (lastenv != environ)
@@ -74,10 +138,8 @@ setenv(const char *name, const char *value, int rewrite)
 		offset = cnt;
 		environ[cnt + 1] = NULL;
 	}
-	for (C = (char *)name; *C && *C != '='; ++C)
-		;				/* no `=' in name */
 	if (!(environ[offset] =			/* name + `=' + value */
-	    malloc((size_t)((int)(C - name) + l_value + 2))))
+	    malloc((size_t)((int)(np - name) + l_value + 2))))
 		return (-1);
 	for (C = environ[offset]; (*C = *name++) && *C != '='; ++C)
 		;
@@ -94,12 +156,25 @@ int
 unsetenv(const char *name)
 {
 	char **P;
-	int offset;
+	const char *np;
+	int offset = 0;
 
-	while (__findenv(name, &offset))	/* if set multiple times */
+	if (!name || !*name) {
+		errno = EINVAL;
+		return (-1);
+	}
+	for (np = name; *np && *np != '='; ++np)
+		;
+	if (*np) {
+		errno = EINVAL;
+		return (-1);			/* has `=' in name */
+	}
+
+	/* could be set multiple times */
+	while (__findenv(name, (int)(np - name), &offset)) {
 		for (P = &environ[offset];; ++P)
 			if (!(*P = *(P + 1)))
 				break;
-
-        return 0;
+	}
+	return (0);
 }