Add POSIX getsubopt(3).

Bug: http://b/27952303
Change-Id: I8a816477545dadcbd5c055714e76263574446b6f
diff --git a/libc/Android.mk b/libc/Android.mk
index e9ee7fc..6d358cc 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -491,6 +491,7 @@
     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/getsubopt.c \
     upstream-openbsd/lib/libc/stdlib/insque.c \
     upstream-openbsd/lib/libc/stdlib/imaxabs.c \
     upstream-openbsd/lib/libc/stdlib/imaxdiv.c \
diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h
index d9d277a..88930b1 100644
--- a/libc/include/stdlib.h
+++ b/libc/include/stdlib.h
@@ -135,6 +135,8 @@
 int ptsname_r(int, char*, size_t);
 int unlockpt(int);
 
+int getsubopt(char**, char* const*, char**);
+
 typedef struct {
     int  quot;
     int  rem;
diff --git a/libc/libc.arm.brillo.map b/libc/libc.arm.brillo.map
index b8cdd3c..f631ad9 100644
--- a/libc/libc.arm.brillo.map
+++ b/libc/libc.arm.brillo.map
@@ -1274,6 +1274,7 @@
 LIBC_O {
   global:
     getdomainname;
+    getsubopt;
     hasmntopt;
     pthread_getname_np;
     setdomainname;
diff --git a/libc/libc.arm.map b/libc/libc.arm.map
index 57060ae..4c2a272 100644
--- a/libc/libc.arm.map
+++ b/libc/libc.arm.map
@@ -1274,6 +1274,7 @@
 LIBC_O {
   global:
     getdomainname;
+    getsubopt;
     hasmntopt;
     pthread_getname_np;
     setdomainname;
diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map
index ac9d009..c42d1b6 100644
--- a/libc/libc.arm64.map
+++ b/libc/libc.arm64.map
@@ -1196,6 +1196,7 @@
 LIBC_O {
   global:
     getdomainname;
+    getsubopt;
     hasmntopt;
     pthread_getname_np;
     setdomainname;
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 9d51b8d..25f647d 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1300,6 +1300,7 @@
 LIBC_O {
   global:
     getdomainname;
+    getsubopt;
     hasmntopt;
     pthread_getname_np;
     setdomainname;
diff --git a/libc/libc.mips.brillo.map b/libc/libc.mips.brillo.map
index 7133f4b..d55f32d 100644
--- a/libc/libc.mips.brillo.map
+++ b/libc/libc.mips.brillo.map
@@ -1258,6 +1258,7 @@
 LIBC_O {
   global:
     getdomainname;
+    getsubopt;
     hasmntopt;
     pthread_getname_np;
     setdomainname;
diff --git a/libc/libc.mips.map b/libc/libc.mips.map
index e9b15c3..44d7d81 100644
--- a/libc/libc.mips.map
+++ b/libc/libc.mips.map
@@ -1258,6 +1258,7 @@
 LIBC_O {
   global:
     getdomainname;
+    getsubopt;
     hasmntopt;
     pthread_getname_np;
     setdomainname;
diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map
index ac9d009..c42d1b6 100644
--- a/libc/libc.mips64.map
+++ b/libc/libc.mips64.map
@@ -1196,6 +1196,7 @@
 LIBC_O {
   global:
     getdomainname;
+    getsubopt;
     hasmntopt;
     pthread_getname_np;
     setdomainname;
diff --git a/libc/libc.x86.brillo.map b/libc/libc.x86.brillo.map
index c67f533..9c0b2ec 100644
--- a/libc/libc.x86.brillo.map
+++ b/libc/libc.x86.brillo.map
@@ -1257,6 +1257,7 @@
 LIBC_O {
   global:
     getdomainname;
+    getsubopt;
     hasmntopt;
     pthread_getname_np;
     setdomainname;
diff --git a/libc/libc.x86.map b/libc/libc.x86.map
index 6838184..980322a 100644
--- a/libc/libc.x86.map
+++ b/libc/libc.x86.map
@@ -1257,6 +1257,7 @@
 LIBC_O {
   global:
     getdomainname;
+    getsubopt;
     hasmntopt;
     pthread_getname_np;
     setdomainname;
diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map
index ac9d009..c42d1b6 100644
--- a/libc/libc.x86_64.map
+++ b/libc/libc.x86_64.map
@@ -1196,6 +1196,7 @@
 LIBC_O {
   global:
     getdomainname;
+    getsubopt;
     hasmntopt;
     pthread_getname_np;
     setdomainname;
diff --git a/libc/upstream-openbsd/lib/libc/stdlib/getsubopt.c b/libc/upstream-openbsd/lib/libc/stdlib/getsubopt.c
new file mode 100644
index 0000000..735c85b
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/stdlib/getsubopt.c
@@ -0,0 +1,92 @@
+/*	$OpenBSD: getsubopt.c,v 1.4 2005/08/08 08:05:36 espie Exp $	*/
+
+/*-
+ * Copyright (c) 1990, 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 <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * The SVID interface to getsubopt provides no way of figuring out which
+ * part of the suboptions list wasn't matched.  This makes error messages
+ * tricky...  The extern variable suboptarg is a pointer to the token
+ * which didn't match.
+ */
+char *suboptarg;
+
+int
+getsubopt(char **optionp, char * const *tokens, char **valuep)
+{
+	int cnt;
+	char *p;
+
+	suboptarg = *valuep = NULL;
+
+	if (!optionp || !*optionp)
+		return(-1);
+
+	/* skip leading white-space, commas */
+	for (p = *optionp; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p);
+
+	if (!*p) {
+		*optionp = p;
+		return(-1);
+	}
+
+	/* save the start of the token, and skip the rest of the token. */
+	for (suboptarg = p;
+	    *++p && *p != ',' && *p != '=' && *p != ' ' && *p != '\t';);
+
+	if (*p) {
+		/*
+		 * If there's an equals sign, set the value pointer, and
+		 * skip over the value part of the token.  Terminate the
+		 * token.
+		 */
+		if (*p == '=') {
+			*p = '\0';
+			for (*valuep = ++p;
+			    *p && *p != ',' && *p != ' ' && *p != '\t'; ++p);
+			if (*p) 
+				*p++ = '\0';
+		} else
+			*p++ = '\0';
+		/* Skip any whitespace or commas after this token. */
+		for (; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p);
+	}
+
+	/* set optionp for next round. */
+	*optionp = p;
+
+	for (cnt = 0; *tokens; ++tokens, ++cnt)
+		if (!strcmp(suboptarg, *tokens))
+			return(cnt);
+	return(-1);
+}