summaryrefslogtreecommitdiff
path: root/cmd/ioworkload/scenario_ioctl.go
blob: ad7ed7d7c32ee2584c4aadc403a6ac2537abf1de (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package main

import (
	"fmt"
	"path/filepath"
	"syscall"

	"golang.org/x/sys/unix"
)

// fionread is the FIONREAD ioctl request (number of bytes available to read).
// golang.org/x/sys/unix does not export it as a portable constant, so we define
// it here. The value 0x541B is shared by the architectures this project targets
// (amd64, arm64; see scenario_mountfs.go's listns arch table).
const fionread = 0x541B

// ioctlBasic issues a benign, deterministic ioctl on a known fd so the
// enter_ioctl tracepoint fires under our control rather than only implicitly
// (via the Go runtime / terminal). ioctl is FamilyFS / KindFd (fd@arg0), so
// the captured event resolves the fd to the temp file path.
//
// We open a regular temp file and call FIONREAD via unix.IoctlGetInt, which
// reports the number of bytes available to read. On a regular file this is a
// harmless query that does not mutate state; we ignore its result. The file is
// cleaned up via the deferred cleanup.
func ioctlBasic() error {
	dir, cleanup, err := makeTempDir("ioctl-basic")
	if err != nil {
		return err
	}
	defer cleanup()

	path := filepath.Join(dir, "ioctlfile.txt")
	fd, err := syscall.Open(path, syscall.O_RDWR|syscall.O_CREAT, 0o644)
	if err != nil {
		return fmt.Errorf("open: %w", err)
	}
	defer syscall.Close(fd)

	// FIONREAD on a regular file is safe and portable. Even if the kernel
	// rejects it for this fd type, the enter_ioctl tracepoint fires on syscall
	// entry, so coverage holds regardless of the return value.
	if _, err := unix.IoctlGetInt(fd, fionread); err != nil {
		// Tolerated: the sys_enter_ioctl tracepoint has already fired.
		return nil
	}
	return nil
}