From bf419d1b9fecbf7d2f62147fabe7ad1bb20256e6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Henrik=20Grubbstr=C3=B6m=20=28Grubba=29?=
 <grubba@grubba.org>
Date: Mon, 30 Apr 2018 12:39:35 +0200
Subject: [PATCH] I/O [Solaris]: Fix getcwd() on Solaris.

On Solaris getcwd(NULL, x) only works if x is > 0.

Fixes building issues on Solaris.
---
 src/acconfig.h   |  9 ++++-
 src/configure.in | 90 ++++++++++++++++++++++++++++++++++++++++++++++--
 src/fdlib.h      | 28 +++++++++++++--
 3 files changed, 120 insertions(+), 7 deletions(-)

diff --git a/src/acconfig.h b/src/acconfig.h
index 2bd41b04e6..9e3cb9e8d4 100644
--- a/src/acconfig.h
+++ b/src/acconfig.h
@@ -153,7 +153,14 @@
  * __chkstk. */
 #undef HAVE_BROKEN_CHKSTK
 
-/* Define if you have a working getcwd */
+/* Define if you have a working getcwd(3) (ie one that returns a malloc()ed
+ * buffer if the first argument is NULL).
+ *
+ * Define to 1 if the second argument being 0 causes getcwd(3) to allocate
+ * a buffer of suitable size (ie never fail with ERANGE).
+ *
+ * Define to 0 if the second argument MUST be > 0.
+ */
 #undef HAVE_WORKING_GETCWD
 
 /* Define for solaris */
diff --git a/src/configure.in b/src/configure.in
index b68c937692..3d5d154835 100644
--- a/src/configure.in
+++ b/src/configure.in
@@ -4705,6 +4705,82 @@ AC_DEFINE_UNQUOTED(ACCEPT_SIZE_T, $pike_cv_accept_size_t)
 AC_MSG_CHECKING(for working getcwd)
 AC_CACHE_VAL(pike_cv_func_working_getcwd,
 [
+# First try getcwd(NULL, 0).
+# This is the working == yes case, and is true on glibc and win32.
+AC_TRY_RUN([
+#ifndef _LARGEFILE_SOURCE
+#  define _FILE_OFFSET_BITS 64
+#  define _LARGEFILE_SOURCE
+#  define _LARGEFILE64_SOURCE 1
+#endif
+/* HPUX needs these too... */
+#ifndef __STDC_EXT__
+#  define __STDC_EXT__
+#endif /* !__STDC_EXT__ */
+
+#ifndef POSIX_SOURCE
+#define POSIX_SOURCE
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_DIRECT_H
+#include <direct.h>
+#endif /* HAVE_DIRECT_H */
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#include <signal.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef __NT__
+int sig_child(int arg)
+{
+#ifdef HAVE_WAITPID
+  waitpid(-1,0,WNOHANG);
+#else
+#ifdef HAVE_WAIT3
+  wait3(0,WNOHANG,0);
+#else
+#ifdef HAVE_WAIT4
+  wait3(-1,0,WNOHANG,0);
+#else
+
+  /* Leave them hanging */
+
+#endif /* HAVE_WAIT4 */
+#endif /* HAVE_WAIT3 */
+#endif /* HAVE_WAITPID */
+
+#ifdef SIGNAL_ONESHOT
+  signal(SIGCHLD, sig_child);
+#endif
+}
+
+int sig_alarm() { exit(1); }
+#endif /* !__NT__ */
+
+int main()
+{
+  char *tmp;
+#ifndef __NT__
+  signal(SIGCHLD,sig_child);
+  signal(SIGALRM,sig_alarm);
+  alarm(4);
+#endif /* !__NT__ */
+  tmp=getcwd(0,0);
+  if(tmp && tmp[0] && (strlen(tmp) < 10000)) {
+    free(tmp);
+    exit(0);
+  }
+  exit(1);
+}
+],pike_cv_func_working_getcwd=yes,
+# The getcwd(NULL, 0) case failed.
+# Retry with getcwd(NULL, 10000).
+# This is the working == some case, and is true on Solaris.
 AC_TRY_RUN([
 #ifndef _LARGEFILE_SOURCE
 #  define _FILE_OFFSET_BITS 64
@@ -4775,12 +4851,20 @@ int main()
   }
   exit(1);
 }
-],pike_cv_func_working_getcwd=yes,pike_cv_func_working_getcwd=no,
-  pike_cv_func_working_getcwd=yes)])
+],pike_cv_func_working_getcwd=some,
+  pike_cv_func_working_getcwd=no,
+  # NB: This should be unreachable.
+  pike_cv_func_working_getcwd=no),
+  # Assume that getcwd(NULL, val) works.
+  pike_cv_func_working_getcwd=some)
+])
 
 if test "$pike_cv_func_working_getcwd" = yes; then
   AC_MSG_RESULT(yes)
-  AC_DEFINE(HAVE_WORKING_GETCWD)
+  AC_DEFINE(HAVE_WORKING_GETCWD, [1])
+elif test "$pike_cv_func_working_getcwd" = some; then
+  AC_MSG_RESULT(some)
+  AC_DEFINE(HAVE_WORKING_GETCWD, [0])
 else
   AC_MSG_RESULT(no)
 fi
diff --git a/src/fdlib.h b/src/fdlib.h
index a2988c85d7..076de7d8e4 100644
--- a/src/fdlib.h
+++ b/src/fdlib.h
@@ -387,13 +387,35 @@ static int PIKE_UNUSED_ATTRIBUTE debug_fd_mkdir(const char *dir, int mode)
 /* Glibc extension... */
 #define fd_get_current_dir_name()	get_current_dir_name()
 #elif defined(HAVE_WORKING_GETCWD)
-/* getcwd(NULL, 0) gives malloced buffer. */
+#if HAVE_WORKING_GETCWD
+/* Glibc and win32 (HAVE_WORKING_GETCWD == 1).
+ *
+ * getcwd(NULL, 0) gives malloced buffer.
+ */
 #define fd_get_current_dir_name()	getcwd(NULL, 0)
 #else
+/* Solaris-style (HAVE_WORKING_GETCWD == 0).
+ *
+ * getcwd(NULL, x) gives malloced buffer as long as x > 0, and the path fits.
+ */
 static char PIKE_UNUSED_ATTRIBUTE *debug_get_current_dir_name(void)
 {
   char *buf;
-  size_t buf_size = 1000;
+  size_t buf_size = 128;
+  do {
+    buf = getcwd(NULL, buf_size);
+    if (buf) return buf;
+    buf_size <<= 1;
+  } while (errno == ERANGE);
+  return NULL;
+}
+#define fd_get_current_dir_name()	debug_get_current_dir_name()
+#endif
+#else
+static char PIKE_UNUSED_ATTRIBUTE *debug_get_current_dir_name(void)
+{
+  char *buf;
+  size_t buf_size = 128;
   do {
     buf = malloc(buf_size);
 
@@ -406,7 +428,7 @@ static char PIKE_UNUSED_ATTRIBUTE *debug_get_current_dir_name(void)
       free(buf);
 
       if (errno == ERANGE) {
-	bufsize <<= 1;
+	buf_size <<= 1;
 	continue;
       }
 
-- 
GitLab