unix: match ioctl req argument type to libc type

On Solaris, AIX, and zOS, the req argument of ioctl() is a signed int,
not an unsigned long like on other platforms, which means many constants
are negative, causing friction when passing them to a uint argument.
Correct the signature of these functions to pass the req argument as
signed, just like libc.

Fixes golang/go#59030.

Change-Id: Ia14e92a150f4b5fb9488c5032ca296cb786e9811
Reviewed-on: https://go-review.googlesource.com/c/sys/+/476515
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Bryan Mills <bcmills@google.com>
Run-TryBot: Jason Donenfeld <Jason@zx2c4.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Nahum Shalman <nahamu@gmail.com>
diff --git a/unix/ioctl.go b/unix/ioctl_signed.go
similarity index 75%
copy from unix/ioctl.go
copy to unix/ioctl_signed.go
index 7ce8dd4..7def958 100644
--- a/unix/ioctl.go
+++ b/unix/ioctl_signed.go
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris
+//go:build aix || solaris
+// +build aix solaris
 
 package unix
 
@@ -16,7 +16,7 @@
 
 // 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) error {
+func IoctlSetInt(fd int, req int, value int) error {
 	return ioctl(fd, req, uintptr(value))
 }
 
@@ -24,7 +24,7 @@
 // integer value on fd, using the specified request number. The ioctl
 // argument is called with a pointer to the integer value, rather than
 // passing the integer value directly.
-func IoctlSetPointerInt(fd int, req uint, value int) error {
+func IoctlSetPointerInt(fd int, req int, value int) error {
 	v := int32(value)
 	return ioctlPtr(fd, req, unsafe.Pointer(&v))
 }
@@ -32,7 +32,7 @@
 // IoctlSetWinsize performs an ioctl on fd with a *Winsize argument.
 //
 // To change fd's window size, the req argument should be TIOCSWINSZ.
-func IoctlSetWinsize(fd int, req uint, value *Winsize) error {
+func IoctlSetWinsize(fd int, req int, value *Winsize) error {
 	// TODO: if we get the chance, remove the req parameter and
 	// hardcode TIOCSWINSZ.
 	return ioctlPtr(fd, req, unsafe.Pointer(value))
@@ -41,7 +41,7 @@
 // IoctlSetTermios performs an ioctl on fd with a *Termios.
 //
 // The req value will usually be TCSETA or TIOCSETA.
-func IoctlSetTermios(fd int, req uint, value *Termios) error {
+func IoctlSetTermios(fd int, req int, value *Termios) error {
 	// TODO: if we get the chance, remove the req parameter.
 	return ioctlPtr(fd, req, unsafe.Pointer(value))
 }
@@ -51,19 +51,19 @@
 //
 // A few ioctl requests use the return value as an output parameter;
 // for those, IoctlRetInt should be used instead of this function.
-func IoctlGetInt(fd int, req uint) (int, error) {
+func IoctlGetInt(fd int, req int) (int, error) {
 	var value int
 	err := ioctlPtr(fd, req, unsafe.Pointer(&value))
 	return value, err
 }
 
-func IoctlGetWinsize(fd int, req uint) (*Winsize, error) {
+func IoctlGetWinsize(fd int, req int) (*Winsize, error) {
 	var value Winsize
 	err := ioctlPtr(fd, req, unsafe.Pointer(&value))
 	return &value, err
 }
 
-func IoctlGetTermios(fd int, req uint) (*Termios, error) {
+func IoctlGetTermios(fd int, req int) (*Termios, error) {
 	var value Termios
 	err := ioctlPtr(fd, req, unsafe.Pointer(&value))
 	return &value, err
diff --git a/unix/ioctl.go b/unix/ioctl_unsigned.go
similarity index 92%
rename from unix/ioctl.go
rename to unix/ioctl_unsigned.go
index 7ce8dd4..649913d 100644
--- a/unix/ioctl.go
+++ b/unix/ioctl_unsigned.go
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris
+//go:build darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd
+// +build darwin dragonfly freebsd hurd linux netbsd openbsd
 
 package unix
 
diff --git a/unix/ioctl_zos.go b/unix/ioctl_zos.go
index 6532f09..cdc21bf 100644
--- a/unix/ioctl_zos.go
+++ b/unix/ioctl_zos.go
@@ -17,14 +17,14 @@
 
 // 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) error {
+func IoctlSetInt(fd int, req int, value int) error {
 	return ioctl(fd, req, uintptr(value))
 }
 
 // IoctlSetWinsize performs an ioctl on fd with a *Winsize argument.
 //
 // To change fd's window size, the req argument should be TIOCSWINSZ.
-func IoctlSetWinsize(fd int, req uint, value *Winsize) error {
+func IoctlSetWinsize(fd int, req int, value *Winsize) error {
 	// TODO: if we get the chance, remove the req parameter and
 	// hardcode TIOCSWINSZ.
 	return ioctlPtr(fd, req, unsafe.Pointer(value))
@@ -33,7 +33,7 @@
 // IoctlSetTermios performs an ioctl on fd with a *Termios.
 //
 // The req value is expected to be TCSETS, TCSETSW, or TCSETSF
-func IoctlSetTermios(fd int, req uint, value *Termios) error {
+func IoctlSetTermios(fd int, req int, value *Termios) error {
 	if (req != TCSETS) && (req != TCSETSW) && (req != TCSETSF) {
 		return ENOSYS
 	}
@@ -47,13 +47,13 @@
 //
 // A few ioctl requests use the return value as an output parameter;
 // for those, IoctlRetInt should be used instead of this function.
-func IoctlGetInt(fd int, req uint) (int, error) {
+func IoctlGetInt(fd int, req int) (int, error) {
 	var value int
 	err := ioctlPtr(fd, req, unsafe.Pointer(&value))
 	return value, err
 }
 
-func IoctlGetWinsize(fd int, req uint) (*Winsize, error) {
+func IoctlGetWinsize(fd int, req int) (*Winsize, error) {
 	var value Winsize
 	err := ioctlPtr(fd, req, unsafe.Pointer(&value))
 	return &value, err
@@ -62,7 +62,7 @@
 // IoctlGetTermios performs an ioctl on fd with a *Termios.
 //
 // The req value is expected to be TCGETS
-func IoctlGetTermios(fd int, req uint) (*Termios, error) {
+func IoctlGetTermios(fd int, req int) (*Termios, error) {
 	var value Termios
 	if req != TCGETS {
 		return &value, ENOSYS
diff --git a/unix/syscall_aix.go b/unix/syscall_aix.go
index d9f5544..c406ae0 100644
--- a/unix/syscall_aix.go
+++ b/unix/syscall_aix.go
@@ -408,8 +408,8 @@
 
 func (w WaitStatus) TrapCause() int { return -1 }
 
-//sys	ioctl(fd int, req uint, arg uintptr) (err error)
-//sys	ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) = ioctl
+//sys	ioctl(fd int, req int, arg uintptr) (err error)
+//sys	ioctlPtr(fd int, req int, arg unsafe.Pointer) (err error) = ioctl
 
 // fcntl must never be called with cmd=F_DUP2FD because it doesn't work on AIX
 // There is no way to create a custom fcntl and to keep //sys fcntl easily,
diff --git a/unix/syscall_solaris.go b/unix/syscall_solaris.go
index 3120d44..b600a28 100644
--- a/unix/syscall_solaris.go
+++ b/unix/syscall_solaris.go
@@ -545,24 +545,24 @@
  * Expose the ioctl function
  */
 
-//sys	ioctlRet(fd int, req uint, arg uintptr) (ret int, err error) = libc.ioctl
-//sys	ioctlPtrRet(fd int, req uint, arg unsafe.Pointer) (ret int, err error) = libc.ioctl
+//sys	ioctlRet(fd int, req int, arg uintptr) (ret int, err error) = libc.ioctl
+//sys	ioctlPtrRet(fd int, req int, arg unsafe.Pointer) (ret int, err error) = libc.ioctl
 
-func ioctl(fd int, req uint, arg uintptr) (err error) {
+func ioctl(fd int, req int, arg uintptr) (err error) {
 	_, err = ioctlRet(fd, req, arg)
 	return err
 }
 
-func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) {
+func ioctlPtr(fd int, req int, arg unsafe.Pointer) (err error) {
 	_, err = ioctlPtrRet(fd, req, arg)
 	return err
 }
 
-func IoctlSetTermio(fd int, req uint, value *Termio) error {
+func IoctlSetTermio(fd int, req int, value *Termio) error {
 	return ioctlPtr(fd, req, unsafe.Pointer(value))
 }
 
-func IoctlGetTermio(fd int, req uint) (*Termio, error) {
+func IoctlGetTermio(fd int, req int) (*Termio, error) {
 	var value Termio
 	err := ioctlPtr(fd, req, unsafe.Pointer(&value))
 	return &value, err
@@ -1079,11 +1079,11 @@
 	return retCl, retData, flags, nil
 }
 
-func IoctlSetIntRetInt(fd int, req uint, arg int) (int, error) {
+func IoctlSetIntRetInt(fd int, req int, arg int) (int, error) {
 	return ioctlRet(fd, req, uintptr(arg))
 }
 
-func IoctlSetString(fd int, req uint, val string) error {
+func IoctlSetString(fd int, req int, val string) error {
 	bs := make([]byte, len(val)+1)
 	copy(bs[:len(bs)-1], val)
 	err := ioctlPtr(fd, req, unsafe.Pointer(&bs[0]))
@@ -1119,7 +1119,7 @@
 	return *(*uint)(unsafe.Pointer(&l.Lifru[0]))
 }
 
-func IoctlLifreq(fd int, req uint, l *Lifreq) error {
+func IoctlLifreq(fd int, req int, l *Lifreq) error {
 	return ioctlPtr(fd, req, unsafe.Pointer(l))
 }
 
@@ -1130,6 +1130,6 @@
 	s.Dp = (*int8)(unsafe.Pointer(&i))
 }
 
-func IoctlSetStrioctlRetInt(fd int, req uint, s *Strioctl) (int, error) {
+func IoctlSetStrioctlRetInt(fd int, req int, s *Strioctl) (int, error) {
 	return ioctlPtrRet(fd, req, unsafe.Pointer(s))
 }
diff --git a/unix/syscall_solaris_test.go b/unix/syscall_solaris_test.go
index 88eccaf..773c28e 100644
--- a/unix/syscall_solaris_test.go
+++ b/unix/syscall_solaris_test.go
@@ -405,17 +405,13 @@
 	if err != nil {
 		t.Fatalf("could not open udp socket: %v", err)
 	}
-	// SIOCGLIFMTU is negative which confuses the compiler if used inline:
-	// Using "unix.IoctlLifreq(ip_fd, unix.SIOCGLIFMTU, &l)" results in
-	// "constant -1065850502 overflows uint"
-	reqnum := int(unix.SIOCGLIFMTU)
 	var l unix.Lifreq
 	for link, mtu := range tc {
 		err = l.SetName(link)
 		if err != nil {
 			t.Fatalf("Lifreq.SetName(%q) failed: %v", link, err)
 		}
-		if err = unix.IoctlLifreq(ip_fd, uint(reqnum), &l); err != nil {
+		if err = unix.IoctlLifreq(ip_fd, unix.SIOCGLIFMTU, &l); err != nil {
 			t.Fatalf("unable to SIOCGLIFMTU: %v", err)
 		}
 		m := l.GetLifruUint()
diff --git a/unix/syscall_zos_s390x.go b/unix/syscall_zos_s390x.go
index b295497..d3d49ec 100644
--- a/unix/syscall_zos_s390x.go
+++ b/unix/syscall_zos_s390x.go
@@ -212,8 +212,8 @@
 //sys	sendmsg(s int, msg *Msghdr, flags int) (n int, err error) = SYS___SENDMSG_A
 //sys   mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) = SYS_MMAP
 //sys   munmap(addr uintptr, length uintptr) (err error) = SYS_MUNMAP
-//sys   ioctl(fd int, req uint, arg uintptr) (err error) = SYS_IOCTL
-//sys   ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) = SYS_IOCTL
+//sys   ioctl(fd int, req int, arg uintptr) (err error) = SYS_IOCTL
+//sys   ioctlPtr(fd int, req int, arg unsafe.Pointer) (err error) = SYS_IOCTL
 
 //sys   Access(path string, mode uint32) (err error) = SYS___ACCESS_A
 //sys   Chdir(path string) (err error) = SYS___CHDIR_A
diff --git a/unix/zsyscall_aix_ppc.go b/unix/zsyscall_aix_ppc.go
index 0a9984e..9a25721 100644
--- a/unix/zsyscall_aix_ppc.go
+++ b/unix/zsyscall_aix_ppc.go
@@ -212,7 +212,7 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func ioctl(fd int, req uint, arg uintptr) (err error) {
+func ioctl(fd int, req int, arg uintptr) (err error) {
 	r0, er := C.ioctl(C.int(fd), C.int(req), C.uintptr_t(arg))
 	if r0 == -1 && er != nil {
 		err = er
@@ -222,7 +222,7 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) {
+func ioctlPtr(fd int, req int, arg unsafe.Pointer) (err error) {
 	r0, er := C.ioctl(C.int(fd), C.int(req), C.uintptr_t(uintptr(arg)))
 	if r0 == -1 && er != nil {
 		err = er
diff --git a/unix/zsyscall_aix_ppc64.go b/unix/zsyscall_aix_ppc64.go
index c3783bf..6de80c2 100644
--- a/unix/zsyscall_aix_ppc64.go
+++ b/unix/zsyscall_aix_ppc64.go
@@ -93,8 +93,8 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func ioctl(fd int, req uint, arg uintptr) (err error) {
-	_, e1 := callioctl(fd, int(req), arg)
+func ioctl(fd int, req int, arg uintptr) (err error) {
+	_, e1 := callioctl(fd, req, arg)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
@@ -103,8 +103,8 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) {
-	_, e1 := callioctl_ptr(fd, int(req), arg)
+func ioctlPtr(fd int, req int, arg unsafe.Pointer) (err error) {
+	_, e1 := callioctl_ptr(fd, req, arg)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/unix/zsyscall_solaris_amd64.go b/unix/zsyscall_solaris_amd64.go
index 305162f..609d1c5 100644
--- a/unix/zsyscall_solaris_amd64.go
+++ b/unix/zsyscall_solaris_amd64.go
@@ -643,7 +643,7 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func ioctlRet(fd int, req uint, arg uintptr) (ret int, err error) {
+func ioctlRet(fd int, req int, arg uintptr) (ret int, err error) {
 	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procioctl)), 3, uintptr(fd), uintptr(req), uintptr(arg), 0, 0, 0)
 	ret = int(r0)
 	if e1 != 0 {
@@ -654,7 +654,7 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func ioctlPtrRet(fd int, req uint, arg unsafe.Pointer) (ret int, err error) {
+func ioctlPtrRet(fd int, req int, arg unsafe.Pointer) (ret int, err error) {
 	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procioctl)), 3, uintptr(fd), uintptr(req), uintptr(arg), 0, 0, 0)
 	ret = int(r0)
 	if e1 != 0 {
diff --git a/unix/zsyscall_zos_s390x.go b/unix/zsyscall_zos_s390x.go
index 07bfe2e..c316817 100644
--- a/unix/zsyscall_zos_s390x.go
+++ b/unix/zsyscall_zos_s390x.go
@@ -257,7 +257,7 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func ioctl(fd int, req uint, arg uintptr) (err error) {
+func ioctl(fd int, req int, arg uintptr) (err error) {
 	_, _, e1 := syscall_syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
 	if e1 != 0 {
 		err = errnoErr(e1)
@@ -267,7 +267,7 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) {
+func ioctlPtr(fd int, req int, arg unsafe.Pointer) (err error) {
 	_, _, e1 := syscall_syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
 	if e1 != 0 {
 		err = errnoErr(e1)