libgo: fix building, and some testing, on Solaris

Restore some of the fixes that were applied to golang_org/x/net/lif
but were lost when 1.12 moved the directory to internal/x/net/lif.

Add support for reading /proc to fetch argc/argv/env for c-archive mode.

Change-Id: I3178d92e619b9d4b66fe489172d9f984b49d9acf
Reviewed-on: https://go-review.googlesource.com/c/158640
Reviewed-by: Than McIntosh <thanm@google.com>
diff --git a/libgo/Makefile.am b/libgo/Makefile.am
index 2ee4a28..b9ff88c 100644
--- a/libgo/Makefile.am
+++ b/libgo/Makefile.am
@@ -1082,7 +1082,7 @@
 internal_x_net_lif_lo = \
 	internal/x/net/lif.lo
 internal_x_net_lif_check = \
-	internal_org/x/net/lif/check
+	internal/x/net/lif/check
 
 endif
 
diff --git a/libgo/Makefile.in b/libgo/Makefile.in
index 1695dd0..abda064 100644
--- a/libgo/Makefile.in
+++ b/libgo/Makefile.in
@@ -1131,7 +1131,7 @@
 @LIBGO_IS_SOLARIS_TRUE@	internal/x/net/lif.lo
 
 @LIBGO_IS_SOLARIS_TRUE@internal_x_net_lif_check = \
-@LIBGO_IS_SOLARIS_TRUE@	internal_org/x/net/lif/check
+@LIBGO_IS_SOLARIS_TRUE@	internal/x/net/lif/check
 
 TPACKAGES = $(shell cat $(srcdir)/check-packages.txt)
 TEST_PACKAGES = $(addsuffix /check,$(TPACKAGES)) \
diff --git a/libgo/go/internal/x/net/lif/syscall.go b/libgo/go/internal/x/net/lif/syscall.go
index aadab2e..ea75414 100644
--- a/libgo/go/internal/x/net/lif/syscall.go
+++ b/libgo/go/internal/x/net/lif/syscall.go
@@ -11,18 +11,12 @@
 	"unsafe"
 )
 
