Merge "libc: fix kernel cleanup script typo."
diff --git a/libc/netbsd/net/getaddrinfo.c b/libc/netbsd/net/getaddrinfo.c
index 778f44c..bb6645c 100644
--- a/libc/netbsd/net/getaddrinfo.c
+++ b/libc/netbsd/net/getaddrinfo.c
@@ -347,35 +347,55 @@
 		return -1;
 }
 
-/* Determine whether IPv6 connectivity is available. */
+/*
+ * Connect a UDP socket to a given unicast address. This will cause no network
+ * traffic, but will fail fast if the system has no or limited reachability to
+ * the destination (e.g., no IPv4 address, no IPv6 default route, ...).
+ */
 static int
-_have_ipv6() {
-	/*
-	 * Connect a UDP socket to an global unicast IPv6 address. This will
-	 * cause no network traffic, but will fail fast if the system has no or
-	 * limited IPv6 connectivity (e.g., only a link-local address).
-	 */
-	static const struct sockaddr_in6 sin6_test = {
-		/* family, port, flow label */
-		AF_INET6, 0, 0,
-		/* 2000:: */
-		{{{ 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}},
-		/* scope ID */
-		0};
-        sockaddr_union addr_test;
-        addr_test.in6 = sin6_test;
-	int s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+_test_connect(int pf, struct sockaddr *addr, size_t addrlen) {
+	int s = socket(pf, SOCK_DGRAM, IPPROTO_UDP);
 	if (s < 0)
 		return 0;
 	int ret;
 	do {
-		ret = connect(s, &addr_test.generic, sizeof(addr_test.in6));
+		ret = connect(s, addr, addrlen);
 	} while (ret < 0 && errno == EINTR);
-	int have_ipv6 = (ret == 0);
+	int success = (ret == 0);
 	do {
 		ret = close(s);
 	} while (ret < 0 && errno == EINTR);
-	return have_ipv6;
+	return success;
+}
+
+/*
+ * The following functions determine whether IPv4 or IPv6 connectivity is
+ * available in order to implement AI_ADDRCONFIG.
+ *
+ * Strictly speaking, AI_ADDRCONFIG should not look at whether connectivity is
+ * available, but whether addresses of the specified family are "configured
+ * on the local system". However, bionic doesn't currently support getifaddrs,
+ * so checking for connectivity is the next best thing.
+ */
+static int
+_have_ipv6() {
+	static const struct sockaddr_in6 sin6_test = {
+		.sin6_family = AF_INET6,
+		.sin6_addr.s6_addr = {  // 2000::
+			0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+		};
+        sockaddr_union addr = { .in6 = sin6_test };
+	return _test_connect(PF_INET6, &addr.generic, sizeof(addr.in6));
+}
+
+static int
+_have_ipv4() {
+	static const struct sockaddr_in sin_test = {
+		.sin_family = AF_INET,
+		.sin_addr.s_addr = __constant_htonl(0x08080808L)  // 8.8.8.8
+	};
+        sockaddr_union addr = { .in = sin_test };
+        return _test_connect(PF_INET, &addr.generic, sizeof(addr.in));
 }
 
 // Returns 0 on success, else returns non-zero on error (in which case
@@ -1525,9 +1545,13 @@
 #define IN6_IS_ADDR_6TO4(a)	 \
 	(((a)->s6_addr[0] == 0x20) && ((a)->s6_addr[1] == 0x02))
 
+/* 6bone testing address area (3ffe::/16), deprecated in RFC 3701. */
+#define IN6_IS_ADDR_6BONE(a)      \
+	(((a)->s6_addr[0] == 0x3f) && ((a)->s6_addr[1] == 0xfe))
+
 /*
  * Get the label for a given IPv4/IPv6 address.
- * RFC 3484, section 2.1, plus Teredo added in with label 5.
+ * RFC 3484, section 2.1, plus changes from draft-ietf-6man-rfc3484-revise-01.
  */
 
 /*ARGSUSED*/
@@ -1535,19 +1559,27 @@
 _get_label(const struct sockaddr *addr)
 {
 	if (addr->sa_family == AF_INET) {
-		return 4;
+		return 3;
 	} else if (addr->sa_family == AF_INET6) {
 		const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
 		if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr)) {
 			return 0;
-		} else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr)) {
+		} else if (IN6_IS_ADDR_ULA(&addr6->sin6_addr)) {
+			return 1;
+		} else if (IN6_IS_ADDR_V4MAPPED(&addr6->sin6_addr)) {
 			return 3;
+		} else if (IN6_IS_ADDR_6TO4(&addr6->sin6_addr)) {
+			return 4;
 		} else if (IN6_IS_ADDR_TEREDO(&addr6->sin6_addr)) {
 			return 5;
-		} else if (IN6_IS_ADDR_6TO4(&addr6->sin6_addr)) {
-			return 2;
+		} else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr)) {
+			return 10;
+		} else if (IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr)) {
+			return 11;
+		} else if (IN6_IS_ADDR_6BONE(&addr6->sin6_addr)) {
+			return 12;
 		} else {
-			return 1;
+			return 2;
 		}
 	} else {
 		/*
@@ -1560,7 +1592,7 @@
 
 /*
  * Get the precedence for a given IPv4/IPv6 address.
- * RFC 3484, section 2.1, plus Teredo added in with precedence 25.
+ * RFC 3484, section 2.1, plus changes from draft-ietf-6man-rfc3484-revise-01.
  */
 
 /*ARGSUSED*/
@@ -1568,22 +1600,28 @@
 _get_precedence(const struct sockaddr *addr)
 {
 	if (addr->sa_family == AF_INET) {
-		return 10;
+		return 30;
 	} else if (addr->sa_family == AF_INET6) {
 		const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
 		if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr)) {
+			return 60;
+		} else if (IN6_IS_ADDR_ULA(&addr6->sin6_addr)) {
 			return 50;
-		} else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr)) {
+		} else if (IN6_IS_ADDR_V4MAPPED(&addr6->sin6_addr)) {
+			return 30;
+		} else if (IN6_IS_ADDR_6TO4(&addr6->sin6_addr)) {
 			return 20;
 		} else if (IN6_IS_ADDR_TEREDO(&addr6->sin6_addr)) {
-			return 25;
-		} else if (IN6_IS_ADDR_6TO4(&addr6->sin6_addr)) {
-			return 30;
+			return 10;
+		} else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr) ||
+		           IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr) ||
+		           IN6_IS_ADDR_6BONE(&addr6->sin6_addr)) {
+			return 1;
 		} else {
 			return 40;
 		}
 	} else {
-		return 5;
+		return 1;
 	}
 }
 
