Skip to content

On illumos tcsetattr() is unusably buggy as it truncates termios fields #2071

Open
@nospam3089

Description

@nospam3089

Attempting to run:

use nix::sys::termios::{tcgetattr, tcsetattr};

fn main() {
    let tty_in = std::io::stdin();
    let original_mode = tcgetattr(&tty_in).unwrap();
    println!("tcgetattr(): {original_mode:?}");
    println!("c_iflag: {}", libc::BRKINT | libc::IGNPAR | libc::ICRNL | libc::IXON |
        libc::IMAXBEL);
    println!("c_oflag: {}", libc::OPOST | libc::ONLCR);
    println!("c_cflag: {}", libc::CS6 | libc::CS7 | libc::CREAD);
    println!("c_lflag: {}", libc::ECHOKE | libc::ECHOE | libc::ECHOK | libc::ECHO | libc::ECHOCTL |
        libc::ISIG | libc::ICANON | libc::IEXTEN);

    std::thread::sleep(std::time::Duration::from_secs(10));
    tcsetattr(&tty_in, nix::sys::termios::SetArg::TCSADRAIN, &original_mode).unwrap();
    println!("Back from tcsetattr()?");
    std::thread::sleep(std::time::Duration::from_secs(10));
}

will output something like:

tcgetattr(): Termios { inner: RefCell { value: termios { c_iflag: 9478, c_oflag: 6149, c_cflag: 983231, c_lflag: 35387, c_cc: [3, 28, 127, 21, 4, 0, 0, 0, 17, 19, 26, 25, 18, 15, 23, 22, 20, 8, 0] } }, input_flags: InputFlags(BRKINT | IGNPAR | ICRNL | IXON | IMAXBEL), output_flags: OutputFlags(OPOST | ONLCR), control_flags: ControlFlags(CS6 | CS7 | CREAD), local_flags: LocalFlags(ECHOKE | ECHOE | ECHOK | ECHO | ECHOCTL | ISIG | ICANON | IEXTEN), control_chars: [3, 28, 127, 21, 4, 0, 0, 0, 17, 19, 26, 25, 18, 15, 23, 22, 20, 8, 0] }
c_iflag: 9478
c_oflag: 5
c_cflag: 176
c_lflag: 35387

Please notice two things:

  • The values of c_oflag and c_cflag have been truncated.
  • The terminal was hung up/terminated prior to the string Back from tcsetattr()? had any chance to get printed.

Quoting tcsetattr (3C):

The effect of tcsetattr() is undefined if the value of the termios structure pointed to by termios_p was not derived from the result of a call to tcgetattr(3C) on fildes; an application should modify only fields and flags defined by this document between the call to tcgetattr(3C) and tcsetattr(), leaving all other fields and flags unmodified.

There are also other relevant sections in the manual, but the bottom line is that tcsetattr() practically always close the terminal when called on illumos as currently implemented.

I can think of three ways to improve the current situation:

  • Make nix and libc aware of all flags on illumos.
  • Pass through the original values unmodified from their raw representation for all unknown bits.
  • Simply disable tcsetattr() on illumos.

Given the state of #935 and rust-lang/libc#1405, the first alternative does not seems likely to happen any time soon. The second alternative seems pragmatic, but would be a bit messy both to implement and maintain. The third alternative seems less desired than actually fixing the functionality.

I could do a PR to remove tcsetattr() (or rather the entire termios module?) on illumos, unless someone has a better feasible idea.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions