Какой файловый дескриптор следует использовать в ioctl, чтобы узнать размер экрана терминала? - PullRequest
1 голос
/ 18 апреля 2020

Я хочу достоверно знать размер терминала, даже когда приложение работает в подоболочке. Кажется, что единственный работающий способ - использовать stdin fd, но я хотел бы знать, почему есть ссылки на документацию, подтверждающую это. Есть много вопросов, например, зачем использовать stdout (или, в этом случае, stdin) fd, чтобы узнать размер терминала?

fn main() {
    let mut size = winsize {
        ws_row: 0,
        ws_col: 0,
        ws_xpixel: 0,
        ws_ypixel: 0,
    };
    let fd = std::fs::OpenOptions::new()
        .read(true)
        .write(true)
        .open("/dev/tty")
        .map(|file| file.as_raw_fd())
        .unwrap()
        ;
    unsafe { ioctl(fd, TIOCGWINSZ.into(), &mut size) };
    println!("/dev/tty cols: {}, lines: {}", size.ws_row, size.ws_col);
    unsafe { ioctl(STDOUT_FILENO, TIOCGWINSZ.into(), &mut size) };
    println!("stdout cols: {}, lines: {}", size.ws_row, size.ws_col);
    unsafe { ioctl(STDERR_FILENO, TIOCGWINSZ.into(), &mut size) };
    println!("stderr cols: {}, lines: {}", size.ws_row, size.ws_col);
    unsafe { ioctl(STDIN_FILENO, TIOCGWINSZ.into(), &mut size) };
    println!("stdin cols: {}, lines: {}", size.ws_row, size.ws_col);
}

Я запустил echo (cargo run 2>&1) в оболочке fi sh и получил это:

   Compiling test_term_size v0.1.0 (/home/m/code/test_term_size) warning: unused import: `File`  --> src/main.rs:2:15   | 2 | use std::fs::{File};   |               ^^^^   |   = note: `#[warn(unused_imports)]` on by default  warning: unused imports: `O_RDWR`, `open`  --> src/main.rs:4:5   | 4 |     O_RDWR,   |     ^^^^^^ 5 |     open, ioctl, winsize, STDIN_FILENO,   |     ^^^^      Finished dev [unoptimized + debuginfo] target(s) in 0.21s      Running `target/debug/test_term_size` /dev/tty cols: 0, lines: 0 stdout cols: 0, lines: 0 stderr cols: 0, lines: 0 stdin cols: 52, lines: 106
strace -e trace=ioctl,open target/debug/test_term_size
ioctl(3, TIOCGWINSZ, 0x7ffdb9805578)    = -1 EBADF (Bad file descriptor)
/dev/tty cols: 0, lines: 0
ioctl(1, TIOCGWINSZ, {ws_row=52, ws_col=213, ws_xpixel=3834, ws_ypixel=2028}) = 0
stdout cols: 52, lines: 213
ioctl(2, TIOCGWINSZ, {ws_row=52, ws_col=213, ws_xpixel=3834, ws_ypixel=2028}) = 0
stderr cols: 52, lines: 213
ioctl(0, TIOCGWINSZ, {ws_row=52, ws_col=213, ws_xpixel=3834, ws_ypixel=2028}) = 0
stdin cols: 52, lines: 213
+++ exited with 0 +++
strace -e trace=ioctl,open cargo run
ioctl(2, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(2, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(2, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(2, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(2, TIOCGWINSZ, {ws_row=52, ws_col=213, ws_xpixel=3834, ws_ypixel=2028}) = 0
ioctl(2, TIOCGWINSZ, {ws_row=52, ws_col=213, ws_xpixel=3834, ws_ypixel=2028}) = 0
ioctl(2, TIOCGWINSZ, {ws_row=52, ws_col=213, ws_xpixel=3834, ws_ypixel=2028}) = 0
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/test_term_size`
ioctl(3, TIOCGWINSZ, 0x7ffea819b008)    = -1 EBADF (Bad file descriptor)
/dev/tty cols: 0, lines: 0
ioctl(1, TIOCGWINSZ, {ws_row=52, ws_col=213, ws_xpixel=3834, ws_ypixel=2028}) = 0
stdout cols: 52, lines: 213
ioctl(2, TIOCGWINSZ, {ws_row=52, ws_col=213, ws_xpixel=3834, ws_ypixel=2028}) = 0
stderr cols: 52, lines: 213
ioctl(0, TIOCGWINSZ, {ws_row=52, ws_col=213, ws_xpixel=3834, ws_ypixel=2028}) = 0
stdin cols: 52, lines: 213
+++ exited with 0 +++
echo (strace -e trace=ioctl,open cargo run 2>&1)
ioctl(2, TCGETS, 0x7ffdae149cb0)        = -1 ENOTTY (Inappropriate ioctl for device) ioctl(2, TCGETS, 0x7ffdae149a30)        = -1 ENOTTY (Inappropriate ioctl for device) ioctl(2, TCGETS, 0x7ffdae149a30)        = -1 ENOTTY (Inappropriate ioctl for device) ioctl(2, TCGETS, 0x7ffdae149540)        = -1 ENOTTY (Inappropriate ioctl for device) warning: unused import: `File`  --> src/main.rs:2:15   | 2 | use std::fs::{File};   |               ^^^^   |   = note: `#[warn(unused_imports)]` on by default  warning: unused imports: `O_RDWR`, `open`  --> src/main.rs:4:5   | 4 |     O_RDWR,   |     ^^^^^^ 5 |     open, ioctl, winsize, STDIN_FILENO,   |     ^^^^      Finished dev [unoptimized + debuginfo] target(s) in 0.02s      Running `target/debug/test_term_size` ioctl(3, TIOCGWINSZ, 0x7ffd8c3ae728)    = -1 EBADF (Bad file descriptor) /dev/tty cols: 0, lines: 0 ioctl(1, TIOCGWINSZ, 0x7ffd8c3ae728)    = -1 ENOTTY (Inappropriate ioctl for device) stdout cols: 0, lines: 0 ioctl(2, TIOCGWINSZ, 0x7ffd8c3ae728)    = -1 ENOTTY (Inappropriate ioctl for device) stderr cols: 0, lines: 0 ioctl(0, TIOCGWINSZ, {ws_row=52, ws_col=213, ws_xpixel=3834, ws_ypixel=2028}) = 0 stdin cols: 52, lines: 213 +++ exited with 0 +++
echo (strace -e trace=ioctl,open target/debug/test_term_size 2>&1)
ioctl(3, TIOCGWINSZ, 0x7fffdc82e938)    = -1 EBADF (Bad file descriptor) /dev/tty cols: 0, lines: 0 ioctl(1, TIOCGWINSZ, 0x7fffdc82e938)    = -1 ENOTTY (Inappropriate ioctl for device) stdout cols: 0, lines: 0 ioctl(2, TIOCGWINSZ, 0x7fffdc82e938)    = -1 ENOTTY (Inappropriate ioctl for device) stderr cols: 0, lines: 0 ioctl(0, TIOCGWINSZ, {ws_row=52, ws_col=213, ws_xpixel=3834, ws_ypixel=2028}) = 0 stdin cols: 52, lines: 213 +++ exited with 0 +++
echo (strace -e trace=ioctl,open target/debug/test_term_size 2>&1)
ioctl(3, TIOCGWINSZ, 0x7fffdc82e938)    = -1 EBADF (Bad file descriptor) /dev/tty cols: 0, lines: 0 ioctl(1, TIOCGWINSZ, 0x7fffdc82e938)    = -1 ENOTTY (Inappropriate ioctl for device) stdout cols: 0, lines: 0 ioctl(2, TIOCGWINSZ, 0x7fffdc82e938)    = -1 ENOTTY (Inappropriate ioctl for device) stderr cols: 0, lines: 0 ioctl(0, TIOCGWINSZ, {ws_row=52, ws_col=213, ws_xpixel=3834, ws_ypixel=2028}) = 0 stdin cols: 52, lines: 213 +++ exited with 0 +++

1 Ответ

0 голосов
/ 19 апреля 2020

Правильный источник информации TTY всегда / dev / tty. Не используйте stdin или любые другие странные хаки. Вот почему, похоже, это не работает для вас:

let fd = std::fs::OpenOptions::new()
    .read(true)
    .write(true)
    .open("/dev/tty")
    .map(|file| file.as_raw_fd())
    .unwrap()
    ;

Вы открываете / dev / tty и получаете его FD, но затем файл удаляется и, следовательно, закрывается, прежде чем вы сможете используйте его, поэтому ioctl на нем завершится неудачно с EBADF "Bad file descriptor". Чтобы устранить проблему, оставьте файл живым до тех пор, пока вы не закончите использовать FD.

...