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