unix: add readv/writev for illumos

iovec read/writes (readv, writev, preadv, pwritev) are present on
illumos, but they weren't added to the package. This commit adds
those missing features.

Updates golang/go#36201

Change-Id: Iecf2bab7ef846f5ca5d693e833491d819618c15d
GitHub-Last-Rev: 81a479f4c5f851f81e748cef6eb529c3f89cd1e1
GitHub-Pull-Request: golang/sys#64
Reviewed-on: https://go-review.googlesource.com/c/sys/+/224238
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Tobias Klauser <tobias.klauser@gmail.com>
diff --git a/unix/mkall.sh b/unix/mkall.sh
index 0b50bf5..ece31e9 100755
--- a/unix/mkall.sh
+++ b/unix/mkall.sh
@@ -190,6 +190,12 @@
 	mksysnum=
 	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
 	;;
+illumos_amd64)
+        mksyscall="go run mksyscall_solaris.go"
+	mkerrors=
+	mksysnum=
+	mktypes=
+	;;
 *)
 	echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2
 	exit 1
@@ -217,6 +223,11 @@
 				echo "$mksyscall -tags $GOOS,$GOARCH,go1.12 $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go";
 				# 1.13 and later, syscalls via libSystem (including syscallPtr)
 				echo "$mksyscall -tags $GOOS,$GOARCH,go1.13 syscall_darwin.1_13.go |gofmt >zsyscall_$GOOSARCH.1_13.go";
+			elif [ "$GOOS" == "illumos" ]; then
+			        # illumos code generation requires a --illumos switch
+			        echo "$mksyscall -illumos -tags illumos,$GOARCH syscall_illumos.go |gofmt > zsyscall_illumos_$GOARCH.go";
+			        # illumos implies solaris, so solaris code generation is also required
+				echo "$mksyscall -tags solaris,$GOARCH syscall_solaris.go syscall_solaris_$GOARCH.go |gofmt >zsyscall_solaris_$GOARCH.go";
 			else
 				echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go";
 			fi
diff --git a/unix/mksyscall_solaris.go b/unix/mksyscall_solaris.go
index 3d86473..675597e 100644
--- a/unix/mksyscall_solaris.go
+++ b/unix/mksyscall_solaris.go
@@ -32,9 +32,10 @@
 )
 
 var (
-	b32  = flag.Bool("b32", false, "32bit big-endian")
-	l32  = flag.Bool("l32", false, "32bit little-endian")
-	tags = flag.String("tags", "", "build tags")
+	b32     = flag.Bool("b32", false, "32bit big-endian")
+	l32     = flag.Bool("l32", false, "32bit little-endian")
+	tags    = flag.String("tags", "", "build tags")
+	illumos = flag.Bool("illumos", false, "illumos specific code generation")
 )
 
 // cmdLine returns this programs's commandline arguments
@@ -306,11 +307,16 @@
 	imp := ""
 	if pack != "unix" {
 		imp = "import \"golang.org/x/sys/unix\"\n"
-
 	}
+
+	syscallimp := ""
+	if !*illumos {
+		syscallimp = "\"syscall\""
+	}
+
 	vardecls := "\t" + strings.Join(vars, ",\n\t")
 	vardecls += " syscallFunc"
-	fmt.Printf(srcTemplate, cmdLine(), buildTags(), pack, imp, dynimports, linknames, vardecls, text)
+	fmt.Printf(srcTemplate, cmdLine(), buildTags(), pack, syscallimp, imp, dynimports, linknames, vardecls, text)
 }
 
 const srcTemplate = `// %s
@@ -321,8 +327,8 @@
 package %s
 
 import (
-	"syscall"
-	"unsafe"
+        "unsafe"
+        %s
 )
 %s
 %s
diff --git a/unix/syscall_illumos.go b/unix/syscall_illumos.go
new file mode 100644
index 0000000..99e62dc
--- /dev/null
+++ b/unix/syscall_illumos.go
@@ -0,0 +1,57 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// illumos system calls not present on Solaris.
+
+// +build amd64,illumos
+
+package unix
+
+import "unsafe"
+
+func bytes2iovec(bs [][]byte) []Iovec {
+	iovecs := make([]Iovec, len(bs))
+	for i, b := range bs {
+		iovecs[i].SetLen(len(b))
+		if len(b) > 0 {
+			// somehow Iovec.Base on illumos is (*int8), not (*byte)
+			iovecs[i].Base = (*int8)(unsafe.Pointer(&b[0]))
+		} else {
+			iovecs[i].Base = (*int8)(unsafe.Pointer(&_zero))
+		}
+	}
+	return iovecs
+}
+
+//sys   readv(fd int, iovs []Iovec) (n int, err error)
+
+func Readv(fd int, iovs [][]byte) (n int, err error) {
+	iovecs := bytes2iovec(iovs)
+	n, err = readv(fd, iovecs)
+	return n, err
+}
+
+//sys   preadv(fd int, iovs []Iovec, off int64) (n int, err error)
+
+func Preadv(fd int, iovs [][]byte, off int64) (n int, err error) {
+	iovecs := bytes2iovec(iovs)
+	n, err = preadv(fd, iovecs, off)
+	return n, err
+}
+
+//sys   writev(fd int, iovs []Iovec) (n int, err error)
+
+func Writev(fd int, iovs [][]byte) (n int, err error) {
+	iovecs := bytes2iovec(iovs)
+	n, err = writev(fd, iovecs)
+	return n, err
+}
+
+//sys   pwritev(fd int, iovs []Iovec, off int64) (n int, err error)
+
+func Pwritev(fd int, iovs [][]byte, off int64) (n int, err error) {
+	iovecs := bytes2iovec(iovs)
+	n, err = pwritev(fd, iovecs, off)
+	return n, err
+}
diff --git a/unix/zsyscall_illumos_amd64.go b/unix/zsyscall_illumos_amd64.go
new file mode 100644
index 0000000..92efa1d
--- /dev/null
+++ b/unix/zsyscall_illumos_amd64.go
@@ -0,0 +1,87 @@
+// go run mksyscall_solaris.go -illumos -tags illumos,amd64 syscall_illumos.go
+// Code generated by the command above; see README.md. DO NOT EDIT.
+
+// +build illumos,amd64
+
+package unix
+
+import (
+	"unsafe"
+)
+
+//go:cgo_import_dynamic libc_readv readv "libc.so"
+//go:cgo_import_dynamic libc_preadv preadv "libc.so"
+//go:cgo_import_dynamic libc_writev writev "libc.so"
+//go:cgo_import_dynamic libc_pwritev pwritev "libc.so"
+
+//go:linkname procreadv libc_readv
+//go:linkname procpreadv libc_preadv
+//go:linkname procwritev libc_writev
+//go:linkname procpwritev libc_pwritev
+
+var (
+	procreadv,
+	procpreadv,
+	procwritev,
+	procpwritev syscallFunc
+)
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func readv(fd int, iovs []Iovec) (n int, err error) {
+	var _p0 *Iovec
+	if len(iovs) > 0 {
+		_p0 = &iovs[0]
+	}
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procreadv)), 3, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(iovs)), 0, 0, 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func preadv(fd int, iovs []Iovec, off int64) (n int, err error) {
+	var _p0 *Iovec
+	if len(iovs) > 0 {
+		_p0 = &iovs[0]
+	}
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procpreadv)), 4, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(iovs)), uintptr(off), 0, 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func writev(fd int, iovs []Iovec) (n int, err error) {
+	var _p0 *Iovec
+	if len(iovs) > 0 {
+		_p0 = &iovs[0]
+	}
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procwritev)), 3, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(iovs)), 0, 0, 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func pwritev(fd int, iovs []Iovec, off int64) (n int, err error) {
+	var _p0 *Iovec
+	if len(iovs) > 0 {
+		_p0 = &iovs[0]
+	}
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procpwritev)), 4, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(iovs)), uintptr(off), 0, 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}