unix: add IoctlGetInt and IoctlSetInt on Linux

This CL adds basic integer get/set functions which wrap a generic
ioctl call.  The API is similar the one introduced for solaris/amd64
in CL 14587, but the request parameter has been changed to a uint
instead of an int.  This makes requests with a number larger than the
maximum signed 32-bit integer work on linux/386.

For consistency, the solaris/amd64 API has also been updated to make
use of a uint instead of an int for the request number.

Fixes golang/go#20474

Change-Id: Iaae1ee2e4bb4bfcc420dcec252fe53c8d90ce81d
Reviewed-on: https://go-review.googlesource.com/44009
Run-TryBot: Matt Layher <mdlayher@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/unix/linux/types.go b/unix/linux/types.go
index d9aae05..7236b72 100644
--- a/unix/linux/types.go
+++ b/unix/linux/types.go
@@ -59,6 +59,7 @@
 #include <linux/if_alg.h>
 #include <linux/fs.h>
 #include <linux/vm_sockets.h>
+#include <linux/random.h>
 
 // On mips64, the glibc stat and kernel stat do not agree
 #if (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI64)
@@ -530,6 +531,8 @@
 
 type Sigset_t C.sigset_t
 
+const RNDGETENTCNT = C.RNDGETENTCNT
+
 // sysconf information
 
 const _SC_PAGESIZE = C._SC_PAGESIZE
diff --git a/unix/syscall_linux.go b/unix/syscall_linux.go
index 4832bf5..c1abe45 100644
--- a/unix/syscall_linux.go
+++ b/unix/syscall_linux.go
@@ -36,6 +36,25 @@
 	return Open(path, O_CREAT|O_WRONLY|O_TRUNC, mode)
 }
 
+//sys	ioctl(fd int, req uint, arg uintptr) (err error)
+
+// ioctl itself should not be exposed directly, but additional get/set
+// functions for specific types are permissible.
+
+// IoctlSetInt performs an ioctl operation which sets an integer value
+// on fd, using the specified request number.
+func IoctlSetInt(fd int, req uint, value int) (err error) {
+	return ioctl(fd, req, uintptr(value))
+}
+
+// IoctlGetInt performs an ioctl operation which gets an integer value
+// from fd, using the specified request number.
+func IoctlGetInt(fd int, req uint) (int, error) {
+	var value int
+	err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
+	return value, err
+}
+
 //sys	Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error)
 
 func Link(oldpath string, newpath string) (err error) {
@@ -1312,7 +1331,6 @@
 // IoGetevents
 // IoSetup
 // IoSubmit
-// Ioctl
 // IoprioGet
 // IoprioSet
 // KexecLoad
diff --git a/unix/syscall_linux_test.go b/unix/syscall_linux_test.go
index 91184ca..e42b4ee 100644
--- a/unix/syscall_linux_test.go
+++ b/unix/syscall_linux_test.go
@@ -15,6 +15,21 @@
 	"golang.org/x/sys/unix"
 )
 
+func TestIoctlGetInt(t *testing.T) {
+	f, err := os.Open("/dev/random")
+	if err != nil {
+		t.Fatalf("failed to open device: %v", err)
+	}
+	defer f.Close()
+
+	v, err := unix.IoctlGetInt(int(f.Fd()), unix.RNDGETENTCNT)
+	if err != nil {
+		t.Fatalf("failed to perform ioctl: %v", err)
+	}
+
+	t.Logf("%d bits of entropy available", v)
+}
+
 func TestPoll(t *testing.T) {
 	f, cleanup := mktmpfifo(t)
 	defer cleanup()
diff --git a/unix/syscall_solaris.go b/unix/syscall_solaris.go
index cab9b4f..4b8ddab 100644
--- a/unix/syscall_solaris.go
+++ b/unix/syscall_solaris.go
@@ -519,43 +519,43 @@
  * Expose the ioctl function
  */
 
-//sys	ioctl(fd int, req int, arg uintptr) (err error)
+//sys	ioctl(fd int, req uint, arg uintptr) (err error)
 
-func IoctlSetInt(fd int, req int, value int) (err error) {
+func IoctlSetInt(fd int, req uint, value int) (err error) {
 	return ioctl(fd, req, uintptr(value))
 }
 
-func IoctlSetWinsize(fd int, req int, value *Winsize) (err error) {
+func IoctlSetWinsize(fd int, req uint, value *Winsize) (err error) {
 	return ioctl(fd, req, uintptr(unsafe.Pointer(value)))
 }
 
-func IoctlSetTermios(fd int, req int, value *Termios) (err error) {
+func IoctlSetTermios(fd int, req uint, value *Termios) (err error) {
 	return ioctl(fd, req, uintptr(unsafe.Pointer(value)))
 }
 
-func IoctlSetTermio(fd int, req int, value *Termio) (err error) {
+func IoctlSetTermio(fd int, req uint, value *Termio) (err error) {
 	return ioctl(fd, req, uintptr(unsafe.Pointer(value)))
 }
 
-func IoctlGetInt(fd int, req int) (int, error) {
+func IoctlGetInt(fd int, req uint) (int, error) {
 	var value int
 	err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
 	return value, err
 }
 
-func IoctlGetWinsize(fd int, req int) (*Winsize, error) {
+func IoctlGetWinsize(fd int, req uint) (*Winsize, error) {
 	var value Winsize
 	err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
 	return &value, err
 }
 
-func IoctlGetTermios(fd int, req int) (*Termios, error) {
+func IoctlGetTermios(fd int, req uint) (*Termios, error) {
 	var value Termios
 	err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
 	return &value, err
 }
 
-func IoctlGetTermio(fd int, req int) (*Termio, error) {
+func IoctlGetTermio(fd int, req uint) (*Termio, error) {
 	var value Termio
 	err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
 	return &value, err
diff --git a/unix/zsyscall_linux_386.go b/unix/zsyscall_linux_386.go
index d71acc1..e119de0 100644
--- a/unix/zsyscall_linux_386.go
+++ b/unix/zsyscall_linux_386.go
@@ -14,6 +14,16 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func ioctl(fd int, req uint, arg uintptr) (err error) {
+	_, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(oldpath)
diff --git a/unix/zsyscall_linux_amd64.go b/unix/zsyscall_linux_amd64.go
index 6282311..5a6b63e 100644
--- a/unix/zsyscall_linux_amd64.go
+++ b/unix/zsyscall_linux_amd64.go
@@ -14,6 +14,16 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func ioctl(fd int, req uint, arg uintptr) (err error) {
+	_, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(oldpath)
diff --git a/unix/zsyscall_linux_arm.go b/unix/zsyscall_linux_arm.go
index d48e206..7de84dc 100644
--- a/unix/zsyscall_linux_arm.go
+++ b/unix/zsyscall_linux_arm.go
@@ -14,6 +14,16 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func ioctl(fd int, req uint, arg uintptr) (err error) {
+	_, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(oldpath)
diff --git a/unix/zsyscall_linux_arm64.go b/unix/zsyscall_linux_arm64.go
index 1ceabe5..4a6a122 100644
--- a/unix/zsyscall_linux_arm64.go
+++ b/unix/zsyscall_linux_arm64.go
@@ -14,6 +14,16 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func ioctl(fd int, req uint, arg uintptr) (err error) {
+	_, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(oldpath)
diff --git a/unix/zsyscall_linux_mips.go b/unix/zsyscall_linux_mips.go
index fd3e972..3b4c934 100644
--- a/unix/zsyscall_linux_mips.go
+++ b/unix/zsyscall_linux_mips.go
@@ -14,6 +14,16 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func ioctl(fd int, req uint, arg uintptr) (err error) {
+	_, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(oldpath)
diff --git a/unix/zsyscall_linux_mips64.go b/unix/zsyscall_linux_mips64.go
index dfa9d93..5a496a9 100644
--- a/unix/zsyscall_linux_mips64.go
+++ b/unix/zsyscall_linux_mips64.go
@@ -14,6 +14,16 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func ioctl(fd int, req uint, arg uintptr) (err error) {
+	_, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(oldpath)
diff --git a/unix/zsyscall_linux_mips64le.go b/unix/zsyscall_linux_mips64le.go
index 2c41e34..cfa7fe8 100644
--- a/unix/zsyscall_linux_mips64le.go
+++ b/unix/zsyscall_linux_mips64le.go
@@ -14,6 +14,16 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func ioctl(fd int, req uint, arg uintptr) (err error) {
+	_, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(oldpath)
diff --git a/unix/zsyscall_linux_mipsle.go b/unix/zsyscall_linux_mipsle.go
index da9c71f..7f83efd 100644
--- a/unix/zsyscall_linux_mipsle.go
+++ b/unix/zsyscall_linux_mipsle.go
@@ -14,6 +14,16 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func ioctl(fd int, req uint, arg uintptr) (err error) {
+	_, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(oldpath)
diff --git a/unix/zsyscall_linux_ppc64.go b/unix/zsyscall_linux_ppc64.go
index 170560a..9a57e35 100644
--- a/unix/zsyscall_linux_ppc64.go
+++ b/unix/zsyscall_linux_ppc64.go
@@ -14,6 +14,16 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func ioctl(fd int, req uint, arg uintptr) (err error) {
+	_, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(oldpath)
diff --git a/unix/zsyscall_linux_ppc64le.go b/unix/zsyscall_linux_ppc64le.go
index e03a81c..d12ce4d 100644
--- a/unix/zsyscall_linux_ppc64le.go
+++ b/unix/zsyscall_linux_ppc64le.go
@@ -14,6 +14,16 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func ioctl(fd int, req uint, arg uintptr) (err error) {
+	_, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(oldpath)
diff --git a/unix/zsyscall_linux_s390x.go b/unix/zsyscall_linux_s390x.go
index e6c13aa..bd28929 100644
--- a/unix/zsyscall_linux_s390x.go
+++ b/unix/zsyscall_linux_s390x.go
@@ -14,6 +14,16 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func ioctl(fd int, req uint, arg uintptr) (err error) {
+	_, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(oldpath)
diff --git a/unix/zsyscall_solaris_amd64.go b/unix/zsyscall_solaris_amd64.go
index cbc6f6e..d1ed021 100644
--- a/unix/zsyscall_solaris_amd64.go
+++ b/unix/zsyscall_solaris_amd64.go
@@ -519,7 +519,7 @@
 	return
 }
 
-func ioctl(fd int, req int, arg uintptr) (err error) {
+func ioctl(fd int, req uint, arg uintptr) (err error) {
 	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procioctl)), 3, uintptr(fd), uintptr(req), uintptr(arg), 0, 0, 0)
 	if e1 != 0 {
 		err = e1
diff --git a/unix/ztypes_linux_386.go b/unix/ztypes_linux_386.go
index 20ae16b..7fc1eb2 100644
--- a/unix/ztypes_linux_386.go
+++ b/unix/ztypes_linux_386.go
@@ -660,6 +660,8 @@
 	X__val [32]uint32
 }
 
+const RNDGETENTCNT = 0x80045200
+
 const _SC_PAGESIZE = 0x1e
 
 type Termios struct {
diff --git a/unix/ztypes_linux_amd64.go b/unix/ztypes_linux_amd64.go
index 1878142..60a26ee 100644
--- a/unix/ztypes_linux_amd64.go
+++ b/unix/ztypes_linux_amd64.go
@@ -678,6 +678,8 @@
 	X__val [16]uint64
 }
 
+const RNDGETENTCNT = 0x80045200
+
 const _SC_PAGESIZE = 0x1e
 
 type Termios struct {
diff --git a/unix/ztypes_linux_arm.go b/unix/ztypes_linux_arm.go
index b755668..b994baa 100644
--- a/unix/ztypes_linux_arm.go
+++ b/unix/ztypes_linux_arm.go
@@ -649,6 +649,8 @@
 	X__val [32]uint32
 }
 
+const RNDGETENTCNT = 0x80045200
+
 const _SC_PAGESIZE = 0x1e
 
 type Termios struct {
diff --git a/unix/ztypes_linux_arm64.go b/unix/ztypes_linux_arm64.go
index 1e99b93..c19c478 100644
--- a/unix/ztypes_linux_arm64.go
+++ b/unix/ztypes_linux_arm64.go
@@ -657,6 +657,8 @@
 	X__val [16]uint64
 }
 
+const RNDGETENTCNT = 0x80045200
+
 const _SC_PAGESIZE = 0x1e
 
 type Termios struct {
diff --git a/unix/ztypes_linux_mips.go b/unix/ztypes_linux_mips.go
index 9a7916c..c84e462 100644
--- a/unix/ztypes_linux_mips.go
+++ b/unix/ztypes_linux_mips.go
@@ -654,6 +654,8 @@
 	X__val [32]uint32
 }
 
+const RNDGETENTCNT = 0x40045200
+
 const _SC_PAGESIZE = 0x1e
 
 type Termios struct {
diff --git a/unix/ztypes_linux_mips64.go b/unix/ztypes_linux_mips64.go
index 0b58c64..0c75cb9 100644
--- a/unix/ztypes_linux_mips64.go
+++ b/unix/ztypes_linux_mips64.go
@@ -659,6 +659,8 @@
 	X__val [16]uint64
 }
 
+const RNDGETENTCNT = 0x40045200
+
 const _SC_PAGESIZE = 0x1e
 
 type Termios struct {
diff --git a/unix/ztypes_linux_mips64le.go b/unix/ztypes_linux_mips64le.go
index aa6a663..c75f75a 100644
--- a/unix/ztypes_linux_mips64le.go
+++ b/unix/ztypes_linux_mips64le.go
@@ -659,6 +659,8 @@
 	X__val [16]uint64
 }
 
+const RNDGETENTCNT = 0x40045200
+
 const _SC_PAGESIZE = 0x1e
 
 type Termios struct {
diff --git a/unix/ztypes_linux_mipsle.go b/unix/ztypes_linux_mipsle.go
index b5ef69c..cfc219f 100644
--- a/unix/ztypes_linux_mipsle.go
+++ b/unix/ztypes_linux_mipsle.go
@@ -654,6 +654,8 @@
 	X__val [32]uint32
 }
 
+const RNDGETENTCNT = 0x40045200
+
 const _SC_PAGESIZE = 0x1e
 
 type Termios struct {
diff --git a/unix/ztypes_linux_ppc64.go b/unix/ztypes_linux_ppc64.go
index 326b8e3..4c28522 100644
--- a/unix/ztypes_linux_ppc64.go
+++ b/unix/ztypes_linux_ppc64.go
@@ -667,6 +667,8 @@
 	X__val [16]uint64
 }
 
+const RNDGETENTCNT = 0x40045200
+
 const _SC_PAGESIZE = 0x1e
 
 type Termios struct {
diff --git a/unix/ztypes_linux_ppc64le.go b/unix/ztypes_linux_ppc64le.go
index 1309399..1b511be 100644
--- a/unix/ztypes_linux_ppc64le.go
+++ b/unix/ztypes_linux_ppc64le.go
@@ -667,6 +667,8 @@
 	X__val [16]uint64
 }
 
+const RNDGETENTCNT = 0x40045200
+
 const _SC_PAGESIZE = 0x1e
 
 type Termios struct {
diff --git a/unix/ztypes_linux_s390x.go b/unix/ztypes_linux_s390x.go
index a5c40b8..b408752 100644
--- a/unix/ztypes_linux_s390x.go
+++ b/unix/ztypes_linux_s390x.go
@@ -684,6 +684,8 @@
 	_ [16]uint64
 }
 
+const RNDGETENTCNT = 0x80045200
+
 const _SC_PAGESIZE = 0x1e
 
 type Termios struct {