Skip to content

Commit dc7075d

Browse files
authored
Merge pull request #1626 from hermit-os/fcntl-f_getfl
feat(fd): implement `fcntl(F_GETFL)`
2 parents 56627cc + 7f5cd30 commit dc7075d

File tree

6 files changed

+103
-69
lines changed

6 files changed

+103
-69
lines changed

src/fd/mod.rs

+16-11
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,6 @@ pub(crate) enum SocketOption {
4848
TcpNoDelay,
4949
}
5050

51-
#[allow(dead_code)]
52-
#[derive(Debug, PartialEq)]
53-
pub(crate) enum IoCtl {
54-
NonBlocking,
55-
}
56-
5751
pub(crate) type FileDescriptor = i32;
5852

5953
bitflags! {
@@ -66,13 +60,20 @@ bitflags! {
6660
const O_CREAT = 0o0100;
6761
const O_EXCL = 0o0200;
6862
const O_TRUNC = 0o1000;
69-
const O_APPEND = 0o2000;
70-
const O_NONBLOCK = 0o4000;
7163
const O_DIRECT = 0o40000;
7264
const O_DIRECTORY = 0o200_000;
7365
}
7466
}
7567

68+
bitflags! {
69+
/// File status flags.
70+
#[derive(Debug, Copy, Clone, Default)]
71+
pub struct StatusFlags: i32 {
72+
const O_APPEND = 0o2000;
73+
const O_NONBLOCK = 0o4000;
74+
}
75+
}
76+
7677
bitflags! {
7778
#[derive(Debug, Copy, Clone, Default)]
7879
pub struct PollEvent: i16 {
@@ -253,9 +254,13 @@ pub(crate) trait ObjectInterface: Sync + Send + core::fmt::Debug {
253254
Err(io::Error::ENOSYS)
254255
}
255256

256-
/// The `ioctl` function manipulates the underlying device parameters of special
257-
/// files.
258-
async fn ioctl(&self, _cmd: IoCtl, _value: bool) -> io::Result<()> {
257+
/// Returns the file status flags.
258+
async fn status_flags(&self) -> io::Result<StatusFlags> {
259+
Err(io::Error::ENOSYS)
260+
}
261+
262+
/// Sets the file status flags.
263+
async fn set_status_flags(&self, _status_flags: StatusFlags) -> io::Result<()> {
259264
Err(io::Error::ENOSYS)
260265
}
261266

src/fd/socket/tcp.rs

+19-16
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use smoltcp::time::Duration;
1313

1414
use crate::executor::block_on;
1515
use crate::executor::network::{Handle, NIC};
16-
use crate::fd::{Endpoint, IoCtl, ListenEndpoint, ObjectInterface, PollEvent, SocketOption};
16+
use crate::fd::{self, Endpoint, ListenEndpoint, ObjectInterface, PollEvent, SocketOption};
1717
use crate::{DEFAULT_KEEP_ALIVE_INTERVAL, io};
1818

1919
/// further receives will be disallowed
@@ -435,20 +435,19 @@ impl Socket {
435435
}
436436
}
437437

438-
async fn ioctl(&mut self, cmd: IoCtl, value: bool) -> io::Result<()> {
439-
if cmd == IoCtl::NonBlocking {
440-
if value {
441-
trace!("set device to nonblocking mode");
442-
self.is_nonblocking = true;
443-
} else {
444-
trace!("set device to blocking mode");
445-
self.is_nonblocking = false;
446-
}
447-
448-
Ok(())
438+
async fn status_flags(&self) -> io::Result<fd::StatusFlags> {
439+
let status_flags = if self.is_nonblocking {
440+
fd::StatusFlags::O_NONBLOCK
449441
} else {
450-
Err(io::Error::EINVAL)
451-
}
442+
fd::StatusFlags::empty()
443+
};
444+
445+
Ok(status_flags)
446+
}
447+
448+
async fn set_status_flags(&mut self, status_flags: fd::StatusFlags) -> io::Result<()> {
449+
self.is_nonblocking = status_flags.contains(fd::StatusFlags::O_NONBLOCK);
450+
Ok(())
452451
}
453452
}
454453

@@ -514,7 +513,11 @@ impl ObjectInterface for async_lock::RwLock<Socket> {
514513
self.read().await.shutdown(how).await
515514
}
516515

517-
async fn ioctl(&self, cmd: IoCtl, value: bool) -> io::Result<()> {
518-
self.write().await.ioctl(cmd, value).await
516+
async fn status_flags(&self) -> io::Result<fd::StatusFlags> {
517+
self.read().await.status_flags().await
518+
}
519+
520+
async fn set_status_flags(&self, status_flags: fd::StatusFlags) -> io::Result<()> {
521+
self.write().await.set_status_flags(status_flags).await
519522
}
520523
}

src/fd/socket/udp.rs

+19-16
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use smoltcp::wire::IpEndpoint;
1010

1111
use crate::executor::block_on;
1212
use crate::executor::network::{Handle, NIC};
13-
use crate::fd::{Endpoint, IoCtl, ListenEndpoint, ObjectInterface, PollEvent};
13+
use crate::fd::{self, Endpoint, ListenEndpoint, ObjectInterface, PollEvent};
1414
use crate::io;
1515

1616
#[derive(Debug)]
@@ -214,20 +214,19 @@ impl Socket {
214214
}
215215
}
216216

217-
async fn ioctl(&mut self, cmd: IoCtl, value: bool) -> io::Result<()> {
218-
if cmd == IoCtl::NonBlocking {
219-
if value {
220-
info!("set device to nonblocking mode");
221-
self.nonblocking = true;
222-
} else {
223-
info!("set device to blocking mode");
224-
self.nonblocking = false;
225-
}
226-
227-
Ok(())
217+
async fn status_flags(&self) -> io::Result<fd::StatusFlags> {
218+
let status_flags = if self.nonblocking {
219+
fd::StatusFlags::O_NONBLOCK
228220
} else {
229-
Err(io::Error::EINVAL)
230-
}
221+
fd::StatusFlags::empty()
222+
};
223+
224+
Ok(status_flags)
225+
}
226+
227+
async fn set_status_flags(&mut self, status_flags: fd::StatusFlags) -> io::Result<()> {
228+
self.nonblocking = status_flags.contains(fd::StatusFlags::O_NONBLOCK);
229+
Ok(())
231230
}
232231
}
233232

@@ -268,7 +267,11 @@ impl ObjectInterface for async_lock::RwLock<Socket> {
268267
self.read().await.write(buf).await
269268
}
270269

271-
async fn ioctl(&self, cmd: IoCtl, value: bool) -> io::Result<()> {
272-
self.write().await.ioctl(cmd, value).await
270+
async fn status_flags(&self) -> io::Result<fd::StatusFlags> {
271+
self.read().await.status_flags().await
272+
}
273+
274+
async fn set_status_flags(&self, status_flags: fd::StatusFlags) -> io::Result<()> {
275+
self.write().await.set_status_flags(status_flags).await
273276
}
274277
}

src/fd/socket/vsock.rs

+19-16
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::arch::kernel::mmio as hardware;
1414
#[cfg(feature = "pci")]
1515
use crate::drivers::pci as hardware;
1616
use crate::executor::vsock::{VSOCK_MAP, VsockState};
17-
use crate::fd::{Endpoint, IoCtl, ListenEndpoint, ObjectInterface, PollEvent};
17+
use crate::fd::{self, Endpoint, ListenEndpoint, ObjectInterface, PollEvent};
1818
use crate::io::{self, Error};
1919

2020
#[derive(Debug)]
@@ -297,20 +297,19 @@ impl Socket {
297297
Ok(())
298298
}
299299

300-
async fn ioctl(&mut self, cmd: IoCtl, value: bool) -> io::Result<()> {
301-
if cmd == IoCtl::NonBlocking {
302-
if value {
303-
trace!("set vsock device to nonblocking mode");
304-
self.is_nonblocking = true;
305-
} else {
306-
trace!("set vsock device to blocking mode");
307-
self.is_nonblocking = false;
308-
}
309-
310-
Ok(())
300+
async fn status_flags(&self) -> io::Result<fd::StatusFlags> {
301+
let status_flags = if self.is_nonblocking {
302+
fd::StatusFlags::O_NONBLOCK
311303
} else {
312-
Err(io::Error::EINVAL)
313-
}
304+
fd::StatusFlags::empty()
305+
};
306+
307+
Ok(status_flags)
308+
}
309+
310+
async fn set_status_flags(&mut self, status_flags: fd::StatusFlags) -> io::Result<()> {
311+
self.is_nonblocking = status_flags.contains(fd::StatusFlags::O_NONBLOCK);
312+
Ok(())
314313
}
315314

316315
async fn read(&self, buffer: &mut [MaybeUninit<u8>]) -> io::Result<usize> {
@@ -462,7 +461,11 @@ impl ObjectInterface for async_lock::RwLock<Socket> {
462461
self.read().await.shutdown(how).await
463462
}
464463

465-
async fn ioctl(&self, cmd: IoCtl, value: bool) -> io::Result<()> {
466-
self.write().await.ioctl(cmd, value).await
464+
async fn status_flags(&self) -> io::Result<fd::StatusFlags> {
465+
self.read().await.status_flags().await
466+
}
467+
468+
async fn set_status_flags(&self, status_flags: fd::StatusFlags) -> io::Result<()> {
469+
self.write().await.set_status_flags(status_flags).await
467470
}
468471
}

src/syscalls/mod.rs

+25-5
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub use self::tasks::*;
2121
pub use self::timer::*;
2222
use crate::executor::block_on;
2323
use crate::fd::{
24-
AccessPermission, EventFlags, FileDescriptor, IoCtl, OpenOption, PollFd, dup_object,
24+
self, AccessPermission, EventFlags, FileDescriptor, OpenOption, PollFd, dup_object,
2525
dup_object2, get_object, isatty, remove_object,
2626
};
2727
use crate::fs::{self, FileAttr};
@@ -515,12 +515,17 @@ pub unsafe extern "C" fn sys_ioctl(
515515

516516
if cmd == FIONBIO {
517517
let value = unsafe { *(argp as *const i32) };
518+
let status_flags = if value != 0 {
519+
fd::StatusFlags::O_NONBLOCK
520+
} else {
521+
fd::StatusFlags::empty()
522+
};
518523

519524
let obj = get_object(fd);
520525
obj.map_or_else(
521526
|e| -num::ToPrimitive::to_i32(&e).unwrap(),
522527
|v| {
523-
block_on((*v).ioctl(IoCtl::NonBlocking, value != 0), None)
528+
block_on((*v).set_status_flags(status_flags), None)
524529
.map_or_else(|e| -num::ToPrimitive::to_i32(&e).unwrap(), |()| 0)
525530
},
526531
)
@@ -534,18 +539,33 @@ pub unsafe extern "C" fn sys_ioctl(
534539
#[unsafe(no_mangle)]
535540
pub extern "C" fn sys_fcntl(fd: i32, cmd: i32, arg: i32) -> i32 {
536541
const F_SETFD: i32 = 2;
542+
const F_GETFL: i32 = 3;
537543
const F_SETFL: i32 = 4;
538544
const FD_CLOEXEC: i32 = 1;
539545

540546
if cmd == F_SETFD && arg == FD_CLOEXEC {
541547
0
542-
} else if cmd == F_SETFL && arg == OpenOption::O_NONBLOCK.bits() {
548+
} else if cmd == F_GETFL {
543549
let obj = get_object(fd);
544550
obj.map_or_else(
545551
|e| -num::ToPrimitive::to_i32(&e).unwrap(),
546552
|v| {
547-
block_on((*v).ioctl(IoCtl::NonBlocking, true), None)
548-
.map_or_else(|e| -num::ToPrimitive::to_i32(&e).unwrap(), |()| 0)
553+
block_on((*v).status_flags(), None).map_or_else(
554+
|e| -num::ToPrimitive::to_i32(&e).unwrap(),
555+
|status_flags| status_flags.bits(),
556+
)
557+
},
558+
)
559+
} else if cmd == F_SETFL {
560+
let obj = get_object(fd);
561+
obj.map_or_else(
562+
|e| -num::ToPrimitive::to_i32(&e).unwrap(),
563+
|v| {
564+
block_on(
565+
(*v).set_status_flags(fd::StatusFlags::from_bits_retain(arg)),
566+
None,
567+
)
568+
.map_or_else(|e| -num::ToPrimitive::to_i32(&e).unwrap(), |()| 0)
549569
},
550570
)
551571
} else {

src/syscalls/socket.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ use crate::fd::socket::udp;
2020
#[cfg(feature = "vsock")]
2121
use crate::fd::socket::vsock::{self, VsockEndpoint, VsockListenEndpoint};
2222
use crate::fd::{
23-
Endpoint, ListenEndpoint, ObjectInterface, SocketOption, get_object, insert_object,
23+
self, Endpoint, ListenEndpoint, ObjectInterface, SocketOption, get_object, insert_object,
2424
};
25-
use crate::syscalls::{IoCtl, block_on};
25+
use crate::syscalls::block_on;
2626

2727
pub const AF_INET: i32 = 0;
2828
pub const AF_INET6: i32 = 1;
@@ -427,7 +427,7 @@ pub extern "C" fn sys_socket(domain: i32, type_: SockType, protocol: i32) -> i32
427427
let socket = Arc::new(async_lock::RwLock::new(vsock::Socket::new()));
428428

429429
if type_.contains(SockType::SOCK_NONBLOCK) {
430-
block_on(socket.ioctl(IoCtl::NonBlocking, true), None).unwrap();
430+
block_on(socket.set_status_flags(fd::StatusFlags::O_NONBLOCK), None).unwrap();
431431
}
432432

433433
let fd = insert_object(socket).expect("FD is already used");
@@ -449,7 +449,7 @@ pub extern "C" fn sys_socket(domain: i32, type_: SockType, protocol: i32) -> i32
449449
let socket = Arc::new(async_lock::RwLock::new(udp::Socket::new(handle)));
450450

451451
if type_.contains(SockType::SOCK_NONBLOCK) {
452-
block_on(socket.ioctl(IoCtl::NonBlocking, true), None).unwrap();
452+
block_on(socket.set_status_flags(fd::StatusFlags::O_NONBLOCK), None).unwrap();
453453
}
454454

455455
let fd = insert_object(socket).expect("FD is already used");
@@ -464,7 +464,7 @@ pub extern "C" fn sys_socket(domain: i32, type_: SockType, protocol: i32) -> i32
464464
let socket = Arc::new(async_lock::RwLock::new(tcp::Socket::new(handle)));
465465

466466
if type_.contains(SockType::SOCK_NONBLOCK) {
467-
block_on(socket.ioctl(IoCtl::NonBlocking, true), None).unwrap();
467+
block_on(socket.set_status_flags(fd::StatusFlags::O_NONBLOCK), None).unwrap();
468468
}
469469

470470
let fd = insert_object(socket).expect("FD is already used");

0 commit comments

Comments
 (0)