Skip to content

proposal: x/sys/unix: add IoctlRetInt() #33966

@kolyshkin

Description

@kolyshkin

I propose to add the following function to x/sys/unix:

// IoctlRetInt performs an ioctl operation specified by req on a device
// associated with opened file descriptor fd, and returns a non-negative
// integer that is returned by the ioctl syscall. 
func IoctlRetInt(fd int, req uint) (int, error) {
	ret, _, err := unix.Syscall(unix.SYS_IOCTL, fd, req, 0)
 	if err != 0 {
 		return 0, err
 	}
 	return int(ret), nil
}

and amend the IoctlGetInt() documentation with the following text:

A few ioctl requests use the return value as an output parameter;
for those, use IoctlRetInt instead of this function.

Motivation

Currently, x/sys/unix provides a few functions to deal with ioctls. In particular, IoctlGetInt(), which "performs an ioctl operation which gets an integer value". It does that by passing a pointer to an integer to a syscall and returning that integer. The value returned from syscall is treated as success/failure flag (0 means success, -1 means failure, and in such case errno is used to figure out the underlying error).

It appears that there are a few ioctls in Linux (I'm not sure about other OSs) that does not use the above way to return an int, but rather they use the syscall's return value (in case it's not negative). As ioctl(2) man page says,

RETURN VALUE
Usually, on success zero is returned. A few ioctl() requests use the return value as an
output parameter and return a nonnegative value on success. On error, -1 is returned,
and errno is set appropriately.

Currently I am aware of at least 6 ioctls that do that (return the value directly):

  • LOOP_CTL_* ioctls on /dev/loop-control (all 3 of them). Source: loop(4)
  • NS_* ioctls (3 out of 4) on /proc/PID/ns/*. Source: ioctl_ns(2)

There might be some more, but since in general ioctls are not well documented and there's no definitive list. I am not sure how many more are there.

Obviously, using IoctlGetInt() for such ioctls would be a big mistake, as 0 will always be returned. For example, here is the bug in Docker: moby/moby#39801

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions