uutils / uutils/coreutils

stty: setting a grouped control flag (e.g. cs7) does not clear existing group bits first

Open
#11,963 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

U - stty
Dominant language
Rust
Stars
24.1k
Forks
2k
Avg merge
1d 5h
Merged PRs (30d)
365

Description

Description:

When trying to set a CSIZE character size flag (cs5-cs7) on a terminal which already has cs8 set, the new value is silently ignored.

Sorry for the lengthy issue report, I'm relatively new to this and wanted to give as much info as possible.

Reproduction:

I was trying to set stty to cs7 and noticed an issue.

stty -a -F /dev/ttyA0 | grep -o 'cs[0-9]'
original output: cs8

stty -F /dev/ttyA0 cs7
run the state check again: stty -a -F /dev/ttyA0 | grep -o 'cs[0-9]'
output: cs8

GNU coreutils (albeit an old version in my case) will set it properly.

Presumed Root Cause

In apply_setting, we run setting.flag.apply(termios, !disable), showing just the control flags entry:
https://github.com/uutils/coreutils/blob/22bd03668a8b9f3b5daf7c863b5a92f263086986/src/uu/stty/src/stty.rs#L975-L980

That routes to termios.control_flags.set(*self, val), with val being !disable, or true
https://github.com/uutils/coreutils/blob/22bd03668a8b9f3b5daf7c863b5a92f263086986/src/uu/stty/src/stty.rs#L1298-L1307

From bitflags public.rs, set calls insert, insert calls union, and union is an OR operation:
https://github.com/bitflags/bitflags/blob/7cc8595e93d04d180d39e2f25242dca85dd71228/src/public.rs#L244-L250
https://github.com/bitflags/bitflags/blob/7cc8595e93d04d180d39e2f25242dca85dd71228/src/public.rs#L232-L234
https://github.com/bitflags/bitflags/blob/7cc8595e93d04d180d39e2f25242dca85dd71228/src/public.rs#L256-L258

Rust defines CS bits as the following:

pub const CSIZE: crate::tcflag_t = 0x00000030;
pub const CS6: crate::tcflag_t = 0x00000010;
pub const CS7: crate::tcflag_t = 0x00000020;
pub const CS8: crate::tcflag_t = 0x00000030;

(and cs5 is all 0's)
https://github.com/rust-lang/libc/blob/e879ee90b6cd8f79b352d4d4d1f8ca05f94f2f53/src/unix/linux_like/linux/gnu/b32/arm/mod.rs#L446-L449

So we take up bits 4:5, set at 00, 01, 10, 11 for cs5-8.

Evidence

The OR function is where we encounter issues. Because this is a 2-bit store, a simple OR does not set properly.

Setting cs5->cs6
Image This works as expected because we do 00 | 01 -> 01
Setting cs6 -> cs5
Image Even though we set cs5 it stays at cs6. This makes sense because we are doing 01 | 00 -> 01
Setting cs6 -> cs7
Image This is the best example. Because cs6 is 01 and cs7 is 10, we do 01 | 10 -> 11, and we actually get cs8

Solution Ideas

I haven't looked at GNU source code, but my assumption is they would clear this bitmask before setting.
I think a proper solution would have us clearing/removing that bit group prior to the new application.

Additional Screenshots:

GNU cs8 -> 7
Image
Uutils cs8 -> 7 (doesn't work)
Image
GNU behavior with commands from "Evidence" section. Note that it sets correctly each time.
Image

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in src/uu/stty/src/stty.rs at apply_setting and the control_flags implementation around the referenced lines, then reproduce the transitions between cs5, cs6, cs7, and cs8 on a terminal device. Compare each result with stty -a and GNU stty; done means every requested character size replaces the existing group bits rather than retaining or combining them.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
cli, operating-systems
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.