Skip to content

uucore: decode \012 in mount points - #16102

Open
gibkim wants to merge 3 commits into
uutils:mainfrom
gibkim:fsext-decode-newline
Open

gibkim wants to merge 3 commits into
uutils:mainfrom
gibkim:fsext-decode-newline

Conversation

@gibkim

@gibkim gibkim commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

The kernel escapes newline as \012 in /proc/self/mountinfo and /proc/mounts, but replace_special_chars() only decoded \040, \011 and \134. A mount point with a newline in its name kept a literal \012, so df dropped it and df DIR / stat -c %m DIR reported the parent file system.

This adds \012 to the decoder. \134 stays last so a literal \012 in a name (written by the kernel as \134012) is not turned into a newline. Unit tests cover mountinfo and mtab lines with a newline, all four escapes together, and the \134012 case.

Once the mount is found, printing the newline as is would split its row in two (and fail the GNU test tests/df/problematic-chars), so the "Mounted on" column now replaces ASCII control characters with ?, like GNU df. #16065 does the same for all df columns; whichever lands second can drop the mount-point part.

Addresses the mount-point decoding portion of #15753. Mount-source/root decoding and control-character handling in other columns remain outside this PR; #16065 overlaps with that broader work.

@gibkim gibkim changed the title uucore/fsext: decode \012 in mount points uucore: decode \012 in mount points Nov 1, 2026
@github-actions

github-actions Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

GNU testsuite comparison:

Skipping an intermittent issue tests/misc/usage_vs_getopt (passes in this run but fails in the 'main' branch)

@gibkim
gibkim marked this pull request as draft November 1, 2026 09:46
@codspeed

codspeed Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Merging this PR will improve performance by 9.91%

2 warnings, 1 note

⚠️ 125 benchmarks are dominated by system calls

System calls cannot be simulated consistently and are left out of the measure. The reported value understates the real cost. Switch to the Walltime instrument to measure them.

Learn more about system calls

See affected benchmarks

⚠️ 1 benchmark with a significant change ran on different hardware

Its base and head results were measured on machines with a different CPU, core count or memory, so the change might not come from the code. Run base and head on the same runner type.

Learn more about Macro Runners

See affected benchmarks

ℹ️ 1 benchmark has no flamegraph

The flamegraph wasn't generated: most of the time was spent in runtime internals, which would leave nothing useful to analyze.

See affected benchmarks

⚡ 1 improved benchmark
✅ 400 untouched benchmarks
⏩ 70 skipped benchmarks1

Performance Changes

Mode Benchmark BASE HEAD Efficiency
⚡ CPU Simulation ls_recursive_wide_tree[(10000, 1000)] 73.5 ms 66.8 ms +9.91%

Tip

Curious why performance improved? Comment @codspeedbot explain why performance improved on this PR, or directly use the CodSpeed MCP with your agent.


Comparing gibkim:fsext-decode-newline (7bba917) with main (6c880ea)2

Open in CodSpeed

Footnotes

  1. 70 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

  2. No successful run was found on main (36a00ef) during the generation of this report, so 6c880ea was used instead as the comparison base. There might be some changes unrelated to this pull request in this report. ↩

@gibkim
gibkim marked this pull request as ready for review November 1, 2026 12:41
@sylvestre
sylvestre force-pushed the fsext-decode-newline branch from 9b36ac2 to 7bba917 Compare November 3, 2026 15:35

@montezuma-p montezuma-p left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mount source needs the same decoding. With GNU df 9.7 inside unshare -rm, mount -t tmpfs $'s\nx' $'/tmp/dft/n\nl' gives this mountinfo line:

2455 2443 0:94 / /tmp/dft/n\012l rw,relatime - tmpfs s\012x rw,...

and GNU prints:

s?x            /tmp/dft/n?l

Here the source is still read raw (String::from_utf8_lossy(raw[after_fields + 1]) in MountInfo::new), so from reading the code the Filesystem column would show s\012x. Running replace_special_chars() on the source too, and giving that column the ? treatment, would match GNU. #16065 does both, so the two PRs may want to settle which one carries this.

Comment thread src/uu/df/src/table.rs Outdated
/// with `?` like GNU df, so that a newline in the name can't split the row.
fn from_mount_point(os: &OsString) -> Self {
let bytes: Vec<u8> = uucore::os_str_as_bytes(os)
.unwrap()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you use os_str_as_bytes_lossy here to avoid the unwrap()?

gibkim and others added 3 commits November 15, 2026 01:46
The kernel escapes newline as \012 in /proc/self/mountinfo and
/proc/mounts, but only \040, \011 and \134 were decoded. Mount points
containing a newline were then missing from df and ignored by
df FILE and stat -c %m.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Now that a mount point with a newline is found, printing it raw splits
the row in two. Replace ASCII control characters with ? in the
"Mounted on" column, like GNU df, so the GNU test
tests/df/problematic-chars keeps passing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sylvestre
sylvestre force-pushed the fsext-decode-newline branch from d3cdbc4 to 7b1c289 Compare November 15, 2026 00:46

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants