77
88use std:: convert:: Infallible ;
99use std:: fmt:: Debug ;
10+ use std:: os:: unix:: prelude:: OpenOptionsExt ;
11+ use std:: path:: PathBuf ;
1012use std:: sync:: { Arc , Mutex } ;
1113
1214use acpi:: ACPIDeviceManager ;
@@ -125,13 +127,25 @@ impl DeviceManager {
125127 /// Sets up the serial device.
126128 fn setup_serial_device (
127129 event_manager : & mut EventManager ,
130+ output : Option < & PathBuf > ,
128131 ) -> Result < Arc < Mutex < SerialDevice > > , std:: io:: Error > {
129- Self :: set_stdout_nonblocking ( ) ;
132+ let ( serial_in, serial_out) = match output {
133+ Some ( ref path) => (
134+ None ,
135+ std:: fs:: OpenOptions :: new ( )
136+ . custom_flags ( libc:: O_NONBLOCK )
137+ . write ( true )
138+ . open ( path)
139+ . map ( SerialOut :: File ) ?,
140+ ) ,
141+ None => {
142+ Self :: set_stdout_nonblocking ( ) ;
143+
144+ ( Some ( std:: io:: stdin ( ) ) , SerialOut :: Stdout ( std:: io:: stdout ( ) ) )
145+ }
146+ } ;
130147
131- let serial = Arc :: new ( Mutex :: new ( SerialDevice :: new (
132- Some ( std:: io:: stdin ( ) ) ,
133- SerialOut :: Stdout ( std:: io:: stdout ( ) ) ,
134- ) ?) ) ;
148+ let serial = Arc :: new ( Mutex :: new ( SerialDevice :: new ( serial_in, serial_out) ?) ) ;
135149 event_manager. add_subscriber ( serial. clone ( ) ) ;
136150 Ok ( serial)
137151 }
@@ -141,9 +155,10 @@ impl DeviceManager {
141155 event_manager : & mut EventManager ,
142156 vcpus_exit_evt : & EventFd ,
143157 vm : & Vm ,
158+ serial_output : Option < & PathBuf > ,
144159 ) -> Result < PortIODeviceManager , DeviceManagerCreateError > {
145160 // Create serial device
146- let serial = Self :: setup_serial_device ( event_manager) ?;
161+ let serial = Self :: setup_serial_device ( event_manager, serial_output ) ?;
147162 let reset_evt = vcpus_exit_evt
148163 . try_clone ( )
149164 . map_err ( DeviceManagerCreateError :: EventFd ) ?;
@@ -161,9 +176,11 @@ impl DeviceManager {
161176 event_manager : & mut EventManager ,
162177 vcpus_exit_evt : & EventFd ,
163178 vm : & Vm ,
179+ serial_output : Option < & PathBuf > ,
164180 ) -> Result < Self , DeviceManagerCreateError > {
165181 #[ cfg( target_arch = "x86_64" ) ]
166- let legacy_devices = Self :: create_legacy_devices ( event_manager, vcpus_exit_evt, vm) ?;
182+ let legacy_devices =
183+ Self :: create_legacy_devices ( event_manager, vcpus_exit_evt, vm, serial_output) ?;
167184
168185 Ok ( DeviceManager {
169186 mmio_devices : MMIODeviceManager :: new ( ) ,
@@ -243,6 +260,7 @@ impl DeviceManager {
243260 vm : & Vm ,
244261 event_manager : & mut EventManager ,
245262 cmdline : & mut Cmdline ,
263+ serial_out_path : Option < & PathBuf > ,
246264 ) -> Result < ( ) , AttachDeviceError > {
247265 // Serial device setup.
248266 let cmdline_contains_console = cmdline
@@ -253,7 +271,7 @@ impl DeviceManager {
253271 . contains ( "console=" ) ;
254272
255273 if cmdline_contains_console {
256- let serial = Self :: setup_serial_device ( event_manager) ?;
274+ let serial = Self :: setup_serial_device ( event_manager, serial_out_path ) ?;
257275 self . mmio_devices . register_mmio_serial ( vm, serial, None ) ?;
258276 self . mmio_devices . add_mmio_serial_to_cmdline ( cmdline) ?;
259277 }
@@ -451,6 +469,7 @@ impl<'a> Persist<'a> for DeviceManager {
451469 constructor_args. event_manager ,
452470 constructor_args. vcpus_exit_evt ,
453471 constructor_args. vm ,
472+ constructor_args. vm_resources . serial_out_path . as_ref ( ) ,
454473 ) ?;
455474
456475 // Restore MMIO devices
@@ -580,15 +599,15 @@ pub(crate) mod tests {
580599 let mut cmdline = Cmdline :: new ( 4096 ) . unwrap ( ) ;
581600 let mut event_manager = EventManager :: new ( ) . unwrap ( ) ;
582601 vmm. device_manager
583- . attach_legacy_devices_aarch64 ( & vmm. vm , & mut event_manager, & mut cmdline)
602+ . attach_legacy_devices_aarch64 ( & vmm. vm , & mut event_manager, & mut cmdline, None )
584603 . unwrap ( ) ;
585604 assert ! ( vmm. device_manager. mmio_devices. rtc. is_some( ) ) ;
586605 assert ! ( vmm. device_manager. mmio_devices. serial. is_none( ) ) ;
587606
588607 let mut vmm = default_vmm ( ) ;
589608 cmdline. insert ( "console" , "/dev/blah" ) . unwrap ( ) ;
590609 vmm. device_manager
591- . attach_legacy_devices_aarch64 ( & vmm. vm , & mut event_manager, & mut cmdline)
610+ . attach_legacy_devices_aarch64 ( & vmm. vm , & mut event_manager, & mut cmdline, None )
592611 . unwrap ( ) ;
593612 assert ! ( vmm. device_manager. mmio_devices. rtc. is_some( ) ) ;
594613 assert ! ( vmm. device_manager. mmio_devices. serial. is_some( ) ) ;
0 commit comments