5
5
// Use of this source code is governed by a BSD-style license that can be
6
6
// found in the THIRD-PARTY file.
7
7
use libc:: { open, O_CLOEXEC , O_RDWR } ;
8
+ use std:: ffi:: CStr ;
8
9
use std:: fs:: File ;
9
10
use std:: os:: raw:: { c_char, c_ulong} ;
10
11
use std:: os:: unix:: io:: { AsRawFd , FromRawFd , RawFd } ;
@@ -46,6 +47,32 @@ impl Kvm {
46
47
Ok ( unsafe { Self :: from_raw_fd ( fd) } )
47
48
}
48
49
50
+ /// Opens the KVM device at `kvm_path` and returns a `Kvm` object on success.
51
+ ///
52
+ /// # Arguments
53
+ ///
54
+ /// * `kvm_path`: path to the KVM device. Usually it is `/dev/kvm`.
55
+ ///
56
+ /// # Example
57
+ ///
58
+ /// ```
59
+ /// use kvm_ioctls::Kvm;
60
+ /// use std::ffi::CString;
61
+ /// let kvm_path = CString::new("/dev/kvm").unwrap();
62
+ /// let kvm = Kvm::new_with_path(&kvm_path).unwrap();
63
+ /// ```
64
+ #[ allow( clippy:: new_ret_no_self) ]
65
+ pub fn new_with_path < P > ( kvm_path : P ) -> Result < Self >
66
+ where
67
+ P : AsRef < CStr > ,
68
+ {
69
+ // Open `kvm_path` using `O_CLOEXEC` flag.
70
+ let fd = Self :: open_with_cloexec_at ( kvm_path, true ) ?;
71
+ // SAFETY: Safe because we verify that the fd is valid in `open_with_cloexec_at`
72
+ // and we own the fd.
73
+ Ok ( unsafe { Self :: from_raw_fd ( fd) } )
74
+ }
75
+
49
76
/// Opens `/dev/kvm` and returns the fd number on success.
50
77
///
51
78
/// One usecase for this method is opening `/dev/kvm` before exec-ing into a
@@ -68,9 +95,39 @@ impl Kvm {
68
95
/// let kvm = unsafe { Kvm::from_raw_fd(kvm_fd) };
69
96
/// ```
70
97
pub fn open_with_cloexec ( close_on_exec : bool ) -> Result < RawFd > {
98
+ // SAFETY: Safe because we give a constant nul-terminated string.
99
+ let kvm_path = unsafe { CStr :: from_bytes_with_nul_unchecked ( b"/dev/kvm\0 " ) } ;
100
+ Self :: open_with_cloexec_at ( kvm_path, close_on_exec)
101
+ }
102
+
103
+ /// Opens the KVM device at `kvm_path` and returns the fd number on success.
104
+ /// Same as [open_with_cloexec()](struct.Kvm.html#method.open_with_cloexec)
105
+ /// except this method opens `kvm_path` instead of `/dev/kvm`.
106
+ ///
107
+ /// # Arguments
108
+ ///
109
+ /// * `kvm_path`: path to the KVM device. Usually it is `/dev/kvm`.
110
+ /// * `close_on_exec`: If true opens `kvm_path` using the `O_CLOEXEC` flag.
111
+ ///
112
+ /// # Example
113
+ ///
114
+ /// ```
115
+ /// # use kvm_ioctls::Kvm;
116
+ /// # use std::ffi::CString;
117
+ /// # use std::os::unix::io::FromRawFd;
118
+ /// let kvm_path = CString::new("/dev/kvm").unwrap();
119
+ /// let kvm_fd = Kvm::open_with_cloexec_at(kvm_path, false).unwrap();
120
+ /// // The `kvm_fd` can now be passed to another process where we can use
121
+ /// // `from_raw_fd` for creating a `Kvm` object:
122
+ /// let kvm = unsafe { Kvm::from_raw_fd(kvm_fd) };
123
+ /// ```
124
+ pub fn open_with_cloexec_at < P > ( path : P , close_on_exec : bool ) -> Result < RawFd >
125
+ where
126
+ P : AsRef < CStr > ,
127
+ {
71
128
let open_flags = O_RDWR | if close_on_exec { O_CLOEXEC } else { 0 } ;
72
- // SAFETY: Safe because we give a constant nul-terminated string and verify the result.
73
- let ret = unsafe { open ( "/dev/kvm \0 " . as_ptr ( ) as * const c_char , open_flags) } ;
129
+ // SAFETY: Safe because we verify the result.
130
+ let ret = unsafe { open ( path . as_ref ( ) . as_ptr ( ) as * const c_char , open_flags) } ;
74
131
if ret < 0 {
75
132
Err ( errno:: Error :: last ( ) )
76
133
} else {
@@ -583,6 +640,12 @@ mod tests {
583
640
Kvm :: new ( ) . unwrap ( ) ;
584
641
}
585
642
643
+ #[ test]
644
+ fn test_kvm_new_with_path ( ) {
645
+ let kvm_path = unsafe { CStr :: from_bytes_with_nul_unchecked ( b"/dev/kvm\0 " ) } ;
646
+ Kvm :: new_with_path ( kvm_path) . unwrap ( ) ;
647
+ }
648
+
586
649
#[ test]
587
650
fn test_open_with_cloexec ( ) {
588
651
let fd = Kvm :: open_with_cloexec ( false ) . unwrap ( ) ;
@@ -593,6 +656,17 @@ mod tests {
593
656
assert_eq ! ( flags & FD_CLOEXEC , FD_CLOEXEC ) ;
594
657
}
595
658
659
+ #[ test]
660
+ fn test_open_with_cloexec_at ( ) {
661
+ let kvm_path = std:: ffi:: CString :: new ( "/dev/kvm" ) . unwrap ( ) ;
662
+ let fd = Kvm :: open_with_cloexec_at ( & kvm_path, false ) . unwrap ( ) ;
663
+ let flags = unsafe { fcntl ( fd, F_GETFD , 0 ) } ;
664
+ assert_eq ! ( flags & FD_CLOEXEC , 0 ) ;
665
+ let fd = Kvm :: open_with_cloexec_at ( & kvm_path, true ) . unwrap ( ) ;
666
+ let flags = unsafe { fcntl ( fd, F_GETFD , 0 ) } ;
667
+ assert_eq ! ( flags & FD_CLOEXEC , FD_CLOEXEC ) ;
668
+ }
669
+
596
670
#[ test]
597
671
fn test_kvm_api_version ( ) {
598
672
let kvm = Kvm :: new ( ) . unwrap ( ) ;
0 commit comments