|
| 1 | +# stty save/restore behavior in uutils |
| 2 | + |
| 3 | +This page documents the `-g` (save) format and round-trip behavior of `uutils stty`. |
| 4 | + |
| 5 | +## `-g` output format |
| 6 | + |
| 7 | +`uutils stty -g` prints the current terminal settings in a colon-separated hexadecimal format that is designed to be read back by `uutils stty` itself. |
| 8 | + |
| 9 | +The format is: |
| 10 | + |
| 11 | +``` |
| 12 | +<input_flags_hex>:<output_flags_hex>:<control_flags_hex>:<local_flags_hex>:<cc0>:<cc1>:...:<ccN> |
| 13 | +``` |
| 14 | + |
| 15 | +- The first four fields are the termios flag bitfields (input, output, control, local), printed as hexadecimal numbers. |
| 16 | +- The remaining fields are the control character bytes (CCs), each printed as a 1–2 digit hexadecimal value. The number of CC fields depends on the platform (the platform’s NCCS value). |
| 17 | + |
| 18 | +Example: |
| 19 | + |
| 20 | +``` |
| 21 | +6b02:3:4b00:200005cf:4:ff:ff:7f:17:15:12:0:3:1c:1a:19:11:13:16:f:1:0:14:0 |
| 22 | +``` |
| 23 | + |
| 24 | +## Round-trip compatibility |
| 25 | + |
| 26 | +`uutils stty` supports reading back its own `-g` output: |
| 27 | + |
| 28 | +``` |
| 29 | +stty "$(stty -g)" |
| 30 | +``` |
| 31 | + |
| 32 | +This restores the same settings and exits with code 0. Unknown/unsupported flag bits on a given platform are safely ignored. |
| 33 | + |
| 34 | +## GNU `stty` compatibility (gfmt1) |
| 35 | + |
| 36 | +GNU `stty -g` commonly prints a `gfmt1` key/value format, e.g.: |
| 37 | + |
| 38 | +``` |
| 39 | +gfmt1:cflag=4b00:iflag=6b02:lflag=200005cf:oflag=3:...:ispeed=38400:ospeed=38400 |
| 40 | +``` |
| 41 | + |
| 42 | +Currently, `uutils stty` does not parse `gfmt1`. Use `uutils stty -g` output for restore with `uutils stty`. |
| 43 | + |
| 44 | +Mixing formats between `uutils stty` and GNU `stty` may fail. If you must interoperate, prefer using the same implementation for both save and restore steps. |
| 45 | + |
| 46 | +## Platform notes |
| 47 | + |
| 48 | +- The number of control characters (NCCS) and the underlying bit width for termios flags vary by platform. `uutils stty` reads NCCS at runtime and truncates unknown bits when applying flags. |
| 49 | +- Hexadecimal is case-insensitive. Empty CC fields are treated as 0. |
| 50 | + |
| 51 | +## Error handling |
| 52 | + |
| 53 | +- Malformed hex values or a mismatched number of CC fields result in a non-zero exit code and an error message (e.g., "invalid argument" or "invalid integer argument"). |
| 54 | + |
| 55 | +## Future compatibility |
| 56 | + |
| 57 | +Support for reading GNU `gfmt1` may be considered in future versions. For now, rely on `uutils stty`’s colon-separated hex format for save/restore round-trips. |
| 58 | + |
| 59 | + |
| 60 | + |
| 61 | +## Advanced edge-case validation |
| 62 | + |
| 63 | +The implementation has been validated with an extensive suite of edge-case tests to ensure robustness across platforms and terminals. Highlights: |
| 64 | + |
| 65 | +- Boundary conditions |
| 66 | + - Minimal valid payload: accept a string with the four flag fields plus exactly NCCS control characters, all set to 0; succeeds and normalizes on reprint. |
| 67 | + - Case-insensitivity: accept uppercase and mixed-case hex for all fields; round-trip preserves state. |
| 68 | + - Leading zeros: accept arbitrarily padded fields; output normalizes to minimal-width hex. |
| 69 | + |
| 70 | +- Error handling |
| 71 | + - Insufficient fields (< 5 total): rejected with exit code 1 and "invalid argument". |
| 72 | + - Extra CC fields (> NCCS): rejected with exit code 1 and "invalid argument". |
| 73 | + - Malformed hex in any flag field: rejected with exit code 1 and "invalid integer argument '<chunk>'". |
| 74 | + - Unexpected characters (spaces, punctuation): rejected early with exit code 1 and "invalid integer argument '<input>'". |
| 75 | + |
| 76 | +- Platform compatibility |
| 77 | + - Exact CC count enforced using the platform’s runtime NCCS; NCCS−1 and NCCS+1 inputs are rejected. |
| 78 | + - Flag fields parsed into platform tcflag_t width; unknown bits are safely ignored (truncate semantics). |
| 79 | + |
| 80 | +- Data integrity |
| 81 | + - Unknown/high bits in flags are accepted but do not persist when re-saved; round-tripping returns to canonical values. |
| 82 | + |
| 83 | +- Security considerations |
| 84 | + - Oversized inputs (e.g., thousands of CC entries) are rejected quickly via count validation; no excessive CPU or memory use observed. |
| 85 | + |
| 86 | +These tests live under tests/by-util/test_stty_roundtrip.rs and tests/by-util/test_stty_hex_edges.rs and run under the feature flag `stty`. |
| 87 | + |
| 88 | +## Troubleshooting and examples |
| 89 | + |
| 90 | +- Restore from current settings |
| 91 | + - stty "$(stty -g)" |
| 92 | + |
| 93 | +- Uppercase input |
| 94 | + - stty "$(stty -g | tr 'a-f' 'A-F')" # succeeds |
| 95 | + |
| 96 | +- Leading zeros |
| 97 | + - Provide any number of leading zeros per field; the next `stty -g` prints normalized hex. |
| 98 | + |
| 99 | +- Insufficient fields |
| 100 | + - stty "6b02:3:4b00:200005cf" # fails with: invalid argument '...' |
| 101 | + |
| 102 | +- Malformed hex |
| 103 | + - stty "6b02:zz:4b00:200005cf:..." # fails with: invalid integer argument 'zz' |
| 104 | + |
| 105 | +- Trailing whitespace or punctuation |
| 106 | + - stty "$(stty -g) " # fails with: invalid integer argument '...' |
| 107 | + |
| 108 | +## PTY and /dev/tty |
| 109 | + |
| 110 | +- Tests prefer using /dev/tty when available; CI also exercises a PTY-backed path so behavior is validated on real terminals and pseudo-terminals. |
| 111 | +- If /dev/tty is unavailable, some tests are skipped; the utility itself will error if the selected file descriptor is not a terminal (consistent with termios behavior). |
| 112 | + |
| 113 | +## Cross-platform behavior |
| 114 | + |
| 115 | +- Termios flag widths (tcflag_t) differ (Linux commonly u32; macOS/BSD may be u64). The parser uses tcflag_t and from_bits_truncate to remain portable. |
| 116 | +- The number and meaning of control characters differ across platforms; the parser enforces the exact CC count for the current platform. |
| 117 | +- ispeed/ospeed are not encoded in the colon-hex format; `uutils stty` does not parse or set speeds from `-g` input. This is documented and by design. |
| 118 | + |
| 119 | +## Performance and safety |
| 120 | + |
| 121 | +- Parsing uses safe Rust conversions and bounded operations; no unsafe code paths in the hex parser. |
| 122 | +- Large malformed inputs are rejected by early validation (character filter and CC count), preventing excessive allocations or quadratic behavior. |
| 123 | + |
| 124 | +## CI coverage |
| 125 | + |
| 126 | +- Matrix includes Linux and macOS. Tests cover: |
| 127 | + - Round-trip save/restore |
| 128 | + - Mixed-case hex and leading zeros |
| 129 | + - Error cases (insufficient/extra fields, malformed hex, unexpected characters) |
| 130 | + - NCCS mismatch rejection |
| 131 | + - Unknown flag-bit truncation behavior |
| 132 | + |
0 commit comments