Add hasmntopt(3)

bionic has the Linux-specific mntent.h but is missing hasmntopt().

Change-Id: I0ab7b83626c969704add4e64b37a6fc715d4a723
Signed-off-by: Greg Hackmann <ghackmann@google.com>
diff --git a/libc/bionic/mntent.cpp b/libc/bionic/mntent.cpp
index d169e29..994b84d 100644
--- a/libc/bionic/mntent.cpp
+++ b/libc/bionic/mntent.cpp
@@ -77,3 +77,24 @@
   }
   return 1;
 }
+
+char* hasmntopt(const struct mntent* mnt, const char* opt) {
+  char* token = mnt->mnt_opts;
+  char* const end = mnt->mnt_opts + strlen(mnt->mnt_opts);
+  const size_t optLen = strlen(opt);
+
+  while (token) {
+    char* const tokenEnd = token + optLen;
+    if (tokenEnd > end) break;
+
+    if (memcmp(token, opt, optLen) == 0 &&
+        (*tokenEnd == '\0' || *tokenEnd == ',' || *tokenEnd == '=')) {
+      return token;
+    }
+
+    token = strchr(token, ',');
+    if (token) token++;
+  }
+
+  return nullptr;
+}
diff --git a/libc/include/mntent.h b/libc/include/mntent.h
index de285d0..a190aeb 100644
--- a/libc/include/mntent.h
+++ b/libc/include/mntent.h
@@ -50,6 +50,7 @@
 struct mntent* getmntent(FILE*);
 struct mntent* getmntent_r(FILE*, struct mntent*, char*, int);
 FILE* setmntent(const char*, const char*);
+char* hasmntopt(const struct mntent*, const char*);
 
 __END_DECLS
 
diff --git a/libc/libc.arm.brillo.map b/libc/libc.arm.brillo.map
index 2776b91..b8cdd3c 100644
--- a/libc/libc.arm.brillo.map
+++ b/libc/libc.arm.brillo.map
@@ -1274,6 +1274,7 @@
 LIBC_O {
   global:
     getdomainname;
+    hasmntopt;
     pthread_getname_np;
     setdomainname;
 } LIBC_N;
diff --git a/libc/libc.arm.map b/libc/libc.arm.map
index 5f7ae2d..57060ae 100644
--- a/libc/libc.arm.map
+++ b/libc/libc.arm.map
@@ -1274,6 +1274,7 @@
 LIBC_O {
   global:
     getdomainname;
+    hasmntopt;
     pthread_getname_np;
     setdomainname;
 } LIBC_N;
diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map
index 0890b59..ac9d0096 100644
--- a/libc/libc.arm64.map
+++ b/libc/libc.arm64.map
@@ -1196,6 +1196,7 @@
 LIBC_O {
   global:
     getdomainname;
+    hasmntopt;
     pthread_getname_np;
     setdomainname;
 } LIBC_N;
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 38edff0..9d51b8d 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1300,6 +1300,7 @@
 LIBC_O {
   global:
     getdomainname;
+    hasmntopt;
     pthread_getname_np;
     setdomainname;
 } LIBC_N;
diff --git a/libc/libc.mips.brillo.map b/libc/libc.mips.brillo.map
index c5b1bd3..7133f4b 100644
--- a/libc/libc.mips.brillo.map
+++ b/libc/libc.mips.brillo.map
@@ -1258,6 +1258,7 @@
 LIBC_O {
   global:
     getdomainname;
+    hasmntopt;
     pthread_getname_np;
     setdomainname;
 } LIBC_N;
diff --git a/libc/libc.mips.map b/libc/libc.mips.map
index dde4cb4..e9b15c3 100644
--- a/libc/libc.mips.map
+++ b/libc/libc.mips.map
@@ -1258,6 +1258,7 @@
 LIBC_O {
   global:
     getdomainname;
+    hasmntopt;
     pthread_getname_np;
     setdomainname;
 } LIBC_N;
diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map
index 0890b59..ac9d0096 100644
--- a/libc/libc.mips64.map
+++ b/libc/libc.mips64.map
@@ -1196,6 +1196,7 @@
 LIBC_O {
   global:
     getdomainname;
+    hasmntopt;
     pthread_getname_np;
     setdomainname;
 } LIBC_N;
diff --git a/libc/libc.x86.brillo.map b/libc/libc.x86.brillo.map
index eb99079..c67f533 100644
--- a/libc/libc.x86.brillo.map
+++ b/libc/libc.x86.brillo.map
@@ -1257,6 +1257,7 @@
 LIBC_O {
   global:
     getdomainname;
+    hasmntopt;
     pthread_getname_np;
     setdomainname;
 } LIBC_N;
diff --git a/libc/libc.x86.map b/libc/libc.x86.map
index 8f6c64e..6838184 100644
--- a/libc/libc.x86.map
+++ b/libc/libc.x86.map
@@ -1257,6 +1257,7 @@
 LIBC_O {
   global:
     getdomainname;
+    hasmntopt;
     pthread_getname_np;
     setdomainname;
 } LIBC_N;
diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map
index 0890b59..ac9d0096 100644
--- a/libc/libc.x86_64.map
+++ b/libc/libc.x86_64.map
@@ -1196,6 +1196,7 @@
 LIBC_O {
   global:
     getdomainname;
+    hasmntopt;
     pthread_getname_np;
     setdomainname;
 } LIBC_N;
diff --git a/tests/mntent_test.cpp b/tests/mntent_test.cpp
index a102849..3fb2f86 100644
--- a/tests/mntent_test.cpp
+++ b/tests/mntent_test.cpp
@@ -38,3 +38,20 @@
 
   ASSERT_EQ(1, endmntent(fp));
 }
+
+TEST(mntent, hasmntopt) {
+  // indices                  1  1
+  // of keys:      0    5   9 1  4
+  char mnt_opts[]{"aa=b,a=b,b,bb,c=d"};
+  struct mntent ent;
+  memset(&ent, 0, sizeof(ent));
+  ent.mnt_opts = mnt_opts;
+
+  EXPECT_EQ(mnt_opts, hasmntopt(&ent, "aa"));
+  EXPECT_EQ(mnt_opts + 5, hasmntopt(&ent, "a"));
+  EXPECT_EQ(mnt_opts + 9, hasmntopt(&ent, "b"));
+  EXPECT_EQ(mnt_opts + 11, hasmntopt(&ent, "bb"));
+  EXPECT_EQ(mnt_opts + 14, hasmntopt(&ent, "c"));
+  EXPECT_EQ(nullptr, hasmntopt(&ent, "d"));
+  EXPECT_EQ(nullptr, hasmntopt(&ent, "e"));
+}