• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::convert::TryFrom;
6 use std::fs::File;
7 use std::os::fd::AsFd;
8 use std::os::fd::BorrowedFd;
9 use std::os::unix::io::AsRawFd;
10 use std::os::unix::io::FromRawFd;
11 use std::os::unix::io::IntoRawFd;
12 use std::os::unix::io::OwnedFd;
13 use std::os::unix::io::RawFd;
14 
15 use crate::rutabaga_os::descriptor::AsRawDescriptor;
16 use crate::rutabaga_os::descriptor::Descriptor;
17 use crate::rutabaga_os::descriptor::FromRawDescriptor;
18 use crate::rutabaga_os::descriptor::IntoRawDescriptor;
19 use crate::rutabaga_os::descriptor::SafeDescriptor;
20 
21 type Error = std::io::Error;
22 type Result<T> = std::result::Result<T, Error>;
23 
24 pub type RawDescriptor = RawFd;
25 
26 /// Clones `fd`, returning a new file descriptor that refers to the same open file description as
27 /// `fd`. The cloned fd will have the `FD_CLOEXEC` flag set but will not share any other file
28 /// descriptor flags with `fd`.
clone_fd(fd: &dyn AsRawFd) -> Result<RawFd>29 fn clone_fd(fd: &dyn AsRawFd) -> Result<RawFd> {
30     // SAFETY:
31     // Safe because this doesn't modify any memory and we check the return value.
32     let ret = unsafe { libc::fcntl(fd.as_raw_fd(), libc::F_DUPFD_CLOEXEC, 0) };
33     if ret < 0 {
34         Err(Error::last_os_error())
35     } else {
36         Ok(ret)
37     }
38 }
39 
40 impl Drop for SafeDescriptor {
drop(&mut self)41     fn drop(&mut self) {
42         // SAFETY:
43         // Safe because we own the SafeDescriptor at this point.
44         let _ = unsafe { libc::close(self.descriptor) };
45     }
46 }
47 
48 impl AsRawFd for SafeDescriptor {
as_raw_fd(&self) -> RawFd49     fn as_raw_fd(&self) -> RawFd {
50         self.as_raw_descriptor()
51     }
52 }
53 
54 impl TryFrom<&dyn AsRawFd> for SafeDescriptor {
55     type Error = std::io::Error;
56 
try_from(fd: &dyn AsRawFd) -> Result<Self>57     fn try_from(fd: &dyn AsRawFd) -> Result<Self> {
58         Ok(SafeDescriptor {
59             descriptor: clone_fd(fd)?,
60         })
61     }
62 }
63 
64 impl SafeDescriptor {
65     /// Clones this descriptor, internally creating a new descriptor. The new SafeDescriptor will
66     /// share the same underlying count within the kernel.
try_clone(&self) -> Result<SafeDescriptor>67     pub fn try_clone(&self) -> Result<SafeDescriptor> {
68         // SAFETY:
69         // Safe because this doesn't modify any memory and we check the return value.
70         let descriptor = unsafe { libc::fcntl(self.descriptor, libc::F_DUPFD_CLOEXEC, 0) };
71         if descriptor < 0 {
72             Err(Error::last_os_error())
73         } else {
74             Ok(SafeDescriptor { descriptor })
75         }
76     }
77 }
78 
79 impl From<SafeDescriptor> for File {
from(s: SafeDescriptor) -> File80     fn from(s: SafeDescriptor) -> File {
81         // SAFETY:
82         // Safe because we own the SafeDescriptor at this point.
83         unsafe { File::from_raw_fd(s.into_raw_descriptor()) }
84     }
85 }
86 
87 // AsRawFd for interoperability with interfaces that require it. Within crosvm,
88 // always use AsRawDescriptor when possible.
89 impl AsRawFd for Descriptor {
as_raw_fd(&self) -> RawFd90     fn as_raw_fd(&self) -> RawFd {
91         self.0
92     }
93 }
94 
95 impl AsFd for SafeDescriptor {
as_fd(&self) -> BorrowedFd96     fn as_fd(&self) -> BorrowedFd {
97         // SAFETY: the `BorrowedFd` we return lives no longer than this `SafeDescriptor`, so the
98         // descriptor will remain open.
99         unsafe { BorrowedFd::borrow_raw(self.descriptor) }
100     }
101 }
102 
103 macro_rules! AsRawDescriptor {
104     ($name:ident) => {
105         impl AsRawDescriptor for $name {
106             fn as_raw_descriptor(&self) -> RawDescriptor {
107                 self.as_raw_fd()
108             }
109         }
110     };
111 }
112 
113 macro_rules! FromRawDescriptor {
114     ($name:ident) => {
115         impl FromRawDescriptor for $name {
116             // SAFETY:
117             // It is caller's responsibility to ensure that the descriptor is valid and
118             // stays valid for the lifetime of Self
119             unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self {
120                 $name::from_raw_fd(descriptor)
121             }
122         }
123     };
124 }
125 
126 macro_rules! IntoRawDescriptor {
127     ($name:ident) => {
128         impl IntoRawDescriptor for $name {
129             fn into_raw_descriptor(self) -> RawDescriptor {
130                 self.into_raw_fd()
131             }
132         }
133     };
134 }
135 
136 // Implementations for File. This enables the File-type to use
137 // RawDescriptor, but does not mean File should be used as a generic
138 // descriptor container. That should go to either SafeDescriptor or another more
139 // relevant container type.
140 AsRawDescriptor!(File);
141 FromRawDescriptor!(File);
142 IntoRawDescriptor!(File);
143 AsRawDescriptor!(OwnedFd);
144 FromRawDescriptor!(OwnedFd);
145 IntoRawDescriptor!(OwnedFd);
146