summary refs log tree commit diff
path: root/sys_util
diff options
context:
space:
mode:
authorDylan Reid <dgreid@chromium.org>2019-12-02 11:09:12 +1100
committerCommit Bot <commit-bot@chromium.org>2019-12-12 21:13:37 +0000
commiteaff194759cb25d1bf2725a133ff92f092563675 (patch)
tree9df9a0950ac09603033d8ea57f5449a48f5914cb /sys_util
parent0a433f8ca98700062b786c3af42e1b4fef4f9674 (diff)
downloadcrosvm-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.rs46
-rw-r--r--sys_util/src/terminal.rs35
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.