-//go:cgo_import_dynamic libc_ioctl ioctl "libc.so"
-
-//go:linkname procIoctl libc_ioctl
-
-var procIoctl uintptr
-
-func sysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (uintptr, uintptr, syscall.Errno)
+//extern __go_ioctl_ptr
+func libc_ioctl(int32, int32, unsafe.Pointer) int32
 
 func ioctl(s, ioc uintptr, arg unsafe.Pointer) error {
-	_, _, errno := sysvicall6(uintptr(unsafe.Pointer(&procIoctl)), 3, s, ioc, uintptr(arg), 0, 0, 0)
-	if errno != 0 {
-		return error(errno)
+	if libc_ioctl(int32(s), int32(ioc), arg) < 0 {
+		return syscall.GetErrno()
 	}
 	return nil
 }
diff --git a/libgo/go/internal/x/net/lif/zsys_solaris_amd64.go b/libgo/go/internal/x/net/lif/zsys_solaris.go
similarity index 94%
rename from libgo/go/internal/x/net/lif/zsys_solaris_amd64.go
rename to libgo/go/internal/x/net/lif/zsys_solaris.go
index b5e999b..0d9ed2f 100644
--- a/libgo/go/internal/x/net/lif/zsys_solaris_amd64.go
+++ b/libgo/go/internal/x/net/lif/zsys_solaris.go
@@ -3,6 +3,8 @@
 
 package lif
 
+import "unsafe"
+
 const (
 	sysAF_UNSPEC = 0x0
 	sysAF_INET   = 0x2
@@ -67,7 +69,6 @@
 
 type lifnum struct {
 	Family    uint16
-	Pad_cgo_0 [2]byte
 	Flags     int32
 	Count     int32
 }
@@ -81,16 +82,13 @@
 
 type lifconf struct {
 	Family    uint16
-	Pad_cgo_0 [2]byte
 	Flags     int32
 	Len       int32
-	Pad_cgo_1 [4]byte
-	Lifcu     [8]byte
+	Lifcu     [unsafe.Sizeof(unsafe.Pointer(nil))]byte
 }
 
 type lifIfinfoReq struct {
 	Maxhops      uint8
-	Pad_cgo_0    [3]byte
 	Reachtime    uint32
 	Reachretrans uint32
 	Maxmtu       uint32
diff --git a/libgo/go/runtime/signal_unix.go b/libgo/go/runtime/signal_unix.go
index 0a2cf72..2f89c7c 100644
--- a/libgo/go/runtime/signal_unix.go
+++ b/libgo/go/runtime/signal_unix.go
@@ -441,7 +441,10 @@
 	//
 	// On FreeBSD, the libthr sigaction code prevents
 	// this from working so we fall through to raise.
-	if GOOS != "freebsd" && (isarchive || islibrary) && handler == _SIG_DFL && c.sigcode() != _SI_USER {
+	//
+	// The argument above doesn't hold for SIGPIPE, which won't
+	// necessarily be re-raised if we return.
+	if GOOS != "freebsd" && (isarchive || islibrary) && handler == _SIG_DFL && c.sigcode() != _SI_USER && sig != _SIGPIPE {
 		return
 	}
 
diff --git a/libgo/runtime/go-libmain.c b/libgo/runtime/go-libmain.c
index 5e3b8d9..4f47639 100644
--- a/libgo/runtime/go-libmain.c
+++ b/libgo/runtime/go-libmain.c
@@ -11,11 +11,129 @@
 #include <stdlib.h>
 #include <time.h>
 #include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
 
 #include "runtime.h"
 #include "array.h"
 #include "arch.h"
 
+#if defined(__sun) && defined(__SVR4)
+
+/* Read a file into memory on Solaris, returning an malloc'ed buffer
+   and setting *SIZE to its size.  */
+
+static char *
+read_file (const char *fn, size_t *size)
+{
+  struct stat st;
+  char *buf;
+  int o;
+  ssize_t got;
+
+  if (stat (fn, &st) < 0)
+    return NULL;
+  buf = malloc ((size_t) st.st_size);
+  if (buf == NULL)
+    return NULL;
+  o = open (fn, O_RDONLY);
+  if (o < 0)
+    {
+      free (buf);
+      return NULL;
+    }
+  got = read (o, buf, st.st_size);
+  close (o);
+  if (got != st.st_size)
+    {
+      free (buf);
+      return NULL;
+    }
+
+  *size = (size_t) got;
+  return buf;
+}
+
+/* On Solaris we don't get passed argc/argv, but we can fetch it from
+   /proc/PID/cmdline.  */
+
+static void
+read_cmdline (int *argc, char ***argv)
+{
+  pid_t pid;
+  char fn[50];
+  char *argbuf;
+  size_t argsize;
+  char *envbuf;
+  size_t envsize;
+  char *p;
+  int i;
+  int ac;
+
+  *argc = 0;
+  *argv = NULL;
+
+  pid = getpid ();
+  snprintf (fn, sizeof fn, "/proc/%ld/cmdline", (long) pid);
+  argbuf = read_file (fn, &argsize);
+  if (argbuf == NULL)
+    return;
+
+  snprintf (fn, sizeof fn, "/proc/%ld/environ", (long) pid);
+  envbuf = read_file (fn, &envsize);
+  if (envbuf == NULL)
+    {
+      free (argbuf);
+      return;
+    }
+
+  i = 0;
+  for (p = argbuf; p < argbuf + argsize; p++)
+    if (*p == '\0')
+      ++i;
+  ac = i;
+  ++i; // For trailing NULL.
+  for (p = envbuf; p < envbuf + envsize; p++)
+    if (*p == '\0')
+      ++i;
+  ++i; // For trailing NULL.
+
+  *argv = (char **) malloc (i * sizeof (char *));
+  if (*argv == NULL)
+    {
+      free (argbuf);
+      free (envbuf);
+      return;
+    }
+
+  *argc = ac;
+  (*argv)[0] = argbuf;
+  i = 0;
+  for (p = argbuf; p < argbuf + argsize; p++)
+    {
+      if (*p == '\0')
+	{
+	  ++i;
+	  (*argv)[i] = p + 1;
+	}
+    }
+  (*argv)[i] = NULL;
+  ++i;
+  (*argv)[i] = envbuf;
+  for (p = envbuf; p < envbuf + envsize; p++)
+    {
+      if (*p == '\0')
+	{
+	  ++i;
+	  (*argv)[i] = p + 1;
+	}
+    }
+  (*argv)[i] = NULL;
+}
+
+#endif /* defined(__sun) && defined(__SVR4) */
+
 /* This is used when building a standalone Go library using the Go
    command's -buildmode=c-archive or -buildmode=c-shared option.  It
    starts up the Go code as a global constructor but does not take any
@@ -64,6 +182,10 @@
   struct args *a;
   pthread_t tid;
 
+#if defined(__sun) && defined(__SVR4)
+  read_cmdline (&argc, &argv);
+#endif
+
   runtime_isarchive = true;
 
   setIsCgo ();