From d33ff301454fa1db9919674dbc2a37309bbd529f Mon Sep 17 00:00:00 2001
From: Paul Smith <psmith@gnu.org>
Date: Thu, 30 Jan 2003 05:22:52 +0000
Subject: [PATCH] Portability fix for glob.h building in FreeBSD ports system.

Implement a fix for bug # 2169: too many OSs, even major OSs like Solaris,
don't properly implement SA_RESTART: important system calls like stat() can
still fail when SA_RESTART is set.  So, forget the BROKEN_RESTART config
check and get rid of atomic_stat() and atomic_readdir(), and implement
permanent wrappers for EINTR checking on various system calls (stat(),
fstat(), opendir(), and readdir() so far).
---
 ChangeLog      | 31 +++++++++++++++++++++++++++++++
 arscan.c       |  3 ++-
 commands.c     |  4 +++-
 configure.in   | 15 ---------------
 dir.c          | 15 +++++++++++----
 glob/ChangeLog |  6 ++++++
 glob/glob.h    | 12 ++++++++----
 make.h         | 27 ++++++++-------------------
 misc.c         | 32 --------------------------------
 read.c         | 14 ++++++++++----
 remake.c       |  8 ++++++--
 vpath.c        | 40 +++++++++++++++++++++++-----------------
 12 files changed, 108 insertions(+), 99 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index ef5bd87d..903a64fa 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,34 @@
+2003-01-29  Paul D. Smith  <psmith@gnu.org>
+
+	Fix bug # 2169, also reported by other people on various systems.
+
+	* make.h: Some systems, such as Solaris and PTX, do not fully
+	implement POSIX-compliant SA_RESTART functionality; important
+	system calls like stat() and readdir() can still fail with EINTR
+	even if SA_RESTART has been set on the signal handler.  So,
+	introduce macros EINTRLOOP() and ENULLLOOP() which can loop on
+	EINTR for system calls which return -1 or 0 (NULL), respectively,
+	on error.
+	Also, remove the old atomic_stat()/atomic_readdir() and
+	HAVE_BROKEN_RESTART handling.
+
+	* configure.in: Remove setting of HAVE_BROKEN_RESTART.
+
+	* arscan.c (ar_member_touch): Use EINTRLOOP() to wrap fstat().
+	* remake.c (touch_file): Ditto.
+
+	* commands.c (delete_target): Use EINTRLOOP() to wrap stat().
+	* read.c (construct_include_path): Ditto.
+	* remake.c (name_mtime): Ditto.
+	* vpath.c (selective_vpath_search): Ditto.
+	* dir.c (find_directory): Ditto.
+	(local_stat): Ditto.
+	(find_directory): Use ENULLLOOP() to wrap opendir().
+	(dir_contents_file_exists_p): Use ENULLLOOP() to wrap readdir().
+
+	* misc.c: Remove HAVE_BROKEN_RESTART, atomic_stat(), and
+	atomic_readdir() handling.
+
 2003-01-22  Paul D. Smith  <psmith@gnu.org>
 
 	* function.c (func_call): Fix Bug #1744.  If we're inside a
diff --git a/arscan.c b/arscan.c
index 2c679471..b1e9971a 100644
--- a/arscan.c
+++ b/arscan.c
@@ -781,7 +781,8 @@ ar_member_touch (char *arname, char *memname)
   if (AR_HDR_SIZE != write (fd, (char *) &ar_hdr, AR_HDR_SIZE))
     goto lose;
   /* The file's mtime is the time we we want.  */
-  if (fstat (fd, &statbuf) < 0)
+  EINTRLOOP (i, fstat (fd, &statbuf));
+  if (i < 0)
     goto lose;
 #if defined(ARFMAG) || defined(ARFZMAG) || defined(AIAMAG) || defined(WINDOWS32)
   /* Advance member's time to that time */
diff --git a/commands.c b/commands.c
index 30787a45..a6964d55 100644
--- a/commands.c
+++ b/commands.c
@@ -492,6 +492,7 @@ static void
 delete_target (struct file *file, char *on_behalf_of)
 {
   struct stat st;
+  int e;
 
   if (file->precious || file->phony)
     return;
@@ -515,7 +516,8 @@ delete_target (struct file *file, char *on_behalf_of)
     }
 #endif
 
-  if (stat (file->name, &st) == 0
+  EINTRLOOP (e, stat (file->name, &st));
+  if (e == 0
       && S_ISREG (st.st_mode)
       && FILE_TIMESTAMP_STAT_MODTIME (file->name, st) != file->last_mtime)
     {
diff --git a/configure.in b/configure.in
index 8df2e272..befba089 100644
--- a/configure.in
+++ b/configure.in
@@ -294,21 +294,6 @@ make_cv_sys_gnu_glob=no])])
 # Tell automake about this, so it can build the right .c files.
 AM_CONDITIONAL(USE_LOCAL_GLOB, test "$make_cv_sys_gnu_glob" = no)
 
-# PTX systems have a broken implementation of SA_RESTART.  I know of
-# no way to test for this behavior, so I'll just test for PTX
-
-case "$host" in
-  i386-sequent-sysv4)
-    AC_DEFINE(HAVE_BROKEN_RESTART, 1, [This system has SA_RESTART, but it doesn't work properly.])
-    echo ""
-    echo "WARNING: The SA_RESTART sigaction() flag does not work on PTX."
-    echo "         This causes 'make -j' to fail at random times."
-    echo "         I am installing a workaround, which is mostly but not 100%"
-    echo "         effective.  If you see random failures during 'make -j'"
-    echo "         you should either contact the bug list, or not use -j."
-    echo "" ;;
-esac
-
 # Let the makefile know what our build host is
 
 AC_DEFINE_UNQUOTED(MAKE_HOST,"$host",[Build host information.])
diff --git a/dir.c b/dir.c
index 39f3e2af..7db06977 100644
--- a/dir.c
+++ b/dir.c
@@ -455,7 +455,7 @@ find_directory (char *name)
 #ifdef VMS
       r = vmsstat_dir (name, &st);
 #else
-      r = stat (name, &st);
+      EINTRLOOP (r, stat (name, &st));
 #endif
 
 #ifdef WINDOWS32
@@ -536,7 +536,7 @@ find_directory (char *name)
 # endif
 #endif /* WINDOWS32 */
 	      hash_insert_at (&directory_contents, dc, dc_slot);
-	      dc->dirstream = opendir (name);
+	      ENULLLOOP (dc->dirstream, opendir (name));
 	      if (dc->dirstream == 0)
                 /* Couldn't open the directory.  Mark this by
                    setting the `files' member to a nil pointer.  */
@@ -645,13 +645,17 @@ dir_contents_file_exists_p (struct directory_contents *dir, char *filename)
 	return 0;
     }
 
-  while ((d = readdir (dir->dirstream)) != 0)
+  while (1)
     {
       /* Enter the file in the hash table.  */
       unsigned int len;
       struct dirfile dirfile_key;
       struct dirfile **dirfile_slot;
 
+      ENULLLOOP (d, readdir (dir->dirstream));
+      if (d == 0)
+        break;
+
 #if defined(VMS) && defined(HAVE_DIRENT_H)
       /* In VMS we get file versions too, which have to be stripped off */
       {
@@ -1155,7 +1159,10 @@ extern int stat PARAMS ((const char *path, struct stat *sbuf));
 static int
 local_stat (const char *path, struct stat *buf)
 {
-  return stat (path, buf);
+  int e;
+
+  EINTRLOOP (e, stat (path, buf));
+  return e;
 }
 #endif
 
diff --git a/glob/ChangeLog b/glob/ChangeLog
index 1ebf879b..75c68881 100644
--- a/glob/ChangeLog
+++ b/glob/ChangeLog
@@ -1,3 +1,9 @@
+2003-01-30  Paul D. Smith  <psmith@gnu.org>
+
+	* glob.h: Patch for FreeBSD by Mike Barcroft <mike@freebsd.org>
+	Reported by Gerald Pfeifer <pfeifer@dbai.tuwien.ac.at>.  On
+	FreeBSD, declare __size_t to simply size_t.
+
 2002-04-22  Paul D. Smith  <psmith@gnu.org>
 
 	* Makefile.am: Use automake 1.6.
diff --git a/glob/glob.h b/glob/glob.h
index 9f735fe8..ca523f7a 100644
--- a/glob/glob.h
+++ b/glob/glob.h
@@ -47,9 +47,12 @@ extern "C" {
 
 /* We need `size_t' for the following definitions.  */
 #ifndef __size_t
-# if defined __GNUC__ && __GNUC__ >= 2
-typedef __SIZE_TYPE__ __size_t;
+# if defined __FreeBSD__
+#  define __size_t size_t
 # else
+#  if defined __GNUC__ && __GNUC__ >= 2
+typedef __SIZE_TYPE__ __size_t;
+#  else
 /* This is a guess.  */
 /*hb
  *	Conflicts with DECCs aready defined type __size_t.
@@ -57,9 +60,10 @@ typedef __SIZE_TYPE__ __size_t;
  *	Anyway if DECC is used and __SIZE_T is defined then __size_t is
  *	already defined (and I hope it's exactly the one we need here).
  */
-#if !(defined __DECC && defined __SIZE_T)
+#   if !(defined __DECC && defined __SIZE_T)
 typedef unsigned long int __size_t;
-#endif
+#   endif
+#  endif
 # endif
 #else
 /* The GNU CC stddef.h version defines __size_t as empty.  We need a real
diff --git a/make.h b/make.h
index 6648ea0d..3ac47d13 100644
--- a/make.h
+++ b/make.h
@@ -539,24 +539,13 @@ extern int handling_fatal_signal;
 #endif
 
 
-/* If we have broken SA_RESTART support, then wrap stat() and readdir() with
-   versions that handle EINTR.  Note that there are still plenty of system
-   calls that can fail with EINTR but this, reportedly, gets the vast
-   majority of failure cases.  If you still experience failures you'll need
-   to either get a system where SA_RESTART works, or you need to avoid -j.  */
+/* Some systems (like Solaris, PTX, etc.) do not support the SA_RESTART flag
+   properly according to POSIX.  So, we try to wrap common system calls with
+   checks for EINTR.  Note that there are still plenty of system calls that
+   can fail with EINTR but this, reportedly, gets the vast majority of
+   failure cases.  If you still experience failures you'll need to either get
+   a system where SA_RESTART works, or you need to avoid -j.  */
 
-#ifdef HAVE_BROKEN_RESTART
+#define EINTRLOOP(_v,_c)   while (((_v)=_c)==-1 && errno==EINTR)
 
-/* Here we make an assumption that a system with a broken SA_RESTART has
-   dirent.h.  Right now the only system I know of in this category is PTX, and
-   it does have dirent.h.
-*/
-#include <dirent.h>
-
-#define stat(_f,_b)     atomic_stat ((_f), (_b))
-#define readdir(_d)     atomic_readdir (_d)
-
-extern int atomic_stat PARAMS ((const char *file, struct stat *buf));
-extern struct dirent *atomic_readdir PARAMS ((DIR *dir));
-
-#endif
+#define ENULLLOOP(_v,_c)   while (((_v)=_c)==0 && errno==EINTR)
diff --git a/misc.c b/misc.c
index 5305220f..ef754e50 100644
--- a/misc.c
+++ b/misc.c
@@ -828,35 +828,3 @@ get_path_max (void)
   return value;
 }
 #endif
-
-
-#ifdef HAVE_BROKEN_RESTART
-
-#undef stat
-#undef readdir
-
-int
-atomic_stat (const char *file, struct stat *buf)
-{
-  int r;
-
-  while ((r = stat (file, buf)) < 0)
-    if (errno != EINTR)
-      break;
-
-  return r;
-}
-
-struct dirent *
-atomic_readdir (DIR *dir)
-{
-  struct dirent *r;
-
-  while ((r = readdir (dir)) == NULL)
-    if (errno != EINTR)
-      break;
-
-  return r;
-}
-
-#endif  /* HAVE_BROKEN_RESTART */
diff --git a/read.c b/read.c
index 3e015720..a0bf5caa 100644
--- a/read.c
+++ b/read.c
@@ -2819,6 +2819,7 @@ construct_include_path (char **arg_dirs)
     while (*arg_dirs != 0)
       {
 	char *dir = *arg_dirs++;
+        int e;
 
 	if (dir[0] == '~')
 	  {
@@ -2827,7 +2828,8 @@ construct_include_path (char **arg_dirs)
 	      dir = expanded;
 	  }
 
-	if (stat (dir, &stbuf) == 0 && S_ISDIR (stbuf.st_mode))
+        EINTRLOOP (e, stat (dir, &stbuf));
+	if (e == 0 && S_ISDIR (stbuf.st_mode))
 	  {
 	    if (idx == max - 1)
 	      {
@@ -2860,9 +2862,13 @@ construct_include_path (char **arg_dirs)
 #endif
 
   for (i = 0; default_include_directories[i] != 0; ++i)
-    if (stat (default_include_directories[i], &stbuf) == 0
-	&& S_ISDIR (stbuf.st_mode))
-      dirs[idx++] = default_include_directories[i];
+    {
+      int e;
+
+      EINTRLOOP (e, stat (default_include_directories[i], &stbuf));
+      if (e == 0 && S_ISDIR (stbuf.st_mode))
+        dirs[idx++] = default_include_directories[i];
+    }
 
   dirs[idx] = 0;
 
diff --git a/remake.c b/remake.c
index db1dd2c3..c679d111 100644
--- a/remake.c
+++ b/remake.c
@@ -961,8 +961,10 @@ touch_file (struct file *file)
 	{
 	  struct stat statbuf;
 	  char buf;
+          int e;
 
-	  if (fstat (fd, &statbuf) < 0)
+          EINTRLOOP (e, fstat (fd, &statbuf));
+	  if (e < 0)
 	    TOUCH_ERROR ("touch: fstat: ");
 	  /* Rewrite character 0 same as it already is.  */
 	  if (read (fd, &buf, 1) < 0)
@@ -1257,8 +1259,10 @@ static FILE_TIMESTAMP
 name_mtime (char *name)
 {
   struct stat st;
+  int e;
 
-  if (stat (name, &st) != 0)
+  EINTRLOOP (e, stat (name, &st));
+  if (e != 0)
     {
       if (errno != ENOENT && errno != ENOTDIR)
         perror_with_name ("stat:", name);
diff --git a/vpath.c b/vpath.c
index 18aaaa96..5e04d085 100644
--- a/vpath.c
+++ b/vpath.c
@@ -507,27 +507,33 @@ selective_vpath_search (struct vpath *path, char **file,
 	  *n = '/';
 #endif
 
-	  if (!exists_in_cache	/* Makefile-mentioned file need not exist.  */
-	      || stat (name, &st) == 0) /* Does it really exist?  */
+	  if (exists_in_cache)	/* Makefile-mentioned file need not exist.  */
 	    {
-	      /* We have found a file.
-		 Store the name we found into *FILE for the caller.  */
+              int e;
 
-	      *file = savestring (name, (n + 1 - name) + flen);
+              EINTRLOOP (e, stat (name, &st)); /* Does it really exist?  */
+              if (e != 0)
+                {
+                  exists = 0;
+                  continue;
+                }
+            }
 
-	      if (mtime_ptr != 0)
-		/* Store the modtime into *MTIME_PTR for the caller.
-		   If we have had no need to stat the file here,
-		   we record UNKNOWN_MTIME to indicate this.  */
-		*mtime_ptr = (exists_in_cache
-			      ? FILE_TIMESTAMP_STAT_MODTIME (name, st)
-			      : UNKNOWN_MTIME);
+          /* We have found a file.
+             Store the name we found into *FILE for the caller.  */
 
-	      free (name);
-	      return 1;
-	    }
-	  else
-	    exists = 0;
+          *file = savestring (name, (n + 1 - name) + flen);
+
+          if (mtime_ptr != 0)
+            /* Store the modtime into *MTIME_PTR for the caller.
+               If we have had no need to stat the file here,
+               we record UNKNOWN_MTIME to indicate this.  */
+            *mtime_ptr = (exists_in_cache
+                          ? FILE_TIMESTAMP_STAT_MODTIME (name, st)
+                          : UNKNOWN_MTIME);
+
+          free (name);
+          return 1;
 	}
     }