linux_io/fd/
fcntl.rs

1//! A safer abstraction for `fcntl`.
2//!
3//! The `fcntl` system call is very open-ended, supporting a variety of
4//! different operations with different argument and result types. Passing
5//! the wrong kind of value to the wrong command can cause memory corruption.
6//!
7//! To make `fcntl` a _little_ safer to use, this module provides command
8//! constants that also include information about the argument and result
9//! types, so that the [`super::File::fcntl`] method can then provide a
10//! type-safe interface as long as these constants are defined correctly.
11
12use linux_unsafe::args::AsRawV;
13use linux_unsafe::int;
14
15/// Duplicate the file descriptor fd using the lowest-numbered
16/// available file descriptor greater than or equal to `arg`.
17pub const F_DUPFD: DirectFcntlCmd<int, super::File> = unsafe { fcntl_cmd(0) };
18
19/// Retrieve the function descriptor flags.
20pub const F_GETFD: DirectFcntlCmd<(), int> = unsafe { fcntl_cmd(1) };
21
22/// Set the function descriptor flags.
23pub const F_SETFD: DirectFcntlCmd<int, ()> = unsafe { fcntl_cmd(2) };
24
25/// Retrieve the file access mode and the file status flags.
26pub const F_GETFL: DirectFcntlCmd<(), int> = unsafe { fcntl_cmd(3) };
27
28/// Set the file status flags.
29pub const F_SETFL: DirectFcntlCmd<int, ()> = unsafe { fcntl_cmd(4) };
30
31/// Place a lock on the file.
32pub const F_GETLK: MutPtrFcntlCmd<linux_unsafe::flock, ()> = unsafe { fcntl_cmd_mut_ptr(5) };
33
34/// Acquire a lock or release a lock on the file.
35pub const F_SETLK: MutPtrFcntlCmd<linux_unsafe::flock, ()> = unsafe { fcntl_cmd_mut_ptr(6) };
36
37/// Acquire a lock or release a lock on the file, waiting for any conflicting
38/// lock to be released.
39pub const F_SETLKW: MutPtrFcntlCmd<linux_unsafe::flock, ()> = unsafe { fcntl_cmd_mut_ptr(7) };
40
41/// Place a lock on the file description of the file.
42pub const F_OFD_GETLK: MutPtrFcntlCmd<linux_unsafe::flock, ()> = unsafe { fcntl_cmd_mut_ptr(36) };
43
44/// Acquire a lock or release a lock on the file description of the file.
45pub const F_OFD_SETLK: MutPtrFcntlCmd<linux_unsafe::flock, ()> = unsafe { fcntl_cmd_mut_ptr(37) };
46
47/// Acquire a lock or release a lock on the file description of the file,
48/// waiting for any conflicting lock to be released.
49pub const F_OFD_SETLKW: MutPtrFcntlCmd<linux_unsafe::flock, ()> = unsafe { fcntl_cmd_mut_ptr(38) };
50
51const F_LINUX_SPECIFIC_BASE: int = 1024;
52
53/// Duplicate the file descriptor fd using the lowest-numbered
54/// available file descriptor greater than or equal to `arg`,
55/// setting the `FD_CLOEXEC` flag on the new descriptor.
56pub const F_DUPFD_CLOEXEC: DirectFcntlCmd<int, int> =
57    unsafe { fcntl_cmd(F_LINUX_SPECIFIC_BASE + 6) };
58
59/// Represents a particular command that can be used with the `fcntl` system call.
60///
61/// Safety: Implementers must ensure that they only generate valid combinations
62/// of `fcntl` command and raw argument.
63pub unsafe trait FcntlCmd<'a> {
64    /// The type that the caller will provide when using this `fcntl` command.
65    type ExtArg
66    where
67        Self: 'a;
68
69    /// The type of argument that will be passed to the raw system call.
70    type RawArg: AsRawV;
71
72    /// The type of the result of the `fcntl` call.
73    type Result;
74
75    /// Prepare the `cmd` and `arg` values for a `fcntl` system call.
76    fn prepare_fcntl_args(&self, arg: Self::ExtArg) -> (int, Self::RawArg);
77
78    /// Prepare a raw successful result from a `fcntl` call to be returned.
79    fn prepare_fcntl_result(&self, raw: int) -> Self::Result;
80}
81
82/// Constructs a new "simple" [`FcntlCmd`] with a fixed command code and
83/// an argument type that maps directly to the raw system call argument.
84///
85/// Safety: Callers must ensure that the given `cmd` is valid and that
86/// type `T` is the type that command expects.
87pub const unsafe fn fcntl_cmd<Arg, Result>(cmd: int) -> DirectFcntlCmd<Arg, Result>
88where
89    Arg: AsRawV,
90    Result: FromFcntlResult,
91{
92    DirectFcntlCmd::<Arg, Result> {
93        cmd,
94        _phantom: core::marker::PhantomData,
95    }
96}
97
98/// Constructs a new [`FcntlCmd`] with a fixed command code and
99/// an argument type that will be passed as a raw const pointer.
100///
101/// Safety: Callers must ensure that the given `cmd` is valid and that
102/// type `T` is the type that command expects.
103pub const unsafe fn fcntl_cmd_const_ptr<Arg, Result>(cmd: int) -> ConstPtrFcntlCmd<Arg, Result>
104where
105    *const Arg: AsRawV,
106    Result: FromFcntlResult,
107{
108    ConstPtrFcntlCmd::<Arg, Result> {
109        cmd,
110        _phantom: core::marker::PhantomData,
111    }
112}
113
114/// Constructs a new [`FcntlCmd`] with a fixed command code and
115/// an argument type that will be passed as a raw mut pointer.
116///
117/// Safety: Callers must ensure that the given `cmd` is valid and that
118/// type `T` is the type that command expects.
119pub const unsafe fn fcntl_cmd_mut_ptr<Arg, Result>(cmd: int) -> MutPtrFcntlCmd<Arg, Result>
120where
121    *mut Arg: AsRawV,
122    Result: FromFcntlResult,
123{
124    MutPtrFcntlCmd::<Arg, Result> {
125        cmd,
126        _phantom: core::marker::PhantomData,
127    }
128}
129
130/// Implementation of [`FcntlCmd`] with a fixed `cmd` value and passing the
131/// arg directly through to the underlying system call.
132#[repr(transparent)]
133pub struct DirectFcntlCmd<Arg: AsRawV, Result: FromFcntlResult> {
134    cmd: int,
135    _phantom: core::marker::PhantomData<(Arg, Result)>,
136}
137
138unsafe impl<'a, Arg: AsRawV, Result: FromFcntlResult> FcntlCmd<'a> for DirectFcntlCmd<Arg, Result> {
139    type ExtArg = Arg where Self: 'a;
140    type RawArg = Arg;
141
142    fn prepare_fcntl_args(&self, arg: Arg) -> (int, Self::RawArg) {
143        (self.cmd, arg)
144    }
145
146    type Result = Result;
147
148    fn prepare_fcntl_result(&self, raw: int) -> Self::Result {
149        unsafe { Self::Result::prepare_result(raw) }
150    }
151}
152
153/// Implementation of [`FcntlCmd`] with a fixed `cmd` value and passing the
154/// arg through to the underlying system call as a raw const pointer.
155#[repr(transparent)]
156pub struct ConstPtrFcntlCmd<Arg, Result: FromFcntlResult> {
157    cmd: int,
158    _phantom: core::marker::PhantomData<(Arg, Result)>,
159}
160
161unsafe impl<'a, Arg, Result: FromFcntlResult> FcntlCmd<'a> for ConstPtrFcntlCmd<Arg, Result> {
162    type ExtArg = &'a Arg where Self: 'a;
163    type RawArg = *const Arg;
164
165    fn prepare_fcntl_args(&self, arg: &'a Arg) -> (int, Self::RawArg) {
166        (self.cmd, arg as *const Arg)
167    }
168
169    type Result = Result;
170
171    fn prepare_fcntl_result(&self, raw: int) -> Self::Result {
172        unsafe { Self::Result::prepare_result(raw) }
173    }
174}
175
176/// Implementation of [`FcntlCmd`] with a fixed `cmd` value and passing the
177/// arg through to the underlying system call as a raw mut pointer.
178#[repr(transparent)]
179pub struct MutPtrFcntlCmd<Arg, Result: FromFcntlResult> {
180    cmd: int,
181    _phantom: core::marker::PhantomData<(Arg, Result)>,
182}
183
184unsafe impl<'a, Arg, Result: FromFcntlResult> FcntlCmd<'a> for MutPtrFcntlCmd<Arg, Result> {
185    type ExtArg = &'a mut Arg where Self: 'a;
186    type RawArg = *mut Arg;
187
188    fn prepare_fcntl_args(&self, arg: &'a mut Arg) -> (int, Self::RawArg) {
189        (self.cmd, arg as *mut Arg)
190    }
191
192    type Result = Result;
193
194    fn prepare_fcntl_result(&self, raw: int) -> Self::Result {
195        unsafe { Self::Result::prepare_result(raw) }
196    }
197}
198
199/// Trait for types that can be returned by `fcntl` calls.
200pub trait FromFcntlResult {
201    unsafe fn prepare_result(raw: int) -> Self;
202}
203
204impl FromFcntlResult for int {
205    #[inline(always)]
206    unsafe fn prepare_result(raw: int) -> Self {
207        raw
208    }
209}
210
211impl FromFcntlResult for () {
212    #[inline(always)]
213    unsafe fn prepare_result(_: int) -> () {
214        ()
215    }
216}
217
218impl FromFcntlResult for super::File {
219    #[inline(always)]
220    unsafe fn prepare_result(raw: int) -> Self {
221        super::File::from_raw_fd(raw)
222    }
223}