unix: add Illumos statvfs(2) syscall

Reference: https://www.illumos.org/man/2/statvfs

Change-Id: If7af43da35b3204f5069a48eb08426a145544008
Reviewed-on: https://go-review.googlesource.com/43490
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/unix/syscall_solaris.go b/unix/syscall_solaris.go
index 542b0ba..cab9b4f 100644
--- a/unix/syscall_solaris.go
+++ b/unix/syscall_solaris.go
@@ -583,6 +583,7 @@
 //sys	Fdatasync(fd int) (err error)
 //sys	Fpathconf(fd int, name int) (val int, err error)
 //sys	Fstat(fd int, stat *Stat_t) (err error)
+//sys	Fstatvfs(fd int, vfsstat *Statvfs_t) (err error)
 //sys	Getdents(fd int, buf []byte, basep *uintptr) (n int, err error)
 //sysnb	Getgid() (gid int)
 //sysnb	Getpid() (pid int)
@@ -639,6 +640,7 @@
 //sysnb	Setuid(uid int) (err error)
 //sys	Shutdown(s int, how int) (err error) = libsocket.shutdown
 //sys	Stat(path string, stat *Stat_t) (err error)
+//sys	Statvfs(path string, vfsstat *Statvfs_t) (err error)
 //sys	Symlink(path string, link string) (err error)
 //sys	Sync() (err error)
 //sysnb	Times(tms *Tms) (ticks uintptr, err error)
diff --git a/unix/syscall_solaris_test.go b/unix/syscall_solaris_test.go
new file mode 100644
index 0000000..d3e7d2b
--- /dev/null
+++ b/unix/syscall_solaris_test.go
@@ -0,0 +1,34 @@
+// Copyright 2017 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.
+
+// +build solaris
+
+package unix_test
+
+import (
+	"os/exec"
+	"testing"
+
+	"golang.org/x/sys/unix"
+)
+
+func TestStatvfs(t *testing.T) {
+	if err := unix.Statvfs("", nil); err == nil {
+		t.Fatal(`Statvfs("") expected failure`)
+	}
+
+	statvfs := unix.Statvfs_t{}
+	if err := unix.Statvfs("/", &statvfs); err != nil {
+		t.Errorf(`Statvfs("/") failed: %v`, err)
+	}
+
+	if t.Failed() {
+		mount, err := exec.Command("mount").CombinedOutput()
+		if err != nil {
+			t.Logf("mount: %v\n%s", err, mount)
+		} else {
+			t.Logf("mount: %s", mount)
+		}
+	}
+}
diff --git a/unix/types_solaris.go b/unix/types_solaris.go
index 69bf1bc..393c7f0 100644
--- a/unix/types_solaris.go
+++ b/unix/types_solaris.go
@@ -37,6 +37,7 @@
 #include <sys/signal.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
+#include <sys/statvfs.h>
 #include <sys/time.h>
 #include <sys/times.h>
 #include <sys/types.h>
@@ -139,6 +140,12 @@
 
 type Dirent C.struct_dirent
 
+// Filesystems
+
+type _Fsblkcnt_t C.fsblkcnt_t
+
+type Statvfs_t C.struct_statvfs
+
 // Sockets
 
 type RawSockaddrInet4 C.struct_sockaddr_in
diff --git a/unix/zsyscall_solaris_amd64.go b/unix/zsyscall_solaris_amd64.go
index eb703e8..cbc6f6e 100644
--- a/unix/zsyscall_solaris_amd64.go
+++ b/unix/zsyscall_solaris_amd64.go
@@ -45,6 +45,7 @@
 //go:cgo_import_dynamic libc_fdatasync fdatasync "libc.so"
 //go:cgo_import_dynamic libc_fpathconf fpathconf "libc.so"
 //go:cgo_import_dynamic libc_fstat fstat "libc.so"
+//go:cgo_import_dynamic libc_fstatvfs fstatvfs "libc.so"
 //go:cgo_import_dynamic libc_getdents getdents "libc.so"
 //go:cgo_import_dynamic libc_getgid getgid "libc.so"
 //go:cgo_import_dynamic libc_getpid getpid "libc.so"
@@ -101,6 +102,7 @@
 //go:cgo_import_dynamic libc_setuid setuid "libc.so"
 //go:cgo_import_dynamic libc_shutdown shutdown "libsocket.so"
 //go:cgo_import_dynamic libc_stat stat "libc.so"
+//go:cgo_import_dynamic libc_statvfs statvfs "libc.so"
 //go:cgo_import_dynamic libc_symlink symlink "libc.so"
 //go:cgo_import_dynamic libc_sync sync "libc.so"
 //go:cgo_import_dynamic libc_times times "libc.so"
@@ -163,6 +165,7 @@
 //go:linkname procFdatasync libc_fdatasync
 //go:linkname procFpathconf libc_fpathconf
 //go:linkname procFstat libc_fstat
+//go:linkname procFstatvfs libc_fstatvfs
 //go:linkname procGetdents libc_getdents
 //go:linkname procGetgid libc_getgid
 //go:linkname procGetpid libc_getpid
@@ -219,6 +222,7 @@
 //go:linkname procSetuid libc_setuid
 //go:linkname procshutdown libc_shutdown
 //go:linkname procStat libc_stat
+//go:linkname procStatvfs libc_statvfs
 //go:linkname procSymlink libc_symlink
 //go:linkname procSync libc_sync
 //go:linkname procTimes libc_times
@@ -282,6 +286,7 @@
 	procFdatasync,
 	procFpathconf,
 	procFstat,
+	procFstatvfs,
 	procGetdents,
 	procGetgid,
 	procGetpid,
@@ -338,6 +343,7 @@
 	procSetuid,
 	procshutdown,
 	procStat,
+	procStatvfs,
 	procSymlink,
 	procSync,
 	procTimes,
@@ -713,6 +719,14 @@
 	return
 }
 
+func Fstatvfs(fd int, vfsstat *Statvfs_t) (err error) {
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procFstatvfs)), 2, uintptr(fd), uintptr(unsafe.Pointer(vfsstat)), 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
 func Getdents(fd int, buf []byte, basep *uintptr) (n int, err error) {
 	var _p0 *byte
 	if len(buf) > 0 {
@@ -1302,6 +1316,19 @@
 	return
 }
 
+func Statvfs(path string, vfsstat *Statvfs_t) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procStatvfs)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(vfsstat)), 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
 func Symlink(path string, link string) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
diff --git a/unix/ztypes_solaris_amd64.go b/unix/ztypes_solaris_amd64.go
index 7ff96e5..92336f9 100644
--- a/unix/ztypes_solaris_amd64.go
+++ b/unix/ztypes_solaris_amd64.go
@@ -129,6 +129,24 @@
 	Pad_cgo_0 [5]byte
 }
 
+type _Fsblkcnt_t uint64
+
+type Statvfs_t struct {
+	Bsize    uint64
+	Frsize   uint64
+	Blocks   uint64
+	Bfree    uint64
+	Bavail   uint64
+	Files    uint64
+	Ffree    uint64
+	Favail   uint64
+	Fsid     uint64
+	Basetype [16]int8
+	Flag     uint64
+	Namemax  uint64
+	Fstr     [32]int8
+}
+
 type RawSockaddrInet4 struct {
 	Family uint16
 	Port   uint16