@@ -1867,17 +1905,27 @@
 		q.qclass = C_IN;
 		q.answer = buf->buf;
 		q.anslen = sizeof(buf->buf);
-		/* If AI_ADDRCONFIG, lookup IPv6 only if we have connectivity */
-		if (!(pai->ai_flags & AI_ADDRCONFIG) || _have_ipv6()) {
+		int query_ipv6 = 1, query_ipv4 = 1;
+		if (pai->ai_flags & AI_ADDRCONFIG) {
+			query_ipv6 = _have_ipv6();
+			query_ipv4 = _have_ipv4();
+		}
+		if (query_ipv6) {
 			q.qtype = T_AAAA;
-			q.next = &q2;
-			q2.name = name;
-			q2.qclass = C_IN;
-			q2.qtype = T_A;
-			q2.answer = buf2->buf;
-			q2.anslen = sizeof(buf2->buf);
-		} else {
+			if (query_ipv4) {
+				q.next = &q2;
+				q2.name = name;
+				q2.qclass = C_IN;
+				q2.qtype = T_A;
+				q2.answer = buf2->buf;
+				q2.anslen = sizeof(buf2->buf);
+			}
+		} else if (query_ipv4) {
 			q.qtype = T_A;
+		} else {
+			free(buf);
+			free(buf2);
+			return NS_NOTFOUND;
 		}
 		break;
 	case AF_INET:
diff --git a/libc/stdio/fvwrite.c b/libc/stdio/fvwrite.c
index 57a57e6..39d0604 100644
--- a/libc/stdio/fvwrite.c
+++ b/libc/stdio/fvwrite.c
@@ -48,7 +48,7 @@
 __sfvwrite(FILE *fp, struct __suio *uio)
 {
 	size_t len;
-	char *p;
+	const char *p;
 	struct __siov *iov;
 	int w, s;
 	char *nl;
diff --git a/libc/stdio/fvwrite.h b/libc/stdio/fvwrite.h
index 2344e42..96f65de 100644
--- a/libc/stdio/fvwrite.h
+++ b/libc/stdio/fvwrite.h
@@ -36,7 +36,7 @@
  * I/O descriptors for __sfvwrite().
  */
 struct __siov {
-	void	*iov_base;
+	const void	*iov_base;
 	size_t	iov_len;
 };
 struct __suio {
diff --git a/libc/stdio/vfprintf.c b/libc/stdio/vfprintf.c
index 5c52127..9c36b79 100644
--- a/libc/stdio/vfprintf.c
+++ b/libc/stdio/vfprintf.c
@@ -203,9 +203,9 @@
 	 * below longer.
 	 */
 #define	PADSIZE	16		/* pad chunk size */
-	static char blanks[PADSIZE] =
+	static const char blanks[PADSIZE] =
 	 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
-	static char zeroes[PADSIZE] =
+	static const char zeroes[PADSIZE] =
 	 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
 
 	/*
diff --git a/libc/tzcode/strptime.c b/libc/tzcode/strptime.c
index 1f481c9..0567aa4 100644
--- a/libc/tzcode/strptime.c
+++ b/libc/tzcode/strptime.c
@@ -89,29 +89,31 @@
 #define _LEGAL_ALT(x)       { if (alt_format & ~(x)) return (0); }
 
 
+struct century_relyear {
+    int century;
+    int relyear;
+};
 static  int _conv_num(const unsigned char **, int *, int, int);
-static  unsigned char *_strptime(const unsigned char *, const char *, struct tm *, int);
+static  unsigned char *_strptime(const unsigned char *, const char *, struct tm *,
+        struct century_relyear *);
 
 
 char *
 strptime(const char *buf, const char *fmt, struct tm *tm)
 {
-    return (char*)(_strptime((const unsigned char*)buf, fmt, tm, 1));
+    struct century_relyear cr;
+    cr.century = TM_YEAR_BASE;
+    cr.relyear = -1;
+    return (char*)(_strptime((const unsigned char*)buf, fmt, tm, &cr));
 }
 
 static unsigned char *
-_strptime(const unsigned char *buf, const char *fmt, struct tm *tm, int initialize)
+_strptime(const unsigned char *buf, const char *fmt, struct tm *tm, struct century_relyear *cr)
 {
     unsigned char c;
     const unsigned char *bp;
     size_t len = 0;
     int alt_format, i;
-    static int century, relyear;
-
-    if (initialize) {
-        century = TM_YEAR_BASE;
-        relyear = -1;
-    }
 
     bp = (unsigned char *)buf;
     while ((c = *fmt) != '\0') {
@@ -158,43 +160,43 @@
          */
         case 'c':   /* Date and time, using the locale's format. */
             _LEGAL_ALT(_ALT_E);
-            if (!(bp = _strptime(bp, _ctloc(d_t_fmt), tm, 0)))
+            if (!(bp = _strptime(bp, _ctloc(d_t_fmt), tm, cr)))
                 return (NULL);
             break;
 
         case 'D':   /* The date as "%m/%d/%y". */
             _LEGAL_ALT(0);
-            if (!(bp = _strptime(bp, "%m/%d/%y", tm, 0)))
+            if (!(bp = _strptime(bp, "%m/%d/%y", tm, cr)))
                 return (NULL);
             break;
     
         case 'R':   /* The time as "%H:%M". */
             _LEGAL_ALT(0);
-            if (!(bp = _strptime(bp, "%H:%M", tm, 0)))
+            if (!(bp = _strptime(bp, "%H:%M", tm, cr)))
                 return (NULL);
             break;
 
         case 'r':   /* The time as "%I:%M:%S %p". */
             _LEGAL_ALT(0);
-            if (!(bp = _strptime(bp, "%I:%M:%S %p", tm, 0)))
+            if (!(bp = _strptime(bp, "%I:%M:%S %p", tm, cr)))
                 return (NULL);
             break;
 
         case 'T':   /* The time as "%H:%M:%S". */
             _LEGAL_ALT(0);
-            if (!(bp = _strptime(bp, "%H:%M:%S", tm, 0)))
+            if (!(bp = _strptime(bp, "%H:%M:%S", tm, cr)))
                 return (NULL);
             break;
 
         case 'X':   /* The time, using the locale's format. */
             _LEGAL_ALT(_ALT_E);
-            if (!(bp = _strptime(bp, _ctloc(t_fmt), tm, 0)))
+            if (!(bp = _strptime(bp, _ctloc(t_fmt), tm, cr)))
                 return (NULL);
             break;
 
         case 'x':   /* The date, using the locale's format. */
             _LEGAL_ALT(_ALT_E);
-            if (!(bp = _strptime(bp, _ctloc(d_fmt), tm, 0)))
+            if (!(bp = _strptime(bp, _ctloc(d_fmt), tm, cr)))
                 return (NULL);
             break;
 
@@ -253,7 +255,7 @@
             if (!(_conv_num(&bp, &i, 0, 99)))
                 return (NULL);
 
-            century = i * 100;
+            cr->century = i * 100;
             break;
 
         case 'd':   /* The day of month. */
@@ -359,13 +361,13 @@
             if (!(_conv_num(&bp, &i, 0, 9999)))
                 return (NULL);
 
-            relyear = -1;
+            cr->relyear = -1;
             tm->tm_year = i - TM_YEAR_BASE;
             break;
 
         case 'y':   /* The year within the century (2 digits). */
             _LEGAL_ALT(_ALT_E | _ALT_O);
-            if (!(_conv_num(&bp, &relyear, 0, 99)))
+            if (!(_conv_num(&bp, &cr->relyear, 0, 99)))
                 return (NULL);
             break;
 
@@ -391,14 +393,14 @@
      * We need to evaluate the two digit year spec (%y)
      * last as we can get a century spec (%C) at any time.
      */
-    if (relyear != -1) {
-        if (century == TM_YEAR_BASE) {
-            if (relyear <= 68)
-                tm->tm_year = relyear + 2000 - TM_YEAR_BASE;
+    if (cr->relyear != -1) {
+        if (cr->century == TM_YEAR_BASE) {
+            if (cr->relyear <= 68)
+                tm->tm_year = cr->relyear + 2000 - TM_YEAR_BASE;
             else
-                tm->tm_year = relyear + 1900 - TM_YEAR_BASE;
+                tm->tm_year = cr->relyear + 1900 - TM_YEAR_BASE;
         } else {
-            tm->tm_year = relyear + century - TM_YEAR_BASE;
+            tm->tm_year = cr->relyear + cr->century - TM_YEAR_BASE;
         }
     }
 
diff --git a/libc/unistd/raise.c b/libc/unistd/raise.c
index de099da..7b03a7a 100644
--- a/libc/unistd/raise.c
+++ b/libc/unistd/raise.c
@@ -30,5 +30,5 @@
 
 int raise(int signum)
 {
-    return kill(getpid(), signum);
+    return kill(gettid(), signum);
 }
diff --git a/libc/unistd/time.c b/libc/unistd/time.c
index 13d7366..4b51675 100644
--- a/libc/unistd/time.c
+++ b/libc/unistd/time.c
@@ -42,21 +42,29 @@
 	return (tt.tv_sec);
 }
 
+// return monotonically increasing CPU time in ticks relative to unspecified epoch
+static inline clock_t clock_now(void)
+{
+	struct timespec tm;
+	clock_gettime( CLOCK_MONOTONIC, &tm);
+	return tm.tv_sec * CLOCKS_PER_SEC + (tm.tv_nsec * (CLOCKS_PER_SEC/1e9));
+}
 
+// initialized by the constructor below
+static clock_t clock_start;
+
+// called by dlopen when .so is loaded
+__attribute__((constructor)) static void clock_crt0(void)
+{
+	clock_start = clock_now();
+}
+
+// return elapsed CPU time in clock ticks, since start of program execution
+// (spec says epoch is undefined, but glibc uses crt0 as epoch)
 clock_t
 clock(void)
 {
-	struct timespec  tm;
-	static int       clock_inited;
-	static clock_t   clock_start;
-	clock_t          now;
-
-	clock_gettime( CLOCK_MONOTONIC, &tm);
-	now = tm.tv_sec * CLOCKS_PER_SEC + (tm.tv_nsec * (CLOCKS_PER_SEC/1e9));
-
-	if (!clock_inited) {
-		clock_start  = now;
-		clock_inited = 1;
-	}
-	return  now - clock_start;
+	// note that if we are executing in a different thread than crt0, then the
+	// pthread_create that made us had a memory barrier so clock_start is defined
+	return clock_now() - clock_start;
 }
diff --git a/libm/Android.mk b/libm/Android.mk
index 28e8f33..29c75a2 100644
--- a/libm/Android.mk
+++ b/libm/Android.mk
@@ -117,6 +117,7 @@
 	src/s_lroundf.c \
 	src/s_lroundl.c \
 	src/s_modff.c \
+	src/s_nan.c \
 	src/s_nearbyint.c \
 	src/s_nextafter.c \
 	src/s_nextafterf.c \
@@ -138,6 +139,7 @@
 	src/s_tanf.c \
 	src/s_tanh.c \
 	src/s_tanhf.c \
+	src/s_tgammaf.c \
 	src/s_trunc.c \
 	src/s_truncf.c \
 	src/s_truncl.c \
diff --git a/libm/include/math.h b/libm/include/math.h
index 3b5660f..a86a16f 100644
--- a/libm/include/math.h
+++ b/libm/include/math.h
@@ -251,6 +251,7 @@
 double	logb(double);
 long	lrint(double);
 long	lround(double);
+double	nan(const char *) __pure2;
 double	nextafter(double, double);
 double	remainder(double, double);
 double	remquo(double, double, int *);
@@ -343,6 +344,7 @@
 float	erfcf(float);
 float	hypotf(float, float);
 float	lgammaf(float);
+float	tgammaf(float);
 
 float	acoshf(float);
 float	asinhf(float);
@@ -354,6 +356,7 @@
 long long llroundf(float);
 long	lrintf(float);
 long	lroundf(float);
+float	nanf(const char *) __pure2;
 float	nearbyintf(float);
 float	nextafterf(float, float);
 float	remainderf(float, float);
diff --git a/libm/src/s_nan.c b/libm/src/s_nan.c
new file mode 100644
index 0000000..e366e6b
--- /dev/null
+++ b/libm/src/s_nan.c
@@ -0,0 +1,131 @@
+/*-
+ * Copyright (c) 2007 David Schultz
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/endian.h>
+#include <ctype.h>
+#include <float.h>
+#include <math.h>
+#include <stdint.h>
+#include <strings.h>
+
+#include "math_private.h"
+
+/* digittoint is in the FreeBSD C library, but not Bionic at this point */
+static int
+digittoint(char ch)
+{
+    int d;
+
+    d = ch - '0';
+    if ((unsigned)d < 10) {
+        return d;
+    }
+    d = ch - 'a';
+    if ((unsigned)d < 6) {
+        return d + 10;
+    }
+    d = ch - 'A';
+    if ((unsigned)d < 6) {
+        return d + 10;
+    }
+    return -1;
+}
+
+/*
+ * Scan a string of hexadecimal digits (the format nan(3) expects) and
+ * make a bit array (using the local endianness). We stop when we
+ * encounter an invalid character, NUL, etc.  If we overflow, we do
+ * the same as gcc's __builtin_nan(), namely, discard the high order bits.
+ *
+ * The format this routine accepts needs to be compatible with what is used
+ * in contrib/gdtoa/hexnan.c (for strtod/scanf) and what is used in
+ * __builtin_nan(). In fact, we're only 100% compatible for strings we
+ * consider valid, so we might be violating the C standard. But it's
+ * impossible to use nan(3) portably anyway, so this seems good enough.
+ */
+void
+_scan_nan(uint32_t *words, int num_words, const char *s)
+{
+	int si;		/* index into s */
+	int bitpos;	/* index into words (in bits) */
+
+	bzero(words, num_words * sizeof(uint32_t));
+
+	/* Allow a leading '0x'. (It's expected, but redundant.) */
+	if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
+		s += 2;
+
+	/* Scan forwards in the string, looking for the end of the sequence. */
+	for (si = 0; isxdigit(s[si]); si++)
+		;
+
+	/* Scan backwards, filling in the bits in words[] as we go. */
+#if _BYTE_ORDER == _LITTLE_ENDIAN
+	for (bitpos = 0; bitpos < 32 * num_words; bitpos += 4) {
+#else
+	for (bitpos = 32 * num_words - 4; bitpos >= 0; bitpos -= 4) {
+#endif
+		if (--si < 0)
+			break;
+		words[bitpos / 32] |= digittoint(s[si]) << (bitpos % 32);
+	}
+}
+
+double
+nan(const char *s)
+{
+	union {
+		double d;
+		uint32_t bits[2];
+	} u;
+
+	_scan_nan(u.bits, 2, s);
+#if _BYTE_ORDER == _LITTLE_ENDIAN
+	u.bits[1] |= 0x7ff80000;
+#else
+	u.bits[0] |= 0x7ff80000;
+#endif
+	return (u.d);
+}
+
+float
+nanf(const char *s)
+{
+	union {
+		float f;
+		uint32_t bits[1];
+	} u;
+
+	_scan_nan(u.bits, 1, s);
+	u.bits[0] |= 0x7fc00000;
+	return (u.f);
+}
+
+#if (LDBL_MANT_DIG == 53)
+__weak_alias(nanl, nan);
+#endif
diff --git a/libm/src/s_tgammaf.c b/libm/src/s_tgammaf.c
new file mode 100644
index 0000000..9993d91
--- /dev/null
+++ b/libm/src/s_tgammaf.c
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2008 David Schultz <das@FreeBSD.ORG>
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <math.h>
+
+/*
+ * We simply call tgamma() rather than bloating the math library with
+ * a float-optimized version of it. The reason is that tgammaf() is
+ * essentially useless, since the function is superexponential and
+ * floats have very limited range.
+ */
+float
+tgammaf(float x)
+{
+
+	return (tgamma(x));
+}
diff --git a/linker/README.TXT b/linker/README.TXT
index 052a65b..a8efe35 100644
--- a/linker/README.TXT
+++ b/linker/README.TXT
@@ -77,7 +77,7 @@
       Same as DT_INITARRAY but for finalizers. Note that the
       functions must be called in reverse-order though
 
-      Note: this is generally stroed in a .fini_array section
+      Note: this is generally stored in a .fini_array section
 
   DT_FINI_ARRAYSZ
       Size of FT_FINIARRAY
@@ -88,7 +88,7 @@
       a list of functions that need to be called before any other
       initialization function (i.e. DT_INIT and/or DT_INIT_ARRAY)
 
-      Note: this is generally stroed in a .preinit_array section
+      Note: this is generally stored in a .preinit_array section
 
   DT_PREINIT_ARRAYSZ
       The size of DT_PREINIT_ARRAY
@@ -103,14 +103,14 @@
 much processor dependent, and may use different ELF sections.
 
 On the ARM (see "C++ ABI for ARM" document), the static constructors
-must be called explicitely from the DT_INIT_ARRAY, and each one of them
+must be called explicitly from the DT_INIT_ARRAY, and each one of them
 shall register a destructor by calling the special __eabi_atexit()
 function (provided by the C library). The DT_FINI_ARRAY is not used
 by static C++ destructors.
 
 On x86, the lists of constructors and destructors are placed in special
 sections named ".ctors" and ".dtors", and the DT_INIT / DT_FINI functions
-are in charge of calling them explicitely.
+are in charge of calling them explicitly.
 
 
 Debugging:
@@ -140,4 +140,4 @@
 
 By default, traces are sent to logcat, with the "linker" tag. You can
 change this to go to stdout instead by setting the definition of
-LINKER_DEBUG_TO_LOG to 0 in "linker_debug.h"
+LINKER_DEBUG_TO_LOG to 0 in "linker_debug.h".
diff --git a/linker/linker_environ.c b/linker/linker_environ.c
index 6c5b571..b71dd80 100644
--- a/linker/linker_environ.c
+++ b/linker/linker_environ.c
@@ -110,7 +110,7 @@
     while (envstr[cnt] == name[cnt] && name[cnt] != '\0')
         cnt++;
 
-    if (name[cnt] != '\0' && envstr[cnt] == '=')
+    if (name[cnt] == '\0' && envstr[cnt] == '=')
         return envstr + cnt + 1;
 
     return NULL;