ce426f
commit 0897c551c0a098020f145885de06a5c10e5cc96b
ce426f
Author: Carlos O'Donell <carlos@systemhalted.org>
ce426f
Date:   Wed Jan 21 10:08:18 2015 -0500
ce426f
ce426f
    tst-getpw: Rewrite.
ce426f
    
ce426f
    The test is rewritten to look for the testable conditions and
ce426f
    exit once they are all detected. This prevents the test from
ce426f
    iterating over 2000 UIDs and looking up each one. It speeds up
ce426f
    the test and prevents it from failing if the system under test
ce426f
    has an NSS-based passwd that is slower than the test timeout.
ce426f
    
ce426f
    See:
ce426f
    https://sourceware.org/ml/libc-alpha/2015-01/msg00394.html
ce426f
ce426f
diff --git a/pwd/tst-getpw.c b/pwd/tst-getpw.c
ce426f
index 059c9e0..e3e101b 100644
ce426f
--- a/pwd/tst-getpw.c
ce426f
+++ b/pwd/tst-getpw.c
ce426f
@@ -1,4 +1,4 @@
ce426f
-/* Copyright (C) 1999 Free Software Foundation, Inc.
ce426f
+/* Copyright (C) 1999-2016 Free Software Foundation, Inc.
ce426f
    This file is part of the GNU C Library.
ce426f
 
ce426f
    The GNU C Library is free software; you can redistribute it and/or
ce426f
@@ -15,26 +15,100 @@
ce426f
    License along with the GNU C Library; if not, see
ce426f
    <http://www.gnu.org/licenses/>.  */
ce426f
 
ce426f
+#include <stdio.h>
ce426f
 #include <pwd.h>
ce426f
+#include <errno.h>
ce426f
+#include <stdbool.h>
ce426f
+
ce426f
+/* We want to test getpw by calling it with a uid that does
ce426f
+   exist and one that doesn't exist. We track if we've met those
ce426f
+   conditions and exit. We also track if we've failed due to lack
ce426f
+   of memory. That constitutes all of the standard failure cases.  */
ce426f
+bool seen_hit;
ce426f
+bool seen_miss;
ce426f
+bool seen_oom;
ce426f
+
ce426f
+/* How many errors we've had while running the test.  */
ce426f
+int errors;
ce426f
 
ce426f
 static void
ce426f
 check (uid_t uid)
ce426f
 {
ce426f
+  int ret;
ce426f
   char buf[1024];
ce426f
 
ce426f
-  (void) getpw (uid, buf);
ce426f
+  ret = getpw (uid, buf);
ce426f
+
ce426f
+  /* Successfully read a password line.  */
ce426f
+  if (ret == 0 && !seen_hit)
ce426f
+    {
ce426f
+      printf ("PASS: Read a password line given a uid.\n");
ce426f
+      seen_hit = true;
ce426f
+    }
ce426f
+
ce426f
+  /* Failed to read a password line. Why?  */
ce426f
+  if (ret == -1)
ce426f
+    {
ce426f
+      /* No entry?  Technically the errno could be any number
ce426f
+	 of values including ESRCH, EBADP or EPERM depending
ce426f
+	 on the quality of the nss module that implements the
ce426f
+	 underlying lookup. It should be 0 for getpw.*/
ce426f
+      if (errno == 0 && !seen_miss)
ce426f
+	{
ce426f
+	  printf ("PASS: Found an invalid uid.\n");
ce426f
+	  seen_miss = true;
ce426f
+	  return;
ce426f
+	}
ce426f
+
ce426f
+      /* Out of memory?  */
ce426f
+      if (errno == ENOMEM && !seen_oom)
ce426f
+	{
ce426f
+	  printf ("FAIL: Failed with ENOMEM.\n");
ce426f
+	  seen_oom = true;
ce426f
+	  errors++;
ce426f
+	}
ce426f
+
ce426f
+      /* We don't expect any other values for errno.  */
ce426f
+      if (errno != ENOMEM && errno != 0)
ce426f
+	errors++;
ce426f
+    }
ce426f
 }
ce426f
 
ce426f
-int
ce426f
-main (void)
ce426f
+static int
ce426f
+do_test (void)
ce426f
 {
ce426f
+  int ret;
ce426f
   uid_t uid;
ce426f
 
ce426f
-  /* Just call it a different number of times the range should be
ce426f
-     large enough to find some existing and some non existing uids.  */
ce426f
+  /* Should return -1 and set errnot to EINVAL.  */
ce426f
+  ret = getpw (0, NULL);
ce426f
+  if (ret == -1 && errno == EINVAL)
ce426f
+    {
ce426f
+      printf ("PASS: NULL buffer returns -1 and sets errno to EINVAL.\n");
ce426f
+    }
ce426f
+  else
ce426f
+    {
ce426f
+      printf ("FAIL: NULL buffer did not return -1 or set errno to EINVAL.\n");
ce426f
+      errors++;
ce426f
+    }
ce426f
+
ce426f
+  /* Look for one matching uid, one non-found uid and then stop.
ce426f
+     Set an upper limit at the 16-bit UID mark; no need to go farther.  */
ce426f
+  for (uid = 0; uid < ((uid_t) 65535); ++uid)
ce426f
+    {
ce426f
+      check (uid);
ce426f
+      if (seen_miss && seen_hit)
ce426f
+	break;
ce426f
+    }
ce426f
 
ce426f
-  for (uid = 0; uid < 2000; ++uid)
ce426f
-    check (uid);
ce426f
+  if (!seen_hit)
ce426f
+    printf ("FAIL: Did not read even one password line given a uid.\n");
ce426f
 
ce426f
-  return 0;
ce426f
+  if (!seen_miss)
ce426f
+    printf ("FAIL: Did not find even one invalid uid.\n");
ce426f
+
ce426f
+  return errors;
ce426f
 }
