1
- use std:: fs:: File ;
2
- use std:: io:: { self , ErrorKind } ;
3
- use std:: os:: fd:: { AsFd , AsRawFd , BorrowedFd , OwnedFd , RawFd } ;
4
-
5
- use libc:: { fcntl, F_GETFL , F_SETFL , O_NONBLOCK , STDERR_FILENO , STDIN_FILENO , STDOUT_FILENO } ;
1
+ use libc:: {
2
+ fcntl, F_GETFL , F_SETFL , O_NONBLOCK , STDERR_FILENO , STDIN_FILENO , STDOUT_FILENO , TIOCGWINSZ ,
3
+ } ;
6
4
use log:: Level ;
7
5
use nix:: errno:: Errno ;
6
+ use nix:: ioctl_read_bad;
8
7
use nix:: poll:: { poll, PollFd , PollFlags , PollTimeout } ;
9
- use nix:: unistd:: dup;
8
+ use nix:: unistd:: { dup, isatty} ;
9
+ use std:: fs:: File ;
10
+ use std:: io:: { self , ErrorKind } ;
11
+ use std:: os:: fd:: { AsFd , AsRawFd , BorrowedFd , OwnedFd , RawFd } ;
10
12
use utils:: eventfd:: EventFd ;
11
13
use utils:: eventfd:: EFD_NONBLOCK ;
12
14
use vm_memory:: bitmap:: Bitmap ;
@@ -24,6 +26,11 @@ pub trait PortOutput {
24
26
fn wait_until_writable ( & self ) ;
25
27
}
26
28
29
+ /// Terminal properties associated with this port
30
+ pub trait PortTerminalProperties : Send + Sync {
31
+ fn get_win_size ( & self ) -> ( u16 , u16 ) ;
32
+ }
33
+
27
34
pub fn stdin ( ) -> Result < Box < dyn PortInput + Send > , nix:: Error > {
28
35
let fd = dup_raw_fd_into_owned ( STDIN_FILENO ) ?;
29
36
make_non_blocking ( & fd) ?;
@@ -44,6 +51,21 @@ pub fn stderr() -> Result<Box<dyn PortOutput + Send>, nix::Error> {
44
51
output_to_raw_fd_dup ( STDERR_FILENO )
45
52
}
46
53
54
+ pub fn term_fd (
55
+ term_fd : RawFd ,
56
+ ) -> Result < Box < dyn PortTerminalProperties + Send + Sync > , nix:: Error > {
57
+ let fd = dup_raw_fd_into_owned ( term_fd) ?;
58
+ assert ! (
59
+ isatty( & fd) . is_ok_and( |v| v) ,
60
+ "Expected fd {fd:?}, to be a tty, to query the window size!"
61
+ ) ;
62
+ Ok ( Box :: new ( PortTerminalPropertiesFd ( fd) ) )
63
+ }
64
+
65
+ pub fn term_fixed_size ( width : u16 , height : u16 ) -> Box < dyn PortTerminalProperties + Send + Sync > {
66
+ Box :: new ( PortTerminalPropertiesFixed ( ( width, height) ) )
67
+ }
68
+
47
69
pub fn input_empty ( ) -> Result < Box < dyn PortInput + Send > , nix:: Error > {
48
70
Ok ( Box :: new ( PortInputEmpty { } ) )
49
71
}
@@ -278,3 +300,35 @@ impl PortInput for PortInputEmpty {
278
300
}
279
301
}
280
302
}
303
+
304
+ struct PortTerminalPropertiesFixed ( ( u16 , u16 ) ) ;
305
+
306
+ impl PortTerminalProperties for PortTerminalPropertiesFixed {
307
+ fn get_win_size ( & self ) -> ( u16 , u16 ) {
308
+ self . 0
309
+ }
310
+ }
311
+
312
+ struct PortTerminalPropertiesFd ( OwnedFd ) ;
313
+
314
+ impl PortTerminalProperties for PortTerminalPropertiesFd {
315
+ fn get_win_size ( & self ) -> ( u16 , u16 ) {
316
+ let mut ws: WS = WS :: default ( ) ;
317
+
318
+ if let Err ( err) = unsafe { tiocgwinsz ( self . 0 . as_raw_fd ( ) , & mut ws) } {
319
+ error ! ( "Couldn't get terminal dimensions: {err}" ) ;
320
+ return ( 0 , 0 ) ;
321
+ }
322
+ ( ws. cols , ws. rows )
323
+ }
324
+ }
325
+
326
+ #[ repr( C ) ]
327
+ #[ derive( Default ) ]
328
+ struct WS {
329
+ rows : u16 ,
330
+ cols : u16 ,
331
+ xpixel : u16 ,
332
+ ypixel : u16 ,
333
+ }
334
+ ioctl_read_bad ! ( tiocgwinsz, TIOCGWINSZ , WS ) ;
0 commit comments