diff options
author | Dylan Reid <dgreid@chromium.org> | 2019-12-02 11:09:12 +1100 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2019-12-12 21:13:37 +0000 |
commit | eaff194759cb25d1bf2725a133ff92f092563675 (patch) | |
tree | 9df9a0950ac09603033d8ea57f5449a48f5914cb /sys_util | |
parent | 0a433f8ca98700062b786c3af42e1b4fef4f9674 (diff) | |
download | crosvm-eaff194759cb25d1bf2725a133ff92f092563675.tar crosvm-eaff194759cb25d1bf2725a133ff92f092563675.tar.gz crosvm-eaff194759cb25d1bf2725a133ff92f092563675.tar.bz2 crosvm-eaff194759cb25d1bf2725a133ff92f092563675.tar.lz crosvm-eaff194759cb25d1bf2725a133ff92f092563675.tar.xz crosvm-eaff194759cb25d1bf2725a133ff92f092563675.tar.zst crosvm-eaff194759cb25d1bf2725a133ff92f092563675.zip |
sys_util: Expose setting FD flags as a pub fn
Other users will want to set flags on FDs. Particularly asynchronous code that wants to set FDs as non-blocking. Add a helper that handles fetching and or-ing in the given flags so users don't have to handle that themselves. Signed-off-by: Dylan Reid <dgreid@chromium.org> Change-Id: Iabe438fbbb1ec305f693dbe1348930ef153edcf4 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1955044 Tested-by: kokoro <noreply+kokoro@google.com> Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Diffstat (limited to 'sys_util')
-rw-r--r-- | sys_util/src/lib.rs | 46 | ||||
-rw-r--r-- | sys_util/src/terminal.rs | 35 |
2 files changed, 50 insertions, 31 deletions
diff --git a/sys_util/src/lib.rs b/sys_util/src/lib.rs index 7f97650..bde5eb2 100644 --- a/sys_util/src/lib.rs +++ b/sys_util/src/lib.rs @@ -79,8 +79,8 @@ use std::os::unix::net::UnixDatagram; use std::ptr; use libc::{ - c_long, gid_t, kill, pid_t, pipe2, syscall, sysconf, uid_t, waitpid, O_CLOEXEC, SIGKILL, - WNOHANG, _SC_IOV_MAX, _SC_PAGESIZE, + c_int, c_long, fcntl, gid_t, kill, pid_t, pipe2, syscall, sysconf, uid_t, waitpid, F_GETFL, + F_SETFL, O_CLOEXEC, SIGKILL, WNOHANG, _SC_IOV_MAX, _SC_PAGESIZE, }; use syscall_defines::linux::LinuxSyscall::SYS_getpid; @@ -348,3 +348,45 @@ pub fn poll_in(fd: &dyn AsRawFd) -> bool { } fds.revents & libc::POLLIN != 0 } + +/// Returns the file flags set for the given `RawFD` +/// +/// Returns an error if the OS indicates the flags can't be retrieved. +fn get_fd_flags(fd: RawFd) -> Result<c_int> { + // Safe because no third parameter is expected and we check the return result. + let ret = unsafe { fcntl(fd, F_GETFL) }; + if ret < 0 { + return errno_result(); + } + Ok(ret) +} + +/// Sets the file flags set for the given `RawFD`. +/// +/// Returns an error if the OS indicates the flags can't be retrieved. +fn set_fd_flags(fd: RawFd, flags: c_int) -> Result<()> { + // Safe because we supply the third parameter and we check the return result. + // fcntlt is trusted not to modify the memory of the calling process. + let ret = unsafe { fcntl(fd, F_SETFL, flags) }; + if ret < 0 { + return errno_result(); + } + Ok(()) +} + +/// Performs a logical OR of the given flags with the FD's flags, setting the given bits for the +/// FD. +/// +/// Returns an error if the OS indicates the flags can't be retrieved or set. +pub fn add_fd_flags(fd: RawFd, set_flags: c_int) -> Result<()> { + let start_flags = get_fd_flags(fd)?; + set_fd_flags(fd, start_flags | set_flags) +} + +/// Clears the given flags in the FD's flags. +/// +/// Returns an error if the OS indicates the flags can't be retrieved or set. +pub fn clear_fd_flags(fd: RawFd, clear_flags: c_int) -> Result<()> { + let start_flags = get_fd_flags(fd)?; + set_fd_flags(fd, start_flags & !clear_flags) +} diff --git a/sys_util/src/terminal.rs b/sys_util/src/terminal.rs index fc90e45..eb5141c 100644 --- a/sys_util/src/terminal.rs +++ b/sys_util/src/terminal.rs @@ -7,11 +7,11 @@ use std::mem::zeroed; use std::os::unix::io::RawFd; use libc::{ - c_int, fcntl, isatty, read, tcgetattr, tcsetattr, termios, ECHO, F_GETFL, F_SETFL, ICANON, - ISIG, O_NONBLOCK, STDIN_FILENO, TCSANOW, + isatty, read, tcgetattr, tcsetattr, termios, ECHO, ICANON, ISIG, O_NONBLOCK, STDIN_FILENO, + TCSANOW, }; -use crate::{errno_result, Result}; +use crate::{add_fd_flags, clear_fd_flags, errno_result, Result}; fn modify_mode<F: FnOnce(&mut termios)>(fd: RawFd, f: F) -> Result<()> { // Safe because we check the return value of isatty. @@ -37,24 +37,6 @@ fn modify_mode<F: FnOnce(&mut termios)>(fd: RawFd, f: F) -> Result<()> { Ok(()) } -fn get_flags(fd: RawFd) -> Result<c_int> { - // Safe because no third parameter is expected and we check the return result. - let ret = unsafe { fcntl(fd, F_GETFL) }; - if ret < 0 { - return errno_result(); - } - Ok(ret) -} - -fn set_flags(fd: RawFd, flags: c_int) -> Result<()> { - // Safe because we supply the third parameter and we check the return result. - let ret = unsafe { fcntl(fd, F_SETFL, flags) }; - if ret < 0 { - return errno_result(); - } - Ok(()) -} - /// Trait for file descriptors that are TTYs, according to `isatty(3)`. /// /// This is marked unsafe because the implementation must promise that the returned RawFd is a valid @@ -78,16 +60,11 @@ pub unsafe trait Terminal { /// If `non_block` is `true`, then `read_raw` will not block. If `non_block` is `false`, then /// `read_raw` may block if there is nothing to read. fn set_non_block(&self, non_block: bool) -> Result<()> { - let old_flags = get_flags(self.tty_fd())?; - let new_flags = if non_block { - old_flags | O_NONBLOCK + if non_block { + add_fd_flags(self.tty_fd(), O_NONBLOCK) } else { - old_flags & !O_NONBLOCK - }; - if new_flags != old_flags { - set_flags(self.tty_fd(), new_flags)? + clear_fd_flags(self.tty_fd(), O_NONBLOCK) } - Ok(()) } /// Reads up to `out.len()` bytes from this terminal without any buffering. |