ce426f
+
ce426f
+#define TEST_FUNCTION do_test ()
ce426f
+#include "../test-skeleton.c"
ce426f
    License along with the GNU C Library; if not, see
ce426f
    <http://www.gnu.org/licenses/>.  */
ce426f
 
ce426f
+#include <stdio.h>
ce426f
 #include <pwd.h>
ce426f
+#include <errno.h>
ce426f
+#include <stdbool.h>
ce426f
+
ce426f
+/* We want to test getpw by calling it with a uid that does
ce426f
+   exist and one that doesn't exist. We track if we've met those
ce426f
+   conditions and exit. We also track if we've failed due to lack
ce426f
+   of memory. That constitutes all of the standard failure cases.  */
ce426f
+bool seen_hit;
ce426f
+bool seen_miss;
ce426f
+bool seen_oom;
ce426f
+
ce426f
+/* How many errors we've had while running the test.  */
ce426f
+int errors;
ce426f
 
ce426f
 static void
ce426f
 check (uid_t uid)
ce426f
 {
ce426f
+  int ret;
ce426f
   char buf[1024];
ce426f
 
ce426f
-  (void) getpw (uid, buf);
ce426f
+  ret = getpw (uid, buf);
ce426f
+
ce426f
+  /* Successfully read a password line.  */
ce426f
+  if (ret == 0 && !seen_hit)
ce426f
+    {
ce426f
+      printf ("PASS: Read a password line given a uid.\n");
ce426f
+      seen_hit = true;
ce426f
+    }
ce426f
+
ce426f
+  /* Failed to read a password line. Why?  */
ce426f
+  if (ret == -1)
ce426f
+    {
ce426f
+      /* No entry?  Technically the errno could be any number
ce426f
+	 of values including ESRCH, EBADP or EPERM depending
ce426f
+	 on the quality of the nss module that implements the
ce426f
+	 underlying lookup. It should be 0 for getpw.*/
ce426f
+      if (errno == 0 && !seen_miss)
ce426f
+	{
ce426f
+	  printf ("PASS: Found an invalid uid.\n");
ce426f
+	  seen_miss = true;
ce426f
+	  return;
ce426f
+	}
ce426f
+
ce426f
+      /* Out of memory?  */
ce426f
+      if (errno == ENOMEM && !seen_oom)
ce426f
+	{
ce426f
+	  printf ("FAIL: Failed with ENOMEM.\n");
ce426f
+	  seen_oom = true;
ce426f
+	  errors++;
ce426f
+	}
ce426f
+
ce426f
+      /* We don't expect any other values for errno.  */
ce426f
+      if (errno != ENOMEM && errno != 0)
ce426f
+	errors++;
ce426f
+    }
ce426f
 }
ce426f
 
ce426f
 static int
ce426f
 do_test (void)
ce426f
 {
ce426f
+  int ret;
ce426f
   uid_t uid;
ce426f
 
ce426f
-  /* Just call it a different number of times the range should be
ce426f
-     large enough to find some existing and some non existing uids.  */
ce426f
+  /* Should return -1 and set errnot to EINVAL.  */
ce426f
+  ret = getpw (0, NULL);
ce426f
+  if (ret == -1 && errno == EINVAL)
ce426f
+    {
ce426f
+      printf ("PASS: NULL buffer returns -1 and sets errno to EINVAL.\n");
ce426f
+    }
ce426f
+  else
ce426f
+    {
ce426f
+      printf ("FAIL: NULL buffer did not return -1 or set errno to EINVAL.\n");
ce426f
+      errors++;
ce426f
+    }
ce426f
+
ce426f
+  /* Look for one matching uid, one non-found uid and then stop.
ce426f
+     Set an upper limit at the 16-bit UID mark; no need to go farther.  */
ce426f
+  for (uid = 0; uid < ((uid_t) 65535); ++uid)
ce426f
+    {
ce426f
+      check (uid);
ce426f
+      if (seen_miss && seen_hit)
ce426f
+	break;
ce426f
+    }
ce426f
+
ce426f
+  if (!seen_hit)
ce426f
+    printf ("FAIL: Did not read even one password line given a uid.\n");
ce426f
 
ce426f
-  for (uid = 0; uid < 2000; ++uid)
ce426f
-    check (uid);
ce426f
+  if (!seen_miss)
ce426f
+    printf ("FAIL: Did not find even one invalid uid.\n");
ce426f
 
ce426f
-  return 0;
ce426f
+  return errors;
ce426f
 }
ce426f
 
ce426f
 #define TEST_FUNCTION do_test ()