* src/basenc.c (base32hex_decode_ctx_wrapper): Ensure we don't
accept base32 only characters for base32hex.
* tests/basenc/basenc.pl: Ensure negative base32hex tests have the
appropriate number of characters to test character validation
rather than just input size validation.
* NEWS: Mention the bug fix.
Discovered by Anthropic's OSS Scanner, as bug ANT-2026-EP1XO2G4.
* src/factor.c (strtouuint): Return LONGINT_OVERFLOW only if all of the
characters are digits; otherwise, return LONGINT_INVALID.
* tests/factor/factor.pl: Add two test cases.
* NEWS: Mention the bug fix.
Discovered by Anthropic's OSS Scanner, as bug ANT-2026-IZ8PFQ7Q.
stty currently fails like:
$ stty 9600
$ saved=$(stty -g)
$ stty 19200 "$saved" # Sets 9600 but reports failure
stty: 'standard input': unable to perform all requested operations
Whereas these work fine:
$ stty 19200 9600
$ stty "$saved" 19200
* NEWS: Mention the bug fix.
* src/speedgen (cbaud_to_speed): Determine the speed
from the control flag encoding.
* src/stty.c (recover_mode): If no separate speed specified,
update the speed from the specified control flags.
* tests/stty/stty-save-speed.sh: Add test cases.
Note this changes the output format of -g.
POSIX states that the -g format only needs to be compatible
with the stty implementation that produced it.
However we improve compatibility on Linux by only outputting
the explicit speeds when they're not encoded in the control flags.
* NEWS: Mention the change in behavior.
* src/stty.c (display_recoverable): Output the speeds if needed.
(recover_mode): Read the speeds if present.
* tests/stty/stty-save-speed.sh: Add a new test.
* tests/local.mk: Reference the new test.
Link: https://github.com/coreutils/coreutils/issues/384
* src/stty.c (struct speed_desc): New type, used to differentiate
between errors and (speed_t) -1.
(last_ibaud, last_obaud): Define variables as struct speed_desc instead
of speed_t.
(check_speed): Adjust uses of last_ibaud and last_obaud to their new
definitions.
(set_speed): Likewise. Use a struct speed_desc as the argument instead
of speed_t. Check for its validity using the valid member instead of
whether it is equal to (speed_t) -1.
(apply_settings): Use struct speed_desc instead of speed_t to store the
result of string_to_baud. Check for its validity using the valid member
instead of whether it is equal to (speed_t) -1.
(string_to_baud): Adjust the function to return a struct speed_desc
instead of speed_t.
* src/speedgen (value_to_baud): Likewise.
* NEWS: Mention the bug fix.
Link: https://github.com/coreutils/coreutils/issues/383
This preserves any program name transformations, e.g., when
--program-prefix=g is used as a configuration option, unlike commit
ef874ed6c (all: set /proc/self/comm to the program name in the single
binary, 2026-10-17).
* src/coreutils.c (launch_program): Use the last component of argv[0]
when setting the comm value using prctl (PR_SET_NAME, ...).
* tests/misc/proc-self-comm.sh: When using
--enable-single-binary=shebangs, test that the comm value preserves any
program name transformations, e.g., --program-prefix=g.
* NEWS: Adjust the NEWS entry to refer to last component of argv[0]
instead of the program name.
Suggested by Pádraig Brady.
Replace the O(N) scan of watched names on each directory inotify event
with a Hash_table keyed by (parent_wd, basename), addressing the
long-standing FIXME in tail_forever_inotify.
Keep ownership consistent with wd_to_name: parent_by_name is created
only for Follow_name and returned to the caller, so fallback paths can
return without local hash cleanup.
Hash basenames with hash_string() and mix in parent_wd, matching the
existing gnulib helper rather than a hand-rolled string hash.
Matching cost for N directory events that each compare against N names
(illustrative host timings of the scan vs hash lookup alone):
N=1000: ~0.018s -> ~0.000s
N=5000: ~0.39s -> ~0.000s
N=10000: ~1.5s -> ~0.000s
End-to-end recreate storms remain largely file-system bound on this
host; the hash removes the quadratic name-matching CPU from that path.
* src/tail.c (parent_name_hasher, parent_name_comparator): New.
(tail_forever_inotify): Build and use parent_by_name; return it to the
caller.
(main): Free parent_ht when non-NULL.
* tests/tail/inotify-parent-hash.sh: Require notification mode; cover
multiple names in one directory and the same basename in two
directories.
* tests/local.mk: Reference the new test.
* NEWS: Mention the improvement.
configure accepted (and needed) both --without-libsmack
and --disable-libsmack specified, to fully disable support.
* gl/modules/smack: Require gl_FUNC_ACL_ARG so we
use a consistent and single --without-libsmack option.
This also better aligns with --without-selinux.
* NEWS: Mention the Build-related change.
On systems where the security context reports as unsupported,
and we encountered a file without ACLs, no further lookups
would be performed. Introduced in commit v9.5-156-gb857d66b5.
This fix is along similar lines as commit v9.6-40-gcb2abbac7.
* src/ls.c (file_has_aclinfo_cache): Don't mark file system as
unsupported if there might be ACLs or capabilities present.
* tests/ls/acl-cache.sh: Add a new test.
* tests/local.mk: Reference the new test.
* tests/ls/acl.sh: Add a check.
* NEWS: Mention the bug fix.
Since v9.10 (Feb 2026) --help always outputs bold and hyperlinks
even when output was not a tty, as this was thought more useful
with pagers and grep etc. This change makes the more conservative
choice of only outputting markup to tty so that users who do not
have less setup to display color (-R), or users who enable color
by default in grep, get improved output (though without URLs etc.)
* src/system.h (oputs_): Call isatty() when not
forcing markup with $IN_HELP2MAN. Also reverse the
double negatives to a more natural form.
* man/local.mk: Remove redundant assignment of $TERM.
* doc/coreutils.texi (common options): Mention that --help markup
requires output to be a tty, and that $IN_HELP2MAN overrides that.
* NEWS: Mention the change in behavior.
* NEWS: Mention the crash when invoking various programs --help option
when configured with --disable-bold-man-page-references and
--disable-manual-url.
$ ./configure --without-libgmp --quiet
$ dd bs=64k count=1 if=/dev/urandom of=58.in
$ time src/basenc-before --base58 58.in >/dev/null
real 0m6.588s
$ time src/basenc-after --base58 58.in >/dev/null
real 0m3.463s
* src/basenc.c (base58_encode): Remove an affirm that is very expensive
in the minigmp implementation. Essentially the same affirm was done
at the start of the function anyway.
* NEWS: Mention the improvement (including the impending similar
mpz_sizeinbase() removal from mini-gmp).
With POSIX (and the LI18NUX2000 patch) backspaces back up by 1 column.
This matches terminal output. Note less(1) and thus grotty(1)
use per character backup accounting for their legacy bold/underline
markup format, so we'll keep --characters to enable that mode if needed.
This also avoids the issue of multiple backspaces
using the width of a single previous character.
* src/fold.c (adjust_column): Without -c,
have backspace back up by 1 column.
* doc/coreutils.texi (fold invocation): Mention that --characters
does per character width backspace accounting.
* tests/fold/fold-characters.sh: Add/Adjust test cases.
* NEWS: Mention the change in behavior.
* src/chroot.c (main): When the primary group was inferred from the
uid outside the chroot, let a successful getpwuid() inside the chroot
replace it, as is already done for the uid and supplemental groups.
Previously the gid found outside persisted, so for example
'chroot --userspec=alice NEWROOT' ran with alice's uid from NEWROOT
but alice's gid from the host.
* NEWS: Mention the bug fix.
Link: https://github.com/coreutils/coreutils/pull/363
cut, expand, fold, join, numfmt, unexpand, uniq, on non-GLIBC platforms
treated the \u0085 (next line) character as a blank character.
src/system.h (c32isvertspace): Include 0x0085 so c32issep() excludes it.
Also split out to ...
(c32isnewline): ... a new function, in case we need to
consider unicode newlines in isolation in future.
* tests/unexpand/mb.sh: Add a test case to both ensure
processing of \u0085 characters does not overflow a buffer,
and that those characters are not treated as separators.
* NEWS: Mention the fix.
Link: https://github.com/coreutils/coreutils/pull/361
* src/unexpand.c (unexpand): Clamp a negative c32width() to 1 when
accumulating a blank, matching the sibling non-blank path and expand
and fold. A separator whose display width is negative (e.g. U+0085
where c32issep() accepts it) left 'column' un-advanced, so the pending
blank buffer, sized for one byte of advance per blank, grew without
bound.
* NEWS: Mention the bug fix.
Link: https://github.com/coreutils/coreutils/pull/361
Generate ASCII and UTF-8 data:
$ yes $(yes eeeaae | head -n10K | paste -s -d,) | head -n10K > ll.in
$ yes $(yes éééááé | head -n9 | paste -s -d,) | head -n1M > mb.in
ASCII is 14x faster:
$ time src/wc-before -m < ll.in
real 0m1.801s
$ time src/wc-after -m < ll.in
real 0m0.123s
UTF-8 is 7x faster:
$ time src/wc-before -m < mb.in
real 0m1.399s
$ time src/wc-after -m < mb.in
real 0m0.189s
* src/wc.c (wc): Use the u8_count() routine like cut(1),
to optimize counting valid UTF-8 characters.
* tests/wc/wc.pl: Add a test case.
* NEWS: Mention the improvement.
Commit v9.4-43-ga6064bb86 introduced this edge case
in handling multi-byte characters spanning the input buffer.
* src/wc.c (wc): Ensure we include the bytes previously read
but as yet unprocessed.
* tests/wc/mb-non-utf8.sh: Add a new test for miscounted GB118030 chars.
* tests/local.mk: Reference the new test.
* tests/wc/wc.pl: Add a new check for word count with a
UTF-8 space spanning a buffer boundary.
* NEWS: Mention the bug fix.
Increases throughput when no delimiters found by up to 15x.
$ yes | head -n10M > sl.in
$ time LC_ALL=C src/cut-before -f10 -w sl.in >/dev/null
real 0m0.171s
$ time LC_ALL=C src/cut-after -f10 -w sl.in >/dev/null
real 0m0.011s
* src/cut.c (cut_fields_bytesearch): Also add a byte search
shortcut for the -w case in uni-byte locales.
Performance was tested with GCC 16 on an i7-5600U with
CFLAGS='-march=native -O3 -flto' with the following setup:
$ yes | head -n10M > sl.in
$ yes $(yes eeeaae | head -n10K | paste -s -d' ') | head -n10K > llw.in
$ yes $(yes eeeaae | head -n9 | paste -s -d' ') | head -n1M > asw.in
$ yes $(yes éééááé | head -n9 | paste -s -d$'\xe2\x80\x83') |
head -n1M > mbw.in
for type in sl llw asw mbw; do
cat $type.in >/dev/null;
for imp in '-before' '-after'; do
echo ============ "${imp:-base}" $type ==============;
for d in -c; do
fields='-f1 -f10 -f100'
test "$d" = "-c" && { fields='-c1 -c10 -c100000'; d=''; }
for f in $fields; do
for loc in C.UTF-8; do
# Skip -b for UTF-8 as no different
test "$loc" = C.UTF-8 && echo "$f" | grep -q -- -b \
&& continue
# Skip multi-byte delimiter for C and not allowed
test "$loc" = C && test $(echo -n "$d" | wc -c) -ge 4 \
&& continue
bin=src/cut${imp}
LC_ALL=$loc $bin $f $d /dev/null 2>/dev/null &&
hyperfine --warmup=2 -m2 -M6 \
"LC_ALL=$loc $bin $f $d $type.in >/dev/null" ||
printf 'Benchmark 1: %s\n unsupported\n\n' \
"LC_ALL=$loc $bin $f $d $type.in >/dev/null"
done;
done;
done;
done;
done
After a little post-processing of the results, we get:
-- src/cut-before
| command | sl | llw | asw | mbw |
| ------------- | -------- | -------- | -------- | -------- |
| UTF8 -c1 | 60.7 ms | 1.244 s | 123.5 ms | 515.2 ms |
| UTF8 -c10 | 39.3 ms | 1.248 s | 127.4 ms | 526.0 ms |
| UTF8 -c100000 | 39.4 ms | 1.242 s | 121.4 ms | 514.3 ms |
-- src/cut-after
| command | sl | llw | asw | mbw |
| ------------- | -------- | -------- | -------- | -------- |
| UTF8 -c1 | 70.9 ms | 105.5 ms | 27.0 ms | 47.6 ms |
| UTF8 -c10 | 55.7 ms | 105.7 ms | 48.2 ms | 126.8 ms |
| UTF8 -c100000 | 55.2 ms | 1.596 s | 158.8 ms | 555.1 ms |
* src/cut.c (cut_characters_mode): Shortcut the line delimiter
search if finished processing characters.
* tests/cut/cut.pl: Add a test case.
Reported by Brian Foster in:
<https://bugs.launchpad.net/ubuntu/+source/coreutils/+bug/2161155>
* gnulib: Update to get commit b18879b9ed (canonicalize: Fix a missing
check for symlink loops., 2026-09-25)
* tests/misc/realpath.sh: Add a call to getlimits_. Add a test case.
* NEWS: Mention the bug fix.
This was seen with a NetBSD failure in the pipe-f2.sh test
due to it clearing the EOF indication on a fifo, and thus
blocking in the subsequent read. That was discussed at:
https://lists.gnu.org/r/coreutils/2026-04/msg00129.htmlhttps://bugs.gnu.org/81923
Note the NetBSD issue may be addressed in NetBSD 12 as
discussed in the bug above.
This is more defensive/consistent in the case
where a subsequent read on a file blocks.
We might be operating on non fifos after all.
* src/tail.c (tail_forever): Flush output before we might block.
* tests/tail/pipe-f2.sh: Test non inotify path on all platforms.
* NEWS: Mention the improvement.
zstd compressed sources are less than half the size
of gzip coompressed sources, so are a better secondary
distribution format in addition to xz.
* README-prereq: Remove gzip, Add zstd.
* bootstrap.conf (buildreq): Likewise.
Bump automake version check to 1.16.2 (released 2020).
* configure.ac (AM_INIT_AUTOMAKE): Disable gz, add dist-zstd.
Bump automake version requirement to 1.16.2.
* cfg.mk: Use compression level 18, and multi-threading.
* NEWS: Mention the change.
Quoting is currently only enabled by default when writing to terminals,
but it is usually desired to constrain the output format for processing.
E.g. for processing by a shell you can now:
env --quoting-style=shell-escape | grep ^FOO
We use an option rather than reyling on $QUOTING_STYLE so
that $QUOTING_STYLE is restricted to be user config for terminals
and does not impact redirected processing.
Also it avoids an extra getenv() call if not outputting to tty.
* src/env.c (main): Parse --quoting-style and use that for the output
format for all outputs.
* src/printenv.c (main): Likewise.
* doc/coreutils.texi (env invocation): Describe --quoting-style.
(printenv invocation): Likewise.
* tests/env/env.sh: Reinstate testing of various output modes.
* tests/misc/printenv.sh: Likewise.
* NEWS: Mention the new feature. Also mention the change from
the previous commit not done there so that builders would have
a clean patch against the previous release.
parse_ls_color stores color_indicator[C_LINK].string as a pointer into
the color_buf buffer, then frees color_buf on the unparsable-value path.
The "ln=target" check after the parse loop still read that freed buffer,
e.g. with LS_COLORS='ln=target:x'. Skip it on the failure path, where
color output is disabled anyway and the buffer is gone.
* src/ls.c (parse_ls_color): Return after freeing color_buf on failure,
so the color_indicator[C_LINK] check only runs when the buffer is live.
* tests/ls/color-symlink-target.sh: New test.
* tests/local.mk (all_tests): Add it.
* NEWS: Mention the fix.
Link: https://github.com/coreutils/coreutils/pull/352
This adds an ELF note as per the UAPI Group's .note.dlopen spec:
$ readelf -p .note.dlopen src/sort
String dump of section '.note.dlopen':
[ 4] y
[ a] |@FDO
[ 10] [{"feature":"random-sort",
"description":"Support for random sorting",
"priority":"required",
"soname":["libcrypto.so.3"]}]
* bootstrap.conf: Add sd-dlopen.
* src/sort.c (DLOPEN_LIBCRYPTO && HAVE_OPENSSL_MD5): Add an ELF note
with SD_ELF_NOTE_DLOPEN() so that packagers can determine the libcrypto
dependency, needed when --random-sort is specified.
* NEWS: Mention the Build-related change.
There were no significant performance changes from the test cases
in commit a325c9978, but adding additional whitespace delimited cases
shows significant improvement. Below, with -f1, typical space delimited
input shows 4x more throughput, while the long line test shows 17x more.
Performance was tested with GCC 16 on an i7-5600U with
CFLAGS='-march=native -O3 -flto' with the following setup:
$ yes | head -n10M > sl.in
$ yes $(yes eeeaae | head -n10K | paste -s -d' ') | head -n10K > llw.in
$ yes $(yes eeeaae | head -n9 | paste -s -d' ') | head -n1M > asw.in
$ yes $(yes éééááé | head -n9 | paste -s -d$'\xe2\x80\x83') |
head -n1M > mbw.in
for type in sl llw asw mbw; do
cat $type.in >/dev/null;
for imp in '-before' '-after'; do
echo ============ "${imp:-base}" $type ==============;
for d in -w; do
fields='-f1 -f10 -f100'
test "$d" = "-b" && { fields='-b1 -b10 -b100'; d=''; }
test "$d" = "-c" && { fields='-c1 -c10 -c100'; d=''; }
for f in $fields; do
for loc in C.UTF-8; do
# Skip -b for UTF-8 as no different
test "$loc" = C.UTF-8 && echo "$f" | grep -q -- -b \
&& continue
# Skip multi-byte delimiter for C and not allowed
test "$loc" = C && test $(echo -n "$d" | wc -c) -ge 4 \
&& continue
bin=src/cut${imp}
LC_ALL=$loc $bin $f $d /dev/null 2>/dev/null &&
hyperfine --warmup=2 -m2 -M6 \
"LC_ALL=$loc $bin $f $d $type.in >/dev/null" ||
printf 'Benchmark 1: %s\n unsupported\n\n' \
"LC_ALL=$loc $bin $f $d $type.in >/dev/null"
done;
done;
done;
done;
done
After a little post-processing of the results, we get:
-- src/cut-before
| command | sl | llw | asw | mbw |
| --------------- | -------- | -------- | -------- | -------- |
| UTF8 -f1 -w | 96.2 ms | 1.916 s | 190.6 ms | 906.5 ms |
| UTF8 -f10 -w | 104.6 ms | 1.921 s | 187.7 ms | 845.6 ms |
| UTF8 -f100 -w | 104.4 ms | 1.916 s | 187.4 ms | 846.4 ms |
-- src/cut-after
| command | sl | llw | asw | mbw |
| --------------- | -------- | -------- | -------- | -------- |
| UTF8 -f1 -w | 88.7 ms | 112.4 ms | 43.5 ms | 146.3 ms |
| UTF8 -f10 -w | 95.2 ms | 114.4 ms | 193.5 ms | 848.4 ms |
| UTF8 -f100 -w | 94.8 ms | 130.6 ms | 194.4 ms | 848.1 ms |
* src/cut.c (scan_mb_line_end): A new function to skip
to EOL once we have exhausted the field selection.
(cut_fields_mb_any): Only skip after recognizing a field delimiter.
* tests/cut/cut.pl: Add test cases.
* tests/cut/mb-non-utf8.sh: Likewise.
* NEWS: Mention the improvement.
Problem reported by Pádraig Brady (bug#81776#16).
* src/copy.c (handle_clone_fail): Be more cautious if
ioctl+FICLONE failed with EIO; do not fall back to read+write,
even if --reflink=auto is in effect.
Assume that XFS allocation groups can also fail with EDQUOT etc.,
so treat those failures like ENOSPC.
* src/copy.c (is_terminal_error): Remove; no longer used.
(handle_clone_fail): Remove DEST_DESC arg; no longer needed.
All uses changed. Simplify by acting as if is_terminal_error
always returns false. Change "!= 0" to "< 0" when either will do
for a syscall, as a matter of convention.
reflinking can fail due to failure to allocate metadata,
while a standard copy may succeed.
* src/copy.c (is_terminal_error): Remove ENOSPC from the list.
Fixes https://bugs.gnu.org/81776
eq_mode(), which is used to determine if tcsetattr() was successful,
failed unnecessarily after speed setting under certain circumstances:
1. the kernel MAY round the speed to the nearest supported value,
so allow a variation of +/- 1/4 bit time per character from
what was originally requested.
2. There MAY be more than one internal binary encoding of a specific
speed (e.g. on Linux). On systems where that information
affects c_cflag, this may introduce inconsistencies;
filter out the known speed-related flags in c_cflag.
3. It is undefined in POSIX if cfsetispeed (..., 0) is retained or
normalized across tcsetattr () ... tcgetattr ().
If cfgetispeed () returns 0, compare the output speed instead.
* src/stty.c (eq_mode): Mask of some of the speed related bits
to avoid checking them for exact equality.
(speed_matches): A new helper to apply the more lenient matching
of requested and resulting speeds.
* NEWS: Mention the bug fix.
Note there was worry about redundant linking with -lsystemd
when getlogin() is not replaced, however that is mitigated
in general with the --as-needed linker option (the lib-ignore
gnulib module). Tested with:
./configure --with-systemd gl_cv_func_getlogin_works=no
* NEWS: Mention the Build-related fix.
Reported at https://bugs.debian.org/1129960
* src/copy.c (copy_reg, copy_interal): Don't change the exit status if
copying extended attributes fails and we are 'mv'.
* src/copy.h (struct cp_options): Update some commentary.
* src/mv.c (cp_option_init): Enable require_preserve_xattr in the
cp_options struct.
* tests/cp/cp-mv-enotsup-xattr.sh: Check that the error is emitted when
'mv' is built with extended attribute support.
* doc/coreutils.texi (mv invocation): Mention that all errors are
emitted, but do not modify the exit status.
* NEWS: Mention the bug fix.
Fixes https://bugs.gnu.org/13601