Coverage Report

Created: 2025-10-28 06:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rustix-1.1.2/src/ioctl/linux.rs
Line
Count
Source
1
//! `ioctl` opcode behavior for Linux platforms.
2
3
use super::{Direction, Opcode};
4
use consts::*;
5
6
/// Compose an opcode from its component parts.
7
0
pub(super) const fn compose_opcode(
8
0
    dir: Direction,
9
0
    group: Opcode,
10
0
    num: Opcode,
11
0
    size: Opcode,
12
0
) -> Opcode {
13
    macro_rules! mask_and_shift {
14
        ($val:expr, $shift:expr, $mask:expr) => {{
15
            ($val & $mask) << $shift
16
        }};
17
    }
18
19
0
    let dir = match dir {
20
0
        Direction::None => NONE,
21
0
        Direction::Read => READ,
22
0
        Direction::Write => WRITE,
23
0
        Direction::ReadWrite => READ | WRITE,
24
    };
25
26
0
    mask_and_shift!(group, GROUP_SHIFT, GROUP_MASK)
27
0
        | mask_and_shift!(num, NUM_SHIFT, NUM_MASK)
28
0
        | mask_and_shift!(size, SIZE_SHIFT, SIZE_MASK)
29
0
        | mask_and_shift!(dir, DIR_SHIFT, DIR_MASK)
30
0
}
31
32
const NUM_BITS: Opcode = 8;
33
const GROUP_BITS: Opcode = 8;
34
35
const NUM_SHIFT: Opcode = 0;
36
const GROUP_SHIFT: Opcode = NUM_SHIFT + NUM_BITS;
37
const SIZE_SHIFT: Opcode = GROUP_SHIFT + GROUP_BITS;
38
const DIR_SHIFT: Opcode = SIZE_SHIFT + SIZE_BITS;
39
40
const NUM_MASK: Opcode = (1 << NUM_BITS) - 1;
41
const GROUP_MASK: Opcode = (1 << GROUP_BITS) - 1;
42
const SIZE_MASK: Opcode = (1 << SIZE_BITS) - 1;
43
const DIR_MASK: Opcode = (1 << DIR_BITS) - 1;
44
45
#[cfg(any(
46
    target_arch = "x86",
47
    target_arch = "arm",
48
    target_arch = "s390x",
49
    target_arch = "x86_64",
50
    target_arch = "aarch64",
51
    target_arch = "riscv32",
52
    target_arch = "riscv64",
53
    target_arch = "loongarch64",
54
    target_arch = "csky"
55
))]
56
mod consts {
57
    use super::Opcode;
58
59
    pub(super) const NONE: Opcode = 0;
60
    pub(super) const READ: Opcode = 2;
61
    pub(super) const WRITE: Opcode = 1;
62
    pub(super) const SIZE_BITS: Opcode = 14;
63
    pub(super) const DIR_BITS: Opcode = 2;
64
}
65
66
#[cfg(any(
67
    target_arch = "mips",
68
    target_arch = "mips32r6",
69
    target_arch = "mips64",
70
    target_arch = "mips64r6",
71
    target_arch = "powerpc",
72
    target_arch = "powerpc64",
73
    target_arch = "sparc",
74
    target_arch = "sparc64"
75
))]
76
mod consts {
77
    use super::Opcode;
78
79
    pub(super) const NONE: Opcode = 1;
80
    pub(super) const READ: Opcode = 2;
81
    pub(super) const WRITE: Opcode = 4;
82
    pub(super) const SIZE_BITS: Opcode = 13;
83
    pub(super) const DIR_BITS: Opcode = 3;
84
}
85
86
#[cfg(test)]
87
mod tests {
88
    #[allow(unused_imports)]
89
    use super::*;
90
91
    #[cfg(all(linux_raw_dep, not(any(
92
    // These have no ioctl opcodes defined in linux_raw_sys so we can't use
93
    // that as a known-good value for this test.
94
    target_arch = "sparc",
95
    target_arch = "sparc64"
96
))))]
97
    #[test]
98
    fn check_known_opcodes() {
99
        use crate::backend::c::{c_long, c_uint};
100
        use core::mem::size_of;
101
102
        // _IOR('U', 15, unsigned int)
103
        assert_eq!(
104
            compose_opcode(
105
                Direction::Read,
106
                b'U' as Opcode,
107
                15,
108
                size_of::<c_uint>() as Opcode
109
            ),
110
            linux_raw_sys::ioctl::USBDEVFS_CLAIMINTERFACE as Opcode
111
        );
112
113
        // _IOW('v', 2, long)
114
        assert_eq!(
115
            compose_opcode(
116
                Direction::Write,
117
                b'v' as Opcode,
118
                2,
119
                size_of::<c_long>() as Opcode
120
            ),
121
            linux_raw_sys::ioctl::FS_IOC_SETVERSION as Opcode
122
        );
123
    }
124
}