diff --git a/.coreutils.metadata b/.coreutils.metadata new file mode 100644 index 0000000..c2489a3 --- /dev/null +++ b/.coreutils.metadata @@ -0,0 +1 @@ +cc7fe47b21eb49dd2ee4cdb707570f42fb2c8cc6 SOURCES/coreutils-8.22.tar.xz diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..040d6cc --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/coreutils-8.22.tar.xz diff --git a/SOURCES/coreutils-4.5.3-langinfo.patch b/SOURCES/coreutils-4.5.3-langinfo.patch new file mode 100644 index 0000000..25dec6c --- /dev/null +++ b/SOURCES/coreutils-4.5.3-langinfo.patch @@ -0,0 +1,18 @@ +--- coreutils-5.92/src/date.c.langinfo 2005-09-16 09:06:57.000000000 +0100 ++++ coreutils-5.92/src/date.c 2005-10-24 18:09:16.000000000 +0100 +@@ -451,14 +451,7 @@ + format = DATE_FMT_LANGINFO (); + if (! *format) + { +- /* Do not wrap the following literal format string with _(...). +- For example, suppose LC_ALL is unset, LC_TIME=POSIX, +- and LANG="ko_KR". In that case, POSIX says that LC_TIME +- determines the format and contents of date and time strings +- written by date, which means "date" must generate output +- using the POSIX locale; but adding _() would cause "date" +- to use a Korean translation of the format. */ +- format = "%a %b %e %H:%M:%S %Z %Y"; ++ format = dcgettext(NULL, N_("%a %b %e %H:%M:%S %Z %Y"), LC_TIME); + } + } + diff --git a/SOURCES/coreutils-6.10-configuration.patch b/SOURCES/coreutils-6.10-configuration.patch new file mode 100644 index 0000000..54df1d6 --- /dev/null +++ b/SOURCES/coreutils-6.10-configuration.patch @@ -0,0 +1,157 @@ +diff -urNp coreutils-8.21-orig/gnulib-tests/gnulib.mk coreutils-8.21/gnulib-tests/gnulib.mk +--- coreutils-8.21-orig/gnulib-tests/gnulib.mk 2013-02-07 17:58:44.000000000 +0100 ++++ coreutils-8.21/gnulib-tests/gnulib.mk 2013-02-15 10:12:28.110593165 +0100 +@@ -267,9 +267,9 @@ EXTRA_DIST += nap.h test-chown.h test-ch + + ## begin gnulib module cloexec-tests + +-TESTS += test-cloexec +-check_PROGRAMS += test-cloexec +-EXTRA_DIST += test-cloexec.c macros.h ++#TESTS += test-cloexec ++#check_PROGRAMS += test-cloexec ++#EXTRA_DIST += test-cloexec.c macros.h + + ## end gnulib module cloexec-tests + +@@ -378,9 +378,9 @@ EXTRA_DIST += test-dup.c signature.h mac + + ## begin gnulib module dup2-tests + +-TESTS += test-dup2 +-check_PROGRAMS += test-dup2 +-EXTRA_DIST += test-dup2.c signature.h macros.h ++#TESTS += test-dup2 ++#check_PROGRAMS += test-dup2 ++#EXTRA_DIST += test-dup2.c signature.h macros.h + + ## end gnulib module dup2-tests + +@@ -439,10 +439,10 @@ EXTRA_DIST += test-fadvise.c + + ## begin gnulib module fchdir-tests + +-TESTS += test-fchdir +-check_PROGRAMS += test-fchdir +-test_fchdir_LDADD = $(LDADD) $(LIBINTL) +-EXTRA_DIST += test-fchdir.c signature.h macros.h ++#TESTS += test-fchdir ++#check_PROGRAMS += test-fchdir ++#test_fchdir_LDADD = $(LDADD) $(LIBINTL) ++#EXTRA_DIST += test-fchdir.c signature.h macros.h + + ## end gnulib module fchdir-tests + +@@ -874,9 +874,9 @@ EXTRA_DIST += test-getloadavg.c signatur + + ## begin gnulib module getlogin-tests + +-TESTS += test-getlogin +-check_PROGRAMS += test-getlogin +-EXTRA_DIST += test-getlogin.c signature.h macros.h ++#TESTS += test-getlogin ++#check_PROGRAMS += test-getlogin ++#EXTRA_DIST += test-getlogin.c signature.h macros.h + + ## end gnulib module getlogin-tests + +@@ -1119,10 +1119,10 @@ EXTRA_DIST += test-link.h test-link.c si + + ## begin gnulib module linkat-tests + +-TESTS += test-linkat +-check_PROGRAMS += test-linkat +-test_linkat_LDADD = $(LDADD) @LIBINTL@ +-EXTRA_DIST += test-link.h test-linkat.c signature.h macros.h ++#TESTS += test-linkat ++#check_PROGRAMS += test-linkat ++#test_linkat_LDADD = $(LDADD) @LIBINTL@ ++#EXTRA_DIST += test-link.h test-linkat.c signature.h macros.h + + ## end gnulib module linkat-tests + +@@ -1331,9 +1331,9 @@ EXTRA_DIST += test-memcoll.c macros.h + + ## begin gnulib module memrchr-tests + +-TESTS += test-memrchr +-check_PROGRAMS += test-memrchr +-EXTRA_DIST += test-memrchr.c zerosize-ptr.h signature.h macros.h ++#TESTS += test-memrchr ++#check_PROGRAMS += test-memrchr ++#EXTRA_DIST += test-memrchr.c zerosize-ptr.h signature.h macros.h + + ## end gnulib module memrchr-tests + +@@ -1978,9 +1978,9 @@ EXTRA_DIST += test-statat.c + + ## begin gnulib module stdalign-tests + +-TESTS += test-stdalign +-check_PROGRAMS += test-stdalign +-EXTRA_DIST += test-stdalign.c macros.h ++#TESTS += test-stdalign ++#check_PROGRAMS += test-stdalign ++#EXTRA_DIST += test-stdalign.c macros.h + + ## end gnulib module stdalign-tests + +@@ -2323,9 +2323,9 @@ EXTRA_DIST += test-uname.c signature.h m + + ## begin gnulib module unistd-safer-tests + +-TESTS += test-dup-safer +-check_PROGRAMS += test-dup-safer +-EXTRA_DIST += test-dup-safer.c macros.h ++#TESTS += test-dup-safer ++#check_PROGRAMS += test-dup-safer ++#EXTRA_DIST += test-dup-safer.c macros.h + + ## end gnulib module unistd-safer-tests + +@@ -2438,10 +2438,10 @@ EXTRA_DIST += test-usleep.c signature.h + + ## begin gnulib module utimens-tests + +-TESTS += test-utimens +-check_PROGRAMS += test-utimens +-test_utimens_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_NANOSLEEP) @LIBINTL@ +-EXTRA_DIST += nap.h test-futimens.h test-lutimens.h test-utimens.h test-utimens-common.h test-utimens.c macros.h ++#TESTS += test-utimens ++#check_PROGRAMS += test-utimens ++#test_utimens_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_NANOSLEEP) @LIBINTL@ ++#EXTRA_DIST += nap.h test-futimens.h test-lutimens.h test-utimens.h test-utimens-common.h test-utimens.c macros.h + + ## end gnulib module utimens-tests + +diff -urNp coreutils-8.21-orig/tests/local.mk coreutils-8.21/tests/local.mk +--- coreutils-8.21-orig/tests/local.mk 2013-02-11 11:30:12.000000000 +0100 ++++ coreutils-8.21/tests/local.mk 2013-02-15 10:10:55.890532258 +0100 +@@ -131,6 +131,7 @@ all_root_tests = \ + tests/rm/no-give-up.sh \ + tests/rm/one-file-system.sh \ + tests/rm/read-only.sh \ ++ tests/tail-2/inotify-hash-abuse.sh \ + tests/tail-2/append-only.sh \ + tests/touch/now-owned-by-other.sh + +@@ -163,7 +164,6 @@ all_tests = \ + tests/cp/link-heap.sh \ + tests/cp/no-ctx.sh \ + tests/misc/tty-eof.pl \ +- tests/tail-2/inotify-hash-abuse.sh \ + tests/tail-2/inotify-hash-abuse2.sh \ + tests/tail-2/F-vs-missing.sh \ + tests/tail-2/F-vs-rename.sh \ +diff -urNp coreutils-8.21-orig/tests/touch/no-dereference.sh coreutils-8.21/tests/touch/no-dereference.sh +--- coreutils-8.21-orig/tests/touch/no-dereference.sh 2013-01-31 01:46:25.000000000 +0100 ++++ coreutils-8.21/tests/touch/no-dereference.sh 2013-02-15 10:10:55.889593383 +0100 +@@ -42,6 +42,8 @@ test -f nowhere && fail=1 + grep '^#define HAVE_UTIMENSAT 1' "$CONFIG_HEADER" > /dev/null || + grep '^#define HAVE_LUTIMES 1' "$CONFIG_HEADER" > /dev/null || + skip_ 'this system lacks the utimensat function' ++grep '^#define HAVE_WORKINGKOJI 1' "$CONFIG_HEADER" > /dev/null || ++ skip_ 'rest of the test disabled due to koji lack of utimensat function' + + # Changing time of dangling symlink is okay. + # Skip the test if this fails, but the error text corresponds to diff --git a/SOURCES/coreutils-6.10-manpages.patch b/SOURCES/coreutils-6.10-manpages.patch new file mode 100644 index 0000000..3f5d37b --- /dev/null +++ b/SOURCES/coreutils-6.10-manpages.patch @@ -0,0 +1,13 @@ +diff -urNp coreutils-6.12-orig/src/md5sum.c coreutils-6.12/src/md5sum.c +--- coreutils-6.12-orig/src/md5sum.c 2008-05-26 08:40:33.000000000 +0200 ++++ coreutils-6.12/src/md5sum.c 2008-10-21 16:07:28.000000000 +0200 +@@ -175,6 +175,9 @@ With no FILE, or when FILE is -, read st + fputs (_("\ + -t, --text read in text mode (default)\n\ + "), stdout); ++ fputs (_("\ ++ Note: There is no difference between binary and text mode option on GNU system.\n\ ++"), stdout); + fputs (_("\ + \n\ + The following four options are useful only when verifying checksums:\n\ diff --git a/SOURCES/coreutils-7.4-sttytcsadrain.patch b/SOURCES/coreutils-7.4-sttytcsadrain.patch new file mode 100644 index 0000000..bc3f47b --- /dev/null +++ b/SOURCES/coreutils-7.4-sttytcsadrain.patch @@ -0,0 +1,12 @@ +diff -urNp coreutils-8.13-orig/src/stty.c coreutils-8.13/src/stty.c +--- coreutils-8.13-orig/src/stty.c 2011-07-28 12:38:27.000000000 +0200 ++++ coreutils-8.13/src/stty.c 2011-09-09 10:18:57.526687209 +0200 +@@ -1005,7 +1005,7 @@ main (int argc, char **argv) + spurious difference in an uninitialized portion of the structure. */ + static struct termios new_mode; + +- if (tcsetattr (STDIN_FILENO, TCSADRAIN, &mode)) ++ if (tcsetattr (STDIN_FILENO, TCSANOW, &mode)) + error (EXIT_FAILURE, errno, "%s", device_name); + + /* POSIX (according to Zlotnick's book) tcsetattr returns zero if diff --git a/SOURCES/coreutils-8.2-uname-processortype.patch b/SOURCES/coreutils-8.2-uname-processortype.patch new file mode 100644 index 0000000..4c83df8 --- /dev/null +++ b/SOURCES/coreutils-8.2-uname-processortype.patch @@ -0,0 +1,49 @@ +diff -urNp coreutils-8.2-orig/src/uname.c coreutils-8.2/src/uname.c +--- coreutils-8.2-orig/src/uname.c 2009-09-23 10:25:44.000000000 +0200 ++++ coreutils-8.2/src/uname.c 2009-12-19 09:09:11.663607110 +0100 +@@ -301,7 +301,7 @@ main (int argc, char **argv) + + if (toprint & PRINT_PROCESSOR) + { +- char const *element = unknown; ++ char *element = unknown; + #if HAVE_SYSINFO && defined SI_ARCHITECTURE + { + static char processor[257]; +@@ -308,6 +308,12 @@ main (int argc, char **argv) + if (0 <= sysinfo (SI_ARCHITECTURE, processor, sizeof processor)) + element = processor; + } ++#else ++ { ++ static struct utsname u; ++ uname(&u); ++ element = u.machine; ++ } + #endif + #ifdef UNAME_PROCESSOR + if (element == unknown) +@@ -351,7 +357,7 @@ main (int argc, char **argv) + + if (toprint & PRINT_HARDWARE_PLATFORM) + { +- char const *element = unknown; ++ char *element = unknown; + #if HAVE_SYSINFO && defined SI_PLATFORM + { + static char hardware_platform[257]; +@@ -353,6 +359,14 @@ main (int argc, char **argv) + hardware_platform, sizeof hardware_platform)) + element = hardware_platform; + } ++#else ++ { ++ static struct utsname u; ++ uname(&u); ++ element = u.machine; ++ if(strlen(element)==4 && element[0]=='i' && element[2]=='8' && element[3]=='6') ++ element[1]='3'; ++ } + #endif + #ifdef UNAME_HARDWARE_PLATFORM + if (element == unknown) diff --git a/SOURCES/coreutils-8.22-cp-selinux.patch b/SOURCES/coreutils-8.22-cp-selinux.patch new file mode 100644 index 0000000..ed3fb47 --- /dev/null +++ b/SOURCES/coreutils-8.22-cp-selinux.patch @@ -0,0 +1,109 @@ +From 2b3b5bfcd5f4161d17c0bc3d43f6edcfc4a2b294 Mon Sep 17 00:00:00 2001 +From: Nicolas Looss +Date: Sat, 4 Jan 2014 03:03:51 +0000 +Subject: [PATCH] copy: fix a segfault in SELinux context copying code + +* src/selinux.c (restorecon_private): On ArchLinux the +`fakeroot cp -a file1 file2` command segfaulted due +to getfscreatecon() returning a NULL context. +So map this to the sometimes ignored ENODATA error, +rather than crashing. +* tests/cp/no-ctx.sh: Add a new test case. +* tests/local.mk: Reference the new test. +--- + src/selinux.c | 5 ++++ + tests/cp/no-ctx.sh | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + tests/local.mk | 1 + + 3 files changed, 59 insertions(+), 0 deletions(-) + create mode 100755 tests/cp/no-ctx.sh + +diff --git a/src/selinux.c b/src/selinux.c +index cd38a81..016db16 100644 +--- a/src/selinux.c ++++ b/src/selinux.c +@@ -192,6 +192,11 @@ restorecon_private (char const *path, bool local) + { + if (getfscreatecon (&tcon) < 0) + return rc; ++ if (!tcon) ++ { ++ errno = ENODATA; ++ return rc; ++ } + rc = lsetfilecon (path, tcon); + freecon (tcon); + return rc; +diff --git a/tests/cp/no-ctx.sh b/tests/cp/no-ctx.sh +new file mode 100755 +index 0000000..59d30de +--- /dev/null ++++ b/tests/cp/no-ctx.sh +@@ -0,0 +1,53 @@ ++#!/bin/sh ++# Ensure we handle file systems returning no SELinux context, ++# which triggered a segmentation fault in coreutils-8.22. ++# This test is skipped on systems that lack LD_PRELOAD support; that's fine. ++# Similarly, on a system that lacks lgetfilecon altogether, skipping it is fine. ++ ++# Copyright (C) 2014 Free Software Foundation, Inc. ++ ++# This program is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++ ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++ ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src ++print_ver_ cp ++require_gcc_shared_ ++ ++# Replace each getfilecon and lgetfilecon call with a call to these stubs. ++cat > k.c <<'EOF' || skip_ ++#include ++#include ++ ++int getfilecon (const char *path, security_context_t *con) ++{ errno=ENODATA; return -1; } ++int lgetfilecon (const char *path, security_context_t *con) ++{ errno=ENODATA; return -1; } ++EOF ++ ++# Then compile/link it: ++$CC -shared -fPIC -O2 k.c -o k.so \ ++ || skip_ 'failed to build SELinux shared library' ++ ++touch file_src ++ ++# New file with SELinux context optionally included ++LD_PRELOAD=./k.so cp -a file_src file_dst || fail=1 ++ ++# Existing file with SELinux context optionally included ++LD_PRELOAD=./k.so cp -a file_src file_dst || fail=1 ++ ++# ENODATA should give an immediate error when required to preserve ctx ++# This is debatable, and maybe we should not fail when no context available? ++LD_PRELOAD=./k.so cp --preserve=context file_src file_dst && fail=1 ++ ++Exit $fail +diff --git a/tests/local.mk b/tests/local.mk +index dc7341c..9d556f6 100644 +--- a/tests/local.mk ++++ b/tests/local.mk +@@ -161,6 +161,7 @@ all_tests = \ + tests/rm/ext3-perf.sh \ + tests/rm/cycle.sh \ + tests/cp/link-heap.sh \ ++ tests/cp/no-ctx.sh \ + tests/misc/tty-eof.pl \ + tests/tail-2/inotify-hash-abuse.sh \ + tests/tail-2/inotify-hash-abuse2.sh \ +-- +1.7.7.6 + diff --git a/SOURCES/coreutils-8.22-cp-sparsecorrupt.patch b/SOURCES/coreutils-8.22-cp-sparsecorrupt.patch new file mode 100644 index 0000000..bda9c3a --- /dev/null +++ b/SOURCES/coreutils-8.22-cp-sparsecorrupt.patch @@ -0,0 +1,279 @@ +From eea6b49210edf69682b2d0606bee17bbccb3765b Mon Sep 17 00:00:00 2001 +From: Dmitry Monakhov +Date: Fri, 30 Oct 2015 22:04:46 +0000 +Subject: [PATCH] copy: fix copying of extents beyond the apparent file size + +fallocate can allocate extents beyond EOF via FALLOC_FL_KEEP_SIZE. +Where there is a gap (hole) between the extents, and EOF is within +that gap, the final hole wasn't reproduced, resulting in silent +data corruption in the copied file (size too small). + +* src/copy.c (extent_copy): Ensure we don't process extents +beyond the apparent file size, since processing and allocating +those is not currently supported. +* tests/cp/fiemap-extents.sh: Renamed from tests/cp/fiemap-empty.sh +and re-enable parts checking the extents at and beyond EOF. +* tests/local.mk: Reference the renamed test. +Fixes http://bugs.gnu.org/21790 +--- + src/copy.c | 19 ++++++++- + tests/cp/fiemap-empty.sh | 102 -------------------------------------------- + tests/cp/fiemap-extents.sh | 81 +++++++++++++++++++++++++++++++++++ + tests/local.mk | 2 +- + 5 files changed, 100 insertions(+), 104 deletions(-) + delete mode 100755 tests/cp/fiemap-empty.sh + create mode 100755 tests/cp/fiemap-extents.sh + +diff --git a/src/copy.c b/src/copy.c +index dc1cd29..6771bb5 100644 +--- a/src/copy.c ++++ b/src/copy.c +@@ -432,6 +432,20 @@ extent_copy (int src_fd, int dest_fd, char *buf, size_t buf_size, + ext_len = 0; + } + ++ /* Truncate extent to EOF. Extents starting after EOF are ++ treated as zero length extents starting right after EOF. ++ Generally this will trigger with an extent starting after ++ src_total_size, and result in creating a hole or zeros until EOF. ++ Though in a file in which extents have changed since src_total_size ++ was determined, we might have an extent spanning that size, ++ in which case we'll only copy data up to that size. */ ++ if (src_total_size < ext_start + ext_len) ++ { ++ if (src_total_size < ext_start) ++ ext_start = src_total_size; ++ ext_len = src_total_size - ext_start; ++ } ++ + hole_size = ext_start - last_ext_start - last_ext_len; + + wrote_hole_at_eof = false; +@@ -495,14 +509,17 @@ extent_copy (int src_fd, int dest_fd, char *buf, size_t buf_size, + off_t n_read; + empty_extent = false; + last_ext_len = ext_len; ++ bool read_hole; + + if ( ! sparse_copy (src_fd, dest_fd, buf, buf_size, + sparse_mode == SPARSE_ALWAYS, + src_name, dst_name, ext_len, &n_read, +- &wrote_hole_at_eof)) ++ &read_hole)) + goto fail; + + dest_pos = ext_start + n_read; ++ if (n_read) ++ wrote_hole_at_eof = read_hole; + } + + /* If the file ends with unwritten extents not accounted for in the +deleted file mode 100755 +index b3b2cd7..0000000 +--- a/tests/cp/fiemap-empty.sh ++++ /dev/null +@@ -1,101 +0,0 @@ +-#!/bin/sh +-# Test cp reads unwritten extents efficiently +- +-# Copyright (C) 2011-2013 Free Software Foundation, Inc. +- +-# This program is free software: you can redistribute it and/or modify +-# it under the terms of the GNU General Public License as published by +-# the Free Software Foundation, either version 3 of the License, or +-# (at your option) any later version. +- +-# This program is distributed in the hope that it will be useful, +-# but WITHOUT ANY WARRANTY; without even the implied warranty of +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-# GNU General Public License for more details. +- +-# You should have received a copy of the GNU General Public License +-# along with this program. If not, see . +- +-. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +-print_ver_ cp +- +-# FIXME: enable any part of this test that is still relevant, +-# or, if none are relevant (now that cp does not handle unwritten +-# extents), just remove the test altogether. +-skip_ 'disabled for now' +- +-touch fiemap_chk +-fiemap_capable_ fiemap_chk || +- skip_ 'this file system lacks FIEMAP support' +-rm fiemap_chk +- +-# TODO: rather than requiring $(fallocate), possible add +-# this functionality to truncate --alloc +-fallocate --help >/dev/null || skip_ 'The fallocate utility is required' +-fallocate -l 1 -n falloc.test || +- skip_ 'this file system lacks FALLOCATE support' +-rm falloc.test +- +-# Require more space than we'll actually use, so that +-# tests run in parallel do not run out of space. +-# Otherwise, with inadequate space, simply running the following +-# fallocate command would induce a temporary disk-full condition, +-# which would cause failure of unrelated tests run in parallel. +-require_file_system_bytes_free_ 800000000 +- +-fallocate -l 600MiB space.test || +- skip_ 'this test needs at least 600MiB free space' +- +-# Disable this test on old BTRFS (e.g. Fedora 14) +-# which reports ordinary extents for unwritten ones. +-filefrag space.test || skip_ 'the 'filefrag' utility is missing' +-filefrag -v space.test | grep -F 'unwritten' > /dev/null || +- skip_ 'this file system does not report empty extents as "unwritten"' +- +-rm space.test +- +-# Ensure we read a large empty file quickly +-fallocate -l 300MiB empty.big || framework_failure_ +-timeout 3 cp --sparse=always empty.big cp.test || fail=1 +-test $(stat -c %s empty.big) = $(stat -c %s cp.test) || fail=1 +-rm empty.big cp.test +- +-# Ensure we handle extents beyond file size correctly. +-# Note until we support fallocate, we will not maintain +-# the file allocation. FIXME: amend this test when fallocate is supported. +-fallocate -l 10MiB -n unwritten.withdata || framework_failure_ +-dd count=10 if=/dev/urandom conv=notrunc iflag=fullblock of=unwritten.withdata +-cp unwritten.withdata cp.test || fail=1 +-test $(stat -c %s unwritten.withdata) = $(stat -c %s cp.test) || fail=1 +-cmp unwritten.withdata cp.test || fail=1 +-rm unwritten.withdata cp.test +- +-# The following to generate unaccounted extents followed by a hole, is not +-# supported by ext4 at least. The ftruncate discards all extents not +-# accounted for in the size. +-# fallocate -l 10MiB -n unacc.withholes +-# dd count=10 if=/dev/urandom conv=notrunc iflag=fullblock of=unacc.withholes +-# truncate -s20M unacc.withholes +- +-# Ensure we handle a hole after empty extents correctly. +-# Since all extents are accounted for in the size, +-# we can maintain the allocation independently from +-# fallocate() support. +-fallocate -l 10MiB empty.withholes +-truncate -s 20M empty.withholes +-sectors_per_block=$(expr $(stat -c %o .) / 512) +-cp empty.withholes cp.test || fail=1 +-test $(stat -c %s empty.withholes) = $(stat -c %s cp.test) || fail=1 +-# These are usually equal but can vary by an IO block due to alignment +-alloc_diff=$(expr $(stat -c %b empty.withholes) - $(stat -c %b cp.test)) +-alloc_diff=$(echo $alloc_diff | tr -d -- -) # abs() +-test $alloc_diff -le $sectors_per_block || fail=1 +-# Again with SPARSE_ALWAYS +-cp --sparse=always empty.withholes cp.test || fail=1 +-test $(stat -c %s empty.withholes) = $(stat -c %s cp.test) || fail=1 +-# cp.test should take 0 space, but allowing for some systems +-# that store default extended attributes in data blocks +-test $(stat -c %b cp.test) -le $sectors_per_block || fail=1 +-rm empty.withholes cp.test +- +-Exit $fail +diff --git a/tests/cp/fiemap-extents.sh b/tests/cp/fiemap-extents.sh +new file mode 100755 +index 0000000..55ec5df +--- /dev/null ++++ b/tests/cp/fiemap-extents.sh +@@ -0,0 +1,81 @@ ++#!/bin/sh ++# Test cp handles extents correctly ++ ++# Copyright (C) 2011-2015 Free Software Foundation, Inc. ++ ++# This program is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++ ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++ ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src ++print_ver_ cp ++ ++require_sparse_support_ ++ ++touch fiemap_chk ++fiemap_capable_ fiemap_chk || ++ skip_ 'this file system lacks FIEMAP support' ++rm fiemap_chk ++ ++fallocate --help >/dev/null || skip_ 'The fallocate utility is required' ++touch falloc.test || framework_failure_ ++fallocate -l 1 -o 0 -n falloc.test || ++ skip_ 'this file system lacks FALLOCATE support' ++rm falloc.test ++ ++# We don't currently handle unwritten extents specially ++if false; then ++# Require more space than we'll actually use, so that ++# tests run in parallel do not run out of space. ++# Otherwise, with inadequate space, simply running the following ++# fallocate command would induce a temporary disk-full condition, ++# which would cause failure of unrelated tests run in parallel. ++require_file_system_bytes_free_ 800000000 ++ ++fallocate -l 600MiB space.test || ++ skip_ 'this test needs at least 600MiB free space' ++ ++# Disable this test on old BTRFS (e.g. Fedora 14) ++# which reports ordinary extents for unwritten ones. ++filefrag space.test || skip_ 'the 'filefrag' utility is missing' ++filefrag -v space.test | grep -F 'unwritten' > /dev/null || ++ skip_ 'this file system does not report empty extents as "unwritten"' ++ ++rm space.test ++ ++# Ensure we read a large empty file quickly ++fallocate -l 300MiB empty.big || framework_failure_ ++timeout 3 cp --sparse=always empty.big cp.test || fail=1 ++test $(stat -c %s empty.big) = $(stat -c %s cp.test) || fail=1 ++rm empty.big cp.test ++fi ++ ++# Ensure we handle extents beyond file size correctly. ++# Note until we support fallocate, we will not maintain ++# the file allocation. FIXME: amend this test if fallocate is supported. ++# Note currently this only uses fiemap logic when the allocation (-l) ++# is smaller than the size, thus identifying the file as sparse. ++# Note the '-l 1' case is an effective noop, and just checks ++# a file with a trailing hole is copied correctly. ++for sparse_mode in always auto never; do ++ for alloc in '-l 4MiB ' '-l 1MiB -o 4MiB' '-l 1'; do ++ dd count=10 if=/dev/urandom iflag=fullblock of=unwritten.withdata ++ truncate -s 2MiB unwritten.withdata || framework_failure_ ++ fallocate $alloc -n unwritten.withdata || framework_failure_ ++ cp --sparse=$sparse_mode unwritten.withdata cp.test || fail=1 ++ test $(stat -c %s unwritten.withdata) = $(stat -c %s cp.test) || fail=1 ++ cmp unwritten.withdata cp.test || fail=1 ++ rm unwritten.withdata cp.test ++ done ++done ++ ++Exit $fail +diff --git a/tests/local.mk b/tests/local.mk +index adf96f0..89fdbb0 100644 +--- a/tests/local.mk ++++ b/tests/local.mk +@@ -446,7 +446,7 @@ all_tests = \ + tests/cp/existing-perm-dir.sh \ + tests/cp/existing-perm-race.sh \ + tests/cp/fail-perm.sh \ +- tests/cp/fiemap-empty.sh \ ++ tests/cp/fiemap-extents.sh \ + tests/cp/fiemap-FMR.sh \ + tests/cp/fiemap-perf.sh \ + tests/cp/fiemap-2.sh \ +-- +1.7.2.5 + diff --git a/SOURCES/coreutils-8.22-date-emptyTZ.patch b/SOURCES/coreutils-8.22-date-emptyTZ.patch new file mode 100644 index 0000000..ca62bc8 --- /dev/null +++ b/SOURCES/coreutils-8.22-date-emptyTZ.patch @@ -0,0 +1,46 @@ +From a10acfb1d2118f9a180181d3fed5399dbbe1df3c Mon Sep 17 00:00:00 2001 +From: Pádraig Brady +Date: Tue, 25 Feb 2014 10:58:48 +0000 +Subject: parse-datetime: fix crash or infloop in TZ="" parsing + +This was reported in http://bugs.gnu.org/16872 +from the coreutils command: date -d 'TZ="""' + +The infinite loop for this case was present since the +initial TZ="" parsing support in commit de95bdc2 29-10-2004. +This was changed to a crash or heap corruption depending +on the platform with commit 2e3e4195 18-01-2010. + +* lib/parse-datetime.y (parse_datetime): Break out of the +TZ="" parsing loop once the second significant " is found. +Also skip over any subsequent whitespace to be consistent +with the non TZ= case. +--- +diff --git a/lib/parse-datetime.y b/lib/parse-datetime.y +index 6ece765..0ba0a52 100644 +--- a/lib/parse-datetime.y ++++ b/lib/parse-datetime.y +@@ -1303,8 +1303,6 @@ parse_datetime (struct timespec *result, char const *p, + char tz1buf[TZBUFSIZE]; + bool large_tz = TZBUFSIZE < tzsize; + bool setenv_ok; +- /* Free tz0, in case this is the 2nd or subsequent time through. */ +- free (tz0); + tz0 = get_tz (tz0buf); + z = tz1 = large_tz ? xmalloc (tzsize) : tz1buf; + for (s = tzbase; *s != '"'; s++) +@@ -1316,7 +1314,12 @@ parse_datetime (struct timespec *result, char const *p, + if (!setenv_ok) + goto fail; + tz_was_altered = true; ++ + p = s + 1; ++ while (c = *p, c_isspace (c)) ++ p++; ++ ++ break; + } + } + +-- +cgit v0.9.0.2 diff --git a/SOURCES/coreutils-8.22-date-example-typo.patch b/SOURCES/coreutils-8.22-date-example-typo.patch new file mode 100644 index 0000000..b5835ab --- /dev/null +++ b/SOURCES/coreutils-8.22-date-example-typo.patch @@ -0,0 +1,30 @@ +From f29a7fb5907c09c53784886997899d5f36c37e86 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?P=C3=A1draig=20Brady?= +Date: Thu, 1 Sep 2016 16:39:04 +0100 +Subject: [PATCH] doc: fix typo in date example + +* doc/coreutils.texi (date invocation): Add a missing quotation mark. +Fixes http://bugs.gnu.org/24349 + +Upstream-commit: 22d188e2991ce64445ba89dbb32e3c6bec42e235 +Signed-off-by: Kamil Dudka +--- + doc/coreutils.texi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/doc/coreutils.texi b/doc/coreutils.texi +index a58339a..88d6506 100644 +--- a/doc/coreutils.texi ++++ b/doc/coreutils.texi +@@ -15467,7 +15467,7 @@ of the month, you can use the (GNU extension) + the padding altogether: + + @example +-date -d 1may '+%B %-d ++date -d 1may '+%B %-d' + @end example + + @item +-- +2.17.2 + diff --git a/SOURCES/coreutils-8.22-dd-progress.patch b/SOURCES/coreutils-8.22-dd-progress.patch new file mode 100644 index 0000000..d07a6a2 --- /dev/null +++ b/SOURCES/coreutils-8.22-dd-progress.patch @@ -0,0 +1,479 @@ +From af2a4ed22594badd2719c0123441d69b17bd8328 Mon Sep 17 00:00:00 2001 +From: Federico Simoncelli +Date: Fri, 26 Sep 2014 17:12:32 +0000 +Subject: [PATCH] dd: new status=progress level to print stats periodically + +* src/dd.c: Report the transfer progress every second when the +new status=progress level is used. Adjust the handling and +description of the status= option so that they're treated as +mutually exclusive levels, rather than flags with implicit precedence. +* doc/coreutils.texi (dd invocation): Document the new progress +status level. Reference the new level in the description of SIGUSR1. +* tests/dd/stats.sh: Add new test for status=progress. +* tests/dd/misc.sh: Change so status=none only takes precedence +if it's the last level specified. +--- +diff --git a/doc/coreutils.texi b/doc/coreutils.texi +index 7d32af5..03bb710 100644 +--- a/doc/coreutils.texi ++++ b/doc/coreutils.texi +@@ -8631,24 +8631,32 @@ will ensure that @samp{count=} corresponds to complete input blocks + rather than the traditional POSIX specified behavior of counting + input read operations. + +-@item status=@var{which} ++@item status=@var{level} + @opindex status + Transfer information is normally output to stderr upon + receipt of the @samp{INFO} signal or when @command{dd} exits. +-Specifying @var{which} will identify which information to suppress. ++Specifying @var{level} will adjust the amount of information printed, ++with the last @var{level} specified taking precedence. + + @table @samp + +-@item noxfer +-@opindex noxfer @r{dd status=} +-Do not print the transfer rate and volume statistics +-that normally make up the last status line. +- + @item none + @opindex none @r{dd status=} + Do not print any informational or warning messages to stderr. + Error messages are output as normal. + ++@item noxfer ++@opindex noxfer @r{dd status=} ++Do not print the final transfer rate and volume statistics ++that normally make up the last status line. ++ ++@item progress ++@opindex progress @r{dd status=} ++Print the transfer rate and volume statistics on stderr, ++when processing each input block. Statistics are output ++on a single line at most once every second, but updates ++can be delayed when waiting on I/O. ++ + @end table + + @item conv=@var{conversion}[,@var{conversion}]@dots{} +@@ -9033,6 +9041,9 @@ The above script will output in the following format + 5120000000 bytes (5.1 GB) copied, 18.913 seconds, 271 MB/s + @end example + ++Note also the @samp{status=progress} option which periodically updates ++the last line of the transfer statistics above. ++ + @vindex POSIXLY_CORRECT + On systems lacking the @samp{INFO} signal @command{dd} responds to the + @samp{USR1} signal instead, unless the @env{POSIXLY_CORRECT} +diff --git a/src/dd.c b/src/dd.c +index d22ec59..4018190 100644 +--- a/src/dd.c ++++ b/src/dd.c +@@ -34,6 +34,7 @@ + #include "long-options.h" + #include "quote.h" + #include "quotearg.h" ++#include "verror.h" + #include "xstrtol.h" + #include "xtime.h" + +@@ -132,11 +133,13 @@ enum + C_SPARSE = 0200000 + }; + +-/* Status bit masks. */ ++/* Status levels. */ + enum + { +- STATUS_NOXFER = 01, +- STATUS_NONE = 02 ++ STATUS_NONE = 1, ++ STATUS_NOXFER = 2, ++ STATUS_DEFAULT = 3, ++ STATUS_PROGRESS = 4 + }; + + /* The name of the input file, or NULL for the standard input. */ +@@ -188,7 +191,7 @@ static int input_flags = 0; + static int output_flags = 0; + + /* Status flags for what is printed to stderr. */ +-static int status_flags = 0; ++static int status_level = STATUS_DEFAULT; + + /* If nonzero, filter characters through the translation table. */ + static bool translation_needed = false; +@@ -211,6 +214,12 @@ static uintmax_t w_bytes = 0; + /* Time that dd started. */ + static xtime_t start_time; + ++/* Previous time for periodic progress. */ ++static xtime_t previous_time; ++ ++/* Whether a '\n' is pending after writing progress. */ ++static bool newline_pending; ++ + /* True if input is seekable. */ + static bool input_seekable; + +@@ -373,8 +382,9 @@ static struct symbol_value const flags[] = + /* Status, for status="...". */ + static struct symbol_value const statuses[] = + { +- {"noxfer", STATUS_NOXFER}, + {"none", STATUS_NONE}, ++ {"noxfer", STATUS_NOXFER}, ++ {"progress", STATUS_PROGRESS}, + {"", 0} + }; + +@@ -517,6 +527,25 @@ maybe_close_stdout (void) + _exit (EXIT_FAILURE); + } + ++/* Like error() but handle any pending newline. */ ++ ++static void _GL_ATTRIBUTE_FORMAT ((__printf__, 3, 4)) ++nl_error (int status, int errnum, const char *fmt, ...) ++{ ++ if (newline_pending) ++ { ++ fputc ('\n', stderr); ++ newline_pending = false; ++ } ++ ++ va_list ap; ++ va_start (ap, fmt); ++ verror (status, errnum, fmt, ap); ++ va_end (ap); ++} ++ ++#define error nl_error ++ + void + usage (int status) + { +@@ -546,8 +575,10 @@ Copy a file, converting and formatting according to the operands.\n\ + oflag=FLAGS write as per the comma separated symbol list\n\ + seek=N skip N obs-sized blocks at start of output\n\ + skip=N skip N ibs-sized blocks at start of input\n\ +- status=WHICH WHICH info to suppress outputting to stderr;\n\ +- 'noxfer' suppresses transfer stats, 'none' suppresses all\n\ ++ status=LEVEL The LEVEL of information to print to stderr;\n\ ++ 'none' suppresses everything but error messages,\n\ ++ 'noxfer' suppresses the final transfer statistics,\n\ ++ 'progress' shows periodic transfer statistics\n\ + "), stdout); + fputs (_("\ + \n\ +@@ -724,8 +755,7 @@ multiple_bits_set (int i) + /* Print transfer statistics. */ + + static void +-print_stats (void) +-{ ++print_xfer_stats (xtime_t progress_time) { + char hbuf[LONGEST_HUMAN_READABLE + 1]; + int human_opts = + (human_autoscale | human_round_to_nearest +@@ -733,23 +763,8 @@ print_stats (void) + double delta_s; + char const *bytes_per_second; + +- if (status_flags & STATUS_NONE) +- return; +- +- fprintf (stderr, +- _("%"PRIuMAX"+%"PRIuMAX" records in\n" +- "%"PRIuMAX"+%"PRIuMAX" records out\n"), +- r_full, r_partial, w_full, w_partial); +- +- if (r_truncate != 0) +- fprintf (stderr, +- ngettext ("%"PRIuMAX" truncated record\n", +- "%"PRIuMAX" truncated records\n", +- select_plural (r_truncate)), +- r_truncate); +- +- if (status_flags & STATUS_NOXFER) +- return; ++ if (progress_time) ++ fputc ('\r', stderr); + + /* Use integer arithmetic to compute the transfer rate, + since that makes it easy to use SI abbreviations. */ +@@ -761,7 +776,8 @@ print_stats (void) + w_bytes, + human_readable (w_bytes, hbuf, human_opts, 1, 1)); + +- xtime_t now = gethrxtime (); ++ xtime_t now = progress_time ? progress_time : gethrxtime (); ++ + if (start_time < now) + { + double XTIME_PRECISIONe0 = XTIME_PRECISION; +@@ -787,7 +803,42 @@ print_stats (void) + but that was incorrect for languages like Polish. To fix this + bug we now use SI symbols even though they're a bit more + confusing in English. */ +- fprintf (stderr, _(", %g s, %s/s\n"), delta_s, bytes_per_second); ++ char const *time_fmt = _(", %g s, %s/s\n");; ++ if (progress_time) ++ time_fmt = _(", %.6f s, %s/s"); /* OK with '\r' as increasing width. */ ++ fprintf (stderr, time_fmt, delta_s, bytes_per_second); ++ ++ newline_pending = !!progress_time; ++} ++ ++static void ++print_stats (void) ++{ ++ if (status_level == STATUS_NONE) ++ return; ++ ++ if (newline_pending) ++ { ++ fputc ('\n', stderr); ++ newline_pending = false; ++ } ++ ++ fprintf (stderr, ++ _("%"PRIuMAX"+%"PRIuMAX" records in\n" ++ "%"PRIuMAX"+%"PRIuMAX" records out\n"), ++ r_full, r_partial, w_full, w_partial); ++ ++ if (r_truncate != 0) ++ fprintf (stderr, ++ ngettext ("%"PRIuMAX" truncated record\n", ++ "%"PRIuMAX" truncated records\n", ++ select_plural (r_truncate)), ++ r_truncate); ++ ++ if (status_level == STATUS_NOXFER) ++ return; ++ ++ print_xfer_stats (0); + } + + /* An ordinary signal was received; arrange for the program to exit. */ +@@ -1035,7 +1086,7 @@ iread (int fd, char *buf, size_t size) + if (0 < prev_nread && prev_nread < size) + { + uintmax_t prev = prev_nread; +- if (!(status_flags & STATUS_NONE)) ++ if (status_level != STATUS_NONE) + error (0, 0, ngettext (("warning: partial read (%"PRIuMAX" byte); " + "suggest iflag=fullblock"), + ("warning: partial read (%"PRIuMAX" bytes); " +@@ -1086,7 +1137,7 @@ iwrite (int fd, char const *buf, size_t size) + { + int old_flags = fcntl (STDOUT_FILENO, F_GETFL); + if (fcntl (STDOUT_FILENO, F_SETFL, old_flags & ~O_DIRECT) != 0 +- && !(status_flags & STATUS_NONE)) ++ && status_level != STATUS_NONE) + error (0, errno, _("failed to turn off O_DIRECT: %s"), + quote (output_file)); + +@@ -1219,7 +1270,7 @@ operand_matches (char const *str, char const *pattern, char delim) + + static int + parse_symbols (char const *str, struct symbol_value const *table, +- char const *error_msgid) ++ bool exclusive, char const *error_msgid) + { + int value = 0; + +@@ -1241,7 +1292,10 @@ parse_symbols (char const *str, struct symbol_value const *table, + } + } + +- value |= entry->value; ++ if (exclusive) ++ value = entry->value; ++ else ++ value |= entry->value; + if (!strcomma) + break; + str = strcomma + 1; +@@ -1316,17 +1370,17 @@ scanargs (int argc, char *const *argv) + else if (operand_is (name, "of")) + output_file = val; + else if (operand_is (name, "conv")) +- conversions_mask |= parse_symbols (val, conversions, ++ conversions_mask |= parse_symbols (val, conversions, false, + N_("invalid conversion")); + else if (operand_is (name, "iflag")) +- input_flags |= parse_symbols (val, flags, ++ input_flags |= parse_symbols (val, flags, false, + N_("invalid input flag")); + else if (operand_is (name, "oflag")) +- output_flags |= parse_symbols (val, flags, ++ output_flags |= parse_symbols (val, flags, false, + N_("invalid output flag")); + else if (operand_is (name, "status")) +- status_flags |= parse_symbols (val, statuses, +- N_("invalid status flag")); ++ status_level = parse_symbols (val, statuses, true, ++ N_("invalid status level")); + else + { + bool invalid = false; +@@ -1613,7 +1667,7 @@ skip_via_lseek (char const *filename, int fdesc, off_t offset, int whence) + && ioctl (fdesc, MTIOCGET, &s2) == 0 + && MT_SAME_POSITION (s1, s2)) + { +- if (!(status_flags & STATUS_NONE)) ++ if (status_level != STATUS_NONE) + error (0, 0, _("warning: working around lseek kernel bug for file " + "(%s)\n of mt_type=0x%0lx -- " + "see for the list of types"), +@@ -1787,7 +1841,7 @@ advance_input_after_read_error (size_t nbytes) + if (offset == input_offset) + return true; + diff = input_offset - offset; +- if (! (0 <= diff && diff <= nbytes) && !(status_flags & STATUS_NONE)) ++ if (! (0 <= diff && diff <= nbytes) && status_level != STATUS_NONE) + error (0, 0, _("warning: invalid file offset after failed read")); + if (0 <= skip_via_lseek (input_file, STDIN_FILENO, diff, SEEK_CUR)) + return true; +@@ -1986,7 +2040,7 @@ dd_copy (void) + 2. pipe has not enough data + 3. partial reads */ + if ((us_blocks || (!input_offset_overflow && us_bytes)) +- && !(status_flags & STATUS_NONE)) ++ && status_level != STATUS_NONE) + { + error (0, 0, + _("%s: cannot skip to specified offset"), quote (input_file)); +@@ -2029,6 +2083,19 @@ dd_copy (void) + + while (1) + { ++ if (status_level == STATUS_PROGRESS) ++ { ++ xtime_t progress_time = gethrxtime (); ++ uintmax_t delta_xtime = progress_time; ++ delta_xtime -= previous_time; ++ double XTIME_PRECISIONe0 = XTIME_PRECISION; ++ if (delta_xtime / XTIME_PRECISIONe0 > 1) ++ { ++ print_xfer_stats (progress_time); ++ previous_time = progress_time; ++ } ++ } ++ + if (r_partial + r_full >= max_records + !!max_bytes) + break; + +@@ -2053,7 +2120,7 @@ dd_copy (void) + + if (nread < 0) + { +- if (!(conversions_mask & C_NOERROR) || !(status_flags & STATUS_NONE)) ++ if (!(conversions_mask & C_NOERROR) || status_level != STATUS_NONE) + error (0, errno, _("error reading %s"), quote (input_file)); + + if (conversions_mask & C_NOERROR) +@@ -2345,7 +2412,7 @@ main (int argc, char **argv) + } + } + +- start_time = gethrxtime (); ++ start_time = previous_time = gethrxtime (); + + exit_status = dd_copy (); + +diff --git a/tests/dd/misc.sh b/tests/dd/misc.sh +index f877fdd..34dfba7 100755 +--- a/tests/dd/misc.sh ++++ b/tests/dd/misc.sh +@@ -35,9 +35,12 @@ dd status=none if=$tmp_in of=/dev/null 2> err || fail=1 + test -s err && { cat err; fail=1; } + dd status=none if=$tmp_in skip=2 of=/dev/null 2> err || fail=1 + test -s err && { cat err; fail=1; } +-# check status=none is cumulative with status=noxfer +-dd status=none status=noxfer if=$tmp_in of=/dev/null 2> err || fail=1 ++# check later status=none overrides earlier status=noxfer ++dd status=noxfer status=none if=$tmp_in of=/dev/null 2> err || fail=1 + test -s err && { cat err; fail=1; } ++# check later status=noxfer overrides earlier status=none ++dd status=none status=noxfer if=$tmp_in of=/dev/null 2> err || fail=1 ++compare /dev/null err && fail=1 + + dd if=$tmp_in of=$tmp_out 2> /dev/null || fail=1 + compare $tmp_in $tmp_out || fail=1 +diff --git a/tests/dd/stats.sh b/tests/dd/stats.sh +new file mode 100755 +index 0000000..24b8c49 100755 +--- /dev/null ++++ b/tests/dd/stats.sh +@@ -0,0 +1,65 @@ ++#!/bin/sh ++# Check stats output for SIG{INFO,USR1} and status=progress ++ ++# Copyright (C) 2014 Free Software Foundation, Inc. ++ ++# This program is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++ ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++ ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src ++print_ver_ dd ++ ++env kill -l | grep '^INFO$' && SIGINFO='INFO' || SIGINFO='USR1' ++ ++# This to avoid races in the USR1 case ++# as the dd process will terminate by default until ++# it has its handler enabled. ++trap '' $SIGINFO ++ ++mkfifo_or_skip_ fifo ++ ++for open in '' '1'; do ++ # Run dd with the fullblock iflag to avoid short reads ++ # which can be triggered by reception of signals ++ dd iflag=fullblock if=/dev/zero of=fifo count=100 bs=5000000 2>err & pid=$! ++ ++ # Note if we sleep here we give dd a chance to exec and block on open. ++ # Otherwise we're probably testing SIG_IGN in the forked shell or early dd. ++ test "$open" && sleep .1 ++ ++ # dd will block on open until fifo is opened for reading. ++ # Timeout in case dd goes away erroneously which we check for below. ++ timeout 10 sh -c 'wc -c < fifo > nwritten' & ++ ++ # Send lots of signals immediately to ensure dd not killed due ++ # to race setting handler, or blocking on open of fifo. ++ # Many signals also check that short reads are handled. ++ until ! kill -s $SIGINFO $pid 2>/dev/null; do ++ sleep .01 ++ done ++ ++ wait ++ ++ # Ensure all data processed and at least last status written ++ grep '500000000 bytes .* copied' err || { cat err; fail=1; } ++done ++ ++progress_output() ++{ ++ { sleep "$1"; echo 1; } | dd bs=1 status=progress of=/dev/null 2>err ++ # Progress output should be for "byte ... copied", while final is "bytes ..." ++ grep 'byte .* copied' err ++} ++retry_delay_ progress_output 1 4 || { cat err; fail=1; } ++ ++Exit $fail +-- +cgit v0.9.0.2 diff --git a/SOURCES/coreutils-8.22-df-autofs.patch b/SOURCES/coreutils-8.22-df-autofs.patch new file mode 100644 index 0000000..3ac8521 --- /dev/null +++ b/SOURCES/coreutils-8.22-df-autofs.patch @@ -0,0 +1,40 @@ +From ed936e1909a314febfdb9574bd10cc2d46d2b3e3 Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Fri, 19 Feb 2016 10:41:49 +0100 +Subject: [PATCH] mountlist: recognize autofs-mounted remote file systems, too + +Originally reported at: https://bugzilla.redhat.com/1309247 +* lib/mountlist.c (ME_REMOTE): Return true if a file system is named +"-hosts" because it is used by autofs to mount remote file systems. + +Upstream-commit: 781788eeb5d4d0b816698e8629300cd90a7379bd +Signed-off-by: Kamil Dudka +--- + lib/mountlist.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/lib/mountlist.c b/lib/mountlist.c +index b839cd1..17779f6 100644 +--- a/lib/mountlist.c ++++ b/lib/mountlist.c +@@ -212,13 +212,15 @@ me_remote (char const *fs_name, char const *fs_type _GL_UNUSED) + + #ifndef ME_REMOTE + /* A file system is "remote" if its Fs_name contains a ':' +- or if (it is of type (smbfs or cifs) and its Fs_name starts with '//'). */ ++ or if (it is of type (smbfs or cifs) and its Fs_name starts with '//') ++ or Fs_name is equal to "-hosts" (used by autofs to mount remote fs). */ + # define ME_REMOTE(Fs_name, Fs_type) \ + (strchr (Fs_name, ':') != NULL \ + || ((Fs_name)[0] == '/' \ + && (Fs_name)[1] == '/' \ + && (strcmp (Fs_type, "smbfs") == 0 \ +- || strcmp (Fs_type, "cifs") == 0))) ++ || strcmp (Fs_type, "cifs") == 0)) \ ++ || (strcmp("-hosts", Fs_name) == 0)) + #endif + + #if MOUNTED_GETMNTINFO +-- +2.5.0 + diff --git a/SOURCES/coreutils-8.22-df-bind-mount.patch b/SOURCES/coreutils-8.22-df-bind-mount.patch new file mode 100644 index 0000000..9b2be3e --- /dev/null +++ b/SOURCES/coreutils-8.22-df-bind-mount.patch @@ -0,0 +1,975 @@ +From e82cfd53cfd127e5877aefa5ea1d50bfe71d1788 Mon Sep 17 00:00:00 2001 +From: Fridolin Pokorny +Date: Wed, 27 Aug 2014 15:25:30 +0200 +Subject: [PATCH 1/9] mountlist: use /proc/self/mountinfo when available + +Use libmount to propagate device IDs provided by Linux in +/proc/self/mountinfo. This will give more accurate output when +using df in chroot'ed environments as the device IDs are not +determined by stat() which may be inaccurate within the chroot. + +* lib/mountlist.c (read_file_system_list): Use the libmount routines +from util-linux to parse "/proc/self/mountinfo" or fall back to +standard getmntent() processing. +* m4/ls-mntd-fs.m4: Check for libmount only when 1-argument +getmntent() is used, as is the case on GNU/Linux. +* DEPENDENCIES: Mention the optional util-linux dependency. + +Upstream-commit: 3ea43e02541ece750ffc6cd1dfe34195421b4ef3 +Signed-off-by: Kamil Dudka +--- + lib/mountlist.c | 82 ++++++++++++++++++++++++++++++++++++------------ + m4/ls-mntd-fs.m4 | 15 ++++++++- + 2 files changed, 76 insertions(+), 21 deletions(-) + +diff --git a/lib/mountlist.c b/lib/mountlist.c +index 17779f6..617fa88 100644 +--- a/lib/mountlist.c ++++ b/lib/mountlist.c +@@ -128,6 +128,12 @@ + # include + #endif + ++#ifdef MOUNTED_PROC_MOUNTINFO ++/* Use /proc/self/mountinfo instead of /proc/self/mounts (/etc/mtab) ++ * on Linux, if available */ ++# include ++#endif ++ + #ifndef HAVE_HASMNTOPT + # define hasmntopt(mnt, opt) ((char *) 0) + #endif +@@ -430,32 +436,68 @@ read_file_system_list (bool need_fs_type) + + #ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix. */ + { +- struct mntent *mnt; +- char const *table = MOUNTED; +- FILE *fp; ++#ifdef MOUNTED_PROC_MOUNTINFO ++ struct libmnt_table *fstable = NULL; + +- fp = setmntent (table, "r"); +- if (fp == NULL) +- return NULL; ++ fstable = mnt_new_table_from_file ("/proc/self/mountinfo"); + +- while ((mnt = getmntent (fp))) ++ if (fstable != NULL) + { +- me = xmalloc (sizeof *me); +- me->me_devname = xstrdup (mnt->mnt_fsname); +- me->me_mountdir = xstrdup (mnt->mnt_dir); +- me->me_type = xstrdup (mnt->mnt_type); +- me->me_type_malloced = 1; +- me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, mnt); +- me->me_remote = ME_REMOTE (me->me_devname, me->me_type); +- me->me_dev = dev_from_mount_options (mnt->mnt_opts); ++ struct libmnt_fs *fs; ++ struct libmnt_iter *iter; + +- /* Add to the linked list. */ +- *mtail = me; +- mtail = &me->me_next; ++ iter = mnt_new_iter (MNT_ITER_FORWARD); ++ ++ while (iter && mnt_table_next_fs (fstable, iter, &fs) == 0) ++ { ++ me = xmalloc (sizeof *me); ++ ++ me->me_devname = xstrdup (mnt_fs_get_source (fs)); ++ me->me_mountdir = xstrdup (mnt_fs_get_target (fs)); ++ me->me_type = xstrdup (mnt_fs_get_fstype (fs)); ++ me->me_type_malloced = 1; ++ me->me_dev = mnt_fs_get_devno (fs); ++ me->me_dummy = mnt_fs_is_pseudofs (fs); ++ me->me_remote = mnt_fs_is_netfs (fs); ++ ++ /* Add to the linked list. */ ++ *mtail = me; ++ mtail = &me->me_next; ++ } ++ ++ mnt_free_iter (iter); ++ mnt_free_table (fstable); + } ++ else /* fallback to /proc/self/mounts (/etc/mtab) if anything failed */ ++#endif /* MOUNTED_PROC_MOUNTINFO */ ++ { ++ FILE * fp; ++ struct mntent *mnt; ++ char const *table = MOUNTED; + +- if (endmntent (fp) == 0) +- goto free_then_fail; ++ fp = setmntent (table, "r"); ++ if (fp == NULL) ++ return NULL; ++ ++ while ((mnt = getmntent (fp))) ++ { ++ me = xmalloc (sizeof *me); ++ me->me_devname = xstrdup (mnt->mnt_fsname); ++ me->me_mountdir = xstrdup (mnt->mnt_dir); ++ me->me_type = xstrdup (mnt->mnt_type); ++ me->me_type_malloced = 1; ++ me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, mnt); ++ me->me_remote = ME_REMOTE (me->me_devname, me->me_type); ++ me->me_dev = dev_from_mount_options (mnt->mnt_opts); ++ ++ /* Add to the linked list. */ ++ *mtail = me; ++ mtail = &me->me_next; ++ } ++ ++ if (endmntent (fp) == 0) ++ goto free_then_fail; ++ } + } + #endif /* MOUNTED_GETMNTENT1. */ + +diff --git a/m4/ls-mntd-fs.m4 b/m4/ls-mntd-fs.m4 +index fb116c8..bc5ed82 100644 +--- a/m4/ls-mntd-fs.m4 ++++ b/m4/ls-mntd-fs.m4 +@@ -1,4 +1,4 @@ +-# serial 30 ++# serial 31 + # How to list mounted file systems. + + # Copyright (C) 1998-2004, 2006, 2009-2013 Free Software Foundation, Inc. +@@ -168,6 +168,19 @@ if test $ac_cv_func_getmntent = yes; then + [Define if there is a function named getmntent for reading the list of + mounted file systems, and that function takes two arguments. (SVR4)]) + AC_CHECK_FUNCS([hasmntopt]) ++ ++ # Check for libmount to support /proc/self/mountinfo on Linux ++ AC_CACHE_VAL([ac_cv_lib_libmount_mnt_table_parse_stream], ++ [AC_CHECK_LIB([mount], [mnt_new_table_from_file], ++ ac_cv_lib_mount_mnt_table_parse_stream=yes, ++ ac_cv_lib_mount_mnt_table_parse_stream=no)]) ++ if test $ac_cv_lib_mount_mnt_table_parse_stream = yes; then ++ AC_DEFINE([MOUNTED_PROC_MOUNTINFO], [1], ++ [Define if want to use /proc/self/mountinfo on Linux.]) ++ LIBS="-lmount $LIBS" ++ elif test -f /proc/self/mountinfo; then ++ AC_MSG_WARN([/proc/self/mountinfo present but libmount is missing.]) ++ fi + fi + fi + +-- +2.17.2 + + +From 7e5e39933b60761dbd5ad1b0e2d8c075d72ef322 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?P=C3=A1draig=20Brady?= +Date: Thu, 30 Oct 2014 04:08:50 +0000 +Subject: [PATCH 2/9] mountlist: don't use libmount to decide on dummy/remote + +* lib/mountlist.c (read_file_system_list): Don't use the libmount +routines to determine whether a file system is dummy or remote, +as they're not currently compatible. For example the remoteness +is determined on file system type (for which the list seems incomplete), +rather than simply checking for a ':' in the device name. +Also libmount currently determines that 'tmpfs' is a dummy file system +even though it has associated storage. + +Upstream-commit: 2768ceb7994506e2cfba88be3b6bd13ef5440a90 +Signed-off-by: Kamil Dudka +--- + lib/mountlist.c | 19 +++++++++++++------ + 1 file changed, 13 insertions(+), 6 deletions(-) + +diff --git a/lib/mountlist.c b/lib/mountlist.c +index 617fa88..b01846c 100644 +--- a/lib/mountlist.c ++++ b/lib/mountlist.c +@@ -182,10 +182,9 @@ + we grant an exception to any with "bind" in its list of mount options. + I.e., those are *not* dummy entries. */ + #ifdef MOUNTED_GETMNTENT1 +-# define ME_DUMMY(Fs_name, Fs_type, Fs_ent) \ ++# define ME_DUMMY(Fs_name, Fs_type, Bind) \ + (ME_DUMMY_0 (Fs_name, Fs_type) \ +- || (strcmp (Fs_type, "none") == 0 \ +- && !hasmntopt (Fs_ent, "bind"))) ++ || (strcmp (Fs_type, "none") == 0 && !Bind)) + #else + # define ME_DUMMY(Fs_name, Fs_type) \ + (ME_DUMMY_0 (Fs_name, Fs_type) || strcmp (Fs_type, "none") == 0) +@@ -457,8 +456,14 @@ read_file_system_list (bool need_fs_type) + me->me_type = xstrdup (mnt_fs_get_fstype (fs)); + me->me_type_malloced = 1; + me->me_dev = mnt_fs_get_devno (fs); +- me->me_dummy = mnt_fs_is_pseudofs (fs); +- me->me_remote = mnt_fs_is_netfs (fs); ++ /* Note we don't use mnt_fs_is_pseudofs() or mnt_fs_is_netfs() here ++ as libmount's classification is non-compatible currently. ++ Also we pass "false" for the "Bind" option as that's only ++ significant when the Fs_type is "none" which will not be ++ the case when parsing "/proc/self/mountinfo", and only ++ applies for static /etc/mtab files. */ ++ me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, false); ++ me->me_remote = ME_REMOTE (me->me_devname, me->me_type); + + /* Add to the linked list. */ + *mtail = me; +@@ -481,12 +486,14 @@ read_file_system_list (bool need_fs_type) + + while ((mnt = getmntent (fp))) + { ++ bool bind = hasmntopt (mnt, "bind"); ++ + me = xmalloc (sizeof *me); + me->me_devname = xstrdup (mnt->mnt_fsname); + me->me_mountdir = xstrdup (mnt->mnt_dir); + me->me_type = xstrdup (mnt->mnt_type); + me->me_type_malloced = 1; +- me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, mnt); ++ me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, bind); + me->me_remote = ME_REMOTE (me->me_devname, me->me_type); + me->me_dev = dev_from_mount_options (mnt->mnt_opts); + +-- +2.17.2 + + +From e51d88d267c5222ed2bd852bc4701dfe87d8360a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?P=C3=A1draig=20Brady?= +Date: Thu, 2 Apr 2015 04:18:02 +0100 +Subject: [PATCH 3/9] mountlist: remove dependency on libmount + +* lib/mountlist.c (read_file_system_list): Parse /proc/self/mountinfo +directly, rather than depending on libmount, which has many +dependencies due to its dependence on libselinux, as detailed at: +http://lists.gnu.org/archive/html/bug-gnulib/2015-01/msg00063.html +Note we restrict this to __linux__ as that's probably where this +interface will remain. If ever porting, it would be best +to first pull the makedev() wrapper from coreutils to a gnulib module. +Note also we don't add a getline dependency to the mountlist module, +as all Linux versions are sufficient. + +Upstream-commit: 3fb6e360363744462ce15c381f0b116c6fc4ce82 +Signed-off-by: Kamil Dudka +--- + lib/mountlist.c | 128 ++++++++++++++++++++++++++++++++++++----------- + m4/ls-mntd-fs.m4 | 17 +------ + 2 files changed, 102 insertions(+), 43 deletions(-) + +diff --git a/lib/mountlist.c b/lib/mountlist.c +index b01846c..2dbb245 100644 +--- a/lib/mountlist.c ++++ b/lib/mountlist.c +@@ -58,6 +58,7 @@ + + #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */ + # include ++# include + # if !defined MOUNTED + # if defined _PATH_MOUNTED /* GNU libc */ + # define MOUNTED _PATH_MOUNTED +@@ -128,12 +129,6 @@ + # include + #endif + +-#ifdef MOUNTED_PROC_MOUNTINFO +-/* Use /proc/self/mountinfo instead of /proc/self/mounts (/etc/mtab) +- * on Linux, if available */ +-# include +-#endif +- + #ifndef HAVE_HASMNTOPT + # define hasmntopt(mnt, opt) ((char *) 0) + #endif +@@ -389,6 +384,34 @@ dev_from_mount_options (char const *mount_options) + + #endif + ++#if defined MOUNTED_GETMNTENT1 && defined __linux__ ++ ++/* Unescape the paths in mount tables. ++ STR is updated in place. */ ++ ++static void ++unescape_tab (char *str) ++{ ++ size_t i, j = 0; ++ size_t len = strlen (str) + 1; ++ for (i = 0; i < len; i++) ++ { ++ if (str[i] == '\\' && (i + 4 < len) ++ && str[i + 1] >= '0' && str[i + 1] <= '3' ++ && str[i + 2] >= '0' && str[i + 2] <= '7' ++ && str[i + 3] >= '0' && str[i + 3] <= '7') ++ { ++ str[j++] = (str[i + 1] - '0') * 64 + ++ (str[i + 2] - '0') * 8 + ++ (str[i + 3] - '0'); ++ i += 3; ++ } ++ else ++ str[j++] = str[i]; ++ } ++} ++#endif ++ + /* Return a list of the currently mounted file systems, or NULL on error. + Add each entry to the tail of the list so that they stay in order. + If NEED_FS_TYPE is true, ensure that the file system type fields in +@@ -435,30 +458,70 @@ read_file_system_list (bool need_fs_type) + + #ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix. */ + { +-#ifdef MOUNTED_PROC_MOUNTINFO +- struct libmnt_table *fstable = NULL; +- +- fstable = mnt_new_table_from_file ("/proc/self/mountinfo"); ++ FILE *fp; + +- if (fstable != NULL) ++#ifdef __linux__ ++ /* Try parsing mountinfo first, as that make device IDs available. ++ Note we could use libmount routines to simplify this parsing a little ++ (and that code is in previous versions of this function), however ++ libmount depends on libselinux which pulls in many dependencies. */ ++ char const *mountinfo = "/proc/self/mountinfo"; ++ fp = fopen (mountinfo, "r"); ++ if (fp != NULL) + { +- struct libmnt_fs *fs; +- struct libmnt_iter *iter; ++ char *line = NULL; ++ size_t buf_size = 0; + +- iter = mnt_new_iter (MNT_ITER_FORWARD); +- +- while (iter && mnt_table_next_fs (fstable, iter, &fs) == 0) ++ while (getline (&line, &buf_size, fp) != -1) + { ++ unsigned int devmaj, devmin; ++ int target_s, target_e, type_s, type_e, source_s, source_e; ++ char test; ++ char *dash; ++ int rc; ++ ++ rc = sscanf(line, "%*u " /* id - discarded */ ++ "%*u " /* parent - discarded */ ++ "%u:%u " /* dev major:minor */ ++ "%*s " /* mountroot - discarded */ ++ "%n%*s%n" /* target, start and end */ ++ "%c", /* more data... */ ++ &devmaj, &devmin, ++ &target_s, &target_e, ++ &test); ++ if (rc != 3 && rc != 5) /* 5 if %n included in count. */ ++ continue; ++ ++ /* skip optional fields, terminated by " - " */ ++ dash = strstr (line + target_e, " - "); ++ if (! dash) ++ continue; ++ ++ rc = sscanf(dash, " - " ++ "%n%*s%n " /* FS type, start and end */ ++ "%n%*s%n " /* source, start and end */ ++ "%c", /* more data... */ ++ &type_s, &type_e, ++ &source_s, &source_e, ++ &test); ++ if (rc != 1 && rc != 5) /* 5 if %n included in count. */ ++ continue; ++ ++ /* manipulate the sub-strings in place. */ ++ line[target_e] = '\0'; ++ dash[type_e] = '\0'; ++ dash[source_e] = '\0'; ++ unescape_tab (dash + source_s); ++ unescape_tab (line + target_s); ++ + me = xmalloc (sizeof *me); + +- me->me_devname = xstrdup (mnt_fs_get_source (fs)); +- me->me_mountdir = xstrdup (mnt_fs_get_target (fs)); +- me->me_type = xstrdup (mnt_fs_get_fstype (fs)); ++ me->me_devname = xstrdup (dash + source_s); ++ me->me_mountdir = xstrdup (line + target_s); ++ me->me_type = xstrdup (dash + type_s); + me->me_type_malloced = 1; +- me->me_dev = mnt_fs_get_devno (fs); +- /* Note we don't use mnt_fs_is_pseudofs() or mnt_fs_is_netfs() here +- as libmount's classification is non-compatible currently. +- Also we pass "false" for the "Bind" option as that's only ++ me->me_dev = makedev (devmaj, devmin); ++ /* we pass "false" for the "Bind" option as that's only + significant when the Fs_type is "none" which will not be + the case when parsing "/proc/self/mountinfo", and only + applies for static /etc/mtab files. */ +@@ -470,13 +533,22 @@ read_file_system_list (bool need_fs_type) + mtail = &me->me_next; + } + +- mnt_free_iter (iter); +- mnt_free_table (fstable); ++ free (line); ++ ++ if (ferror (fp)) ++ { ++ int saved_errno = errno; ++ fclose (fp); ++ errno = saved_errno; ++ goto free_then_fail; ++ } ++ ++ if (fclose (fp) == EOF) ++ goto free_then_fail; + } +- else /* fallback to /proc/self/mounts (/etc/mtab) if anything failed */ +-#endif /* MOUNTED_PROC_MOUNTINFO */ ++ else /* fallback to /proc/self/mounts (/etc/mtab). */ ++#endif /* __linux __ */ + { +- FILE * fp; + struct mntent *mnt; + char const *table = MOUNTED; + +diff --git a/m4/ls-mntd-fs.m4 b/m4/ls-mntd-fs.m4 +index bc5ed82..412fbfc 100644 +--- a/m4/ls-mntd-fs.m4 ++++ b/m4/ls-mntd-fs.m4 +@@ -1,4 +1,4 @@ +-# serial 31 ++# serial 32 + # How to list mounted file systems. + + # Copyright (C) 1998-2004, 2006, 2009-2013 Free Software Foundation, Inc. +@@ -120,7 +120,7 @@ if test $ac_cv_func_getmntent = yes; then + # Determine whether it's the one-argument variant or the two-argument one. + + if test -z "$ac_list_mounted_fs"; then +- # 4.3BSD, SunOS, HP-UX, Dynix, Irix ++ # GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix + AC_MSG_CHECKING([for one-argument getmntent function]) + AC_CACHE_VAL([fu_cv_sys_mounted_getmntent1], + [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +@@ -168,19 +168,6 @@ if test $ac_cv_func_getmntent = yes; then + [Define if there is a function named getmntent for reading the list of + mounted file systems, and that function takes two arguments. (SVR4)]) + AC_CHECK_FUNCS([hasmntopt]) +- +- # Check for libmount to support /proc/self/mountinfo on Linux +- AC_CACHE_VAL([ac_cv_lib_libmount_mnt_table_parse_stream], +- [AC_CHECK_LIB([mount], [mnt_new_table_from_file], +- ac_cv_lib_mount_mnt_table_parse_stream=yes, +- ac_cv_lib_mount_mnt_table_parse_stream=no)]) +- if test $ac_cv_lib_mount_mnt_table_parse_stream = yes; then +- AC_DEFINE([MOUNTED_PROC_MOUNTINFO], [1], +- [Define if want to use /proc/self/mountinfo on Linux.]) +- LIBS="-lmount $LIBS" +- elif test -f /proc/self/mountinfo; then +- AC_MSG_WARN([/proc/self/mountinfo present but libmount is missing.]) +- fi + fi + fi + +-- +2.17.2 + + +From a6a7c39b36699fdbbb57679f2f71fc3ae08e8ba2 Mon Sep 17 00:00:00 2001 +From: Dave Chiluk +Date: Mon, 31 Aug 2015 16:07:58 -0500 +Subject: [PATCH 4/9] mountlist: add me_mntroot field on Linux machines + +* lib/mountlist.c (read_file_system_list): Populate me_mntroot in +mount_entry so Linux machines based on /proc/self/mountinfo can +distinguish between bind mounts and original mounts. In reality bind +mounts aren't treated differently than mountroot=/ mounts by the +kernel, but the user often wants these bind mounts distinguished. +* lib/mountlist.h (struct mount_entry): Add me_mntroot element. +More details at https://pad.lv/1432871 + +Upstream-commit: c6148bca89e9465fd6ba3a10d273ec4cb58c2dbe +Signed-off-by: Kamil Dudka +--- + lib/mountlist.c | 25 ++++++++++++++++++++++--- + lib/mountlist.h | 2 ++ + 2 files changed, 24 insertions(+), 3 deletions(-) + +diff --git a/lib/mountlist.c b/lib/mountlist.c +index 2dbb245..f4d285a 100644 +--- a/lib/mountlist.c ++++ b/lib/mountlist.c +@@ -444,6 +444,7 @@ read_file_system_list (bool need_fs_type) + me = xmalloc (sizeof *me); + me->me_devname = xstrdup (mnt->mnt_fsname); + me->me_mountdir = xstrdup (mnt->mnt_dir); ++ me->me_mntroot = NULL; + me->me_type = xstrdup (mnt->mnt_type); + me->me_type_malloced = 1; + me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); +@@ -475,7 +476,8 @@ read_file_system_list (bool need_fs_type) + while (getline (&line, &buf_size, fp) != -1) + { + unsigned int devmaj, devmin; +- int target_s, target_e, type_s, type_e, source_s, source_e; ++ int target_s, target_e, type_s, type_e; ++ int source_s, source_e, mntroot_s, mntroot_e; + char test; + char *dash; + int rc; +@@ -483,13 +485,15 @@ read_file_system_list (bool need_fs_type) + rc = sscanf(line, "%*u " /* id - discarded */ + "%*u " /* parent - discarded */ + "%u:%u " /* dev major:minor */ +- "%*s " /* mountroot - discarded */ ++ "%n%*s%n " /* mountroot */ + "%n%*s%n" /* target, start and end */ + "%c", /* more data... */ + &devmaj, &devmin, ++ &mntroot_s, &mntroot_e, + &target_s, &target_e, + &test); +- if (rc != 3 && rc != 5) /* 5 if %n included in count. */ ++ ++ if (rc != 3 && rc != 7) /* 7 if %n included in count. */ + continue; + + /* skip optional fields, terminated by " - " */ +@@ -508,16 +512,19 @@ read_file_system_list (bool need_fs_type) + continue; + + /* manipulate the sub-strings in place. */ ++ line[mntroot_e] = '\0'; + line[target_e] = '\0'; + dash[type_e] = '\0'; + dash[source_e] = '\0'; + unescape_tab (dash + source_s); + unescape_tab (line + target_s); ++ unescape_tab (line + mntroot_s); + + me = xmalloc (sizeof *me); + + me->me_devname = xstrdup (dash + source_s); + me->me_mountdir = xstrdup (line + target_s); ++ me->me_mntroot = xstrdup (line + mntroot_s); + me->me_type = xstrdup (dash + type_s); + me->me_type_malloced = 1; + me->me_dev = makedev (devmaj, devmin); +@@ -563,6 +570,7 @@ read_file_system_list (bool need_fs_type) + me = xmalloc (sizeof *me); + me->me_devname = xstrdup (mnt->mnt_fsname); + me->me_mountdir = xstrdup (mnt->mnt_dir); ++ me->me_mntroot = NULL; + me->me_type = xstrdup (mnt->mnt_type); + me->me_type_malloced = 1; + me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, bind); +@@ -595,6 +603,7 @@ read_file_system_list (bool need_fs_type) + me = xmalloc (sizeof *me); + me->me_devname = xstrdup (fsp->f_mntfromname); + me->me_mountdir = xstrdup (fsp->f_mntonname); ++ me->me_mntroot = NULL; + me->me_type = fs_type; + me->me_type_malloced = 0; + me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); +@@ -621,6 +630,7 @@ read_file_system_list (bool need_fs_type) + me = xmalloc (sizeof *me); + me->me_devname = xstrdup (fsp->f_mntfromname); + me->me_mountdir = xstrdup (fsp->f_mntonname); ++ me->me_mntroot = NULL; + me->me_type = xstrdup (fsp->f_fstypename); + me->me_type_malloced = 1; + me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); +@@ -647,6 +657,7 @@ read_file_system_list (bool need_fs_type) + me = xmalloc (sizeof *me); + me->me_devname = xstrdup (fsd.fd_req.devname); + me->me_mountdir = xstrdup (fsd.fd_req.path); ++ me->me_mntroot = NULL; + me->me_type = gt_names[fsd.fd_req.fstype]; + me->me_type_malloced = 0; + me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); +@@ -745,6 +756,7 @@ read_file_system_list (bool need_fs_type) + me->me_devname = xstrdup (fi.device_name[0] != '\0' + ? fi.device_name : fi.fsh_name); + me->me_mountdir = xstrdup (re != NULL ? re->name : fi.fsh_name); ++ me->me_mntroot = NULL; + me->me_type = xstrdup (fi.fsh_name); + me->me_type_malloced = 1; + me->me_dev = fi.dev; +@@ -794,6 +806,7 @@ read_file_system_list (bool need_fs_type) + me = xmalloc (sizeof *me); + me->me_devname = xstrdup (stats[counter].f_mntfromname); + me->me_mountdir = xstrdup (stats[counter].f_mntonname); ++ me->me_mntroot = NULL; + me->me_type = xstrdup (FS_TYPE (stats[counter])); + me->me_type_malloced = 1; + me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); +@@ -830,6 +843,7 @@ read_file_system_list (bool need_fs_type) + strcpy (me->me_devname + 5, mnt.mt_dev); + # endif + me->me_mountdir = xstrdup (mnt.mt_filsys); ++ me->me_mntroot = NULL; + me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ + me->me_type = ""; + me->me_type_malloced = 0; +@@ -877,6 +891,7 @@ read_file_system_list (bool need_fs_type) + me = xmalloc (sizeof *me); + me->me_devname = xstrdup ((*ent)->mt_resource); + me->me_mountdir = xstrdup ((*ent)->mt_directory); ++ me->me_mntroot = NULL; + me->me_type = xstrdup ((*ent)->mt_fstype); + me->me_type_malloced = 1; + me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); +@@ -939,6 +954,7 @@ read_file_system_list (bool need_fs_type) + me = xmalloc (sizeof *me); + me->me_devname = xstrdup (mnt.mnt_special); + me->me_mountdir = xstrdup (mnt.mnt_mountp); ++ me->me_mntroot = NULL; + me->me_type = xstrdup (mnt.mnt_fstype); + me->me_type_malloced = 1; + me->me_dummy = MNT_IGNORE (&mnt) != 0; +@@ -1015,6 +1031,7 @@ read_file_system_list (bool need_fs_type) + vmp->vmt_data[VMT_OBJECT].vmt_off); + } + me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off); ++ me->me_mntroot = NULL; + me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype)); + me->me_type_malloced = 1; + options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off; +@@ -1058,6 +1075,7 @@ read_file_system_list (bool need_fs_type) + me = xmalloc (sizeof *me); + me->me_devname = xstrdup (dev.f_mntfromname); + me->me_mountdir = xstrdup (dev.f_mntonname); ++ me->me_mntroot = NULL; + me->me_type = xstrdup (dev.f_fstypename); + me->me_type_malloced = 1; + me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); +@@ -1100,6 +1118,7 @@ void free_mount_entry (struct mount_entry *me) + { + free (me->me_devname); + free (me->me_mountdir); ++ free (me->me_mntroot); + if (me->me_type_malloced) + free (me->me_type); + free (me); +diff --git a/lib/mountlist.h b/lib/mountlist.h +index 55877e2..1872b2b 100644 +--- a/lib/mountlist.h ++++ b/lib/mountlist.h +@@ -27,6 +27,8 @@ struct mount_entry + { + char *me_devname; /* Device node name, including "/dev/". */ + char *me_mountdir; /* Mount point directory name. */ ++ char *me_mntroot; /* Directory on filesystem of device used */ ++ /* as root for the (bind) mount. */ + char *me_type; /* "nfs", "4.2", etc. */ + dev_t me_dev; /* Device number of me_mountdir. */ + unsigned int me_dummy : 1; /* Nonzero for dummy file systems. */ +-- +2.17.2 + + +From 6b301e5f89d4555e33b267e3ea5a709a4b584038 Mon Sep 17 00:00:00 2001 +From: Andrew Borodin +Date: Sun, 27 Sep 2015 11:41:17 +0300 +Subject: [PATCH 5/9] mountlist: clean up of variable duplication + +* lib/mountlist.c (read_file_system_list) [MOUNTED_LISTMNTENT]: +the 'me' variable is already declared above. Remove it here. + +Upstream-commit: 1eda6d17e93fa496368f82cac6317b8045cc9373 +Signed-off-by: Kamil Dudka +--- + lib/mountlist.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/lib/mountlist.c b/lib/mountlist.c +index f4d285a..6f66996 100644 +--- a/lib/mountlist.c ++++ b/lib/mountlist.c +@@ -429,7 +429,6 @@ read_file_system_list (bool need_fs_type) + { + struct tabmntent *mntlist, *p; + struct mntent *mnt; +- struct mount_entry *me; + + /* the third and fourth arguments could be used to filter mounts, + but Crays doesn't seem to have any mounts that we want to +-- +2.17.2 + + +From b2063df8d13fc279f3fa38d1315e3ff3f66c70e5 Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Wed, 14 Sep 2016 19:21:42 -0500 +Subject: [PATCH 6/9] mountlist: include sysmacros.h for glibc + +On Fedora rawhide (glibc 2.25), './gnulib-tool --test mountlist' +reports: +../../gllib/mountlist.c: In function 'read_file_system_list': +../../gllib/mountlist.c:534:13: warning: '__makedev_from_sys_types' is deprecated: + In the GNU C Library, `makedev' is defined by . + For historical compatibility, it is currently defined by + as well, but we plan to remove this soon. + To use `makedev', include directly. + If you did not intend to use a system-defined macro `makedev', + you should #undef it after including . + [-Wdeprecated-declarations] + me->me_dev = makedev (devmaj, devmin); + ^~ +In file included from /usr/include/features.h:397:0, + from /usr/include/sys/types.h:25, + from ./sys/types.h:28, + from ../../gllib/mountlist.h:23, + from ../../gllib/mountlist.c:20: +/usr/include/sys/sysmacros.h:89:1: note: declared here + __SYSMACROS_DEFINE_MAKEDEV (__SYSMACROS_FST_IMPL_TEMPL) + ^ + +Fix it by including the right headers. We also need a fix to +autoconf's AC_HEADER_MAJOR, but that's a separate patch. + +* m4/mountlist.m4 (gl_PREREQ_MOUTLIST_EXTRA): Include +AC_HEADER_MAJOR. +* lib/mountlist.c (includes): Use correct headers. + +Signed-off-by: Eric Blake + +Upstream-commit: 4da63c5881f60f71999a943612da9112232b9161 +Signed-off-by: Kamil Dudka +--- + lib/mountlist.c | 6 ++++++ + m4/mountlist.m4 | 3 ++- + 2 files changed, 8 insertions(+), 1 deletion(-) + +diff --git a/lib/mountlist.c b/lib/mountlist.c +index 6f66996..40338ac 100644 +--- a/lib/mountlist.c ++++ b/lib/mountlist.c +@@ -37,6 +37,12 @@ + # include + #endif + ++#if MAJOR_IN_MKDEV ++# include ++#elif MAJOR_IN_SYSMACROS ++# include ++#endif ++ + #if defined MOUNTED_GETFSSTAT /* OSF_1 and Darwin1.3.x */ + # if HAVE_SYS_UCRED_H + # include /* needed on OSF V4.0 for definition of NGROUPS, +diff --git a/m4/mountlist.m4 b/m4/mountlist.m4 +index cd137c9..2f47ce2 100644 +--- a/m4/mountlist.m4 ++++ b/m4/mountlist.m4 +@@ -1,4 +1,4 @@ +-# serial 11 ++# serial 12 + dnl Copyright (C) 2002-2006, 2009-2013 Free Software Foundation, Inc. + dnl This file is free software; the Free Software Foundation + dnl gives unlimited permission to copy and/or distribute it, +@@ -15,5 +15,6 @@ AC_DEFUN([gl_PREREQ_MOUNTLIST_EXTRA], + [ + dnl Note gl_LIST_MOUNTED_FILE_SYSTEMS checks for mntent.h, not sys/mntent.h. + AC_CHECK_HEADERS([sys/mntent.h]) ++ AC_HEADER_MAJOR()dnl for use of makedev () + gl_FSTYPENAME + ]) +-- +2.17.2 + + +From 472ef28870dce7ca7505fa2ca477040da347a567 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?P=C3=A1draig=20Brady?= +Date: Thu, 2 Apr 2015 05:34:07 +0100 +Subject: [PATCH 7/9] df: fix use of uninitialized variable reported by + valgrind + + Conditional jump or move depends on uninitialised value(s) + at 0x40380C: get_field_values (df.c:840) + by 0x403E16: get_dev (df.c:994) + by 0x404D65: get_all_entries (df.c:1364) + by 0x405926: main (df.c:1714) + +* src/df.c (get_dev): Initialize the fsu.fsu_bavail_top_bit_set +member, when adding placeholder entries. +(main): Avoid a "definitely lost" memory leak warning from valgrind, +reported by Bernhard Voelker. + +Upstream-commit: bf180f8f5a53eb82054e85e26dcd1ea7c43dbdfe +Signed-off-by: Kamil Dudka +--- + src/df.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/df.c b/src/df.c +index ce11b50..5ffd0a5 100644 +--- a/src/df.c ++++ b/src/df.c +@@ -935,6 +935,7 @@ get_dev (char const *disk, char const *mount_point, char const* file, + return; + + fstype = "-"; ++ fsu.fsu_bavail_top_bit_set = false; + fsu.fsu_blocksize = fsu.fsu_blocks = fsu.fsu_bfree = + fsu.fsu_bavail = fsu.fsu_files = fsu.fsu_ffree = UINTMAX_MAX; + } +@@ -959,6 +960,7 @@ get_dev (char const *disk, char const *mount_point, char const* file, + && (! dev_me->me_remote || ! me_remote)) + { + fstype = "-"; ++ fsu.fsu_bavail_top_bit_set = false; + fsu.fsu_blocksize = fsu.fsu_blocks = fsu.fsu_bfree = + fsu.fsu_bavail = fsu.fsu_files = fsu.fsu_ffree = UINTMAX_MAX; + } +@@ -1736,6 +1738,8 @@ main (int argc, char **argv) + for (i = optind; i < argc; ++i) + if (argv[i]) + get_entry (argv[i], &stats[i - optind]); ++ ++ IF_LINT (free (stats)); + } + else + get_all_entries (); +-- +2.17.2 + + +From fc6104cc9d8d2908b3225b035def82d3a95bdfd0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?P=C3=A1draig=20Brady?= +Date: Sun, 5 Apr 2015 18:21:38 +0100 +Subject: [PATCH 8/9] df: fix --local hanging with inaccessible remote mounts + +* src/df.c (filter_mount_list): With -l, avoid stating remote mounts. +* init.cfg: Avoid test hangs with inaccessible remote mounts. +* tests/df/no-mtab-status.sh: Skip with inaccessible remote mounts. +* tests/df/skip-rootfs.sh: Likewise. +* tests/df/total-verify.sh: Likewise. +* NEWS: Mention the bug fix. +Reported at http://bugzilla.redhat.com/1199679 + +Upstream-commit: 1b1c40e1d6f8cf30b6c7c9d31bbddbc3d5cc72e6 +Signed-off-by: Kamil Dudka +--- + init.cfg | 2 +- + tests/df/no-mtab-status.sh | 3 ++- + tests/df/skip-rootfs.sh | 3 ++- + tests/df/total-verify.sh | 3 ++- + 4 files changed, 7 insertions(+), 4 deletions(-) + +diff --git a/init.cfg b/init.cfg +index 3364a73..d5a80bb 100644 +--- a/init.cfg ++++ b/init.cfg +@@ -79,7 +79,7 @@ is_local_dir_() + require_mount_list_() + { + local mount_list_fail='cannot read table of mounted file systems' +- df 2>&1 | grep -F "$mount_list_fail" >/dev/null && ++ df --local 2>&1 | grep -F "$mount_list_fail" >/dev/null && + skip_ "$mount_list_fail" + } + +diff --git a/tests/df/no-mtab-status.sh b/tests/df/no-mtab-status.sh +index 2e6b61b..9b6b9d3 100755 +--- a/tests/df/no-mtab-status.sh ++++ b/tests/df/no-mtab-status.sh +@@ -21,7 +21,8 @@ + print_ver_ df + require_gcc_shared_ + +-df || skip_ "df fails" ++# Protect against inaccessible remote mounts etc. ++timeout 10 df || skip_ "df fails" + + # Simulate "mtab" failure. + cat > k.c <<'EOF' || framework_failure_ +diff --git a/tests/df/skip-rootfs.sh b/tests/df/skip-rootfs.sh +index 9c5d0a9..b79751e 100755 +--- a/tests/df/skip-rootfs.sh ++++ b/tests/df/skip-rootfs.sh +@@ -19,7 +19,8 @@ + . "${srcdir=.}/tests/init.sh"; path_prepend_ ./src + print_ver_ df + +-df || skip_ "df fails" ++# Protect against inaccessible remote mounts etc. ++timeout 10 df || skip_ "df fails" + + # Verify that rootfs is in mtab (and shown when the -a option is specified). + df -a >out || fail=1 +diff --git a/tests/df/total-verify.sh b/tests/df/total-verify.sh +index a045ccf..f05a91e 100755 +--- a/tests/df/total-verify.sh ++++ b/tests/df/total-verify.sh +@@ -20,7 +20,8 @@ + print_ver_ df + require_perl_ + +-df || skip_ "df fails" ++# Protect against inaccessible remote mounts etc. ++timeout 10 df || skip_ "df fails" + + cat <<\EOF > check-df || framework_failure_ + my ($total, $used, $avail) = (0, 0, 0); +-- +2.17.2 + + +From 9a52ebdc70071076a1b7263b64b118972d203778 Mon Sep 17 00:00:00 2001 +From: Dave Chiluk +Date: Mon, 21 Sep 2015 15:04:11 -0500 +Subject: [PATCH 9/9] df: prioritize mounts nearer the device root + +In the presence of bind mounts of a device, the 4th "mount root" field +from /proc/self/mountinfo is now considered, so as to prefer mount +points closer to the root of the device. Note on older systems with +an /etc/mtab file, the source device was listed as the originating +directory, and so this was not an issue. +Details at http://pad.lv/1432871 + +* src/df.c (filter_mount_list): When deduplicating mount entries, +only prefer sources nearer or at the root of the device, when the +target is nearer the root of the device. +* NEWS: Mention the change in behavior. + +Upstream-commit: 3babaf83875ceac896c8dd3a64248e955dfecef9 +Signed-off-by: Kamil Dudka +--- + src/df.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/src/df.c b/src/df.c +index 5ffd0a5..c50aa80 100644 +--- a/src/df.c ++++ b/src/df.c +@@ -649,6 +649,13 @@ filter_mount_list (bool devices_only) + + if (devlist) + { ++ bool target_nearer_root = strlen (devlist->me->me_mountdir) ++ > strlen (me->me_mountdir); ++ /* With bind mounts, prefer items nearer the root of the source */ ++ bool source_below_root = devlist->me->me_mntroot != NULL ++ && me->me_mntroot != NULL ++ && (strlen (devlist->me->me_mntroot) ++ < strlen (me->me_mntroot)); + if (! print_grand_total && me->me_remote && devlist->me->me_remote + && ! STREQ (devlist->me->me_devname, me->me_devname)) + { +@@ -660,9 +667,8 @@ filter_mount_list (bool devices_only) + else if ((strchr (me->me_devname, '/') + /* let "real" devices with '/' in the name win. */ + && ! strchr (devlist->me->me_devname, '/')) +- /* let a shorter mountdir win. */ +- || (strlen (devlist->me->me_mountdir) +- > strlen (me->me_mountdir)) ++ /* let points towards the root of the device win. */ ++ || (target_nearer_root && ! source_below_root) + /* let an entry overmounted on a new device win... */ + || (! STREQ (devlist->me->me_devname, me->me_devname) + /* ... but only when matching an existing mnt point, +-- +2.17.2 + diff --git a/SOURCES/coreutils-8.22-df-dummy-local.patch b/SOURCES/coreutils-8.22-df-dummy-local.patch new file mode 100644 index 0000000..07b971f --- /dev/null +++ b/SOURCES/coreutils-8.22-df-dummy-local.patch @@ -0,0 +1,45 @@ +From 20e22775051d4392b9e41b717711535178395ec4 Mon Sep 17 00:00:00 2001 +From: Josef Cejka +Date: Tue, 1 Aug 2017 01:50:34 +0200 +Subject: [PATCH] df: avoid stat() for dummy file systems with -l + +When systemd is configured to automount a remote file system - see +'man systemd.automount(5)', then the mount point is initially +mounted by systemd with the file system type "autofs". +When the resource is used later on, then the wanted file system is +mounted over that mount point on demand. +'df -l' triggered systemd to mount the file system because it called +stat() on the mount point. +Instead of single-casing "autofs" targets, we can avoid stat()ing +all dummy file systems (which includes "autofs"), because those are +skipped later on in get_dev() anyway. + +*src/df.c (filter_mount_list): Also skip dummy file systems unless +the -a option or a specific target are given. +* NEWS: Mention the fix. + +Co-authored-by: Bernhard Voelker + +Fixes http://bugzilla.suse.com/show_bug.cgi?id=1043059 + +Upstream-commit: a19ff5d8179a7de38109fc78278229fd96f3941a +Signed-off-by: Kamil Dudka +--- + src/df.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/df.c b/src/df.c +index c50aa80..fa20493 100644 +--- a/src/df.c ++++ b/src/df.c +@@ -632,6 +632,7 @@ filter_mount_list (bool devices_only) + On Linux we probably have me_dev populated from /proc/self/mountinfo, + however we still stat() in case another device was mounted later. */ + if ((me->me_remote && show_local_fs) ++ || (me->me_dummy && !show_all_fs && !show_listed_fs) + || (!selected_fstype (me->me_type) || excluded_fstype (me->me_type)) + || -1 == stat (me->me_mountdir, &buf)) + { +-- +2.17.2 + diff --git a/SOURCES/coreutils-8.22-df-filtermountlistupdate.patch b/SOURCES/coreutils-8.22-df-filtermountlistupdate.patch new file mode 100644 index 0000000..b50fb56 --- /dev/null +++ b/SOURCES/coreutils-8.22-df-filtermountlistupdate.patch @@ -0,0 +1,513 @@ +diff --git a/src/df.c b/src/df.c +index e28a656..fe222d9 100644 +--- a/src/df.c ++++ b/src/df.c +@@ -45,12 +45,12 @@ + + /* Filled with device numbers of examined file systems to avoid + duplicities in output. */ +-struct devlist ++static struct devlist + { + dev_t dev_num; + struct mount_entry *me; + struct devlist *next; +-}; ++} *device_list; + + /* If true, show even file systems with zero size or + uninteresting types. */ +@@ -609,13 +609,10 @@ excluded_fstype (const char *fstype) + me_mountdir wins. */ + + static void +-filter_mount_list (void) ++filter_mount_list (bool devices_only) + { + struct mount_entry *me; + +- /* Store of already-processed device numbers. */ +- struct devlist *devlist_head = NULL; +- + /* Sort all 'wanted' entries into the list devlist_head. */ + for (me = mount_list; me;) + { +@@ -623,41 +620,66 @@ filter_mount_list (void) + struct devlist *devlist; + struct mount_entry *discard_me = NULL; + +- if (-1 == stat (me->me_mountdir, &buf)) ++ /* Avoid stating remote file systems as that may hang. ++ On Linux we probably have me_dev populated from /proc/self/mountinfo, ++ however we still stat() in case another device was mounted later. */ ++ if ((me->me_remote && show_local_fs) ++ || -1 == stat (me->me_mountdir, &buf)) + { +- /* Stat failed - add ME to be able to complain about it later. */ ++ /* If remote, and showing just local, add ME for filtering later. ++ If stat failed; add ME to be able to complain about it later. */ + buf.st_dev = me->me_dev; + } + else + { +- /* If the device name is a real path name ... */ +- if (strchr (me->me_devname, '/')) +- { +- /* ... try to find its device number in the devlist. */ +- for (devlist = devlist_head; devlist; devlist = devlist->next) +- if (devlist->dev_num == buf.st_dev) +- break; ++ /* If we've already seen this device... */ ++ for (devlist = device_list; devlist; devlist = devlist->next) ++ if (devlist->dev_num == buf.st_dev) ++ break; + +- if (devlist) ++ if (devlist) ++ { ++ if (! print_grand_total && me->me_remote && devlist->me->me_remote ++ && ! STREQ (devlist->me->me_devname, me->me_devname)) + { ++ /* Don't discard remote entries with different locations, ++ as these are more likely to be explicitly mounted. ++ However avoid this when producing a total to give ++ a more accurate value in that case. */ ++ } ++ else if ((strchr (me->me_devname, '/') ++ /* let "real" devices with '/' in the name win. */ ++ && ! strchr (devlist->me->me_devname, '/')) ++ /* let a shorter mountdir win. */ ++ || (strlen (devlist->me->me_mountdir) ++ > strlen (me->me_mountdir)) ++ /* let an entry overmounted on a new device win... */ ++ || (! STREQ (devlist->me->me_devname, me->me_devname) ++ /* ... but only when matching an existing mnt point, ++ to avoid problematic replacement when given ++ inaccurate mount lists, seen with some chroot ++ environments for example. */ ++ && STREQ (me->me_mountdir, ++ devlist->me->me_mountdir))) ++ { ++ /* Discard mount entry for existing device. */ ++ discard_me = devlist->me; ++ devlist->me = me; ++ } ++ else ++ { ++ /* Discard mount entry currently being processed. */ + discard_me = me; +- +- /* Let the shorter mountdir win. */ +- if (! strchr (devlist->me->me_devname, '/') +- || (strlen (devlist->me->me_mountdir) +- > strlen (me->me_mountdir))) +- { +- discard_me = devlist->me; +- devlist->me = me; +- } + } ++ + } + } + + if (discard_me) + { + me = me->me_next; +- free_mount_entry (discard_me); ++ if (! devices_only) ++ free_mount_entry (discard_me); + } + else + { +@@ -665,28 +687,49 @@ filter_mount_list (void) + devlist = xmalloc (sizeof *devlist); + devlist->me = me; + devlist->dev_num = buf.st_dev; +- devlist->next = devlist_head; +- devlist_head = devlist; ++ devlist->next = device_list; ++ device_list = devlist; + + me = me->me_next; + } + } + + /* Finally rebuild the mount_list from the devlist. */ +- mount_list = NULL; +- while (devlist_head) ++ if (! devices_only) { ++ mount_list = NULL; ++ while (device_list) ++ { ++ /* Add the mount entry. */ ++ me = device_list->me; ++ me->me_next = mount_list; ++ mount_list = me; ++ /* Free devlist entry and advance. */ ++ struct devlist *devlist = device_list->next; ++ free (device_list); ++ device_list = devlist; ++ } ++ } ++} ++ ++/* Search a mount entry list for device id DEV. ++ Return the corresponding mount entry if found or NULL if not. */ ++ ++static struct mount_entry const * _GL_ATTRIBUTE_PURE ++me_for_dev (dev_t dev) ++{ ++ struct devlist *dl = device_list; ++ ++ while (dl) + { +- /* Add the mount entry. */ +- me = devlist_head->me; +- me->me_next = mount_list; +- mount_list = me; +- /* Free devlist entry and advance. */ +- struct devlist *devlist = devlist_head->next; +- free (devlist_head); +- devlist_head = devlist; ++ if (dl->dev_num == dev) ++ return dl->me; ++ dl = dl->next; + } ++ ++ return NULL; + } + ++ + /* Return true if N is a known integer value. On many file systems, + UINTMAX_MAX represents an unknown value; on AIX, UINTMAX_MAX - 1 + represents unknown. Use a rule that works on AIX file systems, and +@@ -856,6 +899,11 @@ get_dev (char const *disk, char const *mount_point, char const* file, + if (!selected_fstype (fstype) || excluded_fstype (fstype)) + return; + ++ /* Ignore relative MOUNT_POINTs, which are present for example ++ in /proc/mounts on Linux with network namespaces. */ ++ if (!force_fsu && mount_point && ! IS_ABSOLUTE_FILE_NAME (mount_point)) ++ return; ++ + /* If MOUNT_POINT is NULL, then the file system is not mounted, and this + program reports on the file system that the special file is on. + It would be better to report on the unmounted file system, +@@ -868,9 +916,43 @@ get_dev (char const *disk, char const *mount_point, char const* file, + fsu = *force_fsu; + else if (get_fs_usage (stat_file, disk, &fsu)) + { +- error (0, errno, "%s", quote (stat_file)); +- exit_status = EXIT_FAILURE; +- return; ++ /* If we can't access a system provided entry due ++ to it not being present (now), or due to permissions, ++ just output placeholder values rather than failing. */ ++ if (process_all && (errno == EACCES || errno == ENOENT)) ++ { ++ if (! show_all_fs) ++ return; ++ ++ fstype = "-"; ++ fsu.fsu_blocksize = fsu.fsu_blocks = fsu.fsu_bfree = ++ fsu.fsu_bavail = fsu.fsu_files = fsu.fsu_ffree = UINTMAX_MAX; ++ } ++ else ++ { ++ error (0, errno, "%s", quote (stat_file)); ++ exit_status = EXIT_FAILURE; ++ return; ++ } ++ } ++ else if (process_all && show_all_fs) ++ { ++ /* Ensure we don't output incorrect stats for over-mounted directories. ++ Discard stats when the device name doesn't match. Though don't ++ discard when used and current mount entries are both remote due ++ to the possibility of aliased host names or exports. */ ++ struct stat sb; ++ if (stat (stat_file, &sb) == 0) ++ { ++ struct mount_entry const * dev_me = me_for_dev (sb.st_dev); ++ if (dev_me && ! STREQ (dev_me->me_devname, disk) ++ && (! dev_me->me_remote || ! me_remote)) ++ { ++ fstype = "-"; ++ fsu.fsu_blocksize = fsu.fsu_blocks = fsu.fsu_bfree = ++ fsu.fsu_bavail = fsu.fsu_files = fsu.fsu_ffree = UINTMAX_MAX; ++ } ++ } + } + + if (fsu.fsu_blocks == 0 && !show_all_fs && !show_listed_fs) +@@ -1275,8 +1357,7 @@ get_all_entries (void) + { + struct mount_entry *me; + +- if (!show_all_fs) +- filter_mount_list (); ++ filter_mount_list (show_all_fs); + + for (me = mount_list; me; me = me->me_next) + get_dev (me->me_devname, me->me_mountdir, NULL, NULL, me->me_type, +@@ -1325,7 +1406,7 @@ or all file systems by default.\n\ + emit_mandatory_arg_note (); + + fputs (_("\ +- -a, --all include dummy file systems\n\ ++ -a, --all include pseudo, duplicate, inaccessible file systems\n\ + -B, --block-size=SIZE scale sizes by SIZE before printing them; e.g.,\n\ + '-BM' prints sizes in units of 1,048,576 bytes;\n\ + see SIZE format below\n\ +diff --git a/doc/coreutils.texi b/doc/coreutils.texi +index 942d9a1..1df1eac 100644 +--- a/doc/coreutils.texi ++++ b/doc/coreutils.texi +@@ -11123,11 +11123,15 @@ The program accepts the following options. Also see @ref{Common options}. + @itemx --all + @opindex -a + @opindex --all +-@cindex automounter file systems + @cindex ignore file systems +-Include in the listing dummy file systems, which +-are omitted by default. Such file systems are typically special-purpose +-pseudo-file-systems, such as automounter entries. ++Include in the listing dummy, duplicate, or inaccessible file systems, which ++are omitted by default. Dummy file systems are typically special purpose ++pseudo file systems such as @samp{/proc}, with no associated storage. ++Duplicate file systems are local or remote file systems that are mounted ++at separate locations in the local file hierarchy, or bind mounted locations. ++Inaccessible file systems are those which are mounted but subsequently ++over-mounted by another file system at that point, or otherwise inaccessible ++due to permissions of the mount point etc. + + @item -B @var{size} + @itemx --block-size=@var{size} +diff --git a/tests/df/skip-duplicates.sh b/tests/df/skip-duplicates.sh +index 1e94dc0..4069604 100755 +--- a/tests/df/skip-duplicates.sh ++++ b/tests/df/skip-duplicates.sh +@@ -2,7 +2,7 @@ + # Test df's behavior when the mount list contains duplicate entries. + # This test is skipped on systems that lack LD_PRELOAD support; that's fine. + +-# Copyright (C) 2012-2013 Free Software Foundation, Inc. ++# Copyright (C) 2012-2015 Free Software Foundation, Inc. + + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU General Public License as published by +@@ -21,19 +21,73 @@ + print_ver_ df + require_gcc_shared_ + +-df || skip_ "df fails" ++# We use --local here so as to not activate ++# potentially very many remote mounts. ++df --local || skip_ 'df fails' + +-# Simulate an mtab file with two entries of the same device number. +-# Also add entries with unstatable mount dirs to ensure that's handled. +-cat > k.c <<'EOF' || framework_failure_ ++export CU_NONROOT_FS=$(df --local --output=target 2>&1 | grep /. | head -n1) ++export CU_REMOTE_FS=$(df --local --output=target 2>&1 | grep /. | ++ tail -n+2 | head -n1) ++ ++unique_entries=1 ++test -z "$CU_NONROOT_FS" || unique_entries=$(expr $unique_entries + 1) ++test -z "$CU_REMOTE_FS" || unique_entries=$(expr $unique_entries + 2) ++ ++grep '^#define HAVE_MNTENT_H 1' $CONFIG_HEADER > /dev/null \ ++ || skip_ "no mntent.h available to confirm the interface" ++ ++grep '^#define HAVE_GETMNTENT 1' $CONFIG_HEADER > /dev/null \ ++ || skip_ "getmntent is not used on this system" ++ ++# Simulate an mtab file to test various cases. ++cat > k.c < + #include ++#include + #include ++#include ++#include ++ ++#define STREQ(a, b) (strcmp (a, b) == 0) ++ ++FILE* fopen(const char *path, const char *mode) ++{ ++ static FILE* (*fopen_func)(char const *, char const *); ++ ++ /* get reference to original (libc provided) fopen */ ++ if (!fopen_func) ++ { ++ fopen_func = (FILE*(*)(char const *, char const *)) ++ dlsym(RTLD_NEXT, "fopen"); ++ if (!fopen_func) ++ { ++ fprintf (stderr, "Failed to find fopen()\n"); ++ errno = ESRCH; ++ return NULL; ++ } ++ } ++ ++ /* Returning ENOENT here will get read_file_system_list() ++ to fall back to using getmntent() below. */ ++ if (STREQ (path, "/proc/self/mountinfo")) ++ { ++ errno = ENOENT; ++ return NULL; ++ } ++ else ++ return fopen_func(path, mode); ++} ++ ++#define STREQ(a, b) (strcmp (a, b) == 0) + + struct mntent *getmntent (FILE *fp) + { ++ static char *nonroot_fs; ++ static char *remote_fs; ++ static int done; ++ + /* Prove that LD_PRELOAD works. */ +- static int done = 0; + if (!done) + { + fclose (fopen ("x", "w")); +@@ -41,50 +95,92 @@ struct mntent *getmntent (FILE *fp) + } + + static struct mntent mntents[] = { +- {.mnt_fsname="/short", .mnt_dir="/invalid/mount/dir"}, +- {.mnt_fsname="fsname", .mnt_dir="/",}, +- {.mnt_fsname="/fsname", .mnt_dir="/root"}, +- {.mnt_fsname="/fsname", .mnt_dir="/"}, ++ {.mnt_fsname="/short", .mnt_dir="/invalid/mount/dir", .mnt_opts=""}, ++ {.mnt_fsname="fsname", .mnt_dir="/", .mnt_opts=""}, ++ {.mnt_fsname="/fsname", .mnt_dir="/.", .mnt_opts=""}, ++ {.mnt_fsname="/fsname", .mnt_dir="/", .mnt_opts=""}, ++ {.mnt_fsname="virtfs", .mnt_dir="/NONROOT", .mnt_type="t1", .mnt_opts=""}, ++ {.mnt_fsname="virtfs2", .mnt_dir="/NONROOT", .mnt_type="t2", .mnt_opts=""}, ++ {.mnt_fsname="netns", .mnt_dir="net:[1234567]", .mnt_opts=""}, ++ {.mnt_fsname="rem:ote1",.mnt_dir="/REMOTE", .mnt_opts=""}, ++ {.mnt_fsname="rem:ote1",.mnt_dir="/REMOTE", .mnt_opts=""}, ++ {.mnt_fsname="rem:ote2",.mnt_dir="/REMOTE", .mnt_opts=""}, + }; + +- if (!getenv ("CU_TEST_DUPE_INVALID") && done == 1) ++ if (done == 1) ++ { ++ nonroot_fs = getenv ("CU_NONROOT_FS"); ++ if (!nonroot_fs || !*nonroot_fs) ++ nonroot_fs = "/"; /* merge into / entries. */ ++ ++ remote_fs = getenv ("CU_REMOTE_FS"); ++ } ++ ++ if (done == 1 && !getenv ("CU_TEST_DUPE_INVALID")) + done++; /* skip the first entry. */ + +- while (done++ <= 4) ++ while (done++ <= 10) + { +- mntents[done-2].mnt_type = "-"; ++ if (!mntents[done-2].mnt_type) ++ mntents[done-2].mnt_type = "-"; ++ if (!mntents[done-2].mnt_opts) ++ mntents[done-2].mnt_opts = "-"; ++ if (STREQ (mntents[done-2].mnt_dir, "/NONROOT")) ++ mntents[done-2].mnt_dir = nonroot_fs; ++ if (STREQ (mntents[done-2].mnt_dir, "/REMOTE")) ++ { ++ if (!remote_fs || !*remote_fs) ++ continue; ++ else ++ mntents[done-2].mnt_dir = remote_fs; ++ } + return &mntents[done-2]; + } ++ + return NULL; + } + EOF + + # Then compile/link it: +-gcc --std=gnu99 -shared -fPIC -ldl -O2 k.c -o k.so \ ++gcc_shared_ k.c k.so \ + || framework_failure_ 'failed to build shared library' + + # Test if LD_PRELOAD works: +-LD_PRELOAD=./k.so df ++LD_PRELOAD=$LD_PRELOAD:./k.so df + test -f x || skip_ "internal test failure: maybe LD_PRELOAD doesn't work?" + + # The fake mtab file should only contain entries + # having the same device number; thus the output should +-# consist of a header and one entry. +-LD_PRELOAD=./k.so df >out || fail=1 +-test $(wc -l out || fail=1 ++test $(wc -l out && fail=1 +-test $(wc -l out || fail=1 ++test "$CU_REMOTE_FS" && elide_remote=1 || elide_remote=0 ++test $(wc -l out || fail=1 ++test $(wc -l out || fail=1 +-test $(wc -l out || fail=1 ++total_fs=6; test "$CU_REMOTE_FS" && total_fs=$(expr $total_fs + 3) ++test $(wc -l me_next) ++ { ++ if (STREQ (me->me_mountdir, mount)) ++ le = me; ++ } ++ ++ if (le) ++ { ++ char *devname = le->me_devname; ++ char *canon_dev = canonicalize_file_name (devname); ++ if (canon_dev && IS_ABSOLUTE_FILE_NAME (canon_dev)) ++ return canon_dev; ++ free (canon_dev); ++ return xstrdup (le->me_devname); ++ } ++ else ++ return NULL; ++} ++ + /* If DISK corresponds to a mount point, show its usage + and return true. Otherwise, return false. */ + static bool +@@ -1064,27 +1091,57 @@ get_disk (char const *disk) + { + struct mount_entry const *me; + struct mount_entry const *best_match = NULL; ++ bool best_match_accessible = false; ++ bool eclipsed_device = false; + char const *file = disk; + + char *resolved = canonicalize_file_name (disk); +- if (resolved && resolved[0] == '/') ++ if (resolved && IS_ABSOLUTE_FILE_NAME (resolved)) + disk = resolved; + + size_t best_match_len = SIZE_MAX; + for (me = mount_list; me; me = me->me_next) + { +- if (STREQ (disk, me->me_devname)) ++ /* TODO: Should cache canon_dev in the mount_entry struct. */ ++ char *devname = me->me_devname; ++ char *canon_dev = canonicalize_file_name (me->me_devname); ++ if (canon_dev && IS_ABSOLUTE_FILE_NAME (canon_dev)) ++ devname = canon_dev; ++ ++ if (STREQ (disk, devname)) + { ++ char *last_device = last_device_for_mount (me->me_mountdir); ++ eclipsed_device = last_device && ! STREQ (last_device, devname); + size_t len = strlen (me->me_mountdir); +- if (len < best_match_len) ++ ++ if (! eclipsed_device ++ && (! best_match_accessible || len < best_match_len)) + { +- best_match = me; +- if (len == 1) /* Traditional root. */ +- break; +- else +- best_match_len = len; ++ struct stat disk_stats; ++ bool this_match_accessible = false; ++ ++ if (stat (me->me_mountdir, &disk_stats) == 0) ++ best_match_accessible = this_match_accessible = true; ++ ++ if (this_match_accessible ++ || (! best_match_accessible && len < best_match_len)) ++ { ++ best_match = me; ++ if (len == 1) /* Traditional root. */ ++ { ++ free (last_device); ++ free (canon_dev); ++ break; ++ } ++ else ++ best_match_len = len; ++ } + } ++ ++ free (last_device); + } ++ ++ free (canon_dev); + } + + free (resolved); +@@ -1096,6 +1153,13 @@ get_disk (char const *disk) + best_match->me_remote, NULL, false); + return true; + } ++ else if (eclipsed_device) ++ { ++ error (0, 0, _("cannot access %s: over-mounted by another device"), ++ quote (file)); ++ exit_status = EXIT_FAILURE; ++ return true; ++ } + + return false; + } diff --git a/SOURCES/coreutils-8.22-df-stat.patch b/SOURCES/coreutils-8.22-df-stat.patch new file mode 100644 index 0000000..fc49946 --- /dev/null +++ b/SOURCES/coreutils-8.22-df-stat.patch @@ -0,0 +1,35 @@ +From 9c4641f42bbecf63ec0a0e05caacbccd5332b831 Mon Sep 17 00:00:00 2001 +From: Philipp Thomas +Date: Sun, 26 Mar 2017 22:34:00 -0700 +Subject: [PATCH] df: avoid querying excluded file systems + +* src/df.c (filter_mount_list): Avoid stat() on +explicitly excluded file systems, which is especially +significant in cases like `-x nfs` which may hang. +* NEWS: Mention the bug fix. + +Upstream-commit: 7c228bc55ed3fd6d56a6ad135438066de2f54a30 +Signed-off-by: Kamil Dudka +--- + src/df.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/df.c b/src/df.c +index 5b9e8fd..e0ebed7 100644 +--- a/src/df.c ++++ b/src/df.c +@@ -632,9 +632,11 @@ filter_mount_list (bool devices_only) + On Linux we probably have me_dev populated from /proc/self/mountinfo, + however we still stat() in case another device was mounted later. */ + if ((me->me_remote && show_local_fs) ++ || (!selected_fstype (me->me_type) || excluded_fstype (me->me_type)) + || -1 == stat (me->me_mountdir, &buf)) + { +- /* If remote, and showing just local, add ME for filtering later. ++ /* If remote, and showing just local, or FS type is excluded, ++ add ME for filtering later. + If stat failed; add ME to be able to complain about it later. */ + buf.st_dev = me->me_dev; + } +-- +2.13.6 diff --git a/SOURCES/coreutils-8.22-doc-ls-kibibytes.patch b/SOURCES/coreutils-8.22-doc-ls-kibibytes.patch new file mode 100644 index 0000000..207fa12 --- /dev/null +++ b/SOURCES/coreutils-8.22-doc-ls-kibibytes.patch @@ -0,0 +1,32 @@ +From c6418e3a5cb3a65af79117162a93a66026cc8c36 Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Thu, 6 Dec 2018 14:28:00 +0100 +Subject: [PATCH] doc: improve wording of the --kibibytes option description + +Bug: https://bugzilla.redhat.com/1527391 +--- + doc/coreutils.texi | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/doc/coreutils.texi b/doc/coreutils.texi +index 88d6506..772aab6 100644 +--- a/doc/coreutils.texi ++++ b/doc/coreutils.texi +@@ -7615,9 +7615,11 @@ Append @samp{*} for executable regular files, otherwise behave as for + @opindex --kibibytes + Set the default block size to its normal value of 1024 bytes, + overriding any contrary specification in environment variables +-(@pxref{Block size}). This option is in turn overridden by the +-@option{--block-size}, @option{-h} or @option{--human-readable}, and +-@option{--si} options. ++(@pxref{Block size}). If @option{--block-size}, @option{-h}, ++@option{--human-readable}, or @option{--si} options are used, ++they take precedence over @option{-k} or @option{--kibibytes} ++even if @option{-k} or @option{--kibibytes} is placed after ++the other options. + + The @option{-k} or @option{--kibibytes} option affects the + per-directory block count written by the @option{-l} and similar +-- +2.17.2 + diff --git a/SOURCES/coreutils-8.22-du-bindmountcycles.patch b/SOURCES/coreutils-8.22-du-bindmountcycles.patch new file mode 100644 index 0000000..8c38057 --- /dev/null +++ b/SOURCES/coreutils-8.22-du-bindmountcycles.patch @@ -0,0 +1,157 @@ +From dc1c0523a61932fb0c26a795b7e7391eadf2171a Mon Sep 17 00:00:00 2001 +From: Boris Ranto +Date: Mon, 1 Dec 2014 09:24:14 +0100 +Subject: [PATCH 1/1] du: handle sub-bind-mount cycles gracefully + +This patch fixes the handling of sub-bind-mount cycles which are +incorrectly detected as the file system errors. If you bind mount the +directory 'a' to its subdirectory 'a/b/c' and then run 'du a/b' you +will get the circular dependency warning even though nothing is wrong +with the file system. This happens because the first directory that is +traversed twice in this case is not a bind mount but a child of bind +mount. The solution is to traverse all the directories in the cycle +that fts detected and check whether they are not a (bind) mount. + +* src/du.c (mount_point_in_fts_cycle): New function that checks whether +any of the directories in the cycle that fts detected is a mount point. +* src/du.c (process_file): Update the function to use the new function +that looks up all the directories in the fts cycle instead of only the +last one. +* tests/du/bind-mount-dir-cycle-v2.sh: New test case that exhibits the +described behavior. +* tests/local.mk: Reference the new root test. +--- + src/du.c | 23 ++++++++++++++++++++- + tests/du/bind-mount-dir-cycle-v2.sh | 38 +++++++++++++++++++++++++++++++++++ + tests/local.mk | 1 + + 3 files changed, 61 insertions(+), 1 deletions(-) + create mode 100755 tests/du/bind-mount-dir-cycle-v2.sh + +diff --git a/src/du.c b/src/du.c +index ba20120..f5726c7 100644 +--- a/src/du.c ++++ b/src/du.c +@@ -419,6 +419,27 @@ print_size (const struct duinfo *pdui, const char *string) + fflush (stdout); + } + ++/* This function checks whether any of the directories in the cycle that ++ fts detected is a mount point. */ ++ ++static bool ++mount_point_in_fts_cycle (FTSENT const *ent) ++{ ++ FTSENT const *cycle_ent = ent->fts_cycle; ++ ++ while (ent && ent != cycle_ent) ++ { ++ if (di_set_lookup (di_mnt, ent->fts_statp->st_dev, ++ ent->fts_statp->st_ino) > 0) ++ { ++ return true; ++ } ++ ent = ent->fts_parent; ++ } ++ ++ return false; ++} ++ + /* This function is called once for every file system object that fts + encounters. fts does a depth-first traversal. This function knows + that and accumulates per-directory totals based on changes in +@@ -514,15 +514,11 @@ process_file (FTS *fts, FTSENT *ent) + break; + + case FTS_DC: +- if (cycle_warning_required (fts, ent)) ++ /* If not following symlinks and not a (bind) mount point. */ ++ if (cycle_warning_required (fts, ent) ++ && ! mount_point_in_fts_cycle (ent)) + { +- /* If this is a mount point, then diagnose it and avoid +- the cycle. */ +- if (di_set_lookup (di_mnt, sb->st_dev, sb->st_ino)) +- error (0, 0, _("mount point %s already traversed"), +- quote (file)); +- else +- emit_cycle_warning (file); ++ emit_cycle_warning (file); + return false; + } + return true; +diff --git a/tests/du/bind-mount-dir-cycle-v2.sh b/tests/du/bind-mount-dir-cycle-v2.sh +new file mode 100755 +index 0000000..08bfae2 +--- /dev/null ++++ b/tests/du/bind-mount-dir-cycle-v2.sh +@@ -0,0 +1,38 @@ ++#!/bin/sh ++# Check that du can handle sub-bind-mounts cycles as well. ++ ++# Copyright (C) 2014 Free Software foundation, Inc. ++ ++# This program is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++ ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++ ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src ++print_ver_ du ++require_root_ ++ ++cleanup_() { umount a/b/c; } ++ ++mkdir -p a/b/c || framework_failure_ ++mount --bind a a/b/c \ ++ || skip_ 'This test requires mount with a working --bind option.' ++ ++echo a/b/c > exp || framework_failure_ ++echo a/b >> exp || framework_failure_ ++ ++du a/b > out 2> err || fail=1 ++sed 's/^[0-9][0-9]* //' out > k && mv k out ++ ++compare /dev/null err || fail=1 ++compare exp out || fail=1 ++ ++Exit $fail +diff --git a/tests/local.mk b/tests/local.mk +index 653c984..349e322 100644 +--- a/tests/local.mk ++++ b/tests/local.mk +@@ -117,6 +117,7 @@ all_root_tests = \ + tests/dd/skip-seek-past-dev.sh \ + tests/df/problematic-chars.sh \ + tests/du/bind-mount-dir-cycle.sh \ ++ tests/du/bind-mount-dir-cycle-v2.sh \ + tests/id/setgid.sh \ + tests/install/install-C-root.sh \ + tests/ls/capability.sh \ +-- +1.7.2.5 +diff -urNp coreutils-8.22-orig/tests/du/bind-mount-dir-cycle.sh coreutils-8.22/tests/du/bind-mount-dir-cycle.sh +--- coreutils-8.22-orig/tests/du/bind-mount-dir-cycle.sh 2013-12-04 15:48:30.000000000 +0100 ++++ coreutils-8.22/tests/du/bind-mount-dir-cycle.sh 2015-07-02 15:58:49.230632316 +0200 +@@ -27,12 +27,11 @@ mount --bind a a/b \ + || skip_ "This test requires mount with a working --bind option." + + echo a > exp || framework_failure_ +-echo "du: mount point 'a/b' already traversed" > exp-err || framework_failure_ + +-du a > out 2> err && fail=1 ++du a > out 2> err || fail=1 + sed 's/^[0-9][0-9]* //' out > k && mv k out + +-compare exp-err err || fail=1 ++compare /dev/null err || fail=1 + compare exp out || fail=1 + + Exit $fail diff --git a/SOURCES/coreutils-8.22-failingtests.patch b/SOURCES/coreutils-8.22-failingtests.patch new file mode 100644 index 0000000..7f60046 --- /dev/null +++ b/SOURCES/coreutils-8.22-failingtests.patch @@ -0,0 +1,32 @@ +diff -urNp coreutils-8.22-orig/tests/cp/cp-a-selinux.sh coreutils-8.22/tests/cp/cp-a-selinux.sh +--- coreutils-8.22-orig/tests/cp/cp-a-selinux.sh 2016-06-24 11:44:21.909303666 +0200 ++++ coreutils-8.22/tests/cp/cp-a-selinux.sh 2016-06-24 11:47:28.473908346 +0200 +@@ -73,7 +73,8 @@ old_type_d=$(get_selinux_type c_d) + # and get the adjusted type for comparison + cp -a c Z1 || fail=1 + cp -a c_d Z1_d || fail=1 +-if restorecon Z1 Z1_d 2>/dev/null; then ++if restorecon Z1 Z1_d 2>restorecon.err \ ++ && compare /dev/null restorecon.err; then + new_type_f=$(get_selinux_type Z1) + new_type_d=$(get_selinux_type Z1_d) + +diff -urNp coreutils-8.22-orig/tests/local.mk coreutils-8.22/tests/local.mk +--- coreutils-8.22-orig/tests/local.mk 2016-06-24 11:44:21.920303760 +0200 ++++ coreutils-8.22/tests/local.mk 2016-06-24 11:49:31.388965563 +0200 +@@ -117,7 +117,6 @@ all_root_tests = \ + tests/df/problematic-chars.sh \ + tests/du/bind-mount-dir-cycle.sh \ + tests/du/bind-mount-dir-cycle-v2.sh \ +- tests/id/setgid.sh \ + tests/install/install-C-root.sh \ + tests/ls/capability.sh \ + tests/ls/nameless-uid.sh \ +@@ -515,7 +514,6 @@ all_tests = \ + tests/id/no-context.sh \ + tests/id/context.sh \ + tests/id/uid.sh \ +- tests/id/setgid.sh \ + tests/id/zero.sh \ + tests/install/basic-1.sh \ + tests/install/create-leading.sh \ diff --git a/SOURCES/coreutils-8.22-id-groups.patch b/SOURCES/coreutils-8.22-id-groups.patch new file mode 100644 index 0000000..76ed9a9 --- /dev/null +++ b/SOURCES/coreutils-8.22-id-groups.patch @@ -0,0 +1,39 @@ +diff -urNp coreutils-8.4-orig/src/id.c coreutils-8.4/src/id.c +--- coreutils-8.4-orig/src/id.c 2014-06-26 08:47:28.435047859 +0200 ++++ coreutils-8.4/src/id.c 2014-06-26 08:55:28.352788022 +0200 +@@ -296,8 +296,12 @@ print_full_info (const char *username) + gid_t *groups; + int i; + +- int n_groups = xgetgroups (username, (pwd ? pwd->pw_gid : -1), +- &groups); ++ gid_t primary_group; ++ if (username) ++ primary_group = pwd ? pwd->pw_gid : -1; ++ else ++ primary_group = egid; ++ int n_groups = xgetgroups (username, primary_group, &groups); + if (n_groups < 0) + { + if (username) + +diff -urNp coreutils-8.22-orig/tests/id/setgid.sh coreutils-8.22/tests/id/setgid.sh +--- coreutils-8.22-orig/tests/id/setgid.sh 2014-06-26 08:47:28.750053213 +0200 ++++ coreutils-8.22/tests/id/setgid.sh 2014-06-26 08:51:02.536624404 +0200 +@@ -1,5 +1,5 @@ + #!/bin/sh +-# Verify that id -G prints the right group when run set-GID. ++# Verify that id [-G] prints the right group when run set-GID. + + # Copyright (C) 2012-2013 Free Software Foundation, Inc. + +@@ -35,4 +35,9 @@ setuidgid -g $gp1 $NON_ROOT_USERNAME env + compare exp out || fail=1 + # With coreutils-8.16 and earlier, id -G would print both: $gp1 $g + ++# With coreutils-8.22 and earlier, id would erroneously print groups=$g ++chroot --user=$NON_ROOT_USERNAME:$gp1 --groups='' / env PATH="$PATH" \ ++ id > out || fail=1 ++grep -F "groups=$gp1" out || fail=1 ++ + Exit $fail diff --git a/SOURCES/coreutils-8.22-ls-interruption.patch b/SOURCES/coreutils-8.22-ls-interruption.patch new file mode 100644 index 0000000..c19d30c --- /dev/null +++ b/SOURCES/coreutils-8.22-ls-interruption.patch @@ -0,0 +1,236 @@ +From e56f09afdbd4bd920e4a1f3b03e29eaccd954dac Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Tue, 6 Sep 2016 17:38:26 +0200 +Subject: [PATCH] ls: allow interruption when reading slow directories + +Postpone installation of signal handlers until they're needed. +That is right before the first escape sequence is printed. + +* src/ls.c (signal_setup): A new function refactored from main() +to set and restore signal handlers. +(main): Move signal handler setup to put_indicator() +so that the default signal handling is untouched as long as possible. +Adjusted condition for restoring signal handlers to reflect the change. +(put_indicator): Install signal handlers if called for the very first +time. It uses the same code that was in main() prior to this commit. +* NEWS: Mention the improvement. + +See https://bugzilla.redhat.com/1365933 +Fixes http://bugs.gnu.org/24232 + +Upstream-commit: 5445f7811ff945ea13aa2a0fd797eb4c0a0e4db0 +Signed-off-by: Kamil Dudka +--- + src/ls.c | 161 ++++++++++++++++++++++++++++++++++++--------------------------- + 1 file changed, 93 insertions(+), 68 deletions(-) + +diff --git a/src/ls.c b/src/ls.c +index a89c87a..1300938 100644 +--- a/src/ls.c ++++ b/src/ls.c +@@ -1246,13 +1246,12 @@ process_signals (void) + } + } + +-int +-main (int argc, char **argv) +-{ +- int i; +- struct pending *thispend; +- int n_files; ++/* Setup signal handlers if INIT is true, ++ otherwise restore to the default. */ + ++static void ++signal_setup (bool init) ++{ + /* The signals that are trapped, and the number of such signals. */ + static int const sig[] = + { +@@ -1280,8 +1279,77 @@ main (int argc, char **argv) + enum { nsigs = ARRAY_CARDINALITY (sig) }; + + #if ! SA_NOCLDSTOP +- bool caught_sig[nsigs]; ++ static bool caught_sig[nsigs]; ++#endif ++ ++ int j; ++ ++ if (init) ++ { ++#if SA_NOCLDSTOP ++ struct sigaction act; ++ ++ sigemptyset (&caught_signals); ++ for (j = 0; j < nsigs; j++) ++ { ++ sigaction (sig[j], NULL, &act); ++ if (act.sa_handler != SIG_IGN) ++ sigaddset (&caught_signals, sig[j]); ++ } ++ ++ act.sa_mask = caught_signals; ++ act.sa_flags = SA_RESTART; ++ ++ for (j = 0; j < nsigs; j++) ++ if (sigismember (&caught_signals, sig[j])) ++ { ++ act.sa_handler = sig[j] == SIGTSTP ? stophandler : sighandler; ++ sigaction (sig[j], &act, NULL); ++ } ++#else ++ for (j = 0; j < nsigs; j++) ++ { ++ caught_sig[j] = (signal (sig[j], SIG_IGN) != SIG_IGN); ++ if (caught_sig[j]) ++ { ++ signal (sig[j], sig[j] == SIGTSTP ? stophandler : sighandler); ++ siginterrupt (sig[j], 0); ++ } ++ } + #endif ++ } ++ else /* restore. */ ++ { ++#if SA_NOCLDSTOP ++ for (j = 0; j < nsigs; j++) ++ if (sigismember (&caught_signals, sig[j])) ++ signal (sig[j], SIG_DFL); ++#else ++ for (j = 0; j < nsigs; j++) ++ if (caught_sig[j]) ++ signal (sig[j], SIG_DFL); ++#endif ++ } ++} ++ ++static inline void ++signal_init (void) ++{ ++ signal_setup (true); ++} ++ ++static inline void ++signal_restore (void) ++{ ++ signal_setup (false); ++} ++ ++int ++main (int argc, char **argv) ++{ ++ int i; ++ struct pending *thispend; ++ int n_files; + + initialize_main (&argc, &argv); + set_program_name (argv[0]); +@@ -1317,46 +1385,6 @@ main (int argc, char **argv) + || (is_colored (C_MISSING) && (format == long_format + || format == security_format))) + check_symlink_color = true; +- +- /* If the standard output is a controlling terminal, watch out +- for signals, so that the colors can be restored to the +- default state if "ls" is suspended or interrupted. */ +- +- if (0 <= tcgetpgrp (STDOUT_FILENO)) +- { +- int j; +-#if SA_NOCLDSTOP +- struct sigaction act; +- +- sigemptyset (&caught_signals); +- for (j = 0; j < nsigs; j++) +- { +- sigaction (sig[j], NULL, &act); +- if (act.sa_handler != SIG_IGN) +- sigaddset (&caught_signals, sig[j]); +- } +- +- act.sa_mask = caught_signals; +- act.sa_flags = SA_RESTART; +- +- for (j = 0; j < nsigs; j++) +- if (sigismember (&caught_signals, sig[j])) +- { +- act.sa_handler = sig[j] == SIGTSTP ? stophandler : sighandler; +- sigaction (sig[j], &act, NULL); +- } +-#else +- for (j = 0; j < nsigs; j++) +- { +- caught_sig[j] = (signal (sig[j], SIG_IGN) != SIG_IGN); +- if (caught_sig[j]) +- { +- signal (sig[j], sig[j] == SIGTSTP ? stophandler : sighandler); +- siginterrupt (sig[j], 0); +- } +- } +-#endif +- } + } + + if (dereference == DEREF_UNDEFINED) +@@ -1467,32 +1495,21 @@ main (int argc, char **argv) + print_dir_name = true; + } + +- if (print_with_color) ++ if (print_with_color && used_color) + { + int j; + +- if (used_color) +- { +- /* Skip the restore when it would be a no-op, i.e., +- when left is "\033[" and right is "m". */ +- if (!(color_indicator[C_LEFT].len == 2 +- && memcmp (color_indicator[C_LEFT].string, "\033[", 2) == 0 +- && color_indicator[C_RIGHT].len == 1 +- && color_indicator[C_RIGHT].string[0] == 'm')) +- restore_default_color (); +- } ++ /* Skip the restore when it would be a no-op, i.e., ++ when left is "\033[" and right is "m". */ ++ if (!(color_indicator[C_LEFT].len == 2 ++ && memcmp (color_indicator[C_LEFT].string, "\033[", 2) == 0 ++ && color_indicator[C_RIGHT].len == 1 ++ && color_indicator[C_RIGHT].string[0] == 'm')) ++ restore_default_color (); ++ + fflush (stdout); + +- /* Restore the default signal handling. */ +-#if SA_NOCLDSTOP +- for (j = 0; j < nsigs; j++) +- if (sigismember (&caught_signals, sig[j])) +- signal (sig[j], SIG_DFL); +-#else +- for (j = 0; j < nsigs; j++) +- if (caught_sig[j]) +- signal (sig[j], SIG_DFL); +-#endif ++ signal_restore (); + + /* Act on any signals that arrived before the default was restored. + This can process signals out of order, but there doesn't seem to +@@ -4512,6 +4529,14 @@ put_indicator (const struct bin_str *ind) + if (! used_color) + { + used_color = true; ++ ++ /* If the standard output is a controlling terminal, watch out ++ for signals, so that the colors can be restored to the ++ default state if "ls" is suspended or interrupted. */ ++ ++ if (0 <= tcgetpgrp (STDOUT_FILENO)) ++ signal_init (); ++ + prep_non_filename_text (); + } + +-- +2.13.5 + diff --git a/SOURCES/coreutils-8.22-mv-hardlinksrace.patch b/SOURCES/coreutils-8.22-mv-hardlinksrace.patch new file mode 100644 index 0000000..4e463a8 --- /dev/null +++ b/SOURCES/coreutils-8.22-mv-hardlinksrace.patch @@ -0,0 +1,365 @@ +diff -urNp coreutils-8.22-orig/src/copy.c coreutils-8.22/src/copy.c +--- coreutils-8.22-orig/src/copy.c 2015-07-03 14:42:56.829772551 +0200 ++++ coreutils-8.22/src/copy.c 2015-07-03 14:51:05.371383675 +0200 +@@ -1292,20 +1292,12 @@ close_src_desc: + copy a regular file onto a symlink that points to it. + Try to minimize the cost of this function in the common case. + Set *RETURN_NOW if we've determined that the caller has no more +- work to do and should return successfully, right away. +- +- Set *UNLINK_SRC if we've determined that the caller wants to do +- 'rename (a, b)' where 'a' and 'b' are distinct hard links to the same +- file. In that case, the caller should try to unlink 'a' and then return +- successfully. Ideally, we wouldn't have to do that, and we'd be +- able to rely on rename to remove the source file. However, POSIX +- mistakenly requires that such a rename call do *nothing* and return +- successfully. */ ++ work to do and should return successfully, right away. */ + + static bool + same_file_ok (char const *src_name, struct stat const *src_sb, + char const *dst_name, struct stat const *dst_sb, +- const struct cp_options *x, bool *return_now, bool *unlink_src) ++ const struct cp_options *x, bool *return_now) + { + const struct stat *src_sb_link; + const struct stat *dst_sb_link; +@@ -1316,7 +1308,6 @@ same_file_ok (char const *src_name, stru + bool same = SAME_INODE (*src_sb, *dst_sb); + + *return_now = false; +- *unlink_src = false; + + /* FIXME: this should (at the very least) be moved into the following + if-block. More likely, it should be removed, because it inhibits +@@ -1348,14 +1339,11 @@ same_file_ok (char const *src_name, stru + /* Here we have two symlinks that are hard-linked together, + and we're not making backups. In this unusual case, simply + returning true would lead to mv calling "rename(A,B)", +- which would do nothing and return 0. I.e., A would +- not be removed. Hence, the solution is to tell the +- caller that all it must do is unlink A and return. */ ++ which would do nothing and return 0. */ + if (same_link) + { +- *unlink_src = true; + *return_now = true; +- return true; ++ return ! x->move_mode; + } + } + +@@ -1443,26 +1431,22 @@ same_file_ok (char const *src_name, stru + return true; + #endif + +- /* They may refer to the same file if we're in move mode and the +- target is a symlink. That is ok, since we remove any existing +- destination file before opening it -- via 'rename' if they're on +- the same file system, via 'unlink (DST_NAME)' otherwise. +- It's also ok if they're distinct hard links to the same file. */ + if (x->move_mode || x->unlink_dest_before_opening) + { ++ /* They may refer to the same file if we're in move mode and the ++ target is a symlink. That is ok, since we remove any existing ++ destination file before opening it -- via 'rename' if they're on ++ the same file system, via 'unlink (DST_NAME)' otherwise. */ + if (S_ISLNK (dst_sb_link->st_mode)) + return true; + ++ /* It's not ok if they're distinct hard links to the same file as ++ this causes a race condition and we may lose data in this case. */ + if (same_link + && 1 < dst_sb_link->st_nlink + && ! same_name (src_name, dst_name)) + { +- if (x->move_mode) +- { +- *unlink_src = true; +- *return_now = true; +- } +- return true; ++ return ! x->move_mode; + } + } + +@@ -1820,11 +1804,10 @@ copy_internal (char const *src_name, cha + { /* Here, we know that dst_name exists, at least to the point + that it is stat'able or lstat'able. */ + bool return_now; +- bool unlink_src; + + have_dst_lstat = !use_stat; + if (! same_file_ok (src_name, &src_sb, dst_name, &dst_sb, +- x, &return_now, &unlink_src)) ++ x, &return_now)) + { + error (0, 0, _("%s and %s are the same file"), + quote_n (0, src_name), quote_n (1, dst_name)); +@@ -1883,22 +1866,14 @@ copy_internal (char const *src_name, cha + cp and mv treat -i and -f differently. */ + if (x->move_mode) + { +- if (abandon_move (x, dst_name, &dst_sb) +- || (unlink_src && unlink (src_name) == 0)) ++ if (abandon_move (x, dst_name, &dst_sb)) + { + /* Pretend the rename succeeded, so the caller (mv) + doesn't end up removing the source file. */ + if (rename_succeeded) + *rename_succeeded = true; +- if (unlink_src && x->verbose) +- printf (_("removed %s\n"), quote (src_name)); + return true; + } +- if (unlink_src) +- { +- error (0, errno, _("cannot remove %s"), quote (src_name)); +- return false; +- } + } + else + { +diff -urNp coreutils-8.22-orig/tests/cp/same-file.sh coreutils-8.22/tests/cp/same-file.sh +--- coreutils-8.22-orig/tests/cp/same-file.sh 2013-12-04 15:48:30.000000000 +0100 ++++ coreutils-8.22/tests/cp/same-file.sh 2015-07-03 14:54:12.539772880 +0200 +@@ -36,7 +36,7 @@ ln dangling-slink hard-link > /dev/null 2>&1 \ + rm -f no-such dangling-slink hard-link + + test $hard_link_to_symlink_does_the_deref = yes \ +- && remove_these_sed='/^0 -[bf]*l .*sl1 ->/d' \ ++ && remove_these_sed='/^0 -[bf]*l .*sl1 ->/d; /hlsl/d' \ + || remove_these_sed='/^ELIDE NO TEST OUTPUT/d' + + exec 3>&1 1> actual +@@ -44,7 +44,8 @@ exec 3>&1 1> actual + # FIXME: This should be bigger: like more than 8k + contents=XYZ + +-for args in 'foo symlink' 'symlink foo' 'foo foo' 'sl1 sl2' 'foo hardlink'; do ++for args in 'foo symlink' 'symlink foo' 'foo foo' 'sl1 sl2' \ ++ 'foo hardlink' 'hlsl sl2'; do + for options in '' -d -f -df --rem -b -bd -bf -bdf \ + -l -dl -fl -dfl -bl -bdl -bfl -bdfl; do + case $args$options in +@@ -76,6 +77,8 @@ for args in 'foo symlink' 'symlink foo' + continue ;; + 'yes:sl1 sl2:-bfl') + continue ;; ++ yes:hlsl*) ++ continue ;; + esac + + rm -rf dir +@@ -86,6 +87,7 @@ for args in 'foo symlink' 'symlink foo' + case "$args" in *hardlink*) ln foo hardlink ;; esac + case "$args" in *sl1*) ln -s foo sl1;; esac + case "$args" in *sl2*) ln -s foo sl2;; esac ++ case "$args" in *hlsl*) ln sl2 hlsl;;esac + ( + ( + # echo 1>&2 cp $options $args +@@ -211,6 +213,24 @@ cat <<\EOF | sed "$remove_these_sed" > e + 0 -bfl (foo hardlink) + 0 -bdfl (foo hardlink) + ++1 [cp: 'hlsl' and 'sl2' are the same file] (foo hlsl -> foo sl2 -> foo) ++0 -d (foo hlsl -> foo sl2 -> foo) ++1 -f [cp: 'hlsl' and 'sl2' are the same file] (foo hlsl -> foo sl2 -> foo) ++0 -df (foo hlsl -> foo sl2 -> foo) ++0 --rem (foo hlsl -> foo sl2) ++0 -b (foo hlsl -> foo sl2 sl2.~1~ -> foo) ++0 -bd (foo hlsl -> foo sl2 -> foo sl2.~1~ -> foo) ++0 -bf (foo hlsl -> foo sl2 sl2.~1~ -> foo) ++0 -bdf (foo hlsl -> foo sl2 -> foo sl2.~1~ -> foo) ++1 -l [cp: cannot create hard link 'sl2' to 'hlsl'] (foo hlsl -> foo sl2 -> foo) ++0 -dl (foo hlsl -> foo sl2 -> foo) ++0 -fl (foo hlsl -> foo sl2) ++0 -dfl (foo hlsl -> foo sl2 -> foo) ++0 -bl (foo hlsl -> foo sl2 sl2.~1~ -> foo) ++0 -bdl (foo hlsl -> foo sl2 -> foo) ++0 -bfl (foo hlsl -> foo sl2 sl2.~1~ -> foo) ++0 -bdfl (foo hlsl -> foo sl2 -> foo) ++ + EOF + + exec 1>&3 3>&- +diff -urNp coreutils-8.22-orig/tests/local.mk coreutils-8.22/tests/local.mk +--- coreutils-8.22-orig/tests/local.mk 2015-07-03 14:42:56.820772485 +0200 ++++ coreutils-8.22/tests/local.mk 2015-07-03 14:55:07.060176869 +0200 +@@ -591,7 +591,6 @@ all_tests = \ + tests/mv/hard-3.sh \ + tests/mv/hard-4.sh \ + tests/mv/hard-link-1.sh \ +- tests/mv/hard-verbose.sh \ + tests/mv/i-1.pl \ + tests/mv/i-2.sh \ + tests/mv/i-3.sh \ +diff -urNp coreutils-8.22-orig/tests/mv/force.sh coreutils-8.22/tests/mv/force.sh +--- coreutils-8.22-orig/tests/mv/force.sh 2013-12-04 15:48:30.000000000 +0100 ++++ coreutils-8.22/tests/mv/force.sh 2015-07-03 14:56:42.840885931 +0200 +@@ -25,18 +25,19 @@ ff2=mvforce2 + echo force-contents > $ff || framework_failure_ + ln $ff $ff2 || framework_failure_ + +-# This mv command should exit nonzero. +-mv $ff $ff > out 2>&1 && fail=1 ++# mv should fail for the same name, or separate hardlinks as in ++# both cases rename() will do nothing and return success. ++# One could unlink(src) in the hardlink case, but that would ++# introduce races with overlapping mv instances removing both hardlinks. + +-cat > exp < out 2>&1 && fail=1 + +-compare exp out || fail=1 +-test $(cat $ff) = force-contents || fail=1 ++ printf "mv: '$ff' and '$dest' are the same file\n" > exp ++ compare exp out || fail=1 + +-# This should succeed, even though the source and destination +-# device and inodes are the same. +-mv $ff $ff2 || fail=1 ++ test $(cat $ff) = force-contents || fail=1 ++done + + Exit $fail +diff -urNp coreutils-8.22-orig/tests/mv/hard-4.sh coreutils-8.22/tests/mv/hard-4.sh +--- coreutils-8.22-orig/tests/mv/hard-4.sh 2013-12-04 15:48:30.000000000 +0100 ++++ coreutils-8.22/tests/mv/hard-4.sh 2015-07-03 14:58:31.179687188 +0200 +@@ -1,5 +1,5 @@ + #!/bin/sh +-# ensure that mv removes a in this case: touch a; ln a b; mv a b ++# ensure that mv maintains a in this case: touch a; ln a b; mv a b + + # Copyright (C) 2003-2013 Free Software Foundation, Inc. + +@@ -21,15 +21,19 @@ print_ver_ mv + touch a || framework_failure_ + ln a b || framework_failure_ + ++# Between coreutils-5.0 and coreutils-8.24, 'a' would be removed. ++# Before coreutils-5.0.1 the issue would not have been diagnosed. ++# We don't emulate the rename(a,b) with unlink(a) as that would ++# introduce races with overlapping mv instances removing both links. ++mv a b 2>err && fail=1 ++printf "mv: 'a' and 'b' are the same file\n" > exp ++compare exp err || fail=1 + +-mv a b || fail=1 + +-# In coreutils-5.0 and earlier, a would not be removed. +-test -r a && fail=1 ++test -r a || fail=1 + test -r b || fail=1 + +-# Make sure it works also with --backup. +-ln b a ++# Make sure it works with --backup. + mv --backup=simple a b || fail=1 + test -r a && fail=1 + test -r b || fail=1 +diff -urNp coreutils-8.22-orig/tests/mv/i-4.sh coreutils-8.22/tests/mv/i-4.sh +--- coreutils-8.22-orig/tests/mv/i-4.sh 2013-12-04 15:48:30.000000000 +0100 ++++ coreutils-8.22/tests/mv/i-4.sh 2015-07-03 15:00:39.533718254 +0200 +@@ -23,6 +23,7 @@ for i in a b; do + echo $i > $i || framework_failure_ + done + echo y > y || framework_failure_ ++echo n > n || framework_failure_ + + mv -i a b < y >/dev/null 2>&1 || fail=1 + +@@ -32,18 +33,15 @@ case "$(cat b)" in + *) fail=1 ;; + esac + +-# Ensure that mv -i a b works properly with 'n' and 'y' +-# responses, even when a and b are hard links to the same file. +-# This 'n' test would fail (no prompt) for coreutils-5.0.1 through 5.3.0. +-echo n > n ++# Ensure that mv -i a b works properly with 'n' and 'y' responses, ++# when a and b are hard links to the same file. + rm -f a b + echo a > a + ln a b +-mv -i a b < n >/dev/null 2>&1 || fail=1 ++mv -i a b < y 2>err && fail=1 + test -r a || fail=1 + test -r b || fail=1 +-mv -i a b < y >/dev/null 2>&1 || fail=1 +-test -r a && fail=1 +-test -r b || fail=1 ++printf "mv: 'a' and 'b' are the same file\n" > exp ++compare exp err || fail=1 + + Exit $fail +diff -urNp coreutils-8.22-orig/tests/mv/symlink-onto-hardlink-to-self.sh coreutils-8.22/tests/mv/symlink-onto-hardlink-to-self.sh +--- coreutils-8.22-orig/tests/mv/symlink-onto-hardlink-to-self.sh 2013-12-04 15:48:30.000000000 +0100 ++++ coreutils-8.22/tests/mv/symlink-onto-hardlink-to-self.sh 2015-07-03 15:01:39.209190741 +0200 +@@ -1,10 +1,10 @@ + #!/bin/sh +-# Demonstrate that when moving a symlink onto a hardlink-to-that-symlink, the +-# source symlink is removed. Depending on your kernel (e.g., Linux, Solaris, ++# Demonstrate that when moving a symlink onto a hardlink-to-that-symlink, ++# an error is presented. Depending on your kernel (e.g., Linux, Solaris, + # but not NetBSD), prior to coreutils-8.16, the mv would successfully perform + # a no-op. I.e., surprisingly, mv s1 s2 would succeed, yet fail to remove s1. + +-# Copyright (C) 2012-2013 Free Software Foundation, Inc. ++# Copyright (C) 2012-2014 Free Software Foundation, Inc. + + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU General Public License as published by +@@ -26,27 +26,34 @@ print_ver_ mv + touch f || framework_failure_ + ln -s f s2 || framework_failure_ + +-for opt in '' --backup; do ++# Attempt to create a hard link to that symlink. ++# On some systems, it's not possible: they create a hard link to the referent. ++ln s2 s1 || framework_failure_ ++ ++# If s1 is not a symlink, skip this test. ++test -h s1 \ ++ || skip_ your kernel or file system cannot create a hard link to a symlink + +- # Attempt to create a hard link to that symlink. +- # On some systems, it's not possible: they create a hard link to the referent. +- ln s2 s1 || framework_failure_ +- +- # If s1 is not a symlink, skip this test. +- test -h s1 \ +- || skip_ your kernel or file system cannot create a hard link to a symlink ++for opt in '' --backup; do + +- mv $opt s1 s2 > out 2>&1 || fail=1 +- compare /dev/null out || fail=1 ++ if test "$opt" = --backup; then ++ mv $opt s1 s2 > out 2>&1 || fail=1 ++ compare /dev/null out || fail=1 + +- # Ensure that s1 is gone. +- test -e s1 && fail=1 ++ # Ensure that s1 is gone. ++ test -e s1 && fail=1 + +- if test "$opt" = --backup; then + # With --backup, ensure that the backup file was created. + ref=$(readlink s2~) || fail=1 + test "$ref" = f || fail=1 + else ++ echo "mv: 's1' and 's2' are the same file" > exp ++ mv $opt s1 s2 2>err && fail=1 ++ compare exp err || fail=1 ++ ++ # Ensure that s1 is still present. ++ test -e s1 || fail=1 ++ + # Without --backup, ensure there is no backup file. + test -e s2~ && fail=1 + fi diff --git a/SOURCES/coreutils-8.22-mv-n-noreplace.patch b/SOURCES/coreutils-8.22-mv-n-noreplace.patch new file mode 100644 index 0000000..574ad19 --- /dev/null +++ b/SOURCES/coreutils-8.22-mv-n-noreplace.patch @@ -0,0 +1,1017 @@ +From 76df06ff8fa39ae0cb0d167b7f622139778dc7d7 Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Thu, 4 Jan 2018 09:42:10 +0100 +Subject: [PATCH] mv -n: do not overwrite the destination + +... if it is created by another process after mv has checked its +non-existence. + +* src/copy.c (copy_internal): Use renameat2 (..., RENAME_NOREPLACE) +if called by mv -n. If it fails with EEXIST in that case, pretend +successful rename as if the existing destination file was detected +by the preceding lstat call. + +Fixes https://bugs.gnu.org/29961 +--- + aclocal.m4 | 1 + + bootstrap.conf | 2 + + gnulib-tests/gnulib.mk | 18 ++++ + gnulib-tests/test-renameat.c | 206 ++++++++++++++++++++++++++++++++++++++ + gnulib-tests/test-renameat2.c | 209 ++++++++++++++++++++++++++++++++++++++ + lib/gnulib.mk | 21 +++- + lib/renameat.c | 25 +++++ + lib/renameat2.c | 227 ++++++++++++++++++++++++++++++++++++++++++ + lib/renameat2.h | 30 ++++++ + m4/gnulib-comp.m4 | 22 ++++ + m4/renameat.m4 | 25 +++++ + src/copy.c | 27 ++++- + 12 files changed, 808 insertions(+), 5 deletions(-) + create mode 100644 gnulib-tests/test-renameat.c + create mode 100644 gnulib-tests/test-renameat2.c + create mode 100644 lib/renameat.c + create mode 100644 lib/renameat2.c + create mode 100644 lib/renameat2.h + create mode 100644 m4/renameat.m4 + +diff --git a/aclocal.m4 b/aclocal.m4 +index 9c5a2b0..c678967 100644 +--- a/aclocal.m4 ++++ b/aclocal.m4 +@@ -1332,6 +1332,7 @@ m4_include([m4/realloc.m4]) + m4_include([m4/regex.m4]) + m4_include([m4/remove.m4]) + m4_include([m4/rename.m4]) ++m4_include([m4/renameat.m4]) + m4_include([m4/rewinddir.m4]) + m4_include([m4/rmdir.m4]) + m4_include([m4/rpmatch.m4]) +diff --git a/bootstrap.conf b/bootstrap.conf +index 7def1f9..9b7c913 100644 +--- a/bootstrap.conf ++++ b/bootstrap.conf +@@ -199,6 +199,8 @@ gnulib_modules=" + regex + remove + rename ++ renameat ++ renameat2 + rmdir + root-dev-ino + rpmatch +diff --git a/gnulib-tests/gnulib.mk b/gnulib-tests/gnulib.mk +index b2da030..38d439c 100644 +--- a/gnulib-tests/gnulib.mk ++++ b/gnulib-tests/gnulib.mk +@@ -1676,6 +1676,24 @@ EXTRA_DIST += test-rename.h test-rename.c signature.h macros.h + + ## end gnulib module rename-tests + ++## begin gnulib module renameat-tests ++ ++TESTS += test-renameat ++check_PROGRAMS += test-renameat ++test_renameat_LDADD = $(LDADD) @LIBINTL@ ++EXTRA_DIST += test-rename.h test-renameat.c signature.h macros.h ++ ++## end gnulib module renameat-tests ++ ++## begin gnulib module renameat2-tests ++ ++TESTS += test-renameat2 ++check_PROGRAMS += test-renameat2 ++test_renameat2_LDADD = $(LDADD) @LIBINTL@ ++EXTRA_DIST += test-rename.h test-renameat2.c signature.h macros.h ++ ++## end gnulib module renameat2-tests ++ + ## begin gnulib module rmdir-tests + + TESTS += test-rmdir +diff --git a/gnulib-tests/test-renameat.c b/gnulib-tests/test-renameat.c +new file mode 100644 +index 0000000..ac96d88 +--- /dev/null ++++ b/gnulib-tests/test-renameat.c +@@ -0,0 +1,206 @@ ++/* Tests of renameat. ++ Copyright (C) 2009-2017 Free Software Foundation, Inc. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++/* Written by Eric Blake , 2009. */ ++ ++#include ++ ++#include ++ ++#include "signature.h" ++SIGNATURE_CHECK (renameat, int, (int, char const *, int, char const *)); ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "filenamecat.h" ++#include "ignore-value.h" ++#include "macros.h" ++ ++#define BASE "test-renameat.t" ++ ++#include "test-rename.h" ++ ++static int dfd1 = AT_FDCWD; ++static int dfd2 = AT_FDCWD; ++ ++/* Wrapper to test renameat like rename. */ ++static int ++do_rename (char const *name1, char const *name2) ++{ ++ return renameat (dfd1, name1, dfd2, name2); ++} ++ ++int ++main (void) ++{ ++ int i; ++ int dfd; ++ char *cwd; ++ int result; ++ ++ /* Clean up any trash from prior testsuite runs. */ ++ ignore_value (system ("rm -rf " BASE "*")); ++ ++ /* Test behaviour for invalid file descriptors. */ ++ { ++ errno = 0; ++ ASSERT (renameat (-1, "foo", AT_FDCWD, "bar") == -1); ++ ASSERT (errno == EBADF); ++ } ++ { ++ close (99); ++ errno = 0; ++ ASSERT (renameat (99, "foo", AT_FDCWD, "bar") == -1); ++ ASSERT (errno == EBADF); ++ } ++ ASSERT (close (creat (BASE "oo", 0600)) == 0); ++ { ++ errno = 0; ++ ASSERT (renameat (AT_FDCWD, BASE "oo", -1, "bar") == -1); ++ ASSERT (errno == EBADF); ++ } ++ { ++ errno = 0; ++ ASSERT (renameat (AT_FDCWD, BASE "oo", 99, "bar") == -1); ++ ASSERT (errno == EBADF); ++ } ++ ASSERT (unlink (BASE "oo") == 0); ++ ++ /* Test basic rename functionality, using current directory. */ ++ result = test_rename (do_rename, false); ++ dfd1 = open (".", O_RDONLY); ++ ASSERT (0 <= dfd1); ++ ASSERT (test_rename (do_rename, false) == result); ++ dfd2 = dfd1; ++ ASSERT (test_rename (do_rename, false) == result); ++ dfd1 = AT_FDCWD; ++ ASSERT (test_rename (do_rename, false) == result); ++ ASSERT (close (dfd2) == 0); ++ ++ /* Create locations to manipulate. */ ++ ASSERT (mkdir (BASE "sub1", 0700) == 0); ++ ASSERT (mkdir (BASE "sub2", 0700) == 0); ++ dfd = creat (BASE "00", 0600); ++ ASSERT (0 <= dfd); ++ ASSERT (close (dfd) == 0); ++ cwd = getcwd (NULL, 0); ++ ASSERT (cwd); ++ ++ dfd = open (BASE "sub1", O_RDONLY); ++ ASSERT (0 <= dfd); ++ ASSERT (chdir (BASE "sub2") == 0); ++ ++ /* There are 16 possible scenarios, based on whether an fd is ++ AT_FDCWD or real, and whether a file is absolute or relative. ++ ++ To ensure that we test all of the code paths (rather than ++ triggering early normalization optimizations), we use a loop to ++ repeatedly rename a file in the parent directory, use an fd open ++ on subdirectory 1, all while executing in subdirectory 2; all ++ relative names are thus given with a leading "../". Finally, the ++ last scenario (two relative paths given, neither one AT_FDCWD) ++ has two paths, based on whether the two fds are equivalent, so we ++ do the other variant after the loop. */ ++ for (i = 0; i < 16; i++) ++ { ++ int fd1 = (i & 8) ? dfd : AT_FDCWD; ++ char *file1 = file_name_concat ((i & 4) ? ".." : cwd, BASE "xx", NULL); ++ int fd2 = (i & 2) ? dfd : AT_FDCWD; ++ char *file2 = file_name_concat ((i & 1) ? ".." : cwd, BASE "xx", NULL); ++ ++ ASSERT (sprintf (strchr (file1, '\0') - 2, "%02d", i) == 2); ++ ASSERT (sprintf (strchr (file2, '\0') - 2, "%02d", i + 1) == 2); ++ ASSERT (renameat (fd1, file1, fd2, file2) == 0); ++ free (file1); ++ free (file2); ++ } ++ dfd2 = open ("..", O_RDONLY); ++ ASSERT (0 <= dfd2); ++ ASSERT (renameat (dfd, "../" BASE "16", dfd2, BASE "17") == 0); ++ ASSERT (close (dfd2) == 0); ++ ++ /* Now we change back to the parent directory, and set dfd to "."; ++ using dfd in remaining tests will expose any bugs if emulation ++ via /proc/self/fd doesn't check for empty names. */ ++ ASSERT (chdir ("..") == 0); ++ ASSERT (close (dfd) == 0); ++ dfd = open (".", O_RDONLY); ++ ASSERT (0 <= dfd); ++ ++ ASSERT (close (creat (BASE "sub2/file", 0600)) == 0); ++ errno = 0; ++ ASSERT (renameat (dfd, BASE "sub1", dfd, BASE "sub2") == -1); ++ ASSERT (errno == EEXIST || errno == ENOTEMPTY); ++ ASSERT (unlink (BASE "sub2/file") == 0); ++ errno = 0; ++ ASSERT (renameat (dfd, BASE "sub2", dfd, BASE "sub1/.") == -1); ++ ASSERT (errno == EINVAL || errno == EISDIR || errno == EBUSY ++ || errno == ENOTEMPTY || errno == EEXIST); ++ errno = 0; ++ ASSERT (renameat (dfd, BASE "sub2/.", dfd, BASE "sub1") == -1); ++ ASSERT (errno == EINVAL || errno == EBUSY || errno == EEXIST); ++ errno = 0; ++ ASSERT (renameat (dfd, BASE "17", dfd, BASE "sub1") == -1); ++ ASSERT (errno == EISDIR); ++ errno = 0; ++ ASSERT (renameat (dfd, BASE "nosuch", dfd, BASE "18") == -1); ++ ASSERT (errno == ENOENT); ++ errno = 0; ++ ASSERT (renameat (dfd, "", dfd, BASE "17") == -1); ++ ASSERT (errno == ENOENT); ++ errno = 0; ++ ASSERT (renameat (dfd, BASE "17", dfd, "") == -1); ++ ASSERT (errno == ENOENT); ++ errno = 0; ++ ASSERT (renameat (dfd, BASE "sub2", dfd, BASE "17") == -1); ++ ASSERT (errno == ENOTDIR); ++ errno = 0; ++ ASSERT (renameat (dfd, BASE "17/", dfd, BASE "18") == -1); ++ ASSERT (errno == ENOTDIR); ++ errno = 0; ++ ASSERT (renameat (dfd, BASE "17", dfd, BASE "18/") == -1); ++ ASSERT (errno == ENOTDIR || errno == ENOENT); ++ ++ /* Finally, make sure we can overwrite existing files. */ ++ ASSERT (close (creat (BASE "sub2/file", 0600)) == 0); ++ errno = 0; ++ ASSERT (renameat (dfd, BASE "sub2", dfd, BASE "sub1") == 0); ++ ASSERT (renameat (dfd, BASE "sub1/file", dfd, BASE "17") == 0); ++ ++ /* Cleanup. */ ++ ASSERT (close (dfd) == 0); ++ errno = 0; ++ ASSERT (unlink (BASE "sub1/file") == -1); ++ ASSERT (errno == ENOENT); ++ ASSERT (unlink (BASE "17") == 0); ++ ASSERT (rmdir (BASE "sub1") == 0); ++ errno = 0; ++ ASSERT (rmdir (BASE "sub2") == -1); ++ ASSERT (errno == ENOENT); ++ free (cwd); ++ ++ if (result) ++ fputs ("skipping test: symlinks not supported on this file system\n", ++ stderr); ++ return result; ++} +diff --git a/gnulib-tests/test-renameat2.c b/gnulib-tests/test-renameat2.c +new file mode 100644 +index 0000000..7c250ea +--- /dev/null ++++ b/gnulib-tests/test-renameat2.c +@@ -0,0 +1,209 @@ ++/* Test renameat2. ++ Copyright (C) 2009-2017 Free Software Foundation, Inc. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++/* Written by Eric Blake , 2009. */ ++ ++#include ++ ++#include ++ ++#include ++ ++#include "signature.h" ++SIGNATURE_CHECK (renameat2, int, ++ (int, char const *, int, char const *, unsigned int)); ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "filenamecat.h" ++#include "ignore-value.h" ++#include "macros.h" ++ ++#define BASE "test-renameat2.t" ++ ++#include "test-rename.h" ++ ++static int dfd1 = AT_FDCWD; ++static int dfd2 = AT_FDCWD; ++ ++/* Wrapper to test renameat2 like rename. */ ++static int ++do_rename (char const *name1, char const *name2) ++{ ++ return renameat2 (dfd1, name1, dfd2, name2, 0); ++} ++ ++int ++main (void) ++{ ++ int i; ++ int dfd; ++ char *cwd; ++ int result; ++ ++ /* Clean up any trash from prior testsuite runs. */ ++ ignore_value (system ("rm -rf " BASE "*")); ++ ++ /* Test behaviour for invalid file descriptors. */ ++ { ++ errno = 0; ++ ASSERT (renameat2 (-1, "foo", AT_FDCWD, "bar", 0) == -1); ++ ASSERT (errno == EBADF); ++ } ++ { ++ close (99); ++ errno = 0; ++ ASSERT (renameat2 (99, "foo", AT_FDCWD, "bar", 0) == -1); ++ ASSERT (errno == EBADF); ++ } ++ ASSERT (close (creat (BASE "oo", 0600)) == 0); ++ { ++ errno = 0; ++ ASSERT (renameat2 (AT_FDCWD, BASE "oo", -1, "bar", 0) == -1); ++ ASSERT (errno == EBADF); ++ } ++ { ++ errno = 0; ++ ASSERT (renameat2 (AT_FDCWD, BASE "oo", 99, "bar", 0) == -1); ++ ASSERT (errno == EBADF); ++ } ++ ASSERT (unlink (BASE "oo") == 0); ++ ++ /* Test basic rename functionality, using current directory. */ ++ result = test_rename (do_rename, false); ++ dfd1 = open (".", O_RDONLY); ++ ASSERT (0 <= dfd1); ++ ASSERT (test_rename (do_rename, false) == result); ++ dfd2 = dfd1; ++ ASSERT (test_rename (do_rename, false) == result); ++ dfd1 = AT_FDCWD; ++ ASSERT (test_rename (do_rename, false) == result); ++ ASSERT (close (dfd2) == 0); ++ ++ /* Create locations to manipulate. */ ++ ASSERT (mkdir (BASE "sub1", 0700) == 0); ++ ASSERT (mkdir (BASE "sub2", 0700) == 0); ++ dfd = creat (BASE "00", 0600); ++ ASSERT (0 <= dfd); ++ ASSERT (close (dfd) == 0); ++ cwd = getcwd (NULL, 0); ++ ASSERT (cwd); ++ ++ dfd = open (BASE "sub1", O_RDONLY); ++ ASSERT (0 <= dfd); ++ ASSERT (chdir (BASE "sub2") == 0); ++ ++ /* There are 16 possible scenarios, based on whether an fd is ++ AT_FDCWD or real, and whether a file is absolute or relative. ++ ++ To ensure that we test all of the code paths (rather than ++ triggering early normalization optimizations), we use a loop to ++ repeatedly rename a file in the parent directory, use an fd open ++ on subdirectory 1, all while executing in subdirectory 2; all ++ relative names are thus given with a leading "../". Finally, the ++ last scenario (two relative paths given, neither one AT_FDCWD) ++ has two paths, based on whether the two fds are equivalent, so we ++ do the other variant after the loop. */ ++ for (i = 0; i < 16; i++) ++ { ++ int fd1 = (i & 8) ? dfd : AT_FDCWD; ++ char *file1 = file_name_concat ((i & 4) ? ".." : cwd, BASE "xx", NULL); ++ int fd2 = (i & 2) ? dfd : AT_FDCWD; ++ char *file2 = file_name_concat ((i & 1) ? ".." : cwd, BASE "xx", NULL); ++ ++ ASSERT (sprintf (strchr (file1, '\0') - 2, "%02d", i) == 2); ++ ASSERT (sprintf (strchr (file2, '\0') - 2, "%02d", i + 1) == 2); ++ ASSERT (renameat2 (fd1, file1, fd2, file2, 0) == 0); ++ free (file1); ++ free (file2); ++ } ++ dfd2 = open ("..", O_RDONLY); ++ ASSERT (0 <= dfd2); ++ ASSERT (renameat2 (dfd, "../" BASE "16", dfd2, BASE "17", 0) == 0); ++ ASSERT (close (dfd2) == 0); ++ ++ /* Now we change back to the parent directory, and set dfd to "."; ++ using dfd in remaining tests will expose any bugs if emulation ++ via /proc/self/fd doesn't check for empty names. */ ++ ASSERT (chdir ("..") == 0); ++ ASSERT (close (dfd) == 0); ++ dfd = open (".", O_RDONLY); ++ ASSERT (0 <= dfd); ++ ++ ASSERT (close (creat (BASE "sub2/file", 0600)) == 0); ++ errno = 0; ++ ASSERT (renameat2 (dfd, BASE "sub1", dfd, BASE "sub2", 0) == -1); ++ ASSERT (errno == EEXIST || errno == ENOTEMPTY); ++ ASSERT (unlink (BASE "sub2/file") == 0); ++ errno = 0; ++ ASSERT (renameat2 (dfd, BASE "sub2", dfd, BASE "sub1/.", 0) == -1); ++ ASSERT (errno == EINVAL || errno == EISDIR || errno == EBUSY ++ || errno == ENOTEMPTY || errno == EEXIST); ++ errno = 0; ++ ASSERT (renameat2 (dfd, BASE "sub2/.", dfd, BASE "sub1", 0) == -1); ++ ASSERT (errno == EINVAL || errno == EBUSY || errno == EEXIST); ++ errno = 0; ++ ASSERT (renameat2 (dfd, BASE "17", dfd, BASE "sub1", 0) == -1); ++ ASSERT (errno == EISDIR); ++ errno = 0; ++ ASSERT (renameat2 (dfd, BASE "nosuch", dfd, BASE "18", 0) == -1); ++ ASSERT (errno == ENOENT); ++ errno = 0; ++ ASSERT (renameat2 (dfd, "", dfd, BASE "17", 0) == -1); ++ ASSERT (errno == ENOENT); ++ errno = 0; ++ ASSERT (renameat2 (dfd, BASE "17", dfd, "", 0) == -1); ++ ASSERT (errno == ENOENT); ++ errno = 0; ++ ASSERT (renameat2 (dfd, BASE "sub2", dfd, BASE "17", 0) == -1); ++ ASSERT (errno == ENOTDIR); ++ errno = 0; ++ ASSERT (renameat2 (dfd, BASE "17/", dfd, BASE "18", 0) == -1); ++ ASSERT (errno == ENOTDIR); ++ errno = 0; ++ ASSERT (renameat2 (dfd, BASE "17", dfd, BASE "18/", 0) == -1); ++ ASSERT (errno == ENOTDIR || errno == ENOENT); ++ ++ /* Finally, make sure we cannot overwrite existing files. */ ++ ASSERT (close (creat (BASE "sub2/file", 0600)) == 0); ++ errno = 0; ++ ASSERT ((renameat2 (dfd, BASE "sub2", dfd, BASE "sub1", RENAME_NOREPLACE) ++ == -1) ++ && errno == EEXIST); ++ ASSERT ((renameat2 (dfd, BASE "sub2/file", dfd, BASE "17", RENAME_NOREPLACE) ++ == -1) ++ && errno == EEXIST); ++ ++ /* Cleanup. */ ++ ASSERT (close (dfd) == 0); ++ ASSERT (unlink (BASE "sub2/file") == 0); ++ ASSERT (unlink (BASE "17") == 0); ++ ASSERT (rmdir (BASE "sub1") == 0); ++ ASSERT (rmdir (BASE "sub2") == 0); ++ free (cwd); ++ ++ if (result) ++ fputs ("skipping test: symlinks not supported on this file system\n", ++ stderr); ++ return result; ++} +diff --git a/lib/gnulib.mk b/lib/gnulib.mk +index 844791b..76729b0 100644 +--- a/lib/gnulib.mk ++++ b/lib/gnulib.mk +@@ -21,7 +21,7 @@ + # the same distribution terms as the rest of that program. + # + # Generated by gnulib-tool. +-# Reproduce by: gnulib-tool --import --dir=. --local-dir=gl --lib=libcoreutils --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=gnulib-tests --aux-dir=build-aux --with-tests --avoid=canonicalize-lgpl --avoid=dummy --makefile-name=gnulib.mk --no-conditional-dependencies --no-libtool --macro-prefix=gl acl alignof alloca announce-gen areadlink-with-size argmatch argv-iter assert autobuild backupfile base64 buffer-lcm c-strcase c-strtod c-strtold calloc-gnu canon-host canonicalize chown cloexec closein closeout config-h configmake crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 cycle-check d-ino d-type di-set diacrit dirfd dirname do-release-commit-and-tag dtoastr dup2 environ error euidaccess exclude exitfail faccessat fadvise fchdir fchmodat fchownat fclose fcntl fcntl-safer fd-reopen fdatasync fdl fdopen fdutimensat file-type fileblocks filemode filenamecat filevercmp fnmatch-gnu fopen-safer fprintftime freopen freopen-safer fseeko fstatat fsusage fsync ftello ftoastr ftruncate fts full-read full-write getgroups gethrxtime getline getloadavg getlogin getndelim2 getopt-gnu getpagesize getpass-gnu gettext-h gettime gettimeofday getugroups getusershell git-version-gen gitlog-to-changelog gnu-make gnu-web-doc-update gnumakefile gnupload group-member hard-locale hash hash-pjw heap host-os human idcache ignore-value inttostr inttypes isapipe isatty isblank largefile lchmod lchown ldtoastr lib-ignore linebuffer link link-follow linkat long-options lstat maintainer-makefile malloc-gnu manywarnings mbrlen mbrtowc mbsalign mbswidth memcasecmp memchr memcmp2 mempcpy memrchr mgetgroups mkancesdirs mkdir mkdir-p mkfifo mknod mkstemp mktime modechange mountlist mpsort netinet_in non-recursive-gnulib-prefix-hack nproc obstack parse-datetime pathmax perl physmem pipe posix-shell posixtm posixver priv-set progname propername pthread putenv quote quotearg randint randperm read-file readlink readtokens readtokens0 readutmp realloc-gnu regex remove rename rmdir root-dev-ino rpmatch safe-read same save-cwd savedir savewd selinux-at settime sig2str sigaction smack ssize_t stat-macros stat-size stat-time statat stdbool stdlib-safer stpcpy stpncpy strdup-posix strftime strncat strnumcmp strpbrk strsignal strtod strtoimax strtoumax symlink sys_ioctl sys_resource sys_stat sys_wait termios timer-time timespec tzset uname unicodeio unistd-safer unlink-busy unlinkat unlocked-io unsetenv update-copyright uptime useless-if-before-free userspec utimecmp utimens vasprintf-posix vc-list-files verify verror version-etc-fsf wcswidth wcwidth winsz-ioctl winsz-termios write-any-file xalloc xfreopen xfts xgetcwd xgetgroups xgethostname xmemcoll xnanosleep xprintf xprintf-posix xreadlink xstrtod xstrtoimax xstrtol xstrtold xstrtoumax yesno ++# Reproduce by: gnulib-tool --import --dir=. --local-dir=gl --lib=libcoreutils --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=gnulib-tests --aux-dir=build-aux --with-tests --avoid=canonicalize-lgpl --avoid=dummy --makefile-name=gnulib.mk --no-conditional-dependencies --no-libtool --macro-prefix=gl acl alignof alloca announce-gen areadlink-with-size argmatch argv-iter assert autobuild backupfile base64 buffer-lcm c-strcase c-strtod c-strtold calloc-gnu canon-host canonicalize chown cloexec closein closeout config-h configmake crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 cycle-check d-ino d-type di-set diacrit dirfd dirname do-release-commit-and-tag dtoastr dup2 environ error euidaccess exclude exitfail faccessat fadvise fchdir fchmodat fchownat fclose fcntl fcntl-safer fd-reopen fdatasync fdl fdopen fdutimensat file-type fileblocks filemode filenamecat filevercmp fnmatch-gnu fopen-safer fprintftime freopen freopen-safer fseeko fstatat fsusage fsync ftello ftoastr ftruncate fts full-read full-write getgroups gethrxtime getline getloadavg getlogin getndelim2 getopt-gnu getpagesize getpass-gnu gettext-h gettime gettimeofday getugroups getusershell git-version-gen gitlog-to-changelog gnu-make gnu-web-doc-update gnumakefile gnupload group-member hard-locale hash hash-pjw heap host-os human idcache ignore-value inttostr inttypes isapipe isatty isblank largefile lchmod lchown ldtoastr lib-ignore linebuffer link link-follow linkat long-options lstat maintainer-makefile malloc-gnu manywarnings mbrlen mbrtowc mbsalign mbswidth memcasecmp memchr memcmp2 mempcpy memrchr mgetgroups mkancesdirs mkdir mkdir-p mkfifo mknod mkstemp mktime modechange mountlist mpsort netinet_in non-recursive-gnulib-prefix-hack nproc obstack parse-datetime pathmax perl physmem pipe posix-shell posixtm posixver priv-set progname propername pthread putenv quote quotearg randint randperm read-file readlink readtokens readtokens0 readutmp realloc-gnu regex remove rename renameat renameat2 rmdir root-dev-ino rpmatch safe-read same save-cwd savedir savewd selinux-at settime sig2str sigaction smack ssize_t stat-macros stat-size stat-time statat stdbool stdlib-safer stpcpy stpncpy strdup-posix strftime strncat strnumcmp strpbrk strsignal strtod strtoimax strtoumax symlink sys_ioctl sys_resource sys_stat sys_wait termios timer-time timespec tzset uname unicodeio unistd-safer unlink-busy unlinkat unlocked-io unsetenv update-copyright uptime useless-if-before-free userspec utimecmp utimens vasprintf-posix vc-list-files verify verror version-etc-fsf wcswidth wcwidth winsz-ioctl winsz-termios write-any-file xalloc xfreopen xfts xgetcwd xgetgroups xgethostname xmemcoll xnanosleep xprintf xprintf-posix xreadlink xstrtod xstrtoimax xstrtol xstrtold xstrtoumax yesno + + + MOSTLYCLEANFILES += lib/core lib/*.stackdump +@@ -3202,6 +3202,25 @@ EXTRA_lib_libcoreutils_a_SOURCES += lib/rename.c + + ## end gnulib module rename + ++## begin gnulib module renameat ++ ++ ++EXTRA_DIST += lib/renameat.c ++ ++EXTRA_lib_libcoreutils_a_SOURCES += lib/renameat.c ++ ++## end gnulib module renameat ++ ++## begin gnulib module renameat2 ++ ++lib_libcoreutils_a_SOURCES += lib/renameat2.c ++ ++EXTRA_DIST += lib/at-func2.c lib/renameat2.h ++ ++EXTRA_lib_libcoreutils_a_SOURCES += lib/at-func2.c ++ ++## end gnulib module renameat2 ++ + ## begin gnulib module rewinddir + + +diff --git a/lib/renameat.c b/lib/renameat.c +new file mode 100644 +index 0000000..48cee4b +--- /dev/null ++++ b/lib/renameat.c +@@ -0,0 +1,25 @@ ++/* Rename a file relative to open directories. ++ Copyright 2017 Free Software Foundation, Inc. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#include ++#include ++#include "renameat2.h" ++ ++int ++renameat (int fd1, char const *src, int fd2, char const *dst) ++{ ++ return renameat2 (fd1, src, fd2, dst, 0); ++} +diff --git a/lib/renameat2.c b/lib/renameat2.c +new file mode 100644 +index 0000000..26cde86 +--- /dev/null ++++ b/lib/renameat2.c +@@ -0,0 +1,227 @@ ++/* Rename a file relative to open directories. ++ Copyright (C) 2009-2017 Free Software Foundation, Inc. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++/* written by Eric Blake and Paul Eggert */ ++ ++#include ++ ++#include "renameat2.h" ++ ++#include ++#include ++#include ++#include ++ ++#ifdef __linux__ ++# include ++#endif ++ ++static int ++errno_fail (int e) ++{ ++ errno = e; ++ return -1; ++} ++ ++#if HAVE_RENAMEAT ++ ++# include ++# include ++# include ++ ++# include "dirname.h" ++# include "openat.h" ++ ++#else ++# include "openat-priv.h" ++ ++static int ++rename_noreplace (char const *src, char const *dst) ++{ ++ /* This has a race between the call to lstat and the call to rename. */ ++ struct stat st; ++ return (lstat (dst, &st) == 0 || errno == EOVERFLOW ? errno_fail (EEXIST) ++ : errno == ENOENT ? rename (src, dst) ++ : -1); ++} ++#endif ++ ++#undef renameat ++ ++/* Rename FILE1, in the directory open on descriptor FD1, to FILE2, in ++ the directory open on descriptor FD2. If possible, do it without ++ changing the working directory. Otherwise, resort to using ++ save_cwd/fchdir, then rename/restore_cwd. If either the save_cwd or ++ the restore_cwd fails, then give a diagnostic and exit nonzero. ++ ++ Obey FLAGS when doing the renaming. If FLAGS is zero, this ++ function is equivalent to renameat (FD1, SRC, FD2, DST). */ ++ ++int ++renameat2 (int fd1, char const *src, int fd2, char const *dst, ++ unsigned int flags) ++{ ++ int ret_val = -1; ++ int err = EINVAL; ++ ++#ifdef SYS_renameat2 ++ ret_val = syscall (SYS_renameat2, fd1, src, fd2, dst, flags); ++ err = errno; ++#elif defined RENAME_EXCL ++ if (! (flags & ~(RENAME_EXCHANGE | RENAME_NOREPLACE))) ++ { ++ ret_val = renameatx_np (fd1, src, fd2, dst, ++ ((flags & RENAME_EXCHANGE ? RENAME_SWAP : 0) ++ | (flags & RENAME_NOREPLACE ? RENAME_EXCL : 0))); ++ err = errno; ++ } ++#endif ++ ++ if (! (ret_val < 0 && (err == EINVAL || err == ENOSYS || err == ENOTSUP))) ++ return ret_val; ++ ++#if HAVE_RENAMEAT ++ { ++ size_t src_len; ++ size_t dst_len; ++ char *src_temp = (char *) src; ++ char *dst_temp = (char *) dst; ++ bool src_slash; ++ bool dst_slash; ++ int rename_errno = ENOTDIR; ++ struct stat src_st; ++ struct stat dst_st; ++ bool dst_found_nonexistent = false; ++ ++ if (flags != 0) ++ { ++ /* RENAME_NOREPLACE is the only flag currently supported. */ ++ if (flags & ~RENAME_NOREPLACE) ++ return errno_fail (ENOTSUP); ++ else ++ { ++ /* This has a race between the call to lstatat and the calls to ++ renameat below. */ ++ if (lstatat (fd2, dst, &dst_st) == 0 || errno == EOVERFLOW) ++ return errno_fail (EEXIST); ++ if (errno != ENOENT) ++ return -1; ++ dst_found_nonexistent = true; ++ } ++ } ++ ++ /* Let strace see any ENOENT failure. */ ++ src_len = strlen (src); ++ dst_len = strlen (dst); ++ if (!src_len || !dst_len) ++ return renameat (fd1, src, fd2, dst); ++ ++ src_slash = src[src_len - 1] == '/'; ++ dst_slash = dst[dst_len - 1] == '/'; ++ if (!src_slash && !dst_slash) ++ return renameat (fd1, src, fd2, dst); ++ ++ /* Presence of a trailing slash requires directory semantics. If ++ the source does not exist, or if the destination cannot be turned ++ into a directory, give up now. Otherwise, strip trailing slashes ++ before calling rename. */ ++ if (lstatat (fd1, src, &src_st)) ++ return -1; ++ if (dst_found_nonexistent) ++ { ++ if (!S_ISDIR (src_st.st_mode)) ++ return errno_fail (ENOENT); ++ } ++ else if (lstatat (fd2, dst, &dst_st)) ++ { ++ if (errno != ENOENT || !S_ISDIR (src_st.st_mode)) ++ return -1; ++ } ++ else if (!S_ISDIR (dst_st.st_mode)) ++ return errno_fail (ENOTDIR); ++ else if (!S_ISDIR (src_st.st_mode)) ++ return errno_fail (EISDIR); ++ ++# if RENAME_TRAILING_SLASH_SOURCE_BUG ++ /* See the lengthy comment in rename.c why Solaris 9 is forced to ++ GNU behavior, while Solaris 10 is left with POSIX behavior, ++ regarding symlinks with trailing slash. */ ++ ret_val = -1; ++ if (src_slash) ++ { ++ src_temp = strdup (src); ++ if (!src_temp) ++ { ++ /* Rather than rely on strdup-posix, we set errno ourselves. */ ++ rename_errno = ENOMEM; ++ goto out; ++ } ++ strip_trailing_slashes (src_temp); ++ if (lstatat (fd1, src_temp, &src_st)) ++ { ++ rename_errno = errno; ++ goto out; ++ } ++ if (S_ISLNK (src_st.st_mode)) ++ goto out; ++ } ++ if (dst_slash) ++ { ++ dst_temp = strdup (dst); ++ if (!dst_temp) ++ { ++ rename_errno = ENOMEM; ++ goto out; ++ } ++ strip_trailing_slashes (dst_temp); ++ if (lstatat (fd2, dst_temp, &dst_st)) ++ { ++ if (errno != ENOENT) ++ { ++ rename_errno = errno; ++ goto out; ++ } ++ } ++ else if (S_ISLNK (dst_st.st_mode)) ++ goto out; ++ } ++# endif /* RENAME_TRAILING_SLASH_SOURCE_BUG */ ++ ++ /* renameat does not honor trailing / on Solaris 10. Solve it in a ++ similar manner to rename. No need to worry about bugs not present ++ on Solaris, since all other systems either lack renameat or honor ++ trailing slash correctly. */ ++ ++ ret_val = renameat (fd1, src_temp, fd2, dst_temp); ++ rename_errno = errno; ++ goto out; ++ out: ++ if (src_temp != src) ++ free (src_temp); ++ if (dst_temp != dst) ++ free (dst_temp); ++ errno = rename_errno; ++ return ret_val; ++ } ++#else /* !HAVE_RENAMEAT */ ++ ++ /* RENAME_NOREPLACE is the only flag currently supported. */ ++ if (flags & ~RENAME_NOREPLACE) ++ return errno_fail (ENOTSUP); ++ return at_func2 (fd1, src, fd2, dst, flags ? rename_noreplace : rename); ++ ++#endif /* !HAVE_RENAMEAT */ ++} +diff --git a/lib/renameat2.h b/lib/renameat2.h +new file mode 100644 +index 0000000..179210f +--- /dev/null ++++ b/lib/renameat2.h +@@ -0,0 +1,30 @@ ++/* Rename a file relative to open directories. ++ Copyright 2017 Free Software Foundation, Inc. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++/* written by Paul Eggert */ ++ ++/* Get RENAME_* macros from linux/fs.h if present, otherwise supply ++ the traditional Linux values. */ ++#if HAVE_LINUX_FS_H ++# include ++#endif ++#ifndef RENAME_NOREPLACE ++# define RENAME_NOREPLACE (1 << 0) ++# define RENAME_EXCHANGE (1 << 1) ++# define RENAME_WHITEOUT (1 << 2) ++#endif ++ ++extern int renameat2 (int, char const *, int, char const *, unsigned int); +diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4 +index 4ef3c43..309e308 100644 +--- a/m4/gnulib-comp.m4 ++++ b/m4/gnulib-comp.m4 +@@ -547,6 +547,10 @@ AC_DEFUN([gl_EARLY], + # Code from module remove-tests: + # Code from module rename: + # Code from module rename-tests: ++ # Code from module renameat: ++ # Code from module renameat-tests: ++ # Code from module renameat2: ++ # Code from module renameat2-tests: + # Code from module rewinddir: + # Code from module rmdir: + # Code from module rmdir-tests: +@@ -1696,6 +1700,18 @@ AC_DEFUN([gl_INIT], + AC_LIBOBJ([rename]) + fi + gl_STDIO_MODULE_INDICATOR([rename]) ++ gl_FUNC_RENAMEAT ++ if test $HAVE_RENAMEAT = 0 || test $REPLACE_RENAMEAT = 1; then ++ AC_LIBOBJ([renameat]) ++ fi ++ if test $HAVE_RENAMEAT = 0; then ++ AC_LIBOBJ([at-func2]) ++ fi ++ gl_STDIO_MODULE_INDICATOR([renameat]) ++ gl_FUNC_RENAMEAT ++ if test $HAVE_RENAMEAT = 0; then ++ AC_LIBOBJ([at-func2]) ++ fi + gl_FUNC_REWINDDIR + if test $HAVE_REWINDDIR = 0; then + AC_LIBOBJ([rewinddir]) +@@ -2868,6 +2884,9 @@ AC_DEFUN([gl_FILE_LIST], [ + lib/regexec.c + lib/remove.c + lib/rename.c ++ lib/renameat.c ++ lib/renameat2.c ++ lib/renameat2.h + lib/rewinddir.c + lib/rmdir.c + lib/root-dev-ino.c +@@ -3372,6 +3391,7 @@ AC_DEFUN([gl_FILE_LIST], [ + m4/regex.m4 + m4/remove.m4 + m4/rename.m4 ++ m4/renameat.m4 + m4/rewinddir.m4 + m4/rmdir.m4 + m4/rpmatch.m4 +@@ -3794,6 +3814,8 @@ AC_DEFUN([gl_FILE_LIST], [ + tests/test-remove.c + tests/test-rename.c + tests/test-rename.h ++ tests/test-renameat.c ++ tests/test-renameat2.c + tests/test-rmdir.c + tests/test-rmdir.h + tests/test-sameacls.c +diff --git a/m4/renameat.m4 b/m4/renameat.m4 +new file mode 100644 +index 0000000..1b97774 +--- /dev/null ++++ b/m4/renameat.m4 +@@ -0,0 +1,25 @@ ++# serial 3 ++# See if we need to provide renameat replacement. ++ ++dnl Copyright (C) 2009-2017 Free Software Foundation, Inc. ++dnl This file is free software; the Free Software Foundation ++dnl gives unlimited permission to copy and/or distribute it, ++dnl with or without modifications, as long as this notice is preserved. ++ ++# Written by Eric Blake. ++ ++AC_DEFUN([gl_FUNC_RENAMEAT], ++[ ++ AC_REQUIRE([gl_FUNC_OPENAT]) ++ AC_REQUIRE([gl_FUNC_RENAME]) ++ AC_REQUIRE([gl_STDIO_H_DEFAULTS]) ++ AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) ++ AC_CHECK_HEADERS([linux/fs.h]) ++ AC_CHECK_FUNCS_ONCE([renameat]) ++ if test $ac_cv_func_renameat = no; then ++ HAVE_RENAMEAT=0 ++ elif test $REPLACE_RENAME = 1; then ++ dnl Solaris 9 and 10 have the same bugs in renameat as in rename. ++ REPLACE_RENAMEAT=1 ++ fi ++]) +diff --git a/src/copy.c b/src/copy.c +index 2a804945e..be4e357a8 100644 +--- a/src/copy.c ++++ b/src/copy.c +@@ -51,6 +51,7 @@ + #include "ignore-value.h" + #include "ioblksize.h" + #include "quote.h" ++#include "renameat2.h" + #include "root-uid.h" + #include "same.h" + #include "savedir.h" +@@ -2093,8 +2094,9 @@ copy_internal (char const *src_name, char const *dst_name, + + /* If the source is a directory, we don't always create the destination + directory. So --verbose should not announce anything until we're +- sure we'll create a directory. */ +- if (x->verbose && !S_ISDIR (src_mode)) ++ sure we'll create a directory. In move mode we delay the diagnostic ++ message until we know whether renameat2() has actually succeeded. */ ++ if (x->verbose && !S_ISDIR (src_mode) && !x->move_mode) + emit_verbose (src_name, dst_name, backup_succeeded ? dst_backup : NULL); + + /* Associate the destination file name with the source device and inode +@@ -2196,9 +2198,14 @@ copy_internal (char const *src_name, char const *dst_name, + + if (x->move_mode) + { +- if (rename (src_name, dst_name) == 0) ++ int flags = 0; ++ if (x->interactive == I_ALWAYS_NO) ++ /* do not replace DST_NAME if it was created since our last check */ ++ flags = RENAME_NOREPLACE; ++ ++ if (renameat2 (AT_FDCWD, src_name, AT_FDCWD, dst_name, flags) == 0) + { +- if (x->verbose && S_ISDIR (src_mode)) ++ if (x->verbose) + emit_verbose (src_name, dst_name, + backup_succeeded ? dst_backup : NULL); + +@@ -2226,6 +2233,15 @@ copy_internal (char const *src_name, char const *dst_name, + return true; + } + ++ if ((flags & RENAME_NOREPLACE) && (errno == EEXIST)) ++ { ++ /* Pretend the rename succeeded, so the caller (mv) ++ doesn't end up removing the source file. */ ++ if (rename_succeeded) ++ *rename_succeeded = true; ++ return true; ++ } ++ + /* FIXME: someday, consider what to do when moving a directory into + itself but when source and destination are on different devices. */ + +@@ -2301,6 +2317,9 @@ copy_internal (char const *src_name, char const *dst_name, + return false; + } + ++ if (x->verbose && !S_ISDIR (src_mode)) ++ emit_verbose (src_name, dst_name, backup_succeeded ? dst_backup : NULL); ++ + new_dst = true; + } + +-- +2.13.6 + diff --git a/SOURCES/coreutils-8.22-newfilesystems.patch b/SOURCES/coreutils-8.22-newfilesystems.patch new file mode 100644 index 0000000..60c3f06 --- /dev/null +++ b/SOURCES/coreutils-8.22-newfilesystems.patch @@ -0,0 +1,347 @@ + src/fs-is-local.h | 23 ++++++++++++++++++++ + src/stat.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++------ + src/tail.c | 2 ++ + 3 files changed, 83 insertions(+), 6 deletions(-) + +diff --git a/src/fs-is-local.h b/src/fs-is-local.h +index 61849da..5f73488 100644 +--- a/src/fs-is-local.h ++++ b/src/fs-is-local.h +@@ -6,30 +6,39 @@ is_local_fs_type (unsigned long int magic) + { + switch (magic) + { ++ case S_MAGIC_AAFS: return 1; ++ case S_MAGIC_ACFS: return 0; + case S_MAGIC_ADFS: return 1; + case S_MAGIC_AFFS: return 1; + case S_MAGIC_AFS: return 0; + case S_MAGIC_ANON_INODE_FS: return 1; + case S_MAGIC_AUFS: return 0; + case S_MAGIC_AUTOFS: return 1; ++ case S_MAGIC_BALLOON_KVM: return 1; + case S_MAGIC_BEFS: return 1; + case S_MAGIC_BDEVFS: return 1; + case S_MAGIC_BFS: return 1; ++ case S_MAGIC_BPF_FS: return 1; + case S_MAGIC_BINFMTFS: return 1; + case S_MAGIC_BTRFS: return 1; ++ case S_MAGIC_BTRFS_TEST: return 1; + case S_MAGIC_CEPH: return 0; + case S_MAGIC_CGROUP: return 1; ++ case S_MAGIC_CGROUP2: return 1; + case S_MAGIC_CIFS: return 0; + case S_MAGIC_CODA: return 0; + case S_MAGIC_COH: return 1; ++ case S_MAGIC_CONFIGFS: return 1; + case S_MAGIC_CRAMFS: return 1; + case S_MAGIC_CRAMFS_WEND: return 1; ++ case S_MAGIC_DAXFS: return 1; + case S_MAGIC_DEBUGFS: return 1; + case S_MAGIC_DEVFS: return 1; + case S_MAGIC_DEVPTS: return 1; + case S_MAGIC_ECRYPTFS: return 1; + case S_MAGIC_EFIVARFS: return 1; + case S_MAGIC_EFS: return 1; ++ case S_MAGIC_EXFS: return 1; + case S_MAGIC_EXOFS: return 1; + case S_MAGIC_EXT: return 1; + case S_MAGIC_EXT2: return 1; +@@ -43,10 +52,13 @@ is_local_fs_type (unsigned long int magic) + case S_MAGIC_GFS: return 0; + case S_MAGIC_GPFS: return 0; + case S_MAGIC_HFS: return 1; ++ case S_MAGIC_HFS_PLUS: return 1; ++ case S_MAGIC_HFS_X: return 1; + case S_MAGIC_HOSTFS: return 1; + case S_MAGIC_HPFS: return 1; + case S_MAGIC_HUGETLBFS: return 1; + case S_MAGIC_MTD_INODE_FS: return 1; ++ case S_MAGIC_IBRIX: return 0; + case S_MAGIC_INOTIFYFS: return 1; + case S_MAGIC_ISOFS: return 1; + case S_MAGIC_ISOFS_R_WIN: return 1; +@@ -55,7 +67,9 @@ is_local_fs_type (unsigned long int magic) + case S_MAGIC_JFFS2: return 1; + case S_MAGIC_JFS: return 1; + case S_MAGIC_KAFS: return 0; ++ case S_MAGIC_LOGFS: return 1; + case S_MAGIC_LUSTRE: return 0; ++ case S_MAGIC_M1FS: return 1; + case S_MAGIC_MINIX: return 1; + case S_MAGIC_MINIX_30: return 1; + case S_MAGIC_MINIX_V2: return 1; +@@ -67,23 +81,29 @@ is_local_fs_type (unsigned long int magic) + case S_MAGIC_NFS: return 0; + case S_MAGIC_NFSD: return 0; + case S_MAGIC_NILFS: return 1; ++ case S_MAGIC_NSFS: return 1; + case S_MAGIC_NTFS: return 1; + case S_MAGIC_OPENPROM: return 1; + case S_MAGIC_OCFS2: return 0; ++ case S_MAGIC_OVERLAYFS: return 0; + case S_MAGIC_PANFS: return 0; + case S_MAGIC_PIPEFS: return 0; ++ case S_MAGIC_PRL_FS: return 0; + case S_MAGIC_PROC: return 1; + case S_MAGIC_PSTOREFS: return 1; + case S_MAGIC_QNX4: return 1; + case S_MAGIC_QNX6: return 1; + case S_MAGIC_RAMFS: return 1; ++ case S_MAGIC_RDTGROUP: return 1; + case S_MAGIC_REISERFS: return 1; + case S_MAGIC_ROMFS: return 1; + case S_MAGIC_RPC_PIPEFS: return 1; ++ case S_MAGIC_SDCARDFS: return 1; + case S_MAGIC_SECURITYFS: return 1; + case S_MAGIC_SELINUX: return 1; + case S_MAGIC_SMACK: return 1; + case S_MAGIC_SMB: return 0; ++ case S_MAGIC_SMB2: return 0; + case S_MAGIC_SNFS: return 0; + case S_MAGIC_SOCKFS: return 1; + case S_MAGIC_SQUASHFS: return 1; +@@ -91,6 +111,7 @@ is_local_fs_type (unsigned long int magic) + case S_MAGIC_SYSV2: return 1; + case S_MAGIC_SYSV4: return 1; + case S_MAGIC_TMPFS: return 1; ++ case S_MAGIC_TRACEFS: return 1; + case S_MAGIC_UBIFS: return 1; + case S_MAGIC_UDF: return 1; + case S_MAGIC_UFS: return 1; +@@ -100,11 +121,13 @@ is_local_fs_type (unsigned long int magic) + case S_MAGIC_VMHGFS: return 0; + case S_MAGIC_VXFS: return 0; + case S_MAGIC_VZFS: return 1; ++ case S_MAGIC_WSLFS: return 1; + case S_MAGIC_XENFS: return 1; + case S_MAGIC_XENIX: return 1; + case S_MAGIC_XFS: return 1; + case S_MAGIC_XIAFS: return 1; + case S_MAGIC_ZFS: return 1; ++ case S_MAGIC_ZSMALLOC: return 1; + default: return -1; + } + } +diff --git a/src/stat.c b/src/stat.c +index ba491f4..718b32a 100644 +--- a/src/stat.c ++++ b/src/stat.c +@@ -240,6 +240,10 @@ human_fstype (STRUCT_STATVFS const *statfsbuf) + a comment. The S_MAGIC_... name and constant are automatically + combined to produce the #define directives in fs.h. */ + ++ case S_MAGIC_AAFS: /* 0x5A3C69F0 local */ ++ return "aafs"; ++ case S_MAGIC_ACFS: /* 0x61636673 remote */ ++ return "acfs"; + case S_MAGIC_ADFS: /* 0xADF5 local */ + return "adfs"; + case S_MAGIC_AFFS: /* 0xADFF local */ +@@ -255,30 +259,42 @@ human_fstype (STRUCT_STATVFS const *statfsbuf) + return "aufs"; + case S_MAGIC_AUTOFS: /* 0x0187 local */ + return "autofs"; ++ case S_MAGIC_BALLOON_KVM: /* 0x13661366 local */ ++ return "balloon-kvm-fs"; + case S_MAGIC_BEFS: /* 0x42465331 local */ + return "befs"; + case S_MAGIC_BDEVFS: /* 0x62646576 local */ + return "bdevfs"; + case S_MAGIC_BFS: /* 0x1BADFACE local */ + return "bfs"; ++ case S_MAGIC_BPF_FS: /* 0xCAFE4A11 local */ ++ return "bpf_fs"; + case S_MAGIC_BINFMTFS: /* 0x42494E4D local */ + return "binfmt_misc"; + case S_MAGIC_BTRFS: /* 0x9123683E local */ + return "btrfs"; ++ case S_MAGIC_BTRFS_TEST: /* 0x73727279 local */ ++ return "btrfs_test"; + case S_MAGIC_CEPH: /* 0x00C36400 remote */ + return "ceph"; + case S_MAGIC_CGROUP: /* 0x0027E0EB local */ + return "cgroupfs"; ++ case S_MAGIC_CGROUP2: /* 0x63677270 local */ ++ return "cgroup2fs"; + case S_MAGIC_CIFS: /* 0xFF534D42 remote */ + return "cifs"; + case S_MAGIC_CODA: /* 0x73757245 remote */ + return "coda"; + case S_MAGIC_COH: /* 0x012FF7B7 local */ + return "coh"; ++ case S_MAGIC_CONFIGFS: /* 0x62656570 local */ ++ return "configfs"; + case S_MAGIC_CRAMFS: /* 0x28CD3D45 local */ + return "cramfs"; + case S_MAGIC_CRAMFS_WEND: /* 0x453DCD28 local */ + return "cramfs-wend"; ++ case S_MAGIC_DAXFS: /* 0x64646178 local */ ++ return "daxfs"; + case S_MAGIC_DEBUGFS: /* 0x64626720 local */ + return "debugfs"; + case S_MAGIC_DEVFS: /* 0x1373 local */ +@@ -291,6 +307,8 @@ human_fstype (STRUCT_STATVFS const *statfsbuf) + return "efivarfs"; + case S_MAGIC_EFS: /* 0x00414A53 local */ + return "efs"; ++ case S_MAGIC_EXFS: /* 0x45584653 local */ ++ return "exfs"; + case S_MAGIC_EXOFS: /* 0x5DF5 local */ + return "exofs"; + case S_MAGIC_EXT: /* 0x137D local */ +@@ -311,13 +329,17 @@ human_fstype (STRUCT_STATVFS const *statfsbuf) + return "fusectl"; + case S_MAGIC_FUTEXFS: /* 0x0BAD1DEA local */ + return "futexfs"; +- case S_MAGIC_GFS: /* 0x1161970 remote */ ++ case S_MAGIC_GFS: /* 0x01161970 remote */ + return "gfs/gfs2"; + case S_MAGIC_GPFS: /* 0x47504653 remote */ + return "gpfs"; + case S_MAGIC_HFS: /* 0x4244 local */ + return "hfs"; +- case S_MAGIC_HOSTFS: /* 0xC0FFEE local */ ++ case S_MAGIC_HFS_PLUS: /* 0x482B local */ ++ return "hfs+"; ++ case S_MAGIC_HFS_X: /* 0x4858 local */ ++ return "hfsx"; ++ case S_MAGIC_HOSTFS: /* 0x00C0FFEE local */ + return "hostfs"; + case S_MAGIC_HPFS: /* 0xF995E849 local */ + return "hpfs"; +@@ -325,6 +347,8 @@ human_fstype (STRUCT_STATVFS const *statfsbuf) + return "hugetlbfs"; + case S_MAGIC_MTD_INODE_FS: /* 0x11307854 local */ + return "inodefs"; ++ case S_MAGIC_IBRIX: /* 0x013111A8 remote */ ++ return "ibrix"; + case S_MAGIC_INOTIFYFS: /* 0x2BAD1DEA local */ + return "inotifyfs"; + case S_MAGIC_ISOFS: /* 0x9660 local */ +@@ -341,8 +365,12 @@ human_fstype (STRUCT_STATVFS const *statfsbuf) + return "jfs"; + case S_MAGIC_KAFS: /* 0x6B414653 remote */ + return "k-afs"; ++ case S_MAGIC_LOGFS: /* 0xC97E8168 local */ ++ return "logfs"; + case S_MAGIC_LUSTRE: /* 0x0BD00BD0 remote */ + return "lustre"; ++ case S_MAGIC_M1FS: /* 0x5346314D local */ ++ return "m1fs"; + case S_MAGIC_MINIX: /* 0x137F local */ + return "minix"; + case S_MAGIC_MINIX_30: /* 0x138F local */ +@@ -365,19 +393,28 @@ human_fstype (STRUCT_STATVFS const *statfsbuf) + return "nfsd"; + case S_MAGIC_NILFS: /* 0x3434 local */ + return "nilfs"; ++ case S_MAGIC_NSFS: /* 0x6E736673 local */ ++ return "nsfs"; + case S_MAGIC_NTFS: /* 0x5346544E local */ + return "ntfs"; + case S_MAGIC_OPENPROM: /* 0x9FA1 local */ + return "openprom"; +- case S_MAGIC_OCFS2: /* 0x7461636f remote */ ++ case S_MAGIC_OCFS2: /* 0x7461636F remote */ + return "ocfs2"; ++ case S_MAGIC_OVERLAYFS: /* 0x794C7630 remote */ ++ /* This may overlay remote file systems. ++ Also there have been issues reported with inotify and overlayfs, ++ so mark as "remote" so that polling is used. */ ++ return "overlayfs"; + case S_MAGIC_PANFS: /* 0xAAD7AAEA remote */ + return "panfs"; + case S_MAGIC_PIPEFS: /* 0x50495045 remote */ + /* FIXME: change syntax or add an optional attribute like "inotify:no". +- The above is labeled as "remote" so that tail always uses polling, +- but this isn't really a remote file system type. */ ++ pipefs and prlfs are labeled as "remote" so that tail always polls, ++ but these aren't really remote file system types. */ + return "pipefs"; ++ case S_MAGIC_PRL_FS: /* 0x7C7C6673 remote */ ++ return "prl_fs"; + case S_MAGIC_PROC: /* 0x9FA0 local */ + return "proc"; + case S_MAGIC_PSTOREFS: /* 0x6165676C local */ +@@ -388,12 +425,16 @@ human_fstype (STRUCT_STATVFS const *statfsbuf) + return "qnx6"; + case S_MAGIC_RAMFS: /* 0x858458F6 local */ + return "ramfs"; ++ case S_MAGIC_RDTGROUP: /* 0x07655821 local */ ++ return "rdt"; + case S_MAGIC_REISERFS: /* 0x52654973 local */ + return "reiserfs"; + case S_MAGIC_ROMFS: /* 0x7275 local */ + return "romfs"; + case S_MAGIC_RPC_PIPEFS: /* 0x67596969 local */ + return "rpc_pipefs"; ++ case S_MAGIC_SDCARDFS: /* 0x5DCA2DF5 local */ ++ return "sdcardfs"; + case S_MAGIC_SECURITYFS: /* 0x73636673 local */ + return "securityfs"; + case S_MAGIC_SELINUX: /* 0xF97CFF8C local */ +@@ -402,6 +443,8 @@ human_fstype (STRUCT_STATVFS const *statfsbuf) + return "smackfs"; + case S_MAGIC_SMB: /* 0x517B remote */ + return "smb"; ++ case S_MAGIC_SMB2: /* 0xFE534D42 remote */ ++ return "smb2"; + case S_MAGIC_SNFS: /* 0xBEEFDEAD remote */ + return "snfs"; + case S_MAGIC_SOCKFS: /* 0x534F434B local */ +@@ -416,6 +459,8 @@ human_fstype (STRUCT_STATVFS const *statfsbuf) + return "sysv4"; + case S_MAGIC_TMPFS: /* 0x01021994 local */ + return "tmpfs"; ++ case S_MAGIC_TRACEFS: /* 0x74726163 local */ ++ return "tracefs"; + case S_MAGIC_UBIFS: /* 0x24051905 local */ + return "ubifs"; + case S_MAGIC_UDF: /* 0x15013346 local */ +@@ -430,10 +475,14 @@ human_fstype (STRUCT_STATVFS const *statfsbuf) + return "v9fs"; + case S_MAGIC_VMHGFS: /* 0xBACBACBC remote */ + return "vmhgfs"; +- case S_MAGIC_VXFS: /* 0xA501FCF5 local */ ++ case S_MAGIC_VXFS: /* 0xA501FCF5 remote */ ++ /* Veritas File System can run in single instance or clustered mode, ++ so mark as remote to cater for the latter case. */ + return "vxfs"; + case S_MAGIC_VZFS: /* 0x565A4653 local */ + return "vzfs"; ++ case S_MAGIC_WSLFS: /* 0x53464846 local */ ++ return "wslfs"; + case S_MAGIC_XENFS: /* 0xABBA1974 local */ + return "xenfs"; + case S_MAGIC_XENIX: /* 0x012FF7B4 local */ +@@ -444,6 +493,9 @@ human_fstype (STRUCT_STATVFS const *statfsbuf) + return "xia"; + case S_MAGIC_ZFS: /* 0x2FC12FC1 local */ + return "zfs"; ++ case S_MAGIC_ZSMALLOC: /* 0x58295829 local */ ++ return "zsmallocfs"; ++ + + # elif __GNU__ + case FSTYPE_UFS: +diff --git a/src/tail.c b/src/tail.c +index dc4e10d..f4575d8 100644 +--- a/src/tail.c ++++ b/src/tail.c +@@ -898,6 +898,7 @@ fremote (int fd, const char *name) + case 0: + break; + case -1: ++#if 0 + { + unsigned long int fs_type = buf.f_type; + error (0, 0, _("unrecognized file system type 0x%08lx for %s. " +@@ -905,6 +906,7 @@ fremote (int fd, const char *name) + fs_type, quote (name), PACKAGE_BUGREPORT); + /* Treat as "remote", so caller polls. */ + } ++#endif + break; + case 1: + remote = false; diff --git a/SOURCES/coreutils-8.22-non-defaulttests.patch b/SOURCES/coreutils-8.22-non-defaulttests.patch new file mode 100644 index 0000000..95a6dee --- /dev/null +++ b/SOURCES/coreutils-8.22-non-defaulttests.patch @@ -0,0 +1,267 @@ +diff -urNp coreutils-8.22-orig/tests/cp/cp-a-selinux.sh coreutils-8.22/tests/cp/cp-a-selinux.sh +--- coreutils-8.22-orig/tests/cp/cp-a-selinux.sh 2013-12-04 15:48:30.000000000 +0100 ++++ coreutils-8.22/tests/cp/cp-a-selinux.sh 2015-08-17 13:59:27.837012142 +0200 +@@ -4,7 +4,7 @@ + # Check also locally if --preserve=context, -a and --preserve=all + # does work + +-# Copyright (C) 2007-2013 Free Software Foundation, Inc. ++# Copyright (C) 2007-2015 Free Software Foundation, Inc. + + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU General Public License as published by +@@ -37,16 +37,36 @@ cp -a c d 2>err || framework_failure_ + cp --preserve=context c e || framework_failure_ + cp --preserve=all c f || framework_failure_ + ls -Z d | grep $ctx || fail=1 +-test -s err && fail=1 #there must be no stderr output for -a ++# there must be no stderr output for -a ++compare /dev/null err || fail=1 + ls -Z e | grep $ctx || fail=1 + ls -Z f | grep $ctx || fail=1 ++rm -f f ++ ++# Check handling of existing dirs which requires specific handling ++# due to recursion, and was handled incorrectly in coreutils-8.22 ++# Note standard permissions are updated for existing directories ++# in the destination, so SELinux contexts should be updated too. ++chmod o+rw restore/existing_dir ++mkdir -p backup/existing_dir/ || framework_failure_ ++ls -Zd backup/existing_dir > ed_ctx || fail=1 ++grep $ctx ed_ctx && framework_failure_ ++touch backup/existing_dir/file || framework_failure_ ++chcon $ctx backup/existing_dir/file || framework_failure_ ++# Set the dir context to ensure it is reset ++mkdir -p --context="$ctx" restore/existing_dir || framework_failure_ ++# Copy and ensure existing directories updated ++cp -a backup/. restore/ ++ls -Zd restore/existing_dir > ed_ctx || fail=1 ++grep $ctx ed_ctx && ++ { ls -lZd restore/existing_dir; fail=1; } + + # Check restorecon (-Z) functionality for file and directory + get_selinux_type() { ls -Zd "$1" | sed -n 's/.*:\(.*_t\):.*/\1/p'; } + # Also make a dir with our known context + mkdir c_d || framework_failure_ + chcon $ctx c_d || framework_failure_ +-# Get the type of this known context for file and dir ++# Get the type of this known context for file and dir for tracing + old_type_f=$(get_selinux_type c) + old_type_d=$(get_selinux_type c_d) + # Setup copies for manipulation with restorecon +@@ -62,7 +82,7 @@ if restorecon Z1 Z1_d 2>/dev/null; then + cpZ_type_f=$(get_selinux_type Z2) + test "$cpZ_type_f" = "$new_type_f" || fail=1 + +- # Ensuze -Z overrides -a and that dirs are handled too ++ # Ensure -Z overrides -a and that dirs are handled too + cp -aZ c Z3 || fail=1 + cp -aZ c_d Z3_d || fail=1 + cpaZ_type_f=$(get_selinux_type Z3) +@@ -93,27 +113,30 @@ test $skip = 1 \ + + cd mnt || framework_failure_ + +-echo > f || framework_failure_ +- ++# Create files with hopefully different contexts ++echo > ../f || framework_failure_ + echo > g || framework_failure_ ++test "$(stat -c%C ../f)" = "$(stat -c%C g)" && ++ skip_ "files on separate file systems have the same security context" ++ + # /bin/cp from coreutils-6.7-3.fc7 would fail this test by letting cp + # succeed (giving no diagnostics), yet leaving the destination file empty. +-cp -a f g 2>err || fail=1 ++cp -a ../f g 2>err || fail=1 + test -s g || fail=1 # The destination file must not be empty. +-test -s err && fail=1 # There must be no stderr output. ++compare /dev/null err || fail=1 + + # ===================================================== + # Here, we expect cp to succeed and not warn with "Operation not supported" + rm -f g + echo > g +-cp --preserve=all f g 2>err || fail=1 ++cp --preserve=all ../f g 2>err || fail=1 + test -s g || fail=1 + grep "Operation not supported" err && fail=1 + + # ===================================================== + # The same as above except destination does not exist + rm -f g +-cp --preserve=all f g 2>err || fail=1 ++cp --preserve=all ../f g 2>err || fail=1 + test -s g || fail=1 + grep "Operation not supported" err && fail=1 + +@@ -133,9 +156,9 @@ echo > g + # ===================================================== + # Here, we expect cp to fail, because it cannot set the SELinux + # security context through NFS or a mount with fixed context. +-cp --preserve=context f g 2> out && fail=1 ++cp --preserve=context ../f g 2> out && fail=1 + # Here, we *do* expect the destination to be empty. +-test -s g && fail=1 ++compare /dev/null g || fail=1 + sed "s/ .g'.*//" out > k + mv k out + compare exp out || fail=1 +@@ -143,9 +166,9 @@ compare exp out || fail=1 + rm -f g + echo > g + # Check if -a option doesn't silence --preserve=context option diagnostics +-cp -a --preserve=context f g 2> out2 && fail=1 ++cp -a --preserve=context ../f g 2> out2 && fail=1 + # Here, we *do* expect the destination to be empty. +-test -s g && fail=1 ++compare /dev/null g || fail=1 + sed "s/ .g'.*//" out2 > k + mv k out2 + compare exp out2 || fail=1 +@@ -154,31 +177,33 @@ for no_g_cmd in '' 'rm -f g'; do + # restorecon equivalent. Note even though the context + # returned from matchpathcon() will not match $ctx + # the resulting ENOTSUP warning will be suppressed. ++ + # With absolute path + $no_g_cmd +- cp -Z f $(realpath g) || fail=1 ++ cp -Z ../f $(realpath g) || fail=1 + # With relative path + $no_g_cmd +- cp -Z f g || fail=1 ++ cp -Z ../f g || fail=1 + # -Z overrides -a + $no_g_cmd +- cp -Z -a f g || fail=1 ++ cp -Z -a ../f g || fail=1 + # -Z doesn't take an arg + $no_g_cmd +- cp -Z "$ctx" f g && fail=1 ++ returns_ 1 cp -Z "$ctx" ../f g || fail=1 + + # Explicit context + $no_g_cmd + # Explicitly defaulting to the global $ctx should work +- cp --context="$ctx" f g || fail=1 ++ cp --context="$ctx" ../f g || fail=1 + # --context overrides -a + $no_g_cmd +- cp -a --context="$ctx" f g || fail=1 ++ cp -a --context="$ctx" ../f g || fail=1 + done + +-# Mutually exlusive options +-cp -Z --preserve=context f g && fail=1 +-cp --preserve=context -Z f g && fail=1 +-cp --preserve=context --context="$ctx" f g && fail=1 ++# Mutually exclusive options ++returns_ 1 cp -Z --preserve=context ../f g || fail=1 ++returns_ 1 cp --preserve=context -Z ../f g || fail=1 ++returns_ 1 cp --preserve=context --context="$ctx" ../f g || fail=1 + + Exit $fail ++ +diff -urNp coreutils-8.22-orig/tests/du/2g.sh coreutils-8.22/tests/du/2g.sh +--- coreutils-8.22-orig/tests/du/2g.sh 2013-12-04 15:48:30.000000000 +0100 ++++ coreutils-8.22/tests/du/2g.sh 2015-08-17 13:59:37.349088611 +0200 +@@ -3,7 +3,7 @@ + # Before coreutils-5.93, on systems with a signed, 32-bit stat.st_blocks + # one of du's computations would overflow. + +-# Copyright (C) 2005-2013 Free Software Foundation, Inc. ++# Copyright (C) 2005-2015 Free Software Foundation, Inc. + + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU General Public License as published by +@@ -24,13 +24,9 @@ print_ver_ du + # Creating a 2GB file counts as 'very expensive'. + very_expensive_ + +- + # Get number of free kilobytes on current partition, so we can + # skip this test if there is insufficient free space. +- +-# This technique relies on the fact that the 'Available' kilobyte +-# count is the number just before the one with a trailing '%'. +-free_kb=$(df -kP .|tail -1|sed 's/ [0-9][0-9]*%.*//;s/ *$//;s/.* //') ++free_kb=$(df -k --output=avail . | tail -n1) + case "$free_kb" in + [0-9]*) ;; + *) skip_ "invalid size from df: $free_kb";; +@@ -45,16 +41,22 @@ test $min_kb -lt $free_kb || + } + + big=big +-rm -f $big +-test -t 1 || printf 'creating a 2GB file...\n' +-for i in $(seq 100); do +- # Note: 2147483648 == 2^31. Print floor(2^31/100) per iteration. +- printf %21474836s x >> $big || fail=1 +- # On the final iteration, append the remaining 48 bytes. +- test $i = 100 && { printf %48s x >> $big || fail=1; } +- test -t 1 && printf 'creating a 2GB file: %d%% complete\r' $i +-done +-echo ++ ++if ! fallocate -l2G $big; then ++ rm -f $big ++ { ++ is_local_dir_ . || skip 'Not writing 2GB data to remote' ++ for i in $(seq 100); do ++ # Note: 2147483648 == 2^31. Print floor(2^31/100) per iteration. ++ printf %21474836s x || fail=1 ++ done ++ # After the final iteration, append the remaining 48 bytes. ++ printf %48s x || fail=1 ++ } > $big || fail=1 ++fi ++ ++# The allocation may be done asynchronously (BTRFS for example) ++sync $big || framework_failure_ + + du -k $big > out1 || fail=1 + rm -f $big +diff -urNp coreutils-8.22-orig/tests/init.sh coreutils-8.22/tests/init.sh +--- coreutils-8.22-orig/tests/init.sh 2013-12-04 15:48:30.000000000 +0100 ++++ coreutils-8.22/tests/init.sh 2015-08-17 13:59:19.900948318 +0200 +@@ -93,6 +93,27 @@ skip_ () { warn_ "$ME_: skipped test: $@ + fatal_ () { warn_ "$ME_: hard error: $@"; Exit 99; } + framework_failure_ () { warn_ "$ME_: set-up failure: $@"; Exit 99; } + ++# This is used to simplify checking of the return value ++# which is useful when ensuring a command fails as desired. ++# I.e., just doing `command ... &&fail=1` will not catch ++# a segfault in command for example. With this helper you ++# instead check an explicit exit code like ++# returns_ 1 command ... || fail ++returns_ () { ++ # Disable tracing so it doesn't interfere with stderr of the wrapped command ++ { set +x; } 2>/dev/null ++ ++ local exp_exit="$1" ++ shift ++ "$@" ++ test $? -eq $exp_exit && ret_=0 || ret_=1 ++ ++ if test "$VERBOSE" = yes && test "$gl_set_x_corrupts_stderr_" = false; then ++ set -x ++ fi ++ { return $ret_; } 2>/dev/null ++} ++ + # Sanitize this shell to POSIX mode, if possible. + DUALCASE=1; export DUALCASE + if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then +diff -urNp coreutils-8.22-orig/tests/local.mk coreutils-8.22/tests/local.mk +--- coreutils-8.22-orig/tests/local.mk 2015-08-17 12:44:49.343344148 +0200 ++++ coreutils-8.22/tests/local.mk 2015-08-17 13:59:12.124885835 +0200 +@@ -121,7 +121,6 @@ all_root_tests = \ + tests/install/install-C-root.sh \ + tests/ls/capability.sh \ + tests/ls/nameless-uid.sh \ +- tests/misc/chcon.sh \ + tests/misc/chroot-credentials.sh \ + tests/misc/selinux.sh \ + tests/misc/truncate-owned-by-other.sh \ diff --git a/SOURCES/coreutils-8.22-ppc64le.patch b/SOURCES/coreutils-8.22-ppc64le.patch new file mode 100644 index 0000000..f8634ed --- /dev/null +++ b/SOURCES/coreutils-8.22-ppc64le.patch @@ -0,0 +1,39 @@ +diff -up coreutils-8.22/gnulib-tests/test-isnanl.h.ppc coreutils-8.22/gnulib-tests/test-isnanl.h +--- coreutils-8.22/gnulib-tests/test-isnanl.h.ppc 2014-06-23 14:01:05.925541920 +0200 ++++ coreutils-8.22/gnulib-tests/test-isnanl.h 2014-06-23 14:01:39.437617584 +0200 +@@ -51,6 +51,15 @@ main () + /* A bit pattern that is different from a Quiet NaN. With a bit of luck, + it's a Signalling NaN. */ + { ++#if defined __powerpc__ && LDBL_MANT_DIG == 106 ++ /* This is PowerPC "double double", a pair of two doubles. Inf and Nan are ++ represented as the corresponding 64-bit IEEE values in the first double; ++ the second is ignored. Manipulate only the first double. */ ++ #undef NWORDS ++ #define NWORDS \ ++ ((sizeof (double) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) ++#endif ++ + memory_long_double m; + m.value = NaNl (); + # if LDBL_EXPBIT0_BIT > 0 +diff -up coreutils-8.22/gnulib-tests/test-signbit.c.ppc coreutils-8.22/gnulib-tests/test-signbit.c +--- coreutils-8.22/gnulib-tests/test-signbit.c.ppc 2013-12-04 15:53:33.000000000 +0100 ++++ coreutils-8.22/gnulib-tests/test-signbit.c 2014-06-23 13:59:20.378307385 +0200 +@@ -151,6 +151,16 @@ test_signbitl () + #define NWORDS \ + ((sizeof (long double) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) + typedef union { long double value; unsigned int word[NWORDS]; } memory_long_double; ++ ++#if defined __powerpc__ && LDBL_MANT_DIG == 106 ++ /* This is PowerPC "double double", a pair of two doubles. Inf and Nan are ++ represented as the corresponding 64-bit IEEE values in the first double; ++ the second is ignored. Manipulate only the first double. */ ++ #undef NWORDS ++ #define NWORDS \ ++ ((sizeof (double) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) ++#endif ++ + memory_long_double m; + m.value = zerol / zerol; + # if LDBL_EXPBIT0_BIT > 0 diff --git a/SOURCES/coreutils-8.22-selinux-optionsseparate.patch b/SOURCES/coreutils-8.22-selinux-optionsseparate.patch new file mode 100644 index 0000000..10743c0 --- /dev/null +++ b/SOURCES/coreutils-8.22-selinux-optionsseparate.patch @@ -0,0 +1,80 @@ +diff -urNp coreutils-8.22-orig/src/cp.c coreutils-8.22/src/cp.c +--- coreutils-8.22-orig/src/cp.c 2015-06-11 15:58:04.230858212 +0200 ++++ coreutils-8.22/src/cp.c 2015-06-11 15:59:13.191396755 +0200 +@@ -233,8 +233,10 @@ Copy SOURCE to DEST, or multiple SOURCE( + -x, --one-file-system stay on this file system\n\ + "), stdout); + fputs (_("\ +- -Z, --context[=CTX] set SELinux security context of destination\n\ +- file to default type, or to CTX if specified\n\ ++ -Z set SELinux security context of destination\n\ ++ file to default type\n\ ++ --context[=CTX] like -Z, or if CTX is specified then set the\n\ ++ SELinux or SMACK security context to CTX\n\ + "), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); +diff -urNp coreutils-8.22-orig/src/install.c coreutils-8.22/src/install.c +--- coreutils-8.22-orig/src/install.c 2015-06-11 15:58:04.230858212 +0200 ++++ coreutils-8.22/src/install.c 2015-06-11 16:00:16.754893027 +0200 +@@ -647,8 +647,10 @@ In the 4th form, create all components o + "), stdout); + fputs (_("\ + -P, --preserve-context preserve SELinux security context (-P deprecated)\n\ +- -Z, --context[=CTX] set SELinux security context of destination file to\n\ +- default type, or to CTX if specified\n\ ++ -Z set SELinux security context of destination\n\ ++ file to default type\n\ ++ --context[=CTX] like -Z, or if CTX is specified then set the\n\ ++ SELinux or SMACK security context to CTX\n\ + "), stdout); + + fputs (HELP_OPTION_DESCRIPTION, stdout); +diff -urNp coreutils-8.22-orig/src/mkdir.c coreutils-8.22/src/mkdir.c +--- coreutils-8.22-orig/src/mkdir.c 2013-12-05 01:59:36.000000000 +0100 ++++ coreutils-8.22/src/mkdir.c 2015-06-11 16:01:17.209364915 +0200 +@@ -66,8 +66,12 @@ Create the DIRECTORY(ies), if they do no + -m, --mode=MODE set file mode (as in chmod), not a=rwx - umask\n\ + -p, --parents no error if existing, make parent directories as needed\n\ + -v, --verbose print a message for each created directory\n\ +- -Z, --context[=CTX] set the SELinux security context of each created\n\ +- directory to default type or to CTX if specified\n\ ++"), stdout); ++ fputs (_("\ ++ -Z set SELinux security context of each created directory\n\ ++ to the default type\n\ ++ --context[=CTX] like -Z, or if CTX is specified then set the SELinux\n\ ++ or SMACK security context to CTX\n\ + "), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); +diff -urNp coreutils-8.22-orig/src/mkfifo.c coreutils-8.22/src/mkfifo.c +--- coreutils-8.22-orig/src/mkfifo.c 2013-12-05 00:43:05.000000000 +0100 ++++ coreutils-8.22/src/mkfifo.c 2015-06-11 16:02:03.389725315 +0200 +@@ -61,8 +61,9 @@ Create named pipes (FIFOs) with the give + -m, --mode=MODE set file permission bits to MODE, not a=rw - umask\n\ + "), stdout); + fputs (_("\ +- -Z, --context[=CTX] set the SELinux security context of each NAME to\n\ +- default type, or CTX if specified\n\ ++ -Z set the SELinux security context to default type\n\ ++ --context[=CTX] like -Z, or if CTX is specified then set the SELinux\n\ ++ or SMACK security context to CTX\n\ + "), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); +diff -urNp coreutils-8.22-orig/src/mknod.c coreutils-8.22/src/mknod.c +--- coreutils-8.22-orig/src/mknod.c 2013-12-05 00:43:05.000000000 +0100 ++++ coreutils-8.22/src/mknod.c 2015-06-11 16:02:36.300982160 +0200 +@@ -63,8 +63,9 @@ Create the special file NAME of the give + -m, --mode=MODE set file permission bits to MODE, not a=rw - umask\n\ + "), stdout); + fputs (_("\ +- -Z, --context[=CTX] set the SELinux security context of NAME to\n\ +- default type, or to CTX if specified\n\ ++ -Z set the SELinux security context to default type\n\ ++ --context[=CTX] like -Z, or if CTX is specified then set the SELinux\n\ ++ or SMACK security context to CTX\n\ + "), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); diff --git a/SOURCES/coreutils-8.22-sort-blanks.patch b/SOURCES/coreutils-8.22-sort-blanks.patch new file mode 100644 index 0000000..a950ffc --- /dev/null +++ b/SOURCES/coreutils-8.22-sort-blanks.patch @@ -0,0 +1,35 @@ +From 3976ef5a20369d8b490907ab2cba2d617305a5e0 Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Mon, 30 May 2016 16:19:20 +0200 +Subject: [PATCH] sort: do not use static array 'blanks' in human_numcompare() + +... because the array is not initialized with MB locales. Note this is +rather a conservative fix. I plan to do more cleanup of the i18n patch +in Fedora to prevent mistakes like this in future updates of coreutils. +--- + src/sort.c | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +diff --git a/src/sort.c b/src/sort.c +index 9e07ad8..e47b039 100644 +--- a/src/sort.c ++++ b/src/sort.c +@@ -2275,12 +2275,10 @@ find_unit_order (char const *number) + < K/k < M < G < T < P < E < Z < Y */ + + static int +-human_numcompare (char const *a, char const *b) ++human_numcompare (char *a, char *b) + { +- while (blanks[to_uchar (*a)]) +- a++; +- while (blanks[to_uchar (*b)]) +- b++; ++ skipblanks(&a, a + strlen(a)); ++ skipblanks(&b, b + strlen(b)); + + int diff = find_unit_order (a) - find_unit_order (b); + return (diff ? diff : strnumcmp (a, b, decimal_point, thousands_sep)); +-- +2.5.5 + diff --git a/SOURCES/coreutils-8.22-temporarytestoff.patch b/SOURCES/coreutils-8.22-temporarytestoff.patch new file mode 100644 index 0000000..c95343b --- /dev/null +++ b/SOURCES/coreutils-8.22-temporarytestoff.patch @@ -0,0 +1,13 @@ +diff -urNp coreutils-8.22-orig/tests/df/df-symlink.sh coreutils-8.22/tests/df/df-symlink.sh +--- coreutils-8.22-orig/tests/df/df-symlink.sh 2013-12-04 15:48:30.000000000 +0100 ++++ coreutils-8.22/tests/df/df-symlink.sh 2013-12-14 18:20:15.822594995 +0100 +@@ -18,6 +18,9 @@ + + . "${srcdir=.}/tests/init.sh"; path_prepend_ ./src + print_ver_ df ++#df doesn't work correctly on symlinks when on LVM/LUKS filesystem, therefore ++#marking expensive_ to disable by default ++expensive_ + + disk=$(df --out=source '.' | tail -n1) || + skip_ "cannot determine '.' file system" diff --git a/SOURCES/coreutils-8.22-vxfs-noinotify.patch b/SOURCES/coreutils-8.22-vxfs-noinotify.patch new file mode 100644 index 0000000..359331c --- /dev/null +++ b/SOURCES/coreutils-8.22-vxfs-noinotify.patch @@ -0,0 +1,12 @@ +diff -urNp coreutils-8.22-orig/src/fs-is-local.h coreutils-8.22/src/fs-is-local.h +--- coreutils-8.22-orig/src/fs-is-local.h 2013-12-13 15:17:10.000000000 +0100 ++++ coreutils-8.22/src/fs-is-local.h 2015-06-04 11:06:34.161072669 +0200 +@@ -98,7 +98,7 @@ is_local_fs_type (unsigned long int magi + case S_MAGIC_USBDEVFS: return 1; + case S_MAGIC_V9FS: return 1; + case S_MAGIC_VMHGFS: return 0; +- case S_MAGIC_VXFS: return 1; ++ case S_MAGIC_VXFS: return 0; + case S_MAGIC_VZFS: return 1; + case S_MAGIC_XENFS: return 1; + case S_MAGIC_XENIX: return 1; diff --git a/SOURCES/coreutils-8.22-xfs-tests.patch b/SOURCES/coreutils-8.22-xfs-tests.patch new file mode 100644 index 0000000..dedff30 --- /dev/null +++ b/SOURCES/coreutils-8.22-xfs-tests.patch @@ -0,0 +1,29 @@ +From: Pádraig Brady + +Avoid false failure due to speculative preallocation on XFS +Avoid false failure due to delayed allocation on BTRFS + +diff -Naur coreutils-8.22.orig/tests/dd/sparse.sh coreutils-8.22/tests/dd/sparse.sh +--- coreutils-8.22.orig/tests/dd/sparse.sh 2013-12-04 14:48:30.000000000 +0000 ++++ coreutils-8.22/tests/dd/sparse.sh 2015-05-19 21:24:55.139941789 +0000 +@@ -58,11 +58,18 @@ + + # Ensure NUL blocks smaller than the block size are not made sparse. + # Here, with a 2MiB block size, dd's conv=sparse must *not* introduce a hole. +- dd if=file.in of=file.out bs=2M conv=sparse ++ dd if=file.in of=file.out bs=2M conv=sparse,fsync + test 2500 -lt $(kb_alloc file.out) || fail=1 + ++ # Note we recreate a sparse file first to avoid ++ # speculative preallocation seen in XFS, where a write() that ++ # extends a file can preallocate some extra space that ++ # a subsequent seek will not convert to a hole. ++ rm -f file.out ++ truncate --size=3M file.out ++ + # Ensure that this 1MiB string of NULs *is* converted to a hole. +- dd if=file.in of=file.out bs=1M conv=sparse ++ dd if=file.in of=file.out bs=1M conv=sparse,notrunc,fsync + test $(kb_alloc file.out) -lt 2500 || fail=1 + + fi diff --git a/SOURCES/coreutils-8.22-xfsbuildfailure.patch b/SOURCES/coreutils-8.22-xfsbuildfailure.patch new file mode 100644 index 0000000..4a0d43a --- /dev/null +++ b/SOURCES/coreutils-8.22-xfsbuildfailure.patch @@ -0,0 +1,93 @@ +From eafaa2e88f7af16756142a31ab63d032b31395e3 Mon Sep 17 00:00:00 2001 +From: Pádraig Brady +Date: Fri, 06 Nov 2015 16:31:22 +0000 +Subject: tests: fix dirent d_type support verification + +* tests/d_type-check: Check also the d_type of files, +which excludes XFS appropriately. Specify all argument +and return types to avoid truncated pointers being passed, +which skipped the test due to crashes on x86_64 at least. +Simplify the C library lookup by reusing the interpreter's. + +chroot issue reported at https://bugzilla.redhat.com/1263341 +--- +diff --git a/tests/d_type-check b/tests/d_type-check +index ff1eb60..1a2f76f 100644 +--- a/tests/d_type-check ++++ b/tests/d_type-check +@@ -1,13 +1,17 @@ + #!/usr/bin/python +-# Exit 0 if "." has useful d_type information, else 1. ++# Exit 0 if "." and "./tempfile" have useful d_type information, else 1. + # Intended to exit 0 only on Linux/GNU systems. ++import os + import sys ++import tempfile + + fail = 1 ++fname = None ++ + try: + import ctypes + +- (DT_UNKNOWN, DT_DIR,) = (0, 4,) ++ (DT_UNKNOWN, DT_DIR, DT_REG) = (0, 4, 8) + + class dirent(ctypes.Structure): + _fields_ = [ +@@ -17,20 +21,48 @@ try: + ("d_type", ctypes.c_ubyte), + ("d_name", ctypes.c_char*256)] + ++ # Pass NULL to dlopen, assuming the python ++ # interpreter is linked with the C runtime ++ libc = ctypes.CDLL(None) ++ ++ # Setup correct types for all args and returns ++ # even if only passing, to avoid truncation etc. ++ dirp = ctypes.c_void_p + direntp = ctypes.POINTER(dirent) + +- # FIXME: find a way to avoid hard-coding libc's so-name. +- libc = ctypes.cdll.LoadLibrary("libc.so.6") ++ libc.readdir.argtypes = [dirp] + libc.readdir.restype = direntp + ++ libc.opendir.restype = dirp ++ ++ # Ensure a file is present ++ f, fname = tempfile.mkstemp(dir='.') ++ fname = os.path.basename(fname) ++ + dirp = libc.opendir(".") + if dirp: +- ep = libc.readdir(dirp) +- if ep: ++ while True: ++ ep = libc.readdir(dirp) ++ if not ep: break ++ d_type = ep.contents.d_type + name = ep.contents.d_name +- if (name == "." or name == "..") and ep.contents.d_type == DT_DIR: ++ if name == "." or name == "..": ++ if d_type != DT_DIR: break ++ # Check files too since on XFS, only dirs have DT_DIR ++ # while everything else has DT_UNKNOWN ++ elif name == fname: ++ if d_type == DT_REG: ++ fail = 0 ++ break ++ elif d_type != DT_DIR and d_type != DT_UNKNOWN: + fail = 0 ++ break ++except: ++ pass + ++try: ++ if fname: ++ os.unlink(fname); + except: + pass + +-- +cgit v0.9.0.2 diff --git a/SOURCES/coreutils-8.4-mkdir-modenote.patch b/SOURCES/coreutils-8.4-mkdir-modenote.patch new file mode 100644 index 0000000..3576ec6 --- /dev/null +++ b/SOURCES/coreutils-8.4-mkdir-modenote.patch @@ -0,0 +1,12 @@ +diff -urNp coreutils-8.4-orig/doc/coreutils.texi coreutils-8.4/doc/coreutils.texi +--- coreutils-8.4-orig/doc/coreutils.texi 2011-01-07 15:01:18.575654333 +0100 ++++ coreutils-8.4/doc/coreutils.texi 2011-01-07 15:05:38.791655243 +0100 +@@ -9058,6 +9058,8 @@ incorrect. @xref{Directory Setuid and S + set-user-ID and set-group-ID bits of directories are inherited unless + overridden in this way. + ++Note: The @option{--mode},@option{-m} option only applies to the right-most directories listed on the command line. When combined with @option{--parents}, @option{-p} option, any parent directories are created with @samp{u+wx} modified by umask. ++ + @item -p + @itemx --parents + @opindex -p diff --git a/SOURCES/coreutils-DIR_COLORS b/SOURCES/coreutils-DIR_COLORS new file mode 100644 index 0000000..6abc937 --- /dev/null +++ b/SOURCES/coreutils-DIR_COLORS @@ -0,0 +1,263 @@ +# Configuration file for the color ls utility +# Synchronized with coreutils 8.5 dircolors +# This file goes in the /etc directory, and must be world readable. +# You can copy this file to .dir_colors in your $HOME directory to override +# the system defaults. + +# COLOR needs one of these arguments: 'tty' colorizes output to ttys, but not +# pipes. 'all' adds color characters to all output. 'none' shuts colorization +# off. +COLOR tty + +# Extra command line options for ls go here. +# Basically these ones are: +# -F = show '/' for dirs, '*' for executables, etc. +# -T 0 = don't trust tab spacing when formatting ls output. +OPTIONS -F -T 0 + +# Below, there should be one TERM entry for each termtype that is colorizable +TERM Eterm +TERM ansi +TERM color-xterm +TERM con132x25 +TERM con132x30 +TERM con132x43 +TERM con132x60 +TERM con80x25 +TERM con80x28 +TERM con80x30 +TERM con80x43 +TERM con80x50 +TERM con80x60 +TERM cons25 +TERM console +TERM cygwin +TERM dtterm +TERM eterm-color +TERM gnome +TERM gnome-256color +TERM jfbterm +TERM konsole +TERM kterm +TERM linux +TERM linux-c +TERM mach-color +TERM mlterm +TERM putty +TERM putty-256color +TERM rxvt +TERM rxvt-256color +TERM rxvt-cygwin +TERM rxvt-cygwin-native +TERM rxvt-unicode +TERM rxvt-unicode-256color +TERM rxvt-unicode256 +TERM screen +TERM screen-256color +TERM screen-256color-bce +TERM screen-bce +TERM screen-w +TERM screen.Eterm +TERM screen.rxvt +TERM screen.linux +TERM st +TERM st-256color +TERM terminator +TERM vt100 +TERM xterm +TERM xterm-16color +TERM xterm-256color +TERM xterm-88color +TERM xterm-color +TERM xterm-debian + +# EIGHTBIT, followed by '1' for on, '0' for off. (8-bit output) +EIGHTBIT 1 + +# Below are the color init strings for the basic file types. A color init +# string consists of one or more of the following numeric codes: +# Attribute codes: +# 00=none 01=bold 04=underscore 05=blink 07=reverse 08=concealed +# Text color codes: +# 30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white +# Background color codes: +# 40=black 41=red 42=green 43=yellow 44=blue 45=magenta 46=cyan 47=white +#NORMAL 00 # no color code at all +#FILE 00 # normal file, use no color at all +RESET 0 # reset to "normal" color +DIR 01;34 # directory +LINK 01;36 # symbolic link (If you set this to 'target' instead of a + # numerical value, the color is as for the file pointed to.) +MULTIHARDLINK 00 # regular file with more than one link +FIFO 40;33 # pipe +SOCK 01;35 # socket +DOOR 01;35 # door +BLK 40;33;01 # block device driver +CHR 40;33;01 # character device driver +ORPHAN 40;31;01 # symlink to nonexistent file, or non-stat'able file +MISSING 01;05;37;41 # ... and the files they point to +SETUID 37;41 # file that is setuid (u+s) +SETGID 30;43 # file that is setgid (g+s) +CAPABILITY 30;41 # file with capability +STICKY_OTHER_WRITABLE 30;42 # dir that is sticky and other-writable (+t,o+w) +OTHER_WRITABLE 34;42 # dir that is other-writable (o+w) and not sticky +STICKY 37;44 # dir with the sticky bit set (+t) and not other-writable + +# This is for files with execute permission: +EXEC 01;32 + +# List any file extensions like '.gz' or '.tar' that you would like ls +# to colorize below. Put the extension, a space, and the color init string. +# (and any comments you want to add after a '#') +# executables (bright green) +#.cmd 01;32 +#.exe 01;32 +#.com 01;32 +#.btm 01;32 +#.bat 01;32 +#.sh 01;32 +#.csh 01;32 + +# archives or compressed (bright red) +.tar 01;31 +.tgz 01;31 +.arc 01;31 +.arj 01;31 +.taz 01;31 +.lha 01;31 +.lz4 01;31 +.lzh 01;31 +.lzma 01;31 +.tlz 01;31 +.txz 01;31 +.tzo 01;31 +.t7z 01;31 +.zip 01;31 +.z 01;31 +.Z 01;31 +.dz 01;31 +.gz 01;31 +.lrz 01;31 +.lz 01;31 +.lzo 01;31 +.xz 01;31 +.bz2 01;31 +.bz 01;31 +.tbz 01;31 +.tbz2 01;31 +.tz 01;31 +.deb 01;31 +.rpm 01;31 +.jar 01;31 +.war 01;31 +.ear 01;31 +.sar 01;31 +.rar 01;31 +.alz 01;31 +.ace 01;31 +.zoo 01;31 +.cpio 01;31 +.7z 01;31 +.rz 01;31 +.cab 01;31 + +# image formats (magenta) +.jpg 01;35 +.jpeg 01;35 +.gif 01;35 +.bmp 01;35 +.pbm 01;35 +.pgm 01;35 +.ppm 01;35 +.tga 01;35 +.xbm 01;35 +.xpm 01;35 +.tif 01;35 +.tiff 01;35 +.png 01;35 +.svg 01;35 +.svgz 01;35 +.mng 01;35 +.pcx 01;35 +.mov 01;35 +.mpg 01;35 +.mpeg 01;35 +.m2v 01;35 +.mkv 01;35 +.webm 01;35 +.ogm 01;35 +.mp4 01;35 +.m4v 01;35 +.mp4v 01;35 +.vob 01;35 +.qt 01;35 +.nuv 01;35 +.wmv 01;35 +.asf 01;35 +.rm 01;35 +.rmvb 01;35 +.flc 01;35 +.avi 01;35 +.fli 01;35 +.flv 01;35 +.gl 01;35 +.dl 01;35 +.xcf 01;35 +.xwd 01;35 +.yuv 01;35 +.cgm 01;35 +.emf 01;35 + +# http://wiki.xiph.org/index.php/MIME_Types_and_File_Extensions +.axv 01;35 +.anx 01;35 +.ogv 01;35 +.ogx 01;35 + +# audio formats (cyan) +.aac 01;36 +.au 01;36 +.flac 01;36 +.mid 01;36 +.midi 01;36 +.mka 01;36 +.mp3 01;36 +.mpc 01;36 +.ogg 01;36 +.ra 01;36 +.wav 01;36 + +# http://wiki.xiph.org/index.php/MIME_Types_and_File_Extensions +.axa 01;36 +.oga 01;36 +.spx 01;36 +.xspf 01;36 + +# colorize binary documents (brown) +#.pdf 00;33 +#.ps 00;33 +#.ps.gz 00;33 +#.tex 00;33 +#.xls 00;33 +#.xlsx 00;33 +#.ppt 00;33 +#.pptx 00;33 +#.rtf 00;33 +#.doc 00;33 +#.docx 00;33 +#.odt 00;33 +#.ods 00;33 +#.odp 00;33 +#.epub 00;33 +#.abw 00;33 +#.wpd 00;33 +# +# colorize text documents (brown) +#.txt 00;33 +#.patch 00;33 +#.diff 00;33 +#.log 00;33 +#.htm 00;33 +#.html 00;33 +#.shtml 00;33 +#.xml 00;33 diff --git a/SOURCES/coreutils-DIR_COLORS.256color b/SOURCES/coreutils-DIR_COLORS.256color new file mode 100644 index 0000000..4efaca1 --- /dev/null +++ b/SOURCES/coreutils-DIR_COLORS.256color @@ -0,0 +1,233 @@ +# Configuration file for the 256color ls utility +# This file goes in the /etc directory, and must be world readable. +# Synchronized with coreutils 8.5 dircolors +# You can copy this file to .dir_colors in your $HOME directory to override +# the system defaults. +# In the case that you are not satisfied with supplied colors, please +# submit your color configuration or attach your file with colors readable +# on ALL color background schemas (white,gray,black) to RedHat Bugzilla +# ticket on https://bugzilla.redhat.com/show_bug.cgi?id=429121 . TIA. +# Please just keep ls color conventions from 8 color scheme. + +# COLOR needs one of these arguments: 'tty' colorizes output to ttys, but not +# pipes. 'all' adds color characters to all output. 'none' shuts colorization +# off. +COLOR tty + +# Extra command line options for ls go here. +# Basically these ones are: +# -F = show '/' for dirs, '*' for executables, etc. +# -T 0 = don't trust tab spacing when formatting ls output. +OPTIONS -F -T 0 + +# Below, there should be one TERM entry for each termtype that is colorizable +TERM putty-256color +TERM rxvt-256color +TERM rxvt-unicode-256color +TERM rxvt-unicode256 +TERM screen-256color +TERM xterm-256color +TERM gnome-256color +TERM st-256color + +# EIGHTBIT, followed by '1' for on, '0' for off. (8-bit output) +EIGHTBIT 1 + +# Below are the color init strings for the basic file types. A color init +# string consists of one or more of the following numeric codes: +# Attribute codes: +# 00=none 01=bold 04=underscore 05=blink 07=reverse 08=concealed +# Text color(8 colors mode) codes: +# 30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white +# Background color(8 colors mode) codes: +# 40=black 41=red 42=green 43=yellow 44=blue 45=magenta 46=cyan 47=white +# Text color(256 colors mode) codes: +# Valid syntax for text 256color is 38;5; , where color number +# is number between 0 and 255. +# You may find following command useful to search the best one for you: +# for ((x=0; x<=255; x++));do echo -e "${x}:\033[38;5;${x}mcolor\033[000m";done +# Background color(256 colors mode) codes: +# Valid syntax for background 256color is 48;5; , where +# color number is number between 0 and 255. +# You may find following command useful to search the best one for you: +# for ((x=0; x<=255; x++));do echo -e "${x}:\033[48;5;${x}mcolor\033[000m";done + +#NORMAL 00 # global default, no color code at all +#FILE 00 # normal file, use no color at all +RESET 0 # reset to "normal" color +DIR 38;5;27 # directory +LINK 38;5;51 # symbolic link (If you set this to 'target' instead of a + # numerical value, the color is as for the file pointed to.) +MULTIHARDLINK 44;38;5;15 # regular file with more than one link +FIFO 40;38;5;11 # pipe +SOCK 38;5;13 # socket +DOOR 38;5;5 # door +BLK 48;5;232;38;5;11 # block device driver +CHR 48;5;232;38;5;3 # character device driver +ORPHAN 48;5;232;38;5;9 # symlink to nonexistent file, or non-stat'able file +MISSING 05;48;5;232;38;5;15 # ... and the files they point to +SETUID 48;5;196;38;5;15 # file that is setuid (u+s) +SETGID 48;5;11;38;5;16 # file that is setgid (g+s) +CAPABILITY 48;5;196;38;5;226 # file with capability +STICKY_OTHER_WRITABLE 48;5;10;38;5;16 # dir that is sticky and other-writable (+t,o+w) +OTHER_WRITABLE 48;5;10;38;5;21 # dir that is other-writable (o+w) and not sticky +STICKY 48;5;21;38;5;15 # dir with the sticky bit set (+t) and not other-writable + +# This is for files with execute permission: +EXEC 38;5;34 + +# List any file extensions like '.gz' or '.tar' that you would like ls +# to colorize below. Put the extension, a space, and the color init string. +# (and any comments you want to add after a '#') +# executables (bright green) +#.cmd 38;5;34 +#.exe 38;5;34 +#.com 38;5;34 +#.btm 38;5;34 +#.bat 38;5;34 +#.sh 38;5;34 +#.csh 38;5;34 + +# archives or compressed (bright red) +.tar 38;5;9 +.tgz 38;5;9 +.arc 38;5;9 +.arj 38;5;9 +.taz 38;5;9 +.lha 38;5;9 +.lz4 38;5;9 +.lzh 38;5;9 +.lzma 38;5;9 +.tlz 38;5;9 +.txz 38;5;9 +.tzo 38;5;9 +.t7z 38;5;9 +.zip 38;5;9 +.z 38;5;9 +.Z 38;5;9 +.dz 38;5;9 +.gz 38;5;9 +.lrz 38;5;9 +.lz 38;5;9 +.lzo 38;5;9 +.xz 38;5;9 +.bz2 38;5;9 +.bz 38;5;9 +.tbz 38;5;9 +.tbz2 38;5;9 +.tz 38;5;9 +.deb 38;5;9 +.rpm 38;5;9 +.jar 38;5;9 +.war 38;5;9 +.ear 38;5;9 +.sar 38;5;9 +.rar 38;5;9 +.alz 38;5;9 +.ace 38;5;9 +.zoo 38;5;9 +.cpio 38;5;9 +.7z 38;5;9 +.rz 38;5;9 +.cab 38;5;9 + +# image formats (magenta) +.jpg 38;5;13 +.jpeg 38;5;13 +.gif 38;5;13 +.bmp 38;5;13 +.pbm 38;5;13 +.pgm 38;5;13 +.ppm 38;5;13 +.tga 38;5;13 +.xbm 38;5;13 +.xpm 38;5;13 +.tif 38;5;13 +.tiff 38;5;13 +.png 38;5;13 +.svg 38;5;13 +.svgz 38;5;13 +.mng 38;5;13 +.pcx 38;5;13 +.mov 38;5;13 +.mpg 38;5;13 +.mpeg 38;5;13 +.m2v 38;5;13 +.mkv 38;5;13 +.webm 38;5;13 +.ogm 38;5;13 +.mp4 38;5;13 +.m4v 38;5;13 +.mp4v 38;5;13 +.vob 38;5;13 +.qt 38;5;13 +.nuv 38;5;13 +.wmv 38;5;13 +.asf 38;5;13 +.rm 38;5;13 +.rmvb 38;5;13 +.flc 38;5;13 +.avi 38;5;13 +.fli 38;5;13 +.flv 38;5;13 +.gl 38;5;13 +.dl 38;5;13 +.xcf 38;5;13 +.xwd 38;5;13 +.yuv 38;5;13 +.cgm 38;5;13 +.emf 38;5;13 + +# http://wiki.xiph.org/index.php/MIME_Types_and_File_Extensions +.axv 38;5;13 +.anx 38;5;13 +.ogv 38;5;13 +.ogx 38;5;13 + +# audio formats (cyan) +.aac 38;5;45 +.au 38;5;45 +.flac 38;5;45 +.mid 38;5;45 +.midi 38;5;45 +.mka 38;5;45 +.mp3 38;5;45 +.mpc 38;5;45 +.ogg 38;5;45 +.ra 38;5;45 +.wav 38;5;45 + +# http://wiki.xiph.org/index.php/MIME_Types_and_File_Extensions +.axa 38;5;45 +.oga 38;5;45 +.spx 38;5;45 +.xspf 38;5;45 + +# colorize binary documents (brown) +#.pdf 00;33 +#.ps 00;33 +#.ps.gz 00;33 +#.tex 00;33 +#.xls 00;33 +#.xlsx 00;33 +#.ppt 00;33 +#.pptx 00;33 +#.rtf 00;33 +#.doc 00;33 +#.docx 00;33 +#.odt 00;33 +#.ods 00;33 +#.odp 00;33 +#.epub 00;33 +#.abw 00;33 +#.wpd 00;33 +# +# colorize text documents (brown) +#.txt 00;33 +#.patch 00;33 +#.diff 00;33 +#.log 00;33 +#.htm 00;33 +#.html 00;33 +#.shtml 00;33 +#.xml 00;33 diff --git a/SOURCES/coreutils-DIR_COLORS.lightbgcolor b/SOURCES/coreutils-DIR_COLORS.lightbgcolor new file mode 100644 index 0000000..43820b2 --- /dev/null +++ b/SOURCES/coreutils-DIR_COLORS.lightbgcolor @@ -0,0 +1,236 @@ +# Configuration file for the color ls utility - modified for gray backgrounds +# Synchronized with coreutils 8.5 dircolors +# This file goes in the /etc directory, and must be world readable. +# You can copy this file to .dir_colors in your $HOME directory to override +# the system defaults. + +# COLOR needs one of these arguments: 'tty' colorizes output to ttys, but not +# pipes. 'all' adds color characters to all output. 'none' shuts colorization +# off. +COLOR tty + +# Extra command line options for ls go here. +# Basically these ones are: +# -F = show '/' for dirs, '*' for executables, etc. +# -T 0 = don't trust tab spacing when formatting ls output. +OPTIONS -F -T 0 + +# Below, there should be one TERM entry for each termtype that is colorizable +TERM linux +TERM console +TERM con132x25 +TERM con132x30 +TERM con132x43 +TERM con132x60 +TERM con80x25 +TERM con80x28 +TERM con80x30 +TERM con80x43 +TERM con80x50 +TERM con80x60 +TERM cons25 +TERM xterm +TERM xterm-16color +TERM xterm-88color +TERM xterm-256color +TERM rxvt +TERM rxvt-256color +TERM rxvt-unicode +TERM rxvt-unicode-256color +TERM rxvt-unicode256 +TERM xterm-color +TERM color-xterm +TERM vt100 +TERM dtterm +TERM color_xterm + +# EIGHTBIT, followed by '1' for on, '0' for off. (8-bit output) +EIGHTBIT 1 + +# Below are the color init strings for the basic file types. A color init +# string consists of one or more of the following numeric codes: +# Attribute codes: +# 00=none 01=bold 04=underscore 05=blink 07=reverse 08=concealed +# Text color codes: +# 30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white +# Background color codes: +# 40=black 41=red 42=green 43=yellow 44=blue 45=magenta 46=cyan 47=white +#NORMAL 00 # no color code at all +#FILE 00 # normal file, use no color at all +RESET 0 +DIR 00;34 # directory +LINK 00;36 # symbolic link (If you set this to 'target' instead of a + # numerical value, the color is as for the file pointed to.) +MULTIHARDLINK 00 # regular file with more than one link +FIFO 40;33 # pipe +SOCK 00;35 # socket +DOOR 00;35 # door +BLK 40;33;01 # block device driver +CHR 40;33;01 # character device driver +ORPHAN 40;31;01 # symlink to nonexistent file, or non-stat'able file +MISSING 01;05;37;41 # ... and the files they point to +SETUID 37;41 # file that is setuid (u+s) +SETGID 30;43 # file that is setgid (g+s) +CAPABILITY 30;41 # file with capability +STICKY_OTHER_WRITABLE 30;42 # dir that is sticky and other-writable (+t,o+w) +OTHER_WRITABLE 34;42 # dir that is other-writable (o+w) and not sticky +STICKY 37;44 # dir with the sticky bit set (+t) and not other-writable + + +# This is for files with execute permission: +EXEC 00;32 + +# List any file extensions like '.gz' or '.tar' that you would like ls +# to colorize below. Put the extension, a space, and the color init string. +# (and any comments you want to add after a '#') +#.cmd 00;32 # executables (green) +#.exe 00;32 +#.com 00;32 +#.btm 00;32 +#.bat 00;32 +#.sh 00;32 +#.csh 00;32 + +# archives or compressed (red) +.tar 00;31 +.tgz 00;31 +.arc 00;31 +.arj 00;31 +.taz 00;31 +.lha 00;31 +.lz4 00;31 +.lzh 00;31 +.lzma 00;31 +.tlz 00;31 +.txz 00;31 +.tzo 00;31 +.t7z 00;31 +.zip 00;31 +.z 00;31 +.Z 00;31 +.dz 00;31 +.gz 00;31 +.lrz 00;31 +.lz 00;31 +.lzo 00;31 +.xz 00;31 +.bz2 00;31 +.bz 00;31 +.tbz 00;31 +.tbz2 00;31 +.tz 00;31 +.deb 00;31 +.rpm 00;31 +.jar 00;31 +.war 00;31 +.ear 00;31 +.sar 00;31 +.rar 00;31 +.alz 00;31 +.ace 00;31 +.zoo 00;31 +.cpio 00;31 +.7z 00;31 +.rz 00;31 +.cab 00;31 + +# image formats (magenta) +.jpg 00;35 +.jpeg 00;35 +.gif 00;35 +.bmp 00;35 +.pbm 00;35 +.pgm 00;35 +.ppm 00;35 +.tga 00;35 +.xbm 00;35 +.xpm 00;35 +.tif 00;35 +.tiff 00;35 +.png 00;35 +.svg 00;35 +.svgz 00;35 +.mng 00;35 +.pcx 00;35 +.mov 00;35 +.mpg 00;35 +.mpeg 00;35 +.m2v 00;35 +.mkv 00;35 +.webm 00;35 +.ogm 00;35 +.mp4 00;35 +.m4v 00;35 +.mp4v 00;35 +.vob 00;35 +.qt 00;35 +.nuv 00;35 +.wmv 00;35 +.asf 00;35 +.rm 00;35 +.rmvb 00;35 +.flc 00;35 +.avi 00;35 +.fli 00;35 +.flv 00;35 +.gl 00;35 +.dl 00;35 +.xcf 00;35 +.xwd 00;35 +.yuv 00;35 +.cgm 00;35 +.emf 00;35 + +# http://wiki.xiph.org/index.php/MIME_Types_and_File_Extensions +.axv 00;35 +.anx 00;35 +.ogv 00;35 +.ogx 00;35 + +# audio formats (cyan) +.aac 00;36 +.au 00;36 +.flac 00;36 +.mid 00;36 +.midi 00;36 +.mka 00;36 +.mp3 00;36 +.mpc 00;36 +.ogg 00;36 +.ra 00;36 +.wav 00;36 + +# http://wiki.xiph.org/index.php/MIME_Types_and_File_Extensions +.axa 00;36 +.oga 00;36 +.spx 00;36 +.xspf 00;36 + +# colorize binary documents (brown) +#.pdf 00;33 +#.ps 00;33 +#.ps.gz 00;33 +#.tex 00;33 +#.xls 00;33 +#.xlsx 00;33 +#.ppt 00;33 +#.pptx 00;33 +#.rtf 00;33 +#.doc 00;33 +#.docx 00;33 +#.odt 00;33 +#.ods 00;33 +#.odp 00;33 +#.epub 00;33 +#.abw 00;33 +#.wpd 00;33 +# +# colorize text documents (brown) +#.txt 00;33 +#.patch 00;33 +#.diff 00;33 +#.log 00;33 +#.htm 00;33 +#.html 00;33 +#.shtml 00;33 +#.xml 00;33 diff --git a/SOURCES/coreutils-colorls.csh b/SOURCES/coreutils-colorls.csh new file mode 100755 index 0000000..f631762 --- /dev/null +++ b/SOURCES/coreutils-colorls.csh @@ -0,0 +1,68 @@ +# skip everything for non-interactive shells +if (! $?prompt) exit + +# color-ls initialization +if ( $?USER_LS_COLORS ) then + if ( "$USER_LS_COLORS" != "" ) then + #when USER_LS_COLORS defined do not override user + #specified LS_COLORS and use them + goto finish + endif +endif + +alias ll 'ls -l' +alias l. 'ls -d .*' +set COLORS=/etc/DIR_COLORS + +if ($?TERM) then + if ( -e "/etc/DIR_COLORS.256color" ) then + if ( "`/usr/bin/tput colors`" == "256" ) then + set COLORS=/etc/DIR_COLORS.256color + endif + endif + if ( -e "/etc/DIR_COLORS.$TERM" ) then + set COLORS="/etc/DIR_COLORS.$TERM" + endif +endif +if ( -f ~/.dircolors ) set COLORS=~/.dircolors +if ( -f ~/.dir_colors ) set COLORS=~/.dir_colors +if ($?TERM) then + if ( -f ~/.dircolors."$TERM" ) set COLORS=~/.dircolors."$TERM" + if ( -f ~/.dir_colors."$TERM" ) set COLORS=~/.dir_colors."$TERM" +endif +set INCLUDE="`/usr/bin/cat "$COLORS" | /usr/bin/grep '^INCLUDE' | /usr/bin/cut -d ' ' -f2-`" + +if ( ! -e "$COLORS" ) exit + +set _tmp="`/usr/bin/mktemp .colorlsXXX -q --tmpdir=/tmp`" +#if mktemp fails, exit when include was active, otherwise use $COLORS file +if ( "$_tmp" == '' ) then + if ( "$INCLUDE" == '' ) then + eval "`/usr/bin/dircolors -c $COLORS`" + endif + goto cleanup +endif + +if ( "$INCLUDE" != '' ) /usr/bin/cat "$INCLUDE" >> $_tmp +/usr/bin/grep -v '^INCLUDE' "$COLORS" >> $_tmp + +eval "`/usr/bin/dircolors -c $_tmp`" + +/usr/bin/rm -f $_tmp + +if ( "$LS_COLORS" == '' ) exit +cleanup: +set color_none=`/usr/bin/sed -n '/^COLOR.*none/Ip' < $COLORS` +if ( "$color_none" != '' ) then + unset color_none + exit +endif +unset color_none +unset _tmp +unset INCLUDE +unset COLORS + +finish: +alias ll 'ls -l --color=auto' +alias l. 'ls -d .* --color=auto' +alias ls 'ls --color=auto' diff --git a/SOURCES/coreutils-colorls.sh b/SOURCES/coreutils-colorls.sh new file mode 100755 index 0000000..ac92268 --- /dev/null +++ b/SOURCES/coreutils-colorls.sh @@ -0,0 +1,57 @@ +# color-ls initialization + +# Skip all for noninteractive shells. +[ ! -t 0 ] && return + +#when USER_LS_COLORS defined do not override user LS_COLORS, but use them. +if [ -z "$USER_LS_COLORS" ]; then + + alias ll='ls -l' 2>/dev/null + alias l.='ls -d .*' 2>/dev/null + + INCLUDE= + COLORS= + + for colors in "$HOME/.dir_colors.$TERM" "$HOME/.dircolors.$TERM" \ + "$HOME/.dir_colors" "$HOME/.dircolors"; do + [ -e "$colors" ] && COLORS="$colors" && \ + INCLUDE="`/usr/bin/cat "$COLORS" | /usr/bin/grep '^INCLUDE' | /usr/bin/cut -d ' ' -f2-`" && \ + break + done + + [ -z "$COLORS" ] && [ -e "/etc/DIR_COLORS.$TERM" ] && \ + COLORS="/etc/DIR_COLORS.$TERM" + + [ -z "$COLORS" ] && [ -e "/etc/DIR_COLORS.256color" ] && \ + [ "x`/usr/bin/tty -s && /usr/bin/tput colors 2>/dev/null`" = "x256" ] && \ + COLORS="/etc/DIR_COLORS.256color" + + [ -z "$COLORS" ] && [ -e "/etc/DIR_COLORS" ] && \ + COLORS="/etc/DIR_COLORS" + + # Existence of $COLORS already checked above. + [ -n "$COLORS" ] || return + + if [ -e "$INCLUDE" ]; + then + TMP="`/usr/bin/mktemp .colorlsXXX -q --tmpdir=/tmp`" + [ -z "$TMP" ] && return + + /usr/bin/cat "$INCLUDE" >> $TMP + /usr/bin/grep -v '^INCLUDE' "$COLORS" >> $TMP + + eval "`/usr/bin/dircolors --sh $TMP 2>/dev/null`" + /usr/bin/rm -f $TMP + else + eval "`/usr/bin/dircolors --sh $COLORS 2>/dev/null`" + fi + + [ -z "$LS_COLORS" ] && return + /usr/bin/grep -qi "^COLOR.*none" $COLORS >/dev/null 2>/dev/null && return +fi + +unset TMP COLORS INCLUDE + +alias ll='ls -l --color=auto' 2>/dev/null +alias l.='ls -d .* --color=auto' 2>/dev/null +alias ls='ls --color=auto' 2>/dev/null diff --git a/SOURCES/coreutils-df-direct.patch b/SOURCES/coreutils-df-direct.patch new file mode 100644 index 0000000..a52307a --- /dev/null +++ b/SOURCES/coreutils-df-direct.patch @@ -0,0 +1,170 @@ +diff -urNp coreutils-8.21-orig/doc/coreutils.texi coreutils-8.21/doc/coreutils.texi +--- coreutils-8.21-orig/doc/coreutils.texi 2013-02-11 10:37:28.000000000 +0100 ++++ coreutils-8.21/doc/coreutils.texi 2013-02-15 10:15:26.497593689 +0100 +@@ -10961,6 +10961,13 @@ pseudo-file-systems, such as automounter + Scale sizes by @var{size} before printing them (@pxref{Block size}). + For example, @option{-BG} prints sizes in units of 1,073,741,824 bytes. + ++@item --direct ++@opindex --direct ++@cindex direct statfs for a file ++Do not resolve mount point and show statistics directly for a file. It can be ++especially useful for NFS mount points if there is a boundary between two ++storage policies behind the mount point. ++ + @item --total + @opindex --total + @cindex grand total of disk size, usage and available space +diff -urNp coreutils-8.21-orig/src/df.c coreutils-8.21/src/df.c +--- coreutils-8.21-orig/src/df.c 2013-02-05 00:40:31.000000000 +0100 ++++ coreutils-8.21/src/df.c 2013-02-15 10:26:41.158651782 +0100 +@@ -116,6 +116,9 @@ static bool print_type; + /* If true, print a grand total at the end. */ + static bool print_grand_total; + ++/* If true, show statistics for a file instead of mount point. */ ++static bool direct_statfs; ++ + /* Grand total data. */ + static struct fs_usage grand_fsu; + +@@ -238,13 +241,15 @@ enum + NO_SYNC_OPTION = CHAR_MAX + 1, + SYNC_OPTION, + TOTAL_OPTION, +- OUTPUT_OPTION ++ OUTPUT_OPTION, ++ DIRECT_OPTION + }; + + static struct option const long_options[] = + { + {"all", no_argument, NULL, 'a'}, + {"block-size", required_argument, NULL, 'B'}, ++ {"direct", no_argument, NULL, DIRECT_OPTION}, + {"inodes", no_argument, NULL, 'i'}, + {"human-readable", no_argument, NULL, 'h'}, + {"si", no_argument, NULL, 'H'}, +@@ -500,7 +505,10 @@ get_header (void) + for (col = 0; col < ncolumns; col++) + { + char *cell = NULL; +- char const *header = _(columns[col]->caption); ++ char const *header = (columns[col]->field == TARGET_FIELD ++ && direct_statfs)? ++ _("File") : ++ _(columns[col]->caption); + + if (columns[col]->field == SIZE_FIELD + && (header_mode == DEFAULT_MODE +@@ -1150,6 +1158,19 @@ get_point (const char *point, const stru + static void + get_entry (char const *name, struct stat const *statp) + { ++ if (direct_statfs) ++ { ++ char *resolved = canonicalize_file_name (name); ++ if (resolved) ++ { ++ char *mp = find_mount_point (name, statp); ++ get_dev (NULL, mp, resolved, NULL, NULL, false, false, NULL, false); ++ free(mp); ++ free (resolved); ++ return; ++ } ++ } ++ + if ((S_ISBLK (statp->st_mode) || S_ISCHR (statp->st_mode)) + && get_disk (name)) + return; +@@ -1219,6 +1238,7 @@ or all file systems by default.\n\ + -B, --block-size=SIZE scale sizes by SIZE before printing them; e.g.,\n\ + '-BM' prints sizes in units of 1,048,576 bytes;\n\ + see SIZE format below\n\ ++ --direct show statistics for a file instead of mount point\n\ + --total produce a grand total\n\ + -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\ + \n\ +@@ -1305,6 +1325,9 @@ main (int argc, char **argv) + xstrtol_fatal (e, oi, c, long_options, optarg); + } + break; ++ case DIRECT_OPTION: ++ direct_statfs = true; ++ break; + case 'i': + if (header_mode == OUTPUT_MODE) + { +@@ -1408,6 +1431,13 @@ main (int argc, char **argv) + } + } + ++ if (direct_statfs && show_local_fs) ++ { ++ error (0, 0, _("options --direct and --local (-l) are mutually " ++ "exclusive")); ++ usage (EXIT_FAILURE); ++ } ++ + if (human_output_opts == -1) + { + if (posix_format) +diff -urNp coreutils-8.21-orig/tests/df/direct.sh coreutils-8.21/tests/df/direct.sh +--- coreutils-8.21-orig/tests/df/direct.sh 1970-01-01 01:00:00.000000000 +0100 ++++ coreutils-8.21/tests/df/direct.sh 2013-02-15 10:15:26.503644446 +0100 +@@ -0,0 +1,55 @@ ++#!/bin/sh ++# Ensure "df --direct" works as documented ++ ++# Copyright (C) 2010 Free Software Foundation, Inc. ++ ++# This program is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++ ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++ ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++. "${srcdir=.}/init.sh"; path_prepend_ ../src ++print_ver_ df ++ ++df || skip_ "df fails" ++ ++DIR=`pwd` || framework_failure ++FILE="$DIR/file" ++touch "$FILE" || framework_failure ++echo "$FILE" > file_exp || framework_failure ++echo "Mounted on" > header_mounted_exp || framework_failure ++echo "File" > header_file_exp || framework_failure ++ ++fail=0 ++ ++df --portability "$FILE" > df_out || fail=1 ++df --portability --direct "$FILE" > df_direct_out || fail=1 ++df --portability --direct --local "$FILE" > /dev/null 2>&1 && fail=1 ++ ++# check df header ++$AWK '{ if (NR==1) print $6 " " $7; }' df_out > header_mounted_out \ ++ || framework_failure ++$AWK '{ if (NR==1) print $6; }' df_direct_out > header_file_out \ ++ || framework_failure ++compare header_mounted_out header_mounted_exp || fail=1 ++compare header_file_out header_file_exp || fail=1 ++ ++# check df output (without --direct) ++$AWK '{ if (NR==2) print $6; }' df_out > file_out \ ++ || framework_failure ++compare file_out file_exp && fail=1 ++ ++# check df output (with --direct) ++$AWK '{ if (NR==2) print $6; }' df_direct_out > file_out \ ++ || framework_failure ++compare file_out file_exp || fail=1 ++ ++Exit $fail diff --git a/SOURCES/coreutils-getgrouplist.patch b/SOURCES/coreutils-getgrouplist.patch new file mode 100644 index 0000000..86bbcef --- /dev/null +++ b/SOURCES/coreutils-getgrouplist.patch @@ -0,0 +1,86 @@ +diff --git a/lib/getugroups.c b/lib/getugroups.c +index 299bae6..8ece29b 100644 +--- a/lib/getugroups.c ++++ b/lib/getugroups.c +@@ -19,6 +19,9 @@ + + #include + ++/* We do not need this code if getgrouplist(3) is available. */ ++#ifndef HAVE_GETGROUPLIST ++ + #include "getugroups.h" + + #include +@@ -123,3 +126,4 @@ getugroups (int maxcount, gid_t *grouplist, char const *username, + } + + #endif /* HAVE_GRP_H */ ++#endif /* have getgrouplist */ +diff --git a/lib/mgetgroups.c b/lib/mgetgroups.c +index 76474c2..0a9d221 100644 +--- a/lib/mgetgroups.c ++++ b/lib/mgetgroups.c +@@ -115,9 +115,17 @@ mgetgroups (char const *username, gid_t gid, gid_t **groups) + /* else no username, so fall through and use getgroups. */ + #endif + +- max_n_groups = (username +- ? getugroups (0, NULL, username, gid) +- : getgroups (0, NULL)); ++ if (!username) ++ max_n_groups = getgroups(0, NULL); ++ else ++ { ++#ifdef HAVE_GETGROUPLIST ++ max_n_groups = 0; ++ getgrouplist (username, gid, NULL, &max_n_groups); ++#else ++ max_n_groups = getugroups (0, NULL, username, gid); ++#endif ++ } + + /* If we failed to count groups because there is no supplemental + group support, then return an array containing just GID. +@@ -139,10 +147,25 @@ mgetgroups (char const *username, gid_t gid, gid_t **groups) + if (g == NULL) + return -1; + +- ng = (username +- ? getugroups (max_n_groups, g, username, gid) +- : getgroups (max_n_groups - (gid != (gid_t) -1), +- g + (gid != (gid_t) -1))); ++ if (!username) ++ ng = getgroups (max_n_groups - (gid != (gid_t)-1), g + (gid != (gid_t)-1)); ++ else ++ { ++#ifdef HAVE_GETGROUPLIST ++ int e; ++ ng = max_n_groups; ++ while ((e = getgrouplist (username, gid, g, &ng)) == -1 ++ && ng > max_n_groups) ++ { ++ max_n_groups = ng; ++ g = xrealloc (g, max_n_groups * sizeof (GETGROUPS_T)); ++ } ++ if (e == -1) ++ ng = -1; ++#else ++ ng = getugroups (max_n_groups, g, username, gid); ++#endif ++ } + + if (ng < 0) + { +diff --git a/m4/jm-macros.m4 b/m4/jm-macros.m4 +index 62777c7..5180243 100644 +--- a/m4/jm-macros.m4 ++++ b/m4/jm-macros.m4 +@@ -78,6 +78,7 @@ + fchown + fchmod + ftruncate ++ getgrouplist + iswspace + mkfifo + mbrlen diff --git a/SOURCES/coreutils-i18n-fold-newline.patch b/SOURCES/coreutils-i18n-fold-newline.patch new file mode 100644 index 0000000..8c3a146 --- /dev/null +++ b/SOURCES/coreutils-i18n-fold-newline.patch @@ -0,0 +1,83 @@ +From 493f1291993a352e47a79fa7471880289df2efc4 Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Fri, 3 Feb 2017 12:26:53 +0100 +Subject: [PATCH] fold: preserve new-lines in mutlibyte text (#1418505) + +--- + src/fold.c | 55 +++++++++++++++++++++++++++---------------------------- + 1 file changed, 27 insertions(+), 28 deletions(-) + +diff --git a/src/fold.c b/src/fold.c +index 51abea8..4106f24 100644 +--- a/src/fold.c ++++ b/src/fold.c +@@ -342,39 +342,38 @@ fold_multibyte_text (FILE *istream, size_t width, int *saved_errno) + } + + rescan: +- if (operating_mode == byte_mode) /* byte mode */ ++ if (convfail) ++ increment = 1; ++ else if (wc == L'\n') ++ { ++ /* preserve newline */ ++ fwrite (line_out, sizeof(char), offset_out, stdout); ++ START_NEW_LINE; ++ continue; ++ } ++ else if (operating_mode == byte_mode) /* byte mode */ + increment = mblength; + else if (operating_mode == character_mode) /* character mode */ + increment = 1; +- else /* column mode */ ++ else /* column mode */ + { +- if (convfail) +- increment = 1; +- else ++ switch (wc) + { +- switch (wc) +- { +- case L'\n': +- fwrite (line_out, sizeof(char), offset_out, stdout); +- START_NEW_LINE; +- continue; +- +- case L'\b': +- increment = (column > 0) ? -1 : 0; +- break; +- +- case L'\r': +- increment = -1 * column; +- break; +- +- case L'\t': +- increment = 8 - column % 8; +- break; +- +- default: +- increment = wcwidth (wc); +- increment = (increment < 0) ? 0 : increment; +- } ++ case L'\b': ++ increment = (column > 0) ? -1 : 0; ++ break; ++ ++ case L'\r': ++ increment = -1 * column; ++ break; ++ ++ case L'\t': ++ increment = 8 - column % 8; ++ break; ++ ++ default: ++ increment = wcwidth (wc); ++ increment = (increment < 0) ? 0 : increment; + } + } + +-- +2.13.5 + diff --git a/SOURCES/coreutils-i18n-sort-memleak.patch b/SOURCES/coreutils-i18n-sort-memleak.patch new file mode 100644 index 0000000..2819b77 --- /dev/null +++ b/SOURCES/coreutils-i18n-sort-memleak.patch @@ -0,0 +1,103 @@ +From e16ae8b0f8a16f05d5881ad282bd58b31645a34f Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Fri, 15 Jun 2018 12:47:38 +0200 +Subject: [PATCH] Resolves: #1259942 - fix memory leak in sort/I18N +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Patches written by Pádraig. + +Note that the corresponding i18n/sort-month test was not included +because it breaks unless sort is compiled -Dlint and we do not want +to decrease performance of the resulting RPMs (and valgrind is not +installed in production buildroots anyway). +--- + src/sort.c | 37 ++++++++++++++++++++++--------------- + 1 file changed, 22 insertions(+), 15 deletions(-) + +diff --git a/src/sort.c b/src/sort.c +index e47b039..c04b513 100644 +--- a/src/sort.c ++++ b/src/sort.c +@@ -2861,8 +2861,8 @@ getmonth_mb (const char *s, size_t len, char **ea) + register int lo = 0, hi = MONTHS_PER_YEAR, result; + char *tmp; + size_t wclength, mblength; +- const char **pp; +- const wchar_t **wpp; ++ const char *pp; ++ const wchar_t *wpp; + wchar_t *month_wcs; + mbstate_t state; + +@@ -2875,17 +2875,19 @@ getmonth_mb (const char *s, size_t len, char **ea) + if (len == 0) + return 0; + +- month = (char *) xmalloc (len + 1); ++ if (SIZE_MAX - len < 1) ++ xalloc_die (); ++ ++ month = (char *) xnmalloc (len + 1, MB_CUR_MAX); + +- tmp = (char *) xmalloc (len + 1); ++ pp = tmp = (char *) xnmalloc (len + 1, MB_CUR_MAX); + memcpy (tmp, s, len); + tmp[len] = '\0'; +- pp = (const char **)&tmp; +- month_wcs = (wchar_t *) xmalloc ((len + 1) * sizeof (wchar_t)); +- memset (&state, '\0', sizeof(mbstate_t)); ++ wpp = month_wcs = (wchar_t *) xnmalloc (len + 1, sizeof (wchar_t)); ++ memset (&state, '\0', sizeof (mbstate_t)); + +- wclength = mbsrtowcs (month_wcs, pp, len + 1, &state); +- if (wclength == (size_t)-1 || *pp != NULL) ++ wclength = mbsrtowcs (month_wcs, &pp, len + 1, &state); ++ if (wclength == (size_t)-1 || pp != NULL) + error (SORT_FAILURE, 0, _("Invalid multibyte input %s."), quote(s)); + + for (i = 0; i < wclength; i++) +@@ -2898,10 +2900,8 @@ getmonth_mb (const char *s, size_t len, char **ea) + } + } + +- wpp = (const wchar_t **)&month_wcs; +- +- mblength = wcsrtombs (month, wpp, len + 1, &state); +- assert (mblength != (-1) && *wpp == NULL); ++ mblength = wcsrtombs (month, &wpp, (len + 1) * MB_CUR_MAX, &state); ++ assert (mblength != (-1) && wpp == NULL); + + do + { +@@ -5363,10 +5363,10 @@ main (int argc, char **argv) + + if (nfiles == 0) + { +- static char *minus = (char *) "-"; + nfiles = 1; + free (files); +- files = − ++ files = xmalloc (sizeof *files); ++ *files = (char *) "-"; + } + + /* Need to re-check that we meet the minimum requirement for memory +@@ -5424,6 +5424,13 @@ main (int argc, char **argv) + sort (files, nfiles, outfile, nthreads); + } + ++#ifdef lint ++ if (files_from) ++ readtokens0_free (&tok); ++ else ++ free (files); ++#endif ++ + if (have_read_stdin && fclose (stdin) == EOF) + die (_("close failed"), "-"); + +-- +2.14.4 + diff --git a/SOURCES/coreutils-i18n.patch b/SOURCES/coreutils-i18n.patch new file mode 100644 index 0000000..a3c7b33 --- /dev/null +++ b/SOURCES/coreutils-i18n.patch @@ -0,0 +1,4751 @@ +diff -urNp coreutils-8.22-orig/lib/linebuffer.h coreutils-8.22/lib/linebuffer.h +--- coreutils-8.22-orig/lib/linebuffer.h 2013-12-04 15:53:33.000000000 +0100 ++++ coreutils-8.22/lib/linebuffer.h 2014-01-08 13:55:56.106375471 +0100 +@@ -21,6 +21,11 @@ + + # include + ++/* Get mbstate_t. */ ++# if HAVE_WCHAR_H ++# include ++# endif ++ + /* A 'struct linebuffer' holds a line of text. */ + + struct linebuffer +@@ -28,6 +33,9 @@ struct linebuffer + size_t size; /* Allocated. */ + size_t length; /* Used. */ + char *buffer; ++# if HAVE_WCHAR_H ++ mbstate_t state; ++# endif + }; + + /* Initialize linebuffer LINEBUFFER for use. */ +diff -urNp coreutils-8.22-orig/src/cut.c coreutils-8.22/src/cut.c +--- coreutils-8.22-orig/src/cut.c 2013-12-04 15:48:30.000000000 +0100 ++++ coreutils-8.22/src/cut.c 2014-01-08 13:55:56.108375451 +0100 +@@ -28,6 +28,11 @@ + #include + #include + #include ++ ++/* Get mbstate_t, mbrtowc(). */ ++#if HAVE_WCHAR_H ++# include ++#endif + #include "system.h" + + #include "error.h" +@@ -37,6 +42,18 @@ + #include "quote.h" + #include "xstrndup.h" + ++/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC ++ installation; work around this configuration error. */ ++#if !defined MB_LEN_MAX || MB_LEN_MAX < 2 ++# undef MB_LEN_MAX ++# define MB_LEN_MAX 16 ++#endif ++ ++/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ ++#if HAVE_MBRTOWC && defined mbstate_t ++# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) ++#endif ++ + /* The official name of this program (e.g., no 'g' prefix). */ + #define PROGRAM_NAME "cut" + +@@ -53,6 +70,52 @@ + } \ + while (0) + ++/* Refill the buffer BUF to get a multibyte character. */ ++#define REFILL_BUFFER(BUF, BUFPOS, BUFLEN, STREAM) \ ++ do \ ++ { \ ++ if (BUFLEN < MB_LEN_MAX && !feof (STREAM) && !ferror (STREAM)) \ ++ { \ ++ memmove (BUF, BUFPOS, BUFLEN); \ ++ BUFLEN += fread (BUF + BUFLEN, sizeof(char), BUFSIZ, STREAM); \ ++ BUFPOS = BUF; \ ++ } \ ++ } \ ++ while (0) ++ ++/* Get wide character on BUFPOS. BUFPOS is not included after that. ++ If byte sequence is not valid as a character, CONVFAIL is true. Otherwise false. */ ++#define GET_NEXT_WC_FROM_BUFFER(WC, BUFPOS, BUFLEN, MBLENGTH, STATE, CONVFAIL) \ ++ do \ ++ { \ ++ mbstate_t state_bak; \ ++ \ ++ if (BUFLEN < 1) \ ++ { \ ++ WC = WEOF; \ ++ break; \ ++ } \ ++ \ ++ /* Get a wide character. */ \ ++ CONVFAIL = false; \ ++ state_bak = STATE; \ ++ MBLENGTH = mbrtowc ((wchar_t *)&WC, BUFPOS, BUFLEN, &STATE); \ ++ \ ++ switch (MBLENGTH) \ ++ { \ ++ case (size_t)-1: \ ++ case (size_t)-2: \ ++ CONVFAIL = true; \ ++ STATE = state_bak; \ ++ /* Fall througn. */ \ ++ \ ++ case 0: \ ++ MBLENGTH = 1; \ ++ break; \ ++ } \ ++ } \ ++ while (0) ++ + + struct range_pair + { +@@ -75,6 +138,8 @@ static size_t n_rp; + /* Number of `struct range_pair's allocated. */ + static size_t n_rp_allocated; + ++/* Length of the delimiter given as argument to -d. */ ++size_t delimlen; + + /* Append LOW, HIGH to the list RP of range pairs, allocating additional + space if necessary. Update global variable N_RP. When allocating, +@@ -106,15 +171,25 @@ enum operating_mode + { + undefined_mode, + +- /* Output characters that are in the given bytes. */ ++ /* Output bytes that are at the given positions. */ + byte_mode, + ++ /* Output characters that are at the given positions. */ ++ character_mode, ++ + /* Output the given delimeter-separated fields. */ + field_mode + }; + + static enum operating_mode operating_mode; + ++/* If nonzero, when in byte mode, don't split multibyte characters. */ ++static int byte_mode_character_aware; ++ ++/* If nonzero, the function for single byte locale is work ++ if this program runs on multibyte locale. */ ++static int force_singlebyte_mode; ++ + /* If true do not output lines containing no delimeter characters. + Otherwise, all such lines are printed. This option is valid only + with field mode. */ +@@ -126,6 +201,9 @@ static bool complement; + + /* The delimeter character for field mode. */ + static unsigned char delim; ++#if HAVE_WCHAR_H ++static wchar_t wcdelim; ++#endif + + /* True if the --output-delimiter=STRING option was specified. */ + static bool output_delimiter_specified; +@@ -188,7 +266,7 @@ Print selected parts of lines from each + -f, --fields=LIST select only these fields; also print any line\n\ + that contains no delimiter character, unless\n\ + the -s option is specified\n\ +- -n (ignored)\n\ ++ -n with -b: don't split multibyte characters\n\ + "), stdout); + fputs (_("\ + --complement complement the set of selected bytes, characters\n\ +@@ -381,6 +459,9 @@ set_fields (const char *fieldstr) + if (operating_mode == byte_mode) + error (0, 0, + _("byte offset %s is too large"), quote (bad_num)); ++ else if (operating_mode == character_mode) ++ error (0, 0, ++ _("character offset %s is too large"), quote (bad_num)); + else + error (0, 0, + _("field number %s is too large"), quote (bad_num)); +@@ -505,6 +586,82 @@ cut_bytes (FILE *stream) + } + } + ++#if HAVE_MBRTOWC ++/* This function is in use for the following case. ++ ++ 1. Read from the stream STREAM, printing to standard output any selected ++ characters. ++ ++ 2. Read from stream STREAM, printing to standard output any selected bytes, ++ without splitting multibyte characters. */ ++ ++static void ++cut_characters_or_cut_bytes_no_split (FILE *stream) ++{ ++ size_t idx; /* number of bytes or characters in the line so far. */ ++ char buf[MB_LEN_MAX + BUFSIZ]; /* For spooling a read byte sequence. */ ++ char *bufpos; /* Next read position of BUF. */ ++ size_t buflen; /* The length of the byte sequence in buf. */ ++ wint_t wc; /* A gotten wide character. */ ++ size_t mblength; /* The byte size of a multibyte character which shows ++ as same character as WC. */ ++ mbstate_t state; /* State of the stream. */ ++ bool convfail = false; /* true, when conversion failed. Otherwise false. */ ++ /* Whether to begin printing delimiters between ranges for the current line. ++ Set after we've begun printing data corresponding to the first range. */ ++ bool print_delimiter = false; ++ ++ idx = 0; ++ buflen = 0; ++ bufpos = buf; ++ memset (&state, '\0', sizeof(mbstate_t)); ++ ++ current_rp = rp; ++ ++ while (1) ++ { ++ REFILL_BUFFER (buf, bufpos, buflen, stream); ++ ++ GET_NEXT_WC_FROM_BUFFER (wc, bufpos, buflen, mblength, state, convfail); ++ (void) convfail; /* ignore unused */ ++ ++ if (wc == WEOF) ++ { ++ if (idx > 0) ++ putchar ('\n'); ++ break; ++ } ++ else if (wc == L'\n') ++ { ++ putchar ('\n'); ++ idx = 0; ++ print_delimiter = false; ++ current_rp = rp; ++ } ++ else ++ { ++ next_item (&idx); ++ if (print_kth (idx)) ++ { ++ if (output_delimiter_specified) ++ { ++ if (print_delimiter && is_range_start_index (idx)) ++ { ++ fwrite (output_delimiter_string, sizeof (char), ++ output_delimiter_length, stdout); ++ } ++ print_delimiter = true; ++ } ++ fwrite (bufpos, mblength, sizeof(char), stdout); ++ } ++ } ++ ++ buflen -= mblength; ++ bufpos += mblength; ++ } ++} ++#endif ++ + /* Read from stream STREAM, printing to standard output any selected fields. */ + + static void +@@ -629,13 +786,211 @@ cut_fields (FILE *stream) + } + } + ++#if HAVE_MBRTOWC ++static void ++cut_fields_mb (FILE *stream) ++{ ++ int c; ++ size_t field_idx; ++ int found_any_selected_field; ++ int buffer_first_field; ++ int empty_input; ++ char buf[MB_LEN_MAX + BUFSIZ]; /* For spooling a read byte sequence. */ ++ char *bufpos; /* Next read position of BUF. */ ++ size_t buflen; /* The length of the byte sequence in buf. */ ++ wint_t wc = 0; /* A gotten wide character. */ ++ size_t mblength; /* The byte size of a multibyte character which shows ++ as same character as WC. */ ++ mbstate_t state; /* State of the stream. */ ++ bool convfail = false; /* true, when conversion failed. Otherwise false. */ ++ ++ current_rp = rp; ++ ++ found_any_selected_field = 0; ++ field_idx = 1; ++ bufpos = buf; ++ buflen = 0; ++ memset (&state, '\0', sizeof(mbstate_t)); ++ ++ c = getc (stream); ++ empty_input = (c == EOF); ++ if (c != EOF) ++ { ++ ungetc (c, stream); ++ wc = 0; ++ } ++ else ++ wc = WEOF; ++ ++ /* To support the semantics of the -s flag, we may have to buffer ++ all of the first field to determine whether it is `delimited.' ++ But that is unnecessary if all non-delimited lines must be printed ++ and the first field has been selected, or if non-delimited lines ++ must be suppressed and the first field has *not* been selected. ++ That is because a non-delimited line has exactly one field. */ ++ buffer_first_field = (suppress_non_delimited ^ !print_kth (1)); ++ ++ while (1) ++ { ++ if (field_idx == 1 && buffer_first_field) ++ { ++ int len = 0; ++ ++ while (1) ++ { ++ REFILL_BUFFER (buf, bufpos, buflen, stream); ++ ++ GET_NEXT_WC_FROM_BUFFER ++ (wc, bufpos, buflen, mblength, state, convfail); ++ ++ if (wc == WEOF) ++ break; ++ ++ field_1_buffer = xrealloc (field_1_buffer, len + mblength); ++ memcpy (field_1_buffer + len, bufpos, mblength); ++ len += mblength; ++ buflen -= mblength; ++ bufpos += mblength; ++ ++ if (!convfail && (wc == L'\n' || wc == wcdelim)) ++ break; ++ } ++ ++ if (len <= 0 && wc == WEOF) ++ break; ++ ++ /* If the first field extends to the end of line (it is not ++ delimited) and we are printing all non-delimited lines, ++ print this one. */ ++ if (convfail || (!convfail && wc != wcdelim)) ++ { ++ if (suppress_non_delimited) ++ { ++ /* Empty. */ ++ } ++ else ++ { ++ fwrite (field_1_buffer, sizeof (char), len, stdout); ++ /* Make sure the output line is newline terminated. */ ++ if (convfail || (!convfail && wc != L'\n')) ++ putchar ('\n'); ++ } ++ continue; ++ } ++ ++ if (print_kth (1)) ++ { ++ /* Print the field, but not the trailing delimiter. */ ++ fwrite (field_1_buffer, sizeof (char), len - 1, stdout); ++ found_any_selected_field = 1; ++ } ++ next_item (&field_idx); ++ } ++ ++ if (wc != WEOF) ++ { ++ if (print_kth (field_idx)) ++ { ++ if (found_any_selected_field) ++ { ++ fwrite (output_delimiter_string, sizeof (char), ++ output_delimiter_length, stdout); ++ } ++ found_any_selected_field = 1; ++ } ++ ++ while (1) ++ { ++ REFILL_BUFFER (buf, bufpos, buflen, stream); ++ ++ GET_NEXT_WC_FROM_BUFFER ++ (wc, bufpos, buflen, mblength, state, convfail); ++ ++ if (wc == WEOF) ++ break; ++ else if (!convfail && (wc == wcdelim || wc == L'\n')) ++ { ++ buflen -= mblength; ++ bufpos += mblength; ++ break; ++ } ++ ++ if (print_kth (field_idx)) ++ fwrite (bufpos, mblength, sizeof(char), stdout); ++ ++ buflen -= mblength; ++ bufpos += mblength; ++ } ++ } ++ ++ if ((!convfail || wc == L'\n') && buflen < 1) ++ wc = WEOF; ++ ++ if (!convfail && wc == wcdelim) ++ next_item (&field_idx); ++ else if (wc == WEOF || (!convfail && wc == L'\n')) ++ { ++ if (found_any_selected_field ++ || (!empty_input && !(suppress_non_delimited && field_idx == 1))) ++ putchar ('\n'); ++ if (wc == WEOF) ++ break; ++ field_idx = 1; ++ current_rp = rp; ++ found_any_selected_field = 0; ++ } ++ } ++} ++#endif ++ + static void + cut_stream (FILE *stream) + { +- if (operating_mode == byte_mode) +- cut_bytes (stream); ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1 && !force_singlebyte_mode) ++ { ++ switch (operating_mode) ++ { ++ case byte_mode: ++ if (byte_mode_character_aware) ++ cut_characters_or_cut_bytes_no_split (stream); ++ else ++ cut_bytes (stream); ++ break; ++ ++ case character_mode: ++ cut_characters_or_cut_bytes_no_split (stream); ++ break; ++ ++ case field_mode: ++ if (delimlen == 1) ++ { ++ /* Check if we have utf8 multibyte locale, so we can use this ++ optimization because of uniqueness of characters, which is ++ not true for e.g. SJIS */ ++ char * loc = setlocale(LC_CTYPE, NULL); ++ if (loc && (strstr (loc, "UTF-8") || strstr (loc, "utf-8") || ++ strstr (loc, "UTF8") || strstr (loc, "utf8"))) ++ { ++ cut_fields (stream); ++ break; ++ } ++ } ++ cut_fields_mb (stream); ++ break; ++ ++ default: ++ abort (); ++ } ++ } + else +- cut_fields (stream); ++#endif ++ { ++ if (operating_mode == field_mode) ++ cut_fields (stream); ++ else ++ cut_bytes (stream); ++ } + } + + /* Process file FILE to standard output. +@@ -687,6 +1042,7 @@ main (int argc, char **argv) + bool ok; + bool delim_specified = false; + char *spec_list_string IF_LINT ( = NULL); ++ char mbdelim[MB_LEN_MAX + 1]; + + initialize_main (&argc, &argv); + set_program_name (argv[0]); +@@ -709,7 +1065,6 @@ main (int argc, char **argv) + switch (optc) + { + case 'b': +- case 'c': + /* Build the byte list. */ + if (operating_mode != undefined_mode) + FATAL_ERROR (_("only one type of list may be specified")); +@@ -717,6 +1072,14 @@ main (int argc, char **argv) + spec_list_string = optarg; + break; + ++ case 'c': ++ /* Build the character list. */ ++ if (operating_mode != undefined_mode) ++ FATAL_ERROR (_("only one type of list may be specified")); ++ operating_mode = character_mode; ++ spec_list_string = optarg; ++ break; ++ + case 'f': + /* Build the field list. */ + if (operating_mode != undefined_mode) +@@ -728,10 +1091,38 @@ main (int argc, char **argv) + case 'd': + /* New delimiter. */ + /* Interpret -d '' to mean 'use the NUL byte as the delimiter.' */ +- if (optarg[0] != '\0' && optarg[1] != '\0') +- FATAL_ERROR (_("the delimiter must be a single character")); +- delim = optarg[0]; +- delim_specified = true; ++ { ++#if HAVE_MBRTOWC ++ if(MB_CUR_MAX > 1) ++ { ++ mbstate_t state; ++ ++ memset (&state, '\0', sizeof(mbstate_t)); ++ delimlen = mbrtowc (&wcdelim, optarg, strnlen(optarg, MB_LEN_MAX), &state); ++ ++ if (delimlen == (size_t)-1 || delimlen == (size_t)-2) ++ ++force_singlebyte_mode; ++ else ++ { ++ delimlen = (delimlen < 1) ? 1 : delimlen; ++ if (wcdelim != L'\0' && *(optarg + delimlen) != '\0') ++ FATAL_ERROR (_("the delimiter must be a single character")); ++ memcpy (mbdelim, optarg, delimlen); ++ mbdelim[delimlen] = '\0'; ++ if (delimlen == 1) ++ delim = *optarg; ++ } ++ } ++ ++ if (MB_CUR_MAX <= 1 || force_singlebyte_mode) ++#endif ++ { ++ if (optarg[0] != '\0' && optarg[1] != '\0') ++ FATAL_ERROR (_("the delimiter must be a single character")); ++ delim = (unsigned char) optarg[0]; ++ } ++ delim_specified = true; ++ } + break; + + case OUTPUT_DELIMITER_OPTION: +@@ -744,6 +1135,7 @@ main (int argc, char **argv) + break; + + case 'n': ++ byte_mode_character_aware = 1; + break; + + case 's': +@@ -783,15 +1175,34 @@ main (int argc, char **argv) + } + + if (!delim_specified) +- delim = '\t'; ++ { ++ delim = '\t'; ++#ifdef HAVE_MBRTOWC ++ wcdelim = L'\t'; ++ mbdelim[0] = '\t'; ++ mbdelim[1] = '\0'; ++ delimlen = 1; ++#endif ++ } + + if (output_delimiter_string == NULL) + { +- static char dummy[2]; +- dummy[0] = delim; +- dummy[1] = '\0'; +- output_delimiter_string = dummy; +- output_delimiter_length = 1; ++#ifdef HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1 && !force_singlebyte_mode) ++ { ++ output_delimiter_string = xstrdup(mbdelim); ++ output_delimiter_length = delimlen; ++ } ++ ++ if (MB_CUR_MAX <= 1 || force_singlebyte_mode) ++#endif ++ { ++ static char dummy[2]; ++ dummy[0] = delim; ++ dummy[1] = '\0'; ++ output_delimiter_string = dummy; ++ output_delimiter_length = 1; ++ } + } + + if (optind == argc) +diff -urNp coreutils-8.22-orig/src/expand.c coreutils-8.22/src/expand.c +--- coreutils-8.22-orig/src/expand.c 2013-12-04 15:48:30.000000000 +0100 ++++ coreutils-8.22/src/expand.c 2014-01-08 13:55:56.110375431 +0100 +@@ -37,12 +37,34 @@ + #include + #include + #include ++ ++/* Get mbstate_t, mbrtowc(), wcwidth(). */ ++#if HAVE_WCHAR_H ++# include ++#endif ++ ++/* Get iswblank(). */ ++#if HAVE_WCTYPE_H ++# include ++#endif ++ + #include "system.h" + #include "error.h" + #include "fadvise.h" + #include "quote.h" + #include "xstrndup.h" + ++/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC ++ installation; work around this configuration error. */ ++#if !defined MB_LEN_MAX || MB_LEN_MAX < 2 ++# define MB_LEN_MAX 16 ++#endif ++ ++/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ ++#if HAVE_MBRTOWC && defined mbstate_t ++# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) ++#endif ++ + /* The official name of this program (e.g., no 'g' prefix). */ + #define PROGRAM_NAME "expand" + +@@ -357,6 +379,142 @@ expand (void) + } + } + ++#if HAVE_MBRTOWC ++static void ++expand_multibyte (void) ++{ ++ FILE *fp; /* Input strem. */ ++ mbstate_t i_state; /* Current shift state of the input stream. */ ++ mbstate_t i_state_bak; /* Back up the I_STATE. */ ++ mbstate_t o_state; /* Current shift state of the output stream. */ ++ char buf[MB_LEN_MAX + BUFSIZ]; /* For spooling a read byte sequence. */ ++ char *bufpos = buf; /* Next read position of BUF. */ ++ size_t buflen = 0; /* The length of the byte sequence in buf. */ ++ wchar_t wc; /* A gotten wide character. */ ++ size_t mblength; /* The byte size of a multibyte character ++ which shows as same character as WC. */ ++ int tab_index = 0; /* Index in `tab_list' of next tabstop. */ ++ int column = 0; /* Column on screen of the next char. */ ++ int next_tab_column; /* Column the next tab stop is on. */ ++ int convert = 1; /* If nonzero, perform translations. */ ++ ++ fp = next_file ((FILE *) NULL); ++ if (fp == NULL) ++ return; ++ ++ memset (&o_state, '\0', sizeof(mbstate_t)); ++ memset (&i_state, '\0', sizeof(mbstate_t)); ++ ++ for (;;) ++ { ++ /* Refill the buffer BUF. */ ++ if (buflen < MB_LEN_MAX && !feof(fp) && !ferror(fp)) ++ { ++ memmove (buf, bufpos, buflen); ++ buflen += fread (buf + buflen, sizeof(char), BUFSIZ, fp); ++ bufpos = buf; ++ } ++ ++ /* No character is left in BUF. */ ++ if (buflen < 1) ++ { ++ fp = next_file (fp); ++ ++ if (fp == NULL) ++ break; /* No more files. */ ++ else ++ { ++ memset (&i_state, '\0', sizeof(mbstate_t)); ++ continue; ++ } ++ } ++ ++ /* Get a wide character. */ ++ i_state_bak = i_state; ++ mblength = mbrtowc (&wc, bufpos, buflen, &i_state); ++ ++ switch (mblength) ++ { ++ case (size_t)-1: /* illegal byte sequence. */ ++ case (size_t)-2: ++ mblength = 1; ++ i_state = i_state_bak; ++ if (convert) ++ { ++ ++column; ++ if (convert_entire_line == 0 && !isblank(*bufpos)) ++ convert = 0; ++ } ++ putchar (*bufpos); ++ break; ++ ++ case 0: /* null. */ ++ mblength = 1; ++ if (convert && convert_entire_line == 0) ++ convert = 0; ++ putchar ('\0'); ++ break; ++ ++ default: ++ if (wc == L'\n') /* LF. */ ++ { ++ tab_index = 0; ++ column = 0; ++ convert = 1; ++ putchar ('\n'); ++ } ++ else if (wc == L'\t' && convert) /* Tab. */ ++ { ++ if (tab_size == 0) ++ { ++ /* Do not let tab_index == first_free_tab; ++ stop when it is 1 less. */ ++ while (tab_index < first_free_tab - 1 ++ && column >= tab_list[tab_index]) ++ tab_index++; ++ next_tab_column = tab_list[tab_index]; ++ if (tab_index < first_free_tab - 1) ++ tab_index++; ++ if (column >= next_tab_column) ++ next_tab_column = column + 1; ++ } ++ else ++ next_tab_column = column + tab_size - column % tab_size; ++ ++ while (column < next_tab_column) ++ { ++ putchar (' '); ++ ++column; ++ } ++ } ++ else /* Others. */ ++ { ++ if (convert) ++ { ++ if (wc == L'\b') ++ { ++ if (column > 0) ++ --column; ++ } ++ else ++ { ++ int width; /* The width of WC. */ ++ ++ width = wcwidth (wc); ++ column += (width > 0) ? width : 0; ++ if (convert_entire_line == 0 && !iswblank(wc)) ++ convert = 0; ++ } ++ } ++ fwrite (bufpos, sizeof(char), mblength, stdout); ++ } ++ } ++ buflen -= mblength; ++ bufpos += mblength; ++ } ++} ++#endif ++ + int + main (int argc, char **argv) + { +@@ -421,7 +579,12 @@ main (int argc, char **argv) + + file_list = (optind < argc ? &argv[optind] : stdin_argv); + +- expand (); ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ expand_multibyte (); ++ else ++#endif ++ expand (); + + if (have_read_stdin && fclose (stdin) != 0) + error (EXIT_FAILURE, errno, "-"); +diff -urNp coreutils-8.22-orig/src/fold.c coreutils-8.22/src/fold.c +--- coreutils-8.22-orig/src/fold.c 2013-12-04 15:48:30.000000000 +0100 ++++ coreutils-8.22/src/fold.c 2014-01-08 13:55:56.111375421 +0100 +@@ -22,12 +22,34 @@ + #include + #include + ++/* Get mbstate_t, mbrtowc(), wcwidth(). */ ++#if HAVE_WCHAR_H ++# include ++#endif ++ ++/* Get iswprint(), iswblank(), wcwidth(). */ ++#if HAVE_WCTYPE_H ++# include ++#endif ++ + #include "system.h" + #include "error.h" + #include "fadvise.h" + #include "quote.h" + #include "xstrtol.h" + ++/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC ++ installation; work around this configuration error. */ ++#if !defined MB_LEN_MAX || MB_LEN_MAX < 2 ++# undef MB_LEN_MAX ++# define MB_LEN_MAX 16 ++#endif ++ ++/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ ++#if HAVE_MBRTOWC && defined mbstate_t ++# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) ++#endif ++ + #define TAB_WIDTH 8 + + /* The official name of this program (e.g., no 'g' prefix). */ +@@ -35,20 +57,41 @@ + + #define AUTHORS proper_name ("David MacKenzie") + ++#define FATAL_ERROR(Message) \ ++ do \ ++ { \ ++ error (0, 0, (Message)); \ ++ usage (2); \ ++ } \ ++ while (0) ++ ++enum operating_mode ++{ ++ /* Fold texts by columns that are at the given positions. */ ++ column_mode, ++ ++ /* Fold texts by bytes that are at the given positions. */ ++ byte_mode, ++ ++ /* Fold texts by characters that are at the given positions. */ ++ character_mode, ++}; ++ ++/* The argument shows current mode. (Default: column_mode) */ ++static enum operating_mode operating_mode; ++ + /* If nonzero, try to break on whitespace. */ + static bool break_spaces; + +-/* If nonzero, count bytes, not column positions. */ +-static bool count_bytes; +- + /* If nonzero, at least one of the files we read was standard input. */ + static bool have_read_stdin; + +-static char const shortopts[] = "bsw:0::1::2::3::4::5::6::7::8::9::"; ++static char const shortopts[] = "bcsw:0::1::2::3::4::5::6::7::8::9::"; + + static struct option const longopts[] = + { + {"bytes", no_argument, NULL, 'b'}, ++ {"characters", no_argument, NULL, 'c'}, + {"spaces", no_argument, NULL, 's'}, + {"width", required_argument, NULL, 'w'}, + {GETOPT_HELP_OPTION_DECL}, +@@ -76,6 +119,7 @@ standard output.\n\ + + fputs (_("\ + -b, --bytes count bytes rather than columns\n\ ++ -c, --characters count characters rather than columns\n\ + -s, --spaces break at spaces\n\ + -w, --width=WIDTH use WIDTH columns instead of 80\n\ + "), stdout); +@@ -93,7 +137,7 @@ standard output.\n\ + static size_t + adjust_column (size_t column, char c) + { +- if (!count_bytes) ++ if (operating_mode != byte_mode) + { + if (c == '\b') + { +@@ -116,30 +160,14 @@ adjust_column (size_t column, char c) + to stdout, with maximum line length WIDTH. + Return true if successful. */ + +-static bool +-fold_file (char const *filename, size_t width) ++static void ++fold_text (FILE *istream, size_t width, int *saved_errno) + { +- FILE *istream; + int c; + size_t column = 0; /* Screen column where next char will go. */ + size_t offset_out = 0; /* Index in 'line_out' for next char. */ + static char *line_out = NULL; + static size_t allocated_out = 0; +- int saved_errno; +- +- if (STREQ (filename, "-")) +- { +- istream = stdin; +- have_read_stdin = true; +- } +- else +- istream = fopen (filename, "r"); +- +- if (istream == NULL) +- { +- error (0, errno, "%s", filename); +- return false; +- } + + fadvise (istream, FADVISE_SEQUENTIAL); + +@@ -169,6 +197,15 @@ fold_file (char const *filename, size_t + bool found_blank = false; + size_t logical_end = offset_out; + ++ /* If LINE_OUT has no wide character, ++ put a new wide character in LINE_OUT ++ if column is bigger than width. */ ++ if (offset_out == 0) ++ { ++ line_out[offset_out++] = c; ++ continue; ++ } ++ + /* Look for the last blank. */ + while (logical_end) + { +@@ -215,11 +252,221 @@ fold_file (char const *filename, size_t + line_out[offset_out++] = c; + } + +- saved_errno = errno; ++ *saved_errno = errno; + + if (offset_out) + fwrite (line_out, sizeof (char), (size_t) offset_out, stdout); + ++} ++ ++#if HAVE_MBRTOWC ++static void ++fold_multibyte_text (FILE *istream, size_t width, int *saved_errno) ++{ ++ char buf[MB_LEN_MAX + BUFSIZ]; /* For spooling a read byte sequence. */ ++ size_t buflen = 0; /* The length of the byte sequence in buf. */ ++ char *bufpos = buf; /* Next read position of BUF. */ ++ wint_t wc; /* A gotten wide character. */ ++ size_t mblength; /* The byte size of a multibyte character which shows ++ as same character as WC. */ ++ mbstate_t state, state_bak; /* State of the stream. */ ++ int convfail = 0; /* 1, when conversion is failed. Otherwise 0. */ ++ ++ static char *line_out = NULL; ++ size_t offset_out = 0; /* Index in `line_out' for next char. */ ++ static size_t allocated_out = 0; ++ ++ int increment; ++ size_t column = 0; ++ ++ size_t last_blank_pos; ++ size_t last_blank_column; ++ int is_blank_seen; ++ int last_blank_increment = 0; ++ int is_bs_following_last_blank; ++ size_t bs_following_last_blank_num; ++ int is_cr_after_last_blank; ++ ++#define CLEAR_FLAGS \ ++ do \ ++ { \ ++ last_blank_pos = 0; \ ++ last_blank_column = 0; \ ++ is_blank_seen = 0; \ ++ is_bs_following_last_blank = 0; \ ++ bs_following_last_blank_num = 0; \ ++ is_cr_after_last_blank = 0; \ ++ } \ ++ while (0) ++ ++#define START_NEW_LINE \ ++ do \ ++ { \ ++ putchar ('\n'); \ ++ column = 0; \ ++ offset_out = 0; \ ++ CLEAR_FLAGS; \ ++ } \ ++ while (0) ++ ++ CLEAR_FLAGS; ++ memset (&state, '\0', sizeof(mbstate_t)); ++ ++ for (;; bufpos += mblength, buflen -= mblength) ++ { ++ if (buflen < MB_LEN_MAX && !feof (istream) && !ferror (istream)) ++ { ++ memmove (buf, bufpos, buflen); ++ buflen += fread (buf + buflen, sizeof(char), BUFSIZ, istream); ++ bufpos = buf; ++ } ++ ++ if (buflen < 1) ++ break; ++ ++ /* Get a wide character. */ ++ state_bak = state; ++ mblength = mbrtowc ((wchar_t *)&wc, bufpos, buflen, &state); ++ ++ switch (mblength) ++ { ++ case (size_t)-1: ++ case (size_t)-2: ++ convfail++; ++ state = state_bak; ++ /* Fall through. */ ++ ++ case 0: ++ mblength = 1; ++ break; ++ } ++ ++rescan: ++ if (operating_mode == byte_mode) /* byte mode */ ++ increment = mblength; ++ else if (operating_mode == character_mode) /* character mode */ ++ increment = 1; ++ else /* column mode */ ++ { ++ if (convfail) ++ increment = 1; ++ else ++ { ++ switch (wc) ++ { ++ case L'\n': ++ fwrite (line_out, sizeof(char), offset_out, stdout); ++ START_NEW_LINE; ++ continue; ++ ++ case L'\b': ++ increment = (column > 0) ? -1 : 0; ++ break; ++ ++ case L'\r': ++ increment = -1 * column; ++ break; ++ ++ case L'\t': ++ increment = 8 - column % 8; ++ break; ++ ++ default: ++ increment = wcwidth (wc); ++ increment = (increment < 0) ? 0 : increment; ++ } ++ } ++ } ++ ++ if (column + increment > width && break_spaces && last_blank_pos) ++ { ++ fwrite (line_out, sizeof(char), last_blank_pos, stdout); ++ putchar ('\n'); ++ ++ offset_out = offset_out - last_blank_pos; ++ column = column - last_blank_column + ((is_cr_after_last_blank) ++ ? last_blank_increment : bs_following_last_blank_num); ++ memmove (line_out, line_out + last_blank_pos, offset_out); ++ CLEAR_FLAGS; ++ goto rescan; ++ } ++ ++ if (column + increment > width && column != 0) ++ { ++ fwrite (line_out, sizeof(char), offset_out, stdout); ++ START_NEW_LINE; ++ goto rescan; ++ } ++ ++ if (allocated_out < offset_out + mblength) ++ { ++ line_out = X2REALLOC (line_out, &allocated_out); ++ } ++ ++ memcpy (line_out + offset_out, bufpos, mblength); ++ offset_out += mblength; ++ column += increment; ++ ++ if (is_blank_seen && !convfail && wc == L'\r') ++ is_cr_after_last_blank = 1; ++ ++ if (is_bs_following_last_blank && !convfail && wc == L'\b') ++ ++bs_following_last_blank_num; ++ else ++ is_bs_following_last_blank = 0; ++ ++ if (break_spaces && !convfail && iswblank (wc)) ++ { ++ last_blank_pos = offset_out; ++ last_blank_column = column; ++ is_blank_seen = 1; ++ last_blank_increment = increment; ++ is_bs_following_last_blank = 1; ++ bs_following_last_blank_num = 0; ++ is_cr_after_last_blank = 0; ++ } ++ } ++ ++ *saved_errno = errno; ++ ++ if (offset_out) ++ fwrite (line_out, sizeof (char), (size_t) offset_out, stdout); ++ ++} ++#endif ++ ++/* Fold file FILENAME, or standard input if FILENAME is "-", ++ to stdout, with maximum line length WIDTH. ++ Return 0 if successful, 1 if an error occurs. */ ++ ++static bool ++fold_file (char const *filename, size_t width) ++{ ++ FILE *istream; ++ int saved_errno; ++ ++ if (STREQ (filename, "-")) ++ { ++ istream = stdin; ++ have_read_stdin = 1; ++ } ++ else ++ istream = fopen (filename, "r"); ++ ++ if (istream == NULL) ++ { ++ error (0, errno, "%s", filename); ++ return 1; ++ } ++ ++ /* Define how ISTREAM is being folded. */ ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ fold_multibyte_text (istream, width, &saved_errno); ++ else ++#endif ++ fold_text (istream, width, &saved_errno); ++ + if (ferror (istream)) + { + error (0, saved_errno, "%s", filename); +@@ -252,7 +499,8 @@ main (int argc, char **argv) + + atexit (close_stdout); + +- break_spaces = count_bytes = have_read_stdin = false; ++ operating_mode = column_mode; ++ break_spaces = have_read_stdin = false; + + while ((optc = getopt_long (argc, argv, shortopts, longopts, NULL)) != -1) + { +@@ -261,7 +509,15 @@ main (int argc, char **argv) + switch (optc) + { + case 'b': /* Count bytes rather than columns. */ +- count_bytes = true; ++ if (operating_mode != column_mode) ++ FATAL_ERROR (_("only one way of folding may be specified")); ++ operating_mode = byte_mode; ++ break; ++ ++ case 'c': ++ if (operating_mode != column_mode) ++ FATAL_ERROR (_("only one way of folding may be specified")); ++ operating_mode = character_mode; + break; + + case 's': /* Break at word boundaries. */ +diff -urNp coreutils-8.22-orig/src/join.c coreutils-8.22/src/join.c +--- coreutils-8.22-orig/src/join.c 2013-12-04 15:48:30.000000000 +0100 ++++ coreutils-8.22/src/join.c 2014-01-08 13:55:56.113375401 +0100 +@@ -22,18 +22,32 @@ + #include + #include + ++/* Get mbstate_t, mbrtowc(), mbrtowc(), wcwidth(). */ ++#if HAVE_WCHAR_H ++# include ++#endif ++ ++/* Get iswblank(), towupper. */ ++#if HAVE_WCTYPE_H ++# include ++#endif ++ + #include "system.h" + #include "error.h" + #include "fadvise.h" + #include "hard-locale.h" + #include "linebuffer.h" +-#include "memcasecmp.h" + #include "quote.h" + #include "stdio--.h" + #include "xmemcoll.h" + #include "xstrtol.h" + #include "argmatch.h" + ++/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ ++#if HAVE_MBRTOWC && defined mbstate_t ++# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) ++#endif ++ + /* The official name of this program (e.g., no 'g' prefix). */ + #define PROGRAM_NAME "join" + +@@ -135,10 +149,12 @@ static struct outlist outlist_head; + /* Last element in 'outlist', where a new element can be added. */ + static struct outlist *outlist_end = &outlist_head; + +-/* Tab character separating fields. If negative, fields are separated +- by any nonempty string of blanks, otherwise by exactly one +- tab character whose value (when cast to unsigned char) equals TAB. */ +-static int tab = -1; ++/* Tab character separating fields. If NULL, fields are separated ++ by any nonempty string of blanks. */ ++static char *tab = NULL; ++ ++/* The number of bytes used for tab. */ ++static size_t tablen = 0; + + /* If nonzero, check that the input is correctly ordered. */ + static enum +@@ -269,13 +285,14 @@ xfields (struct line *line) + if (ptr == lim) + return; + +- if (0 <= tab && tab != '\n') ++ if (tab != NULL) + { ++ unsigned char t = tab[0]; + char *sep; +- for (; (sep = memchr (ptr, tab, lim - ptr)) != NULL; ptr = sep + 1) ++ for (; (sep = memchr (ptr, t, lim - ptr)) != NULL; ptr = sep + 1) + extract_field (line, ptr, sep - ptr); + } +- else if (tab < 0) ++ else + { + /* Skip leading blanks before the first field. */ + while (isblank (to_uchar (*ptr))) +@@ -299,6 +316,147 @@ xfields (struct line *line) + extract_field (line, ptr, lim - ptr); + } + ++#if HAVE_MBRTOWC ++static void ++xfields_multibyte (struct line *line) ++{ ++ char *ptr = line->buf.buffer; ++ char const *lim = ptr + line->buf.length - 1; ++ wchar_t wc = 0; ++ size_t mblength = 1; ++ mbstate_t state, state_bak; ++ ++ memset (&state, 0, sizeof (mbstate_t)); ++ ++ if (ptr >= lim) ++ return; ++ ++ if (tab != NULL) ++ { ++ char *sep = ptr; ++ for (; ptr < lim; ptr = sep + mblength) ++ { ++ sep = ptr; ++ while (sep < lim) ++ { ++ state_bak = state; ++ mblength = mbrtowc (&wc, sep, lim - sep + 1, &state); ++ ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ mblength = 1; ++ state = state_bak; ++ } ++ mblength = (mblength < 1) ? 1 : mblength; ++ ++ if (mblength == tablen && !memcmp (sep, tab, mblength)) ++ break; ++ else ++ { ++ sep += mblength; ++ continue; ++ } ++ } ++ ++ if (sep >= lim) ++ break; ++ ++ extract_field (line, ptr, sep - ptr); ++ } ++ } ++ else ++ { ++ /* Skip leading blanks before the first field. */ ++ while(ptr < lim) ++ { ++ state_bak = state; ++ mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state); ++ ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ mblength = 1; ++ state = state_bak; ++ break; ++ } ++ mblength = (mblength < 1) ? 1 : mblength; ++ ++ if (!iswblank(wc)) ++ break; ++ ptr += mblength; ++ } ++ ++ do ++ { ++ char *sep; ++ state_bak = state; ++ mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state); ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ mblength = 1; ++ state = state_bak; ++ break; ++ } ++ mblength = (mblength < 1) ? 1 : mblength; ++ ++ sep = ptr + mblength; ++ while (sep < lim) ++ { ++ state_bak = state; ++ mblength = mbrtowc (&wc, sep, lim - sep + 1, &state); ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ mblength = 1; ++ state = state_bak; ++ break; ++ } ++ mblength = (mblength < 1) ? 1 : mblength; ++ ++ if (iswblank (wc)) ++ break; ++ ++ sep += mblength; ++ } ++ ++ extract_field (line, ptr, sep - ptr); ++ if (sep >= lim) ++ return; ++ ++ state_bak = state; ++ mblength = mbrtowc (&wc, sep, lim - sep + 1, &state); ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ mblength = 1; ++ state = state_bak; ++ break; ++ } ++ mblength = (mblength < 1) ? 1 : mblength; ++ ++ ptr = sep + mblength; ++ while (ptr < lim) ++ { ++ state_bak = state; ++ mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state); ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ mblength = 1; ++ state = state_bak; ++ break; ++ } ++ mblength = (mblength < 1) ? 1 : mblength; ++ ++ if (!iswblank (wc)) ++ break; ++ ++ ptr += mblength; ++ } ++ } ++ while (ptr < lim); ++ } ++ ++ extract_field (line, ptr, lim - ptr); ++} ++#endif ++ + static void + freeline (struct line *line) + { +@@ -320,56 +478,133 @@ keycmp (struct line const *line1, struct + size_t jf_1, size_t jf_2) + { + /* Start of field to compare in each file. */ +- char *beg1; +- char *beg2; +- +- size_t len1; +- size_t len2; /* Length of fields to compare. */ ++ char *beg[2]; ++ char *copy[2]; ++ size_t len[2]; /* Length of fields to compare. */ + int diff; ++ int i, j; ++ int mallocd = 0; + + if (jf_1 < line1->nfields) + { +- beg1 = line1->fields[jf_1].beg; +- len1 = line1->fields[jf_1].len; ++ beg[0] = line1->fields[jf_1].beg; ++ len[0] = line1->fields[jf_1].len; + } + else + { +- beg1 = NULL; +- len1 = 0; ++ beg[0] = NULL; ++ len[0] = 0; + } + + if (jf_2 < line2->nfields) + { +- beg2 = line2->fields[jf_2].beg; +- len2 = line2->fields[jf_2].len; ++ beg[1] = line2->fields[jf_2].beg; ++ len[1] = line2->fields[jf_2].len; + } + else + { +- beg2 = NULL; +- len2 = 0; ++ beg[1] = NULL; ++ len[1] = 0; + } + +- if (len1 == 0) +- return len2 == 0 ? 0 : -1; +- if (len2 == 0) ++ if (len[0] == 0) ++ return len[1] == 0 ? 0 : -1; ++ if (len[1] == 0) + return 1; + + if (ignore_case) + { +- /* FIXME: ignore_case does not work with NLS (in particular, +- with multibyte chars). */ +- diff = memcasecmp (beg1, beg2, MIN (len1, len2)); ++#ifdef HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ { ++ size_t mblength; ++ wchar_t wc, uwc; ++ mbstate_t state, state_bak; ++ ++ memset (&state, '\0', sizeof (mbstate_t)); ++ ++ for (i = 0; i < 2; i++) ++ { ++ mallocd = 1; ++ copy[i] = xmalloc (len[i] + 1); ++ memset (copy[i], '\0',len[i] + 1); ++ ++ for (j = 0; j < MIN (len[0], len[1]);) ++ { ++ state_bak = state; ++ mblength = mbrtowc (&wc, beg[i] + j, len[i] - j, &state); ++ ++ switch (mblength) ++ { ++ case (size_t) -1: ++ case (size_t) -2: ++ state = state_bak; ++ /* Fall through */ ++ case 0: ++ mblength = 1; ++ break; ++ ++ default: ++ uwc = towupper (wc); ++ ++ if (uwc != wc) ++ { ++ mbstate_t state_wc; ++ size_t mblen; ++ ++ memset (&state_wc, '\0', sizeof (mbstate_t)); ++ mblen = wcrtomb (copy[i] + j, uwc, &state_wc); ++ assert (mblen != (size_t)-1); ++ } ++ else ++ memcpy (copy[i] + j, beg[i] + j, mblength); ++ } ++ j += mblength; ++ } ++ copy[i][j] = '\0'; ++ } ++ } ++ else ++#endif ++ { ++ for (i = 0; i < 2; i++) ++ { ++ mallocd = 1; ++ copy[i] = xmalloc (len[i] + 1); ++ ++ for (j = 0; j < MIN (len[0], len[1]); j++) ++ copy[i][j] = toupper (beg[i][j]); ++ ++ copy[i][j] = '\0'; ++ } ++ } + } + else + { +- if (hard_LC_COLLATE) +- return xmemcoll (beg1, len1, beg2, len2); +- diff = memcmp (beg1, beg2, MIN (len1, len2)); ++ copy[0] = beg[0]; ++ copy[1] = beg[1]; + } + ++ if (hard_LC_COLLATE) ++ { ++ diff = xmemcoll ((char *) copy[0], len[0], (char *) copy[1], len[1]); ++ ++ if (mallocd) ++ for (i = 0; i < 2; i++) ++ free (copy[i]); ++ ++ return diff; ++ } ++ diff = memcmp (copy[0], copy[1], MIN (len[0], len[1])); ++ ++ if (mallocd) ++ for (i = 0; i < 2; i++) ++ free (copy[i]); ++ ++ + if (diff) + return diff; +- return len1 < len2 ? -1 : len1 != len2; ++ return len[0] - len[1]; + } + + /* Check that successive input lines PREV and CURRENT from input file +@@ -461,6 +696,11 @@ get_line (FILE *fp, struct line **linep, + } + ++line_no[which - 1]; + ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ xfields_multibyte (line); ++ else ++#endif + xfields (line); + + if (prevline[which - 1]) +@@ -560,21 +800,28 @@ prfield (size_t n, struct line const *li + + /* Output all the fields in line, other than the join field. */ + ++#define PUT_TAB_CHAR \ ++ do \ ++ { \ ++ (tab != NULL) ? \ ++ fwrite(tab, sizeof(char), tablen, stdout) : putchar (' '); \ ++ } \ ++ while (0) ++ + static void + prfields (struct line const *line, size_t join_field, size_t autocount) + { + size_t i; + size_t nfields = autoformat ? autocount : line->nfields; +- char output_separator = tab < 0 ? ' ' : tab; + + for (i = 0; i < join_field && i < nfields; ++i) + { +- putchar (output_separator); ++ PUT_TAB_CHAR; + prfield (i, line); + } + for (i = join_field + 1; i < nfields; ++i) + { +- putchar (output_separator); ++ PUT_TAB_CHAR; + prfield (i, line); + } + } +@@ -585,7 +832,6 @@ static void + prjoin (struct line const *line1, struct line const *line2) + { + const struct outlist *outlist; +- char output_separator = tab < 0 ? ' ' : tab; + size_t field; + struct line const *line; + +@@ -619,7 +865,7 @@ prjoin (struct line const *line1, struct + o = o->next; + if (o == NULL) + break; +- putchar (output_separator); ++ PUT_TAB_CHAR; + } + putchar (eolchar); + } +@@ -1097,21 +1343,46 @@ main (int argc, char **argv) + + case 't': + { +- unsigned char newtab = optarg[0]; ++ char *newtab = NULL; ++ size_t newtablen; ++ newtab = xstrdup (optarg); ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ { ++ mbstate_t state; ++ ++ memset (&state, 0, sizeof (mbstate_t)); ++ newtablen = mbrtowc (NULL, newtab, ++ strnlen (newtab, MB_LEN_MAX), ++ &state); ++ if (newtablen == (size_t) 0 ++ || newtablen == (size_t) -1 ++ || newtablen == (size_t) -2) ++ newtablen = 1; ++ } ++ else ++#endif ++ newtablen = 1; + if (! newtab) +- newtab = '\n'; /* '' => process the whole line. */ ++ { ++ newtab = (char*)"\n"; /* '' => process the whole line. */ ++ } + else if (optarg[1]) + { +- if (STREQ (optarg, "\\0")) +- newtab = '\0'; +- else +- error (EXIT_FAILURE, 0, _("multi-character tab %s"), +- quote (optarg)); ++ if (newtablen == 1 && newtab[1]) ++ { ++ if (STREQ (newtab, "\\0")) ++ newtab[0] = '\0'; ++ } ++ } ++ if (tab != NULL && strcmp (tab, newtab)) ++ { ++ free (newtab); ++ error (EXIT_FAILURE, 0, _("incompatible tabs")); + } +- if (0 <= tab && tab != newtab) +- error (EXIT_FAILURE, 0, _("incompatible tabs")); + tab = newtab; +- } ++ tablen = newtablen; ++ } + break; + + case 'z': +diff -urNp coreutils-8.22-orig/src/pr.c coreutils-8.22/src/pr.c +--- coreutils-8.22-orig/src/pr.c 2013-12-04 15:48:30.000000000 +0100 ++++ coreutils-8.22/src/pr.c 2014-01-08 13:55:56.118375350 +0100 +@@ -312,6 +312,24 @@ + + #include + #include ++ ++/* Get MB_LEN_MAX. */ ++#include ++/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC ++ installation; work around this configuration error. */ ++#if !defined MB_LEN_MAX || MB_LEN_MAX == 1 ++# define MB_LEN_MAX 16 ++#endif ++ ++/* Get MB_CUR_MAX. */ ++#include ++ ++/* Solaris 2.5 has a bug: must be included before . */ ++/* Get mbstate_t, mbrtowc(), wcwidth(). */ ++#if HAVE_WCHAR_H ++# include ++#endif ++ + #include "system.h" + #include "error.h" + #include "fadvise.h" +@@ -323,6 +341,18 @@ + #include "strftime.h" + #include "xstrtol.h" + ++/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ ++#if HAVE_MBRTOWC && defined mbstate_t ++# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) ++#endif ++ ++#ifndef HAVE_DECL_WCWIDTH ++"this configure-time declaration test was not run" ++#endif ++#if !HAVE_DECL_WCWIDTH ++extern int wcwidth (); ++#endif ++ + /* The official name of this program (e.g., no 'g' prefix). */ + #define PROGRAM_NAME "pr" + +@@ -415,7 +445,20 @@ struct COLUMN + + typedef struct COLUMN COLUMN; + +-static int char_to_clump (char c); ++/* Funtion pointers to switch functions for single byte locale or for ++ multibyte locale. If multibyte functions do not exist in your sysytem, ++ these pointers always point the function for single byte locale. */ ++static void (*print_char) (char c); ++static int (*char_to_clump) (char c); ++ ++/* Functions for single byte locale. */ ++static void print_char_single (char c); ++static int char_to_clump_single (char c); ++ ++/* Functions for multibyte locale. */ ++static void print_char_multi (char c); ++static int char_to_clump_multi (char c); ++ + static bool read_line (COLUMN *p); + static bool print_page (void); + static bool print_stored (COLUMN *p); +@@ -425,6 +468,7 @@ static void print_header (void); + static void pad_across_to (int position); + static void add_line_number (COLUMN *p); + static void getoptarg (char *arg, char switch_char, char *character, ++ int *character_length, int *character_width, + int *number); + static void print_files (int number_of_files, char **av); + static void init_parameters (int number_of_files); +@@ -438,7 +482,6 @@ static void store_char (char c); + static void pad_down (int lines); + static void read_rest_of_line (COLUMN *p); + static void skip_read (COLUMN *p, int column_number); +-static void print_char (char c); + static void cleanup (void); + static void print_sep_string (void); + static void separator_string (const char *optarg_S); +@@ -450,7 +493,7 @@ static COLUMN *column_vector; + we store the leftmost columns contiguously in buff. + To print a line from buff, get the index of the first character + from line_vector[i], and print up to line_vector[i + 1]. */ +-static char *buff; ++static unsigned char *buff; + + /* Index of the position in buff where the next character + will be stored. */ +@@ -554,7 +597,7 @@ static int chars_per_column; + static bool untabify_input = false; + + /* (-e) The input tab character. */ +-static char input_tab_char = '\t'; ++static char input_tab_char[MB_LEN_MAX] = "\t"; + + /* (-e) Tabstops are at chars_per_tab, 2*chars_per_tab, 3*chars_per_tab, ... + where the leftmost column is 1. */ +@@ -564,7 +607,10 @@ static int chars_per_input_tab = 8; + static bool tabify_output = false; + + /* (-i) The output tab character. */ +-static char output_tab_char = '\t'; ++static char output_tab_char[MB_LEN_MAX] = "\t"; ++ ++/* (-i) The byte length of output tab character. */ ++static int output_tab_char_length = 1; + + /* (-i) The width of the output tab. */ + static int chars_per_output_tab = 8; +@@ -634,7 +680,13 @@ static int line_number; + static bool numbered_lines = false; + + /* (-n) Character which follows each line number. */ +-static char number_separator = '\t'; ++static char number_separator[MB_LEN_MAX] = "\t"; ++ ++/* (-n) The byte length of the character which follows each line number. */ ++static int number_separator_length = 1; ++ ++/* (-n) The character width of the character which follows each line number. */ ++static int number_separator_width = 0; + + /* (-n) line counting starts with 1st line of input file (not with 1st + line of 1st page printed). */ +@@ -687,6 +739,7 @@ static bool use_col_separator = false; + -a|COLUMN|-m is a 'space' and with the -J option a 'tab'. */ + static char *col_sep_string = (char *) ""; + static int col_sep_length = 0; ++static int col_sep_width = 0; + static char *column_separator = (char *) " "; + static char *line_separator = (char *) "\t"; + +@@ -843,6 +896,13 @@ separator_string (const char *optarg_S) + col_sep_length = (int) strlen (optarg_S); + col_sep_string = xmalloc (col_sep_length + 1); + strcpy (col_sep_string, optarg_S); ++ ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ col_sep_width = mbswidth (col_sep_string, 0); ++ else ++#endif ++ col_sep_width = col_sep_length; + } + + int +@@ -867,6 +927,21 @@ main (int argc, char **argv) + + atexit (close_stdout); + ++/* Define which functions are used, the ones for single byte locale or the ones ++ for multibyte locale. */ ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ { ++ print_char = print_char_multi; ++ char_to_clump = char_to_clump_multi; ++ } ++ else ++#endif ++ { ++ print_char = print_char_single; ++ char_to_clump = char_to_clump_single; ++ } ++ + n_files = 0; + file_names = (argc > 1 + ? xmalloc ((argc - 1) * sizeof (char *)) +@@ -943,8 +1018,12 @@ main (int argc, char **argv) + break; + case 'e': + if (optarg) +- getoptarg (optarg, 'e', &input_tab_char, +- &chars_per_input_tab); ++ { ++ int dummy_length, dummy_width; ++ ++ getoptarg (optarg, 'e', input_tab_char, &dummy_length, ++ &dummy_width, &chars_per_input_tab); ++ } + /* Could check tab width > 0. */ + untabify_input = true; + break; +@@ -957,8 +1036,12 @@ main (int argc, char **argv) + break; + case 'i': + if (optarg) +- getoptarg (optarg, 'i', &output_tab_char, +- &chars_per_output_tab); ++ { ++ int dummy_width; ++ ++ getoptarg (optarg, 'i', output_tab_char, &output_tab_char_length, ++ &dummy_width, &chars_per_output_tab); ++ } + /* Could check tab width > 0. */ + tabify_output = true; + break; +@@ -985,8 +1068,8 @@ main (int argc, char **argv) + case 'n': + numbered_lines = true; + if (optarg) +- getoptarg (optarg, 'n', &number_separator, +- &chars_per_number); ++ getoptarg (optarg, 'n', number_separator, &number_separator_length, ++ &number_separator_width, &chars_per_number); + break; + case 'N': + skip_count = false; +@@ -1025,7 +1108,7 @@ main (int argc, char **argv) + old_s = false; + /* Reset an additional input of -s, -S dominates -s */ + col_sep_string = bad_cast (""); +- col_sep_length = 0; ++ col_sep_length = col_sep_width = 0; + use_col_separator = true; + if (optarg) + separator_string (optarg); +@@ -1182,10 +1265,45 @@ main (int argc, char **argv) + a number. */ + + static void +-getoptarg (char *arg, char switch_char, char *character, int *number) ++getoptarg (char *arg, char switch_char, char *character, int *character_length, ++ int *character_width, int *number) + { + if (!ISDIGIT (*arg)) +- *character = *arg++; ++ { ++#ifdef HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) /* for multibyte locale. */ ++ { ++ wchar_t wc; ++ size_t mblength; ++ int width; ++ mbstate_t state = {'\0'}; ++ ++ mblength = mbrtowc (&wc, arg, strnlen(arg, MB_LEN_MAX), &state); ++ ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ *character_length = 1; ++ *character_width = 1; ++ } ++ else ++ { ++ *character_length = (mblength < 1) ? 1 : mblength; ++ width = wcwidth (wc); ++ *character_width = (width < 0) ? 0 : width; ++ } ++ ++ strncpy (character, arg, *character_length); ++ arg += *character_length; ++ } ++ else /* for single byte locale. */ ++#endif ++ { ++ *character = *arg++; ++ *character_length = 1; ++ *character_width = 1; ++ } ++ } ++ + if (*arg) + { + long int tmp_long; +@@ -1207,6 +1325,11 @@ static void + init_parameters (int number_of_files) + { + int chars_used_by_number = 0; ++ int mb_len = 1; ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ mb_len = MB_LEN_MAX; ++#endif + + lines_per_body = lines_per_page - lines_per_header - lines_per_footer; + if (lines_per_body <= 0) +@@ -1244,7 +1367,7 @@ init_parameters (int number_of_files) + else + col_sep_string = column_separator; + +- col_sep_length = 1; ++ col_sep_length = col_sep_width = 1; + use_col_separator = true; + } + /* It's rather pointless to define a TAB separator with column +@@ -1274,11 +1397,11 @@ init_parameters (int number_of_files) + + TAB_WIDTH (chars_per_input_tab, chars_per_number); */ + + /* Estimate chars_per_text without any margin and keep it constant. */ +- if (number_separator == '\t') ++ if (number_separator[0] == '\t') + number_width = (chars_per_number + + TAB_WIDTH (chars_per_default_tab, chars_per_number)); + else +- number_width = chars_per_number + 1; ++ number_width = chars_per_number + number_separator_width; + + /* The number is part of the column width unless we are + printing files in parallel. */ +@@ -1287,7 +1410,7 @@ init_parameters (int number_of_files) + } + + chars_per_column = (chars_per_line - chars_used_by_number +- - (columns - 1) * col_sep_length) / columns; ++ - (columns - 1) * col_sep_width) / columns; + + if (chars_per_column < 1) + error (EXIT_FAILURE, 0, _("page width too narrow")); +@@ -1305,7 +1428,7 @@ init_parameters (int number_of_files) + We've to use 8 as the lower limit, if we use chars_per_default_tab = 8 + to expand a tab which is not an input_tab-char. */ + free (clump_buff); +- clump_buff = xmalloc (MAX (8, chars_per_input_tab)); ++ clump_buff = xmalloc (mb_len * MAX (8, chars_per_input_tab)); + } + + /* Open the necessary files, +@@ -1413,7 +1536,7 @@ init_funcs (void) + + /* Enlarge p->start_position of first column to use the same form of + padding_not_printed with all columns. */ +- h = h + col_sep_length; ++ h = h + col_sep_width; + + /* This loop takes care of all but the rightmost column. */ + +@@ -1447,7 +1570,7 @@ init_funcs (void) + } + else + { +- h = h_next + col_sep_length; ++ h = h_next + col_sep_width; + h_next = h + chars_per_column; + } + } +@@ -1738,9 +1861,9 @@ static void + align_column (COLUMN *p) + { + padding_not_printed = p->start_position; +- if (padding_not_printed - col_sep_length > 0) ++ if (padding_not_printed - col_sep_width > 0) + { +- pad_across_to (padding_not_printed - col_sep_length); ++ pad_across_to (padding_not_printed - col_sep_width); + padding_not_printed = ANYWHERE; + } + +@@ -2011,13 +2134,13 @@ store_char (char c) + /* May be too generous. */ + buff = X2REALLOC (buff, &buff_allocated); + } +- buff[buff_current++] = c; ++ buff[buff_current++] = (unsigned char) c; + } + + static void + add_line_number (COLUMN *p) + { +- int i; ++ int i, j; + char *s; + int num_width; + +@@ -2034,22 +2157,24 @@ add_line_number (COLUMN *p) + /* Tabification is assumed for multiple columns, also for n-separators, + but 'default n-separator = TAB' hasn't been given priority over + equal column_width also specified by POSIX. */ +- if (number_separator == '\t') ++ if (number_separator[0] == '\t') + { + i = number_width - chars_per_number; + while (i-- > 0) + (p->char_func) (' '); + } + else +- (p->char_func) (number_separator); ++ for (j = 0; j < number_separator_length; j++) ++ (p->char_func) (number_separator[j]); + } + else + /* To comply with POSIX, we avoid any expansion of default TAB + separator with a single column output. No column_width requirement + has to be considered. */ + { +- (p->char_func) (number_separator); +- if (number_separator == '\t') ++ for (j = 0; j < number_separator_length; j++) ++ (p->char_func) (number_separator[j]); ++ if (number_separator[0] == '\t') + output_position = POS_AFTER_TAB (chars_per_output_tab, + output_position); + } +@@ -2210,7 +2335,7 @@ print_white_space (void) + while (goal - h_old > 1 + && (h_new = POS_AFTER_TAB (chars_per_output_tab, h_old)) <= goal) + { +- putchar (output_tab_char); ++ fwrite (output_tab_char, sizeof(char), output_tab_char_length, stdout); + h_old = h_new; + } + while (++h_old <= goal) +@@ -2230,6 +2355,7 @@ print_sep_string (void) + { + char *s; + int l = col_sep_length; ++ int not_space_flag; + + s = col_sep_string; + +@@ -2243,6 +2369,7 @@ print_sep_string (void) + { + for (; separators_not_printed > 0; --separators_not_printed) + { ++ not_space_flag = 0; + while (l-- > 0) + { + /* 3 types of sep_strings: spaces only, spaces and chars, +@@ -2256,12 +2383,15 @@ print_sep_string (void) + } + else + { ++ not_space_flag = 1; + if (spaces_not_printed > 0) + print_white_space (); + putchar (*s++); +- ++output_position; + } + } ++ if (not_space_flag) ++ output_position += col_sep_width; ++ + /* sep_string ends with some spaces */ + if (spaces_not_printed > 0) + print_white_space (); +@@ -2289,7 +2419,7 @@ print_clump (COLUMN *p, int n, char *clu + required number of tabs and spaces. */ + + static void +-print_char (char c) ++print_char_single (char c) + { + if (tabify_output) + { +@@ -2313,6 +2443,74 @@ print_char (char c) + putchar (c); + } + ++#ifdef HAVE_MBRTOWC ++static void ++print_char_multi (char c) ++{ ++ static size_t mbc_pos = 0; ++ static char mbc[MB_LEN_MAX] = {'\0'}; ++ static mbstate_t state = {'\0'}; ++ mbstate_t state_bak; ++ wchar_t wc; ++ size_t mblength; ++ int width; ++ ++ if (tabify_output) ++ { ++ state_bak = state; ++ mbc[mbc_pos++] = c; ++ mblength = mbrtowc (&wc, mbc, mbc_pos, &state); ++ ++ while (mbc_pos > 0) ++ { ++ switch (mblength) ++ { ++ case (size_t)-2: ++ state = state_bak; ++ return; ++ ++ case (size_t)-1: ++ state = state_bak; ++ ++output_position; ++ putchar (mbc[0]); ++ memmove (mbc, mbc + 1, MB_CUR_MAX - 1); ++ --mbc_pos; ++ break; ++ ++ case 0: ++ mblength = 1; ++ ++ default: ++ if (wc == L' ') ++ { ++ memmove (mbc, mbc + mblength, MB_CUR_MAX - mblength); ++ --mbc_pos; ++ ++spaces_not_printed; ++ return; ++ } ++ else if (spaces_not_printed > 0) ++ print_white_space (); ++ ++ /* Nonprintables are assumed to have width 0, except L'\b'. */ ++ if ((width = wcwidth (wc)) < 1) ++ { ++ if (wc == L'\b') ++ --output_position; ++ } ++ else ++ output_position += width; ++ ++ fwrite (mbc, sizeof(char), mblength, stdout); ++ memmove (mbc, mbc + mblength, MB_CUR_MAX - mblength); ++ mbc_pos -= mblength; ++ } ++ } ++ return; ++ } ++ putchar (c); ++} ++#endif ++ + /* Skip to page PAGE before printing. + PAGE may be larger than total number of pages. */ + +@@ -2492,9 +2690,9 @@ read_line (COLUMN *p) + align_empty_cols = false; + } + +- if (padding_not_printed - col_sep_length > 0) ++ if (padding_not_printed - col_sep_width > 0) + { +- pad_across_to (padding_not_printed - col_sep_length); ++ pad_across_to (padding_not_printed - col_sep_width); + padding_not_printed = ANYWHERE; + } + +@@ -2564,7 +2762,7 @@ print_stored (COLUMN *p) + int i; + + int line = p->current_line++; +- char *first = &buff[line_vector[line]]; ++ unsigned char *first = &buff[line_vector[line]]; + /* FIXME + UMR: Uninitialized memory read: + * This is occurring while in: +@@ -2576,7 +2774,7 @@ print_stored (COLUMN *p) + xmalloc [xmalloc.c:94] + init_store_cols [pr.c:1648] + */ +- char *last = &buff[line_vector[line + 1]]; ++ unsigned char *last = &buff[line_vector[line + 1]]; + + pad_vertically = true; + +@@ -2595,9 +2793,9 @@ print_stored (COLUMN *p) + } + } + +- if (padding_not_printed - col_sep_length > 0) ++ if (padding_not_printed - col_sep_width > 0) + { +- pad_across_to (padding_not_printed - col_sep_length); ++ pad_across_to (padding_not_printed - col_sep_width); + padding_not_printed = ANYWHERE; + } + +@@ -2610,8 +2808,8 @@ print_stored (COLUMN *p) + if (spaces_not_printed == 0) + { + output_position = p->start_position + end_vector[line]; +- if (p->start_position - col_sep_length == chars_per_margin) +- output_position -= col_sep_length; ++ if (p->start_position - col_sep_width == chars_per_margin) ++ output_position -= col_sep_width; + } + + return true; +@@ -2630,7 +2828,7 @@ print_stored (COLUMN *p) + number of characters is 1.) */ + + static int +-char_to_clump (char c) ++char_to_clump_single (char c) + { + unsigned char uc = c; + char *s = clump_buff; +@@ -2640,10 +2838,10 @@ char_to_clump (char c) + int chars; + int chars_per_c = 8; + +- if (c == input_tab_char) ++ if (c == input_tab_char[0]) + chars_per_c = chars_per_input_tab; + +- if (c == input_tab_char || c == '\t') ++ if (c == input_tab_char[0] || c == '\t') + { + width = TAB_WIDTH (chars_per_c, input_position); + +@@ -2724,6 +2922,164 @@ char_to_clump (char c) + return chars; + } + ++#ifdef HAVE_MBRTOWC ++static int ++char_to_clump_multi (char c) ++{ ++ static size_t mbc_pos = 0; ++ static char mbc[MB_LEN_MAX] = {'\0'}; ++ static mbstate_t state = {'\0'}; ++ mbstate_t state_bak; ++ wchar_t wc; ++ size_t mblength; ++ int wc_width; ++ register char *s = clump_buff; ++ register int i, j; ++ char esc_buff[4]; ++ int width; ++ int chars; ++ int chars_per_c = 8; ++ ++ state_bak = state; ++ mbc[mbc_pos++] = c; ++ mblength = mbrtowc (&wc, mbc, mbc_pos, &state); ++ ++ width = 0; ++ chars = 0; ++ while (mbc_pos > 0) ++ { ++ switch (mblength) ++ { ++ case (size_t)-2: ++ state = state_bak; ++ return 0; ++ ++ case (size_t)-1: ++ state = state_bak; ++ mblength = 1; ++ ++ if (use_esc_sequence || use_cntrl_prefix) ++ { ++ width = +4; ++ chars = +4; ++ *s++ = '\\'; ++ sprintf (esc_buff, "%03o", (unsigned char) mbc[0]); ++ for (i = 0; i <= 2; ++i) ++ *s++ = (int) esc_buff[i]; ++ } ++ else ++ { ++ width += 1; ++ chars += 1; ++ *s++ = mbc[0]; ++ } ++ break; ++ ++ case 0: ++ mblength = 1; ++ /* Fall through */ ++ ++ default: ++ if (memcmp (mbc, input_tab_char, mblength) == 0) ++ chars_per_c = chars_per_input_tab; ++ ++ if (memcmp (mbc, input_tab_char, mblength) == 0 || c == '\t') ++ { ++ int width_inc; ++ ++ width_inc = TAB_WIDTH (chars_per_c, input_position); ++ width += width_inc; ++ ++ if (untabify_input) ++ { ++ for (i = width_inc; i; --i) ++ *s++ = ' '; ++ chars += width_inc; ++ } ++ else ++ { ++ for (i = 0; i < mblength; i++) ++ *s++ = mbc[i]; ++ chars += mblength; ++ } ++ } ++ else if ((wc_width = wcwidth (wc)) < 1) ++ { ++ if (use_esc_sequence) ++ { ++ for (i = 0; i < mblength; i++) ++ { ++ width += 4; ++ chars += 4; ++ *s++ = '\\'; ++ sprintf (esc_buff, "%03o", (unsigned char) mbc[i]); ++ for (j = 0; j <= 2; ++j) ++ *s++ = (int) esc_buff[j]; ++ } ++ } ++ else if (use_cntrl_prefix) ++ { ++ if (wc < 0200) ++ { ++ width += 2; ++ chars += 2; ++ *s++ = '^'; ++ *s++ = wc ^ 0100; ++ } ++ else ++ { ++ for (i = 0; i < mblength; i++) ++ { ++ width += 4; ++ chars += 4; ++ *s++ = '\\'; ++ sprintf (esc_buff, "%03o", (unsigned char) mbc[i]); ++ for (j = 0; j <= 2; ++j) ++ *s++ = (int) esc_buff[j]; ++ } ++ } ++ } ++ else if (wc == L'\b') ++ { ++ width += -1; ++ chars += 1; ++ *s++ = c; ++ } ++ else ++ { ++ width += 0; ++ chars += mblength; ++ for (i = 0; i < mblength; i++) ++ *s++ = mbc[i]; ++ } ++ } ++ else ++ { ++ width += wc_width; ++ chars += mblength; ++ for (i = 0; i < mblength; i++) ++ *s++ = mbc[i]; ++ } ++ } ++ memmove (mbc, mbc + mblength, MB_CUR_MAX - mblength); ++ mbc_pos -= mblength; ++ } ++ ++ /* Too many backspaces must put us in position 0 -- never negative. */ ++ if (width < 0 && input_position == 0) ++ { ++ chars = 0; ++ input_position = 0; ++ } ++ else if (width < 0 && input_position <= -width) ++ input_position = 0; ++ else ++ input_position += width; ++ ++ return chars; ++} ++#endif ++ + /* We've just printed some files and need to clean up things before + looking for more options and printing the next batch of files. + +diff -urNp coreutils-8.22-orig/src/sort.c coreutils-8.22/src/sort.c +--- coreutils-8.22-orig/src/sort.c 2013-12-04 15:48:30.000000000 +0100 ++++ coreutils-8.22/src/sort.c 2014-01-08 13:55:56.123375301 +0100 +@@ -29,6 +29,14 @@ + #include + #include + #include ++#if HAVE_WCHAR_H ++# include ++#endif ++/* Get isw* functions. */ ++#if HAVE_WCTYPE_H ++# include ++#endif ++ + #include "system.h" + #include "argmatch.h" + #include "error.h" +@@ -164,14 +172,39 @@ static int decimal_point; + /* Thousands separator; if -1, then there isn't one. */ + static int thousands_sep; + ++/* True if -f is specified. */ ++static bool folding; ++ + /* Nonzero if the corresponding locales are hard. */ + static bool hard_LC_COLLATE; +-#if HAVE_NL_LANGINFO ++#if HAVE_LANGINFO_CODESET + static bool hard_LC_TIME; + #endif + + #define NONZERO(x) ((x) != 0) + ++/* get a multibyte character's byte length. */ ++#define GET_BYTELEN_OF_CHAR(LIM, PTR, MBLENGTH, STATE) \ ++ do \ ++ { \ ++ wchar_t wc; \ ++ mbstate_t state_bak; \ ++ \ ++ state_bak = STATE; \ ++ mblength = mbrtowc (&wc, PTR, LIM - PTR, &STATE); \ ++ \ ++ switch (MBLENGTH) \ ++ { \ ++ case (size_t)-1: \ ++ case (size_t)-2: \ ++ STATE = state_bak; \ ++ /* Fall through. */ \ ++ case 0: \ ++ MBLENGTH = 1; \ ++ } \ ++ } \ ++ while (0) ++ + /* The kind of blanks for '-b' to skip in various options. */ + enum blanktype { bl_start, bl_end, bl_both }; + +@@ -345,13 +378,11 @@ static bool reverse; + they were read if all keys compare equal. */ + static bool stable; + +-/* If TAB has this value, blanks separate fields. */ +-enum { TAB_DEFAULT = CHAR_MAX + 1 }; +- +-/* Tab character separating fields. If TAB_DEFAULT, then fields are ++/* Tab character separating fields. If tab_length is 0, then fields are + separated by the empty string between a non-blank character and a blank + character. */ +-static int tab = TAB_DEFAULT; ++static char tab[MB_LEN_MAX + 1]; ++static size_t tab_length = 0; + + /* Flag to remove consecutive duplicate lines from the output. + Only the last of a sequence of equal lines will be output. */ +@@ -811,6 +842,46 @@ reap_all (void) + reap (-1); + } + ++/* Function pointers. */ ++static void ++(*inittables) (void); ++static char * ++(*begfield) (const struct line*, const struct keyfield *); ++static char * ++(*limfield) (const struct line*, const struct keyfield *); ++static void ++(*skipblanks) (char **ptr, char *lim); ++static int ++(*getmonth) (char const *, size_t, char **); ++static int ++(*keycompare) (const struct line *, const struct line *); ++static int ++(*numcompare) (const char *, const char *); ++ ++/* Test for white space multibyte character. ++ Set LENGTH the byte length of investigated multibyte character. */ ++#if HAVE_MBRTOWC ++static int ++ismbblank (const char *str, size_t len, size_t *length) ++{ ++ size_t mblength; ++ wchar_t wc; ++ mbstate_t state; ++ ++ memset (&state, '\0', sizeof(mbstate_t)); ++ mblength = mbrtowc (&wc, str, len, &state); ++ ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ *length = 1; ++ return 0; ++ } ++ ++ *length = (mblength < 1) ? 1 : mblength; ++ return iswblank (wc); ++} ++#endif ++ + /* Clean up any remaining temporary files. */ + + static void +@@ -1255,7 +1326,7 @@ zaptemp (char const *name) + free (node); + } + +-#if HAVE_NL_LANGINFO ++#if HAVE_LANGINFO_CODESET + + static int + struct_month_cmp (void const *m1, void const *m2) +@@ -1270,7 +1341,7 @@ struct_month_cmp (void const *m1, void c + /* Initialize the character class tables. */ + + static void +-inittables (void) ++inittables_uni (void) + { + size_t i; + +@@ -1282,7 +1353,7 @@ inittables (void) + fold_toupper[i] = toupper (i); + } + +-#if HAVE_NL_LANGINFO ++#if HAVE_LANGINFO_CODESET + /* If we're not in the "C" locale, read different names for months. */ + if (hard_LC_TIME) + { +@@ -1364,6 +1435,84 @@ specify_nmerge (int oi, char c, char con + xstrtol_fatal (e, oi, c, long_options, s); + } + ++#if HAVE_MBRTOWC ++static void ++inittables_mb (void) ++{ ++ int i, j, k, l; ++ char *name, *s, *lc_time, *lc_ctype; ++ size_t s_len, mblength; ++ char mbc[MB_LEN_MAX]; ++ wchar_t wc, pwc; ++ mbstate_t state_mb, state_wc; ++ ++ lc_time = setlocale (LC_TIME, ""); ++ if (lc_time) ++ lc_time = xstrdup (lc_time); ++ ++ lc_ctype = setlocale (LC_CTYPE, ""); ++ if (lc_ctype) ++ lc_ctype = xstrdup (lc_ctype); ++ ++ if (lc_time && lc_ctype) ++ /* temporarily set LC_CTYPE to match LC_TIME, so that we can convert ++ * the names of months to upper case */ ++ setlocale (LC_CTYPE, lc_time); ++ ++ for (i = 0; i < MONTHS_PER_YEAR; i++) ++ { ++ s = (char *) nl_langinfo (ABMON_1 + i); ++ s_len = strlen (s); ++ monthtab[i].name = name = (char *) xmalloc (s_len + 1); ++ monthtab[i].val = i + 1; ++ ++ memset (&state_mb, '\0', sizeof (mbstate_t)); ++ memset (&state_wc, '\0', sizeof (mbstate_t)); ++ ++ for (j = 0; j < s_len;) ++ { ++ if (!ismbblank (s + j, s_len - j, &mblength)) ++ break; ++ j += mblength; ++ } ++ ++ for (k = 0; j < s_len;) ++ { ++ mblength = mbrtowc (&wc, (s + j), (s_len - j), &state_mb); ++ assert (mblength != (size_t)-1 && mblength != (size_t)-2); ++ if (mblength == 0) ++ break; ++ ++ pwc = towupper (wc); ++ if (pwc == wc) ++ { ++ memcpy (mbc, s + j, mblength); ++ j += mblength; ++ } ++ else ++ { ++ j += mblength; ++ mblength = wcrtomb (mbc, pwc, &state_wc); ++ assert (mblength != (size_t)0 && mblength != (size_t)-1); ++ } ++ ++ for (l = 0; l < mblength; l++) ++ name[k++] = mbc[l]; ++ } ++ name[k] = '\0'; ++ } ++ qsort ((void *) monthtab, MONTHS_PER_YEAR, ++ sizeof (struct month), struct_month_cmp); ++ ++ if (lc_time && lc_ctype) ++ /* restore the original locales */ ++ setlocale (LC_CTYPE, lc_ctype); ++ ++ free (lc_ctype); ++ free (lc_time); ++} ++#endif ++ + /* Specify the amount of main memory to use when sorting. */ + static void + specify_sort_size (int oi, char c, char const *s) +@@ -1597,7 +1746,7 @@ buffer_linelim (struct buffer const *buf + by KEY in LINE. */ + + static char * +-begfield (struct line const *line, struct keyfield const *key) ++begfield_uni (const struct line *line, const struct keyfield *key) + { + char *ptr = line->text, *lim = ptr + line->length - 1; + size_t sword = key->sword; +@@ -1606,10 +1755,10 @@ begfield (struct line const *line, struc + /* The leading field separator itself is included in a field when -t + is absent. */ + +- if (tab != TAB_DEFAULT) ++ if (tab_length) + while (ptr < lim && sword--) + { +- while (ptr < lim && *ptr != tab) ++ while (ptr < lim && *ptr != tab[0]) + ++ptr; + if (ptr < lim) + ++ptr; +@@ -1635,11 +1784,70 @@ begfield (struct line const *line, struc + return ptr; + } + ++#if HAVE_MBRTOWC ++static char * ++begfield_mb (const struct line *line, const struct keyfield *key) ++{ ++ int i; ++ char *ptr = line->text, *lim = ptr + line->length - 1; ++ size_t sword = key->sword; ++ size_t schar = key->schar; ++ size_t mblength; ++ mbstate_t state; ++ ++ memset (&state, '\0', sizeof(mbstate_t)); ++ ++ if (tab_length) ++ while (ptr < lim && sword--) ++ { ++ while (ptr < lim && memcmp (ptr, tab, tab_length) != 0) ++ { ++ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); ++ ptr += mblength; ++ } ++ if (ptr < lim) ++ { ++ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); ++ ptr += mblength; ++ } ++ } ++ else ++ while (ptr < lim && sword--) ++ { ++ while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength)) ++ ptr += mblength; ++ if (ptr < lim) ++ { ++ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); ++ ptr += mblength; ++ } ++ while (ptr < lim && !ismbblank (ptr, lim - ptr, &mblength)) ++ ptr += mblength; ++ } ++ ++ if (key->skipsblanks) ++ while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength)) ++ ptr += mblength; ++ ++ for (i = 0; i < schar; i++) ++ { ++ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); ++ ++ if (ptr + mblength > lim) ++ break; ++ else ++ ptr += mblength; ++ } ++ ++ return ptr; ++} ++#endif ++ + /* Return the limit of (a pointer to the first character after) the field + in LINE specified by KEY. */ + + static char * +-limfield (struct line const *line, struct keyfield const *key) ++limfield_uni (const struct line *line, const struct keyfield *key) + { + char *ptr = line->text, *lim = ptr + line->length - 1; + size_t eword = key->eword, echar = key->echar; +@@ -1654,10 +1862,10 @@ limfield (struct line const *line, struc + 'beginning' is the first character following the delimiting TAB. + Otherwise, leave PTR pointing at the first 'blank' character after + the preceding field. */ +- if (tab != TAB_DEFAULT) ++ if (tab_length) + while (ptr < lim && eword--) + { +- while (ptr < lim && *ptr != tab) ++ while (ptr < lim && *ptr != tab[0]) + ++ptr; + if (ptr < lim && (eword || echar)) + ++ptr; +@@ -1703,10 +1911,10 @@ limfield (struct line const *line, struc + */ + + /* Make LIM point to the end of (one byte past) the current field. */ +- if (tab != TAB_DEFAULT) ++ if (tab_length) + { + char *newlim; +- newlim = memchr (ptr, tab, lim - ptr); ++ newlim = memchr (ptr, tab[0], lim - ptr); + if (newlim) + lim = newlim; + } +@@ -1737,6 +1945,130 @@ limfield (struct line const *line, struc + return ptr; + } + ++#if HAVE_MBRTOWC ++static char * ++limfield_mb (const struct line *line, const struct keyfield *key) ++{ ++ char *ptr = line->text, *lim = ptr + line->length - 1; ++ size_t eword = key->eword, echar = key->echar; ++ int i; ++ size_t mblength; ++ mbstate_t state; ++ ++ if (echar == 0) ++ eword++; /* skip all of end field. */ ++ ++ memset (&state, '\0', sizeof(mbstate_t)); ++ ++ if (tab_length) ++ while (ptr < lim && eword--) ++ { ++ while (ptr < lim && memcmp (ptr, tab, tab_length) != 0) ++ { ++ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); ++ ptr += mblength; ++ } ++ if (ptr < lim && (eword | echar)) ++ { ++ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); ++ ptr += mblength; ++ } ++ } ++ else ++ while (ptr < lim && eword--) ++ { ++ while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength)) ++ ptr += mblength; ++ if (ptr < lim) ++ { ++ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); ++ ptr += mblength; ++ } ++ while (ptr < lim && !ismbblank (ptr, lim - ptr, &mblength)) ++ ptr += mblength; ++ } ++ ++ ++# ifdef POSIX_UNSPECIFIED ++ /* Make LIM point to the end of (one byte past) the current field. */ ++ if (tab_length) ++ { ++ char *newlim, *p; ++ ++ newlim = NULL; ++ for (p = ptr; p < lim;) ++ { ++ if (memcmp (p, tab, tab_length) == 0) ++ { ++ newlim = p; ++ break; ++ } ++ ++ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); ++ p += mblength; ++ } ++ } ++ else ++ { ++ char *newlim; ++ newlim = ptr; ++ ++ while (newlim < lim && ismbblank (newlim, lim - newlim, &mblength)) ++ newlim += mblength; ++ if (ptr < lim) ++ { ++ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); ++ ptr += mblength; ++ } ++ while (newlim < lim && !ismbblank (newlim, lim - newlim, &mblength)) ++ newlim += mblength; ++ lim = newlim; ++ } ++# endif ++ ++ if (echar != 0) ++ { ++ /* If we're skipping leading blanks, don't start counting characters ++ * until after skipping past any leading blanks. */ ++ if (key->skipeblanks) ++ while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength)) ++ ptr += mblength; ++ ++ memset (&state, '\0', sizeof(mbstate_t)); ++ ++ /* Advance PTR by ECHAR (if possible), but no further than LIM. */ ++ for (i = 0; i < echar; i++) ++ { ++ GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state); ++ ++ if (ptr + mblength > lim) ++ break; ++ else ++ ptr += mblength; ++ } ++ } ++ ++ return ptr; ++} ++#endif ++ ++static void ++skipblanks_uni (char **ptr, char *lim) ++{ ++ while (*ptr < lim && blanks[to_uchar (**ptr)]) ++ ++(*ptr); ++} ++ ++#if HAVE_MBRTOWC ++static void ++skipblanks_mb (char **ptr, char *lim) ++{ ++ size_t mblength; ++ while (*ptr < lim && ismbblank (*ptr, lim - *ptr, &mblength)) ++ (*ptr) += mblength; ++} ++#endif ++ + /* Fill BUF reading from FP, moving buf->left bytes from the end + of buf->buf to the beginning first. If EOF is reached and the + file wasn't terminated by a newline, supply one. Set up BUF's line +@@ -1823,8 +2155,22 @@ fillbuf (struct buffer *buf, FILE *fp, c + else + { + if (key->skipsblanks) +- while (blanks[to_uchar (*line_start)]) +- line_start++; ++ { ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ { ++ size_t mblength; ++ while (line_start < line->keylim && ++ ismbblank (line_start, ++ line->keylim - line_start, ++ &mblength)) ++ line_start += mblength; ++ } ++ else ++#endif ++ while (blanks[to_uchar (*line_start)]) ++ line_start++; ++ } + line->keybeg = line_start; + } + } +@@ -1945,7 +2291,7 @@ human_numcompare (char const *a, char co + hideously fast. */ + + static int +-numcompare (char const *a, char const *b) ++numcompare_uni (const char *a, const char *b) + { + while (blanks[to_uchar (*a)]) + a++; +@@ -1955,6 +2301,25 @@ numcompare (char const *a, char const *b + return strnumcmp (a, b, decimal_point, thousands_sep); + } + ++#if HAVE_MBRTOWC ++static int ++numcompare_mb (const char *a, const char *b) ++{ ++ size_t mblength, len; ++ len = strlen (a); /* okay for UTF-8 */ ++ while (*a && ismbblank (a, len > MB_CUR_MAX ? MB_CUR_MAX : len, &mblength)) ++ { ++ a += mblength; ++ len -= mblength; ++ } ++ len = strlen (b); /* okay for UTF-8 */ ++ while (*b && ismbblank (b, len > MB_CUR_MAX ? MB_CUR_MAX : len, &mblength)) ++ b += mblength; ++ ++ return strnumcmp (a, b, decimal_point, thousands_sep); ++} ++#endif /* HAV_EMBRTOWC */ ++ + /* Work around a problem whereby the long double value returned by glibc's + strtold ("NaN", ...) contains uninitialized bits: clear all bytes of + A and B before calling strtold. FIXME: remove this function once +@@ -2005,7 +2370,7 @@ general_numcompare (char const *sa, char + Return 0 if the name in S is not recognized. */ + + static int +-getmonth (char const *month, char **ea) ++getmonth_uni (char const *month, size_t len, char **ea) + { + size_t lo = 0; + size_t hi = MONTHS_PER_YEAR; +@@ -2280,15 +2645,14 @@ debug_key (struct line const *line, stru + char saved = *lim; + *lim = '\0'; + +- while (blanks[to_uchar (*beg)]) +- beg++; ++ skipblanks (&beg, lim); + + char *tighter_lim = beg; + + if (lim < beg) + tighter_lim = lim; + else if (key->month) +- getmonth (beg, &tighter_lim); ++ getmonth (beg, lim-beg, &tighter_lim); + else if (key->general_numeric) + ignore_value (strtold (beg, &tighter_lim)); + else if (key->numeric || key->human_numeric) +@@ -2432,7 +2796,7 @@ key_warnings (struct keyfield const *gke + bool maybe_space_aligned = !hard_LC_COLLATE && default_key_compare (key) + && !(key->schar || key->echar); + bool line_offset = key->eword == 0 && key->echar != 0; /* -k1.x,1.y */ +- if (!gkey_only && tab == TAB_DEFAULT && !line_offset ++ if (!gkey_only && !tab_length && !line_offset + && ((!key->skipsblanks && !(implicit_skip || maybe_space_aligned)) + || (!key->skipsblanks && key->schar) + || (!key->skipeblanks && key->echar))) +@@ -2490,11 +2854,87 @@ key_warnings (struct keyfield const *gke + error (0, 0, _("option '-r' only applies to last-resort comparison")); + } + ++#if HAVE_MBRTOWC ++static int ++getmonth_mb (const char *s, size_t len, char **ea) ++{ ++ char *month; ++ register size_t i; ++ register int lo = 0, hi = MONTHS_PER_YEAR, result; ++ char *tmp; ++ size_t wclength, mblength; ++ const char **pp; ++ const wchar_t **wpp; ++ wchar_t *month_wcs; ++ mbstate_t state; ++ ++ while (len > 0 && ismbblank (s, len, &mblength)) ++ { ++ s += mblength; ++ len -= mblength; ++ } ++ ++ if (len == 0) ++ return 0; ++ ++ month = (char *) xmalloc (len + 1); ++ ++ tmp = (char *) xmalloc (len + 1); ++ memcpy (tmp, s, len); ++ tmp[len] = '\0'; ++ pp = (const char **)&tmp; ++ month_wcs = (wchar_t *) xmalloc ((len + 1) * sizeof (wchar_t)); ++ memset (&state, '\0', sizeof(mbstate_t)); ++ ++ wclength = mbsrtowcs (month_wcs, pp, len + 1, &state); ++ if (wclength == (size_t)-1 || *pp != NULL) ++ error (SORT_FAILURE, 0, _("Invalid multibyte input %s."), quote(s)); ++ ++ for (i = 0; i < wclength; i++) ++ { ++ month_wcs[i] = towupper(month_wcs[i]); ++ if (iswblank (month_wcs[i])) ++ { ++ month_wcs[i] = L'\0'; ++ break; ++ } ++ } ++ ++ wpp = (const wchar_t **)&month_wcs; ++ ++ mblength = wcsrtombs (month, wpp, len + 1, &state); ++ assert (mblength != (-1) && *wpp == NULL); ++ ++ do ++ { ++ int ix = (lo + hi) / 2; ++ ++ if (strncmp (month, monthtab[ix].name, strlen (monthtab[ix].name)) < 0) ++ hi = ix; ++ else ++ lo = ix; ++ } ++ while (hi - lo > 1); ++ ++ result = (!strncmp (month, monthtab[lo].name, strlen (monthtab[lo].name)) ++ ? monthtab[lo].val : 0); ++ ++ if (ea && result) ++ *ea = (char*) s + strlen (monthtab[lo].name); ++ ++ free (month); ++ free (tmp); ++ free (month_wcs); ++ ++ return result; ++} ++#endif ++ + /* Compare two lines A and B trying every key in sequence until there + are no more keys or a difference is found. */ + + static int +-keycompare (struct line const *a, struct line const *b) ++keycompare_uni (const struct line *a, const struct line *b) + { + struct keyfield *key = keylist; + +@@ -2579,7 +3019,7 @@ keycompare (struct line const *a, struct + else if (key->human_numeric) + diff = human_numcompare (ta, tb); + else if (key->month) +- diff = getmonth (ta, NULL) - getmonth (tb, NULL); ++ diff = getmonth (ta, tlena, NULL) - getmonth (tb, tlenb, NULL); + else if (key->random) + diff = compare_random (ta, tlena, tb, tlenb); + else if (key->version) +@@ -2695,6 +3135,209 @@ keycompare (struct line const *a, struct + return key->reverse ? -diff : diff; + } + ++#if HAVE_MBRTOWC ++static int ++keycompare_mb (const struct line *a, const struct line *b) ++{ ++ struct keyfield *key = keylist; ++ ++ /* For the first iteration only, the key positions have been ++ precomputed for us. */ ++ char *texta = a->keybeg; ++ char *textb = b->keybeg; ++ char *lima = a->keylim; ++ char *limb = b->keylim; ++ ++ size_t mblength_a, mblength_b; ++ wchar_t wc_a, wc_b; ++ mbstate_t state_a, state_b; ++ ++ int diff = 0; ++ ++ memset (&state_a, '\0', sizeof(mbstate_t)); ++ memset (&state_b, '\0', sizeof(mbstate_t)); ++ /* Ignore keys with start after end. */ ++ if (a->keybeg - a->keylim > 0) ++ return 0; ++ ++ ++ /* Ignore and/or translate chars before comparing. */ ++# define IGNORE_CHARS(NEW_LEN, LEN, TEXT, COPY, WC, MBLENGTH, STATE) \ ++ do \ ++ { \ ++ wchar_t uwc; \ ++ char mbc[MB_LEN_MAX]; \ ++ mbstate_t state_wc; \ ++ \ ++ for (NEW_LEN = i = 0; i < LEN;) \ ++ { \ ++ mbstate_t state_bak; \ ++ \ ++ state_bak = STATE; \ ++ MBLENGTH = mbrtowc (&WC, TEXT + i, LEN - i, &STATE); \ ++ \ ++ if (MBLENGTH == (size_t)-2 || MBLENGTH == (size_t)-1 \ ++ || MBLENGTH == 0) \ ++ { \ ++ if (MBLENGTH == (size_t)-2 || MBLENGTH == (size_t)-1) \ ++ STATE = state_bak; \ ++ if (!ignore) \ ++ COPY[NEW_LEN++] = TEXT[i]; \ ++ i++; \ ++ continue; \ ++ } \ ++ \ ++ if (ignore) \ ++ { \ ++ if ((ignore == nonprinting && !iswprint (WC)) \ ++ || (ignore == nondictionary \ ++ && !iswalnum (WC) && !iswblank (WC))) \ ++ { \ ++ i += MBLENGTH; \ ++ continue; \ ++ } \ ++ } \ ++ \ ++ if (translate) \ ++ { \ ++ \ ++ uwc = towupper(WC); \ ++ if (WC == uwc) \ ++ { \ ++ memcpy (mbc, TEXT + i, MBLENGTH); \ ++ i += MBLENGTH; \ ++ } \ ++ else \ ++ { \ ++ i += MBLENGTH; \ ++ WC = uwc; \ ++ memset (&state_wc, '\0', sizeof (mbstate_t)); \ ++ \ ++ MBLENGTH = wcrtomb (mbc, WC, &state_wc); \ ++ assert (MBLENGTH != (size_t)-1 && MBLENGTH != 0); \ ++ } \ ++ \ ++ for (j = 0; j < MBLENGTH; j++) \ ++ COPY[NEW_LEN++] = mbc[j]; \ ++ } \ ++ else \ ++ for (j = 0; j < MBLENGTH; j++) \ ++ COPY[NEW_LEN++] = TEXT[i++]; \ ++ } \ ++ COPY[NEW_LEN] = '\0'; \ ++ } \ ++ while (0) ++ ++ /* Actually compare the fields. */ ++ ++ for (;;) ++ { ++ /* Find the lengths. */ ++ size_t lena = lima <= texta ? 0 : lima - texta; ++ size_t lenb = limb <= textb ? 0 : limb - textb; ++ ++ char enda IF_LINT (= 0); ++ char endb IF_LINT (= 0); ++ ++ char const *translate = key->translate; ++ bool const *ignore = key->ignore; ++ ++ if (ignore || translate) ++ { ++ char *copy_a = (char *) xmalloc ((lena + lenb) * MB_CUR_MAX + 2); ++ char *copy_b = copy_a + lena * MB_CUR_MAX + 1; ++ size_t new_len_a, new_len_b; ++ size_t i, j; ++ ++ IGNORE_CHARS (new_len_a, lena, texta, copy_a, ++ wc_a, mblength_a, state_a); ++ IGNORE_CHARS (new_len_b, lenb, textb, copy_b, ++ wc_b, mblength_b, state_b); ++ texta = copy_a; textb = copy_b; ++ lena = new_len_a; lenb = new_len_b; ++ } ++ else ++ { ++ /* Use the keys in-place, temporarily null-terminated. */ ++ enda = texta[lena]; texta[lena] = '\0'; ++ endb = textb[lenb]; textb[lenb] = '\0'; ++ } ++ ++ if (key->random) ++ diff = compare_random (texta, lena, textb, lenb); ++ else if (key->numeric | key->general_numeric | key->human_numeric) ++ { ++ char savea = *lima, saveb = *limb; ++ ++ *lima = *limb = '\0'; ++ diff = (key->numeric ? numcompare (texta, textb) ++ : key->general_numeric ? general_numcompare (texta, textb) ++ : human_numcompare (texta, textb)); ++ *lima = savea, *limb = saveb; ++ } ++ else if (key->version) ++ diff = filevercmp (texta, textb); ++ else if (key->month) ++ diff = getmonth (texta, lena, NULL) - getmonth (textb, lenb, NULL); ++ else if (lena == 0) ++ diff = - NONZERO (lenb); ++ else if (lenb == 0) ++ diff = 1; ++ else if (hard_LC_COLLATE && !folding) ++ { ++ diff = xmemcoll0 (texta, lena + 1, textb, lenb + 1); ++ } ++ else ++ { ++ diff = memcmp (texta, textb, MIN (lena, lenb)); ++ if (diff == 0) ++ diff = lena < lenb ? -1 : lena != lenb; ++ } ++ ++ if (ignore || translate) ++ free (texta); ++ else ++ { ++ texta[lena] = enda; ++ textb[lenb] = endb; ++ } ++ ++ if (diff) ++ goto not_equal; ++ ++ key = key->next; ++ if (! key) ++ break; ++ ++ /* Find the beginning and limit of the next field. */ ++ if (key->eword != -1) ++ lima = limfield (a, key), limb = limfield (b, key); ++ else ++ lima = a->text + a->length - 1, limb = b->text + b->length - 1; ++ ++ if (key->sword != -1) ++ texta = begfield (a, key), textb = begfield (b, key); ++ else ++ { ++ texta = a->text, textb = b->text; ++ if (key->skipsblanks) ++ { ++ while (texta < lima && ismbblank (texta, lima - texta, &mblength_a)) ++ texta += mblength_a; ++ while (textb < limb && ismbblank (textb, limb - textb, &mblength_b)) ++ textb += mblength_b; ++ } ++ } ++ } ++ ++not_equal: ++ if (key && key->reverse) ++ return -diff; ++ else ++ return diff; ++} ++#endif ++ + /* Compare two lines A and B, returning negative, zero, or positive + depending on whether A compares less than, equal to, or greater than B. */ + +@@ -2722,7 +3365,7 @@ compare (struct line const *a, struct li + diff = - NONZERO (blen); + else if (blen == 0) + diff = 1; +- else if (hard_LC_COLLATE) ++ else if (hard_LC_COLLATE && !folding) + { + /* Note xmemcoll0 is a performance enhancement as + it will not unconditionally write '\0' after the +@@ -4113,6 +4756,7 @@ set_ordering (char const *s, struct keyf + break; + case 'f': + key->translate = fold_toupper; ++ folding = true; + break; + case 'g': + key->general_numeric = true; +@@ -4190,7 +4834,7 @@ main (int argc, char **argv) + initialize_exit_failure (SORT_FAILURE); + + hard_LC_COLLATE = hard_locale (LC_COLLATE); +-#if HAVE_NL_LANGINFO ++#if HAVE_LANGINFO_CODESET + hard_LC_TIME = hard_locale (LC_TIME); + #endif + +@@ -4211,6 +4855,29 @@ main (int argc, char **argv) + thousands_sep = -1; + } + ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ { ++ inittables = inittables_mb; ++ begfield = begfield_mb; ++ limfield = limfield_mb; ++ skipblanks = skipblanks_mb; ++ getmonth = getmonth_mb; ++ keycompare = keycompare_mb; ++ numcompare = numcompare_mb; ++ } ++ else ++#endif ++ { ++ inittables = inittables_uni; ++ begfield = begfield_uni; ++ limfield = limfield_uni; ++ skipblanks = skipblanks_uni; ++ getmonth = getmonth_uni; ++ keycompare = keycompare_uni; ++ numcompare = numcompare_uni; ++ } ++ + have_read_stdin = false; + inittables (); + +@@ -4485,13 +5152,34 @@ main (int argc, char **argv) + + case 't': + { +- char newtab = optarg[0]; +- if (! newtab) ++ char newtab[MB_LEN_MAX + 1]; ++ size_t newtab_length = 1; ++ strncpy (newtab, optarg, MB_LEN_MAX); ++ if (! newtab[0]) + error (SORT_FAILURE, 0, _("empty tab")); +- if (optarg[1]) ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ { ++ wchar_t wc; ++ mbstate_t state; ++ ++ memset (&state, '\0', sizeof (mbstate_t)); ++ newtab_length = mbrtowc (&wc, newtab, strnlen (newtab, ++ MB_LEN_MAX), ++ &state); ++ switch (newtab_length) ++ { ++ case (size_t) -1: ++ case (size_t) -2: ++ case 0: ++ newtab_length = 1; ++ } ++ } ++#endif ++ if (newtab_length == 1 && optarg[1]) + { + if (STREQ (optarg, "\\0")) +- newtab = '\0'; ++ newtab[0] = '\0'; + else + { + /* Provoke with 'sort -txx'. Complain about +@@ -4502,9 +5190,12 @@ main (int argc, char **argv) + quote (optarg)); + } + } +- if (tab != TAB_DEFAULT && tab != newtab) ++ if (tab_length ++ && (tab_length != newtab_length ++ || memcmp (tab, newtab, tab_length) != 0)) + error (SORT_FAILURE, 0, _("incompatible tabs")); +- tab = newtab; ++ memcpy (tab, newtab, newtab_length); ++ tab_length = newtab_length; + } + break; + +diff -urNp coreutils-8.23-orig/tests/i18n/sort.sh coreutils-8.23/tests/i18n/sort.sh +--- coreutils-8.23-orig/tests/i18n/sort.sh 1970-01-01 01:00:00.000000000 +0100 ++++ coreutils-8.23/tests/i18n/sort.sh 2014-07-22 13:45:52.733652016 +0200 +@@ -0,0 +1,29 @@ ++#!/bin/sh ++# Verify sort's multi-byte support. ++ ++. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src ++print_ver_ sort ++ ++export LC_ALL=en_US.UTF-8 ++locale -k LC_CTYPE | grep -q "charmap.*UTF-8" \ ++ || skip_ "No UTF-8 locale available" ++ ++# Enable heap consistency checkng on older systems ++export MALLOC_CHECK_=2 ++ ++ ++# check buffer overflow issue due to ++# expanding multi-byte representation due to case conversion ++# https://bugzilla.suse.com/show_bug.cgi?id=928749 ++cat < exp ++. ++ɑ ++EOF ++cat < out || fail=1 ++. ++ɑ ++EOF ++compare exp out || { fail=1; cat out; } ++ ++ ++Exit $fail +diff -urNp coreutils-8.22-orig/src/unexpand.c coreutils-8.22/src/unexpand.c +--- coreutils-8.22-orig/src/unexpand.c 2013-12-04 15:48:30.000000000 +0100 ++++ coreutils-8.22/src/unexpand.c 2014-01-08 13:55:56.126375271 +0100 +@@ -38,12 +38,29 @@ + #include + #include + #include ++ ++/* Get mbstate_t, mbrtowc(), wcwidth(). */ ++#if HAVE_WCHAR_H ++# include ++#endif ++ + #include "system.h" + #include "error.h" + #include "fadvise.h" + #include "quote.h" + #include "xstrndup.h" + ++/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC ++ installation; work around this configuration error. */ ++#if !defined MB_LEN_MAX || MB_LEN_MAX < 2 ++# define MB_LEN_MAX 16 ++#endif ++ ++/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ ++#if HAVE_MBRTOWC && defined mbstate_t ++# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) ++#endif ++ + /* The official name of this program (e.g., no 'g' prefix). */ + #define PROGRAM_NAME "unexpand" + +@@ -103,6 +120,210 @@ static struct option const longopts[] = + {NULL, 0, NULL, 0} + }; + ++static FILE *next_file (FILE *fp); ++ ++#if HAVE_MBRTOWC ++static void ++unexpand_multibyte (void) ++{ ++ FILE *fp; /* Input stream. */ ++ mbstate_t i_state; /* Current shift state of the input stream. */ ++ mbstate_t i_state_bak; /* Back up the I_STATE. */ ++ mbstate_t o_state; /* Current shift state of the output stream. */ ++ char buf[MB_LEN_MAX + BUFSIZ]; /* For spooling a read byte sequence. */ ++ char *bufpos = buf; /* Next read position of BUF. */ ++ size_t buflen = 0; /* The length of the byte sequence in buf. */ ++ wint_t wc; /* A gotten wide character. */ ++ size_t mblength; /* The byte size of a multibyte character ++ which shows as same character as WC. */ ++ bool prev_tab = false; ++ ++ /* Index in `tab_list' of next tabstop: */ ++ int tab_index = 0; /* For calculating width of pending tabs. */ ++ int print_tab_index = 0; /* For printing as many tabs as possible. */ ++ unsigned int column = 0; /* Column on screen of next char. */ ++ int next_tab_column; /* Column the next tab stop is on. */ ++ int convert = 1; /* If nonzero, perform translations. */ ++ unsigned int pending = 0; /* Pending columns of blanks. */ ++ ++ fp = next_file ((FILE *) NULL); ++ if (fp == NULL) ++ return; ++ ++ memset (&o_state, '\0', sizeof(mbstate_t)); ++ memset (&i_state, '\0', sizeof(mbstate_t)); ++ ++ for (;;) ++ { ++ if (buflen < MB_LEN_MAX && !feof(fp) && !ferror(fp)) ++ { ++ memmove (buf, bufpos, buflen); ++ buflen += fread (buf + buflen, sizeof(char), BUFSIZ, fp); ++ bufpos = buf; ++ } ++ ++ /* Get a wide character. */ ++ if (buflen < 1) ++ { ++ mblength = 1; ++ wc = WEOF; ++ } ++ else ++ { ++ i_state_bak = i_state; ++ mblength = mbrtowc ((wchar_t *)&wc, bufpos, buflen, &i_state); ++ } ++ ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ i_state = i_state_bak; ++ wc = L'\0'; ++ } ++ ++ if (wc == L' ' && convert && column < INT_MAX) ++ { ++ ++pending; ++ ++column; ++ } ++ else if (wc == L'\t' && convert) ++ { ++ if (tab_size == 0) ++ { ++ /* Do not let tab_index == first_free_tab; ++ stop when it is 1 less. */ ++ while (tab_index < first_free_tab - 1 ++ && column >= tab_list[tab_index]) ++ tab_index++; ++ next_tab_column = tab_list[tab_index]; ++ if (tab_index < first_free_tab - 1) ++ tab_index++; ++ if (column >= next_tab_column) ++ { ++ convert = 0; /* Ran out of tab stops. */ ++ goto flush_pend_mb; ++ } ++ } ++ else ++ { ++ next_tab_column = column + tab_size - column % tab_size; ++ } ++ pending += next_tab_column - column; ++ column = next_tab_column; ++ } ++ else ++ { ++flush_pend_mb: ++ /* Flush pending spaces. Print as many tabs as possible, ++ then print the rest as spaces. */ ++ if (pending == 1 && column != 1 && !prev_tab) ++ { ++ putchar (' '); ++ pending = 0; ++ } ++ column -= pending; ++ while (pending > 0) ++ { ++ if (tab_size == 0) ++ { ++ /* Do not let print_tab_index == first_free_tab; ++ stop when it is 1 less. */ ++ while (print_tab_index < first_free_tab - 1 ++ && column >= tab_list[print_tab_index]) ++ print_tab_index++; ++ next_tab_column = tab_list[print_tab_index]; ++ if (print_tab_index < first_free_tab - 1) ++ print_tab_index++; ++ } ++ else ++ { ++ next_tab_column = ++ column + tab_size - column % tab_size; ++ } ++ if (next_tab_column - column <= pending) ++ { ++ putchar ('\t'); ++ pending -= next_tab_column - column; ++ column = next_tab_column; ++ } ++ else ++ { ++ --print_tab_index; ++ column += pending; ++ while (pending != 0) ++ { ++ putchar (' '); ++ pending--; ++ } ++ } ++ } ++ ++ if (wc == WEOF) ++ { ++ fp = next_file (fp); ++ if (fp == NULL) ++ break; /* No more files. */ ++ else ++ { ++ memset (&i_state, '\0', sizeof(mbstate_t)); ++ continue; ++ } ++ } ++ ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ if (convert) ++ { ++ ++column; ++ if (convert_entire_line == 0) ++ convert = 0; ++ } ++ mblength = 1; ++ putchar (buf[0]); ++ } ++ else if (mblength == 0) ++ { ++ if (convert && convert_entire_line == 0) ++ convert = 0; ++ mblength = 1; ++ putchar ('\0'); ++ } ++ else ++ { ++ if (convert) ++ { ++ if (wc == L'\b') ++ { ++ if (column > 0) ++ --column; ++ } ++ else ++ { ++ int width; /* The width of WC. */ ++ ++ width = wcwidth (wc); ++ column += (width > 0) ? width : 0; ++ if (convert_entire_line == 0) ++ convert = 0; ++ } ++ } ++ ++ if (wc == L'\n') ++ { ++ tab_index = print_tab_index = 0; ++ column = pending = 0; ++ convert = 1; ++ } ++ fwrite (bufpos, sizeof(char), mblength, stdout); ++ } ++ } ++ prev_tab = wc == L'\t'; ++ buflen -= mblength; ++ bufpos += mblength; ++ } ++} ++#endif ++ ++ + void + usage (int status) + { +@@ -523,7 +744,12 @@ main (int argc, char **argv) + + file_list = (optind < argc ? &argv[optind] : stdin_argv); + +- unexpand (); ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ unexpand_multibyte (); ++ else ++#endif ++ unexpand (); + + if (have_read_stdin && fclose (stdin) != 0) + error (EXIT_FAILURE, errno, "-"); +diff -urNp coreutils-8.22-orig/src/uniq.c coreutils-8.22/src/uniq.c +--- coreutils-8.22-orig/src/uniq.c 2013-12-04 15:48:30.000000000 +0100 ++++ coreutils-8.22/src/uniq.c 2014-01-08 13:55:56.127375261 +0100 +@@ -21,6 +21,17 @@ + #include + #include + ++/* Get mbstate_t, mbrtowc(). */ ++#if HAVE_WCHAR_H ++# include ++#endif ++ ++/* Get isw* functions. */ ++#if HAVE_WCTYPE_H ++# include ++#endif ++#include ++ + #include "system.h" + #include "argmatch.h" + #include "linebuffer.h" +@@ -32,7 +43,19 @@ + #include "stdio--.h" + #include "xmemcoll.h" + #include "xstrtol.h" +-#include "memcasecmp.h" ++#include "xmemcoll.h" ++ ++/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC ++ installation; work around this configuration error. */ ++#if !defined MB_LEN_MAX || MB_LEN_MAX < 2 ++# define MB_LEN_MAX 16 ++#endif ++ ++/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ ++#if HAVE_MBRTOWC && defined mbstate_t ++# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) ++#endif ++ + + /* The official name of this program (e.g., no 'g' prefix). */ + #define PROGRAM_NAME "uniq" +@@ -143,6 +166,10 @@ enum + GROUP_OPTION = CHAR_MAX + 1 + }; + ++/* Function pointers. */ ++static char * ++(*find_field) (struct linebuffer *line); ++ + static struct option const longopts[] = + { + {"count", no_argument, NULL, 'c'}, +@@ -249,7 +276,7 @@ size_opt (char const *opt, char const *m + return a pointer to the beginning of the line's field to be compared. */ + + static char * _GL_ATTRIBUTE_PURE +-find_field (struct linebuffer const *line) ++find_field_uni (struct linebuffer *line) + { + size_t count; + char const *lp = line->buffer; +@@ -269,6 +296,83 @@ find_field (struct linebuffer const *lin + return line->buffer + i; + } + ++#if HAVE_MBRTOWC ++ ++# define MBCHAR_TO_WCHAR(WC, MBLENGTH, LP, POS, SIZE, STATEP, CONVFAIL) \ ++ do \ ++ { \ ++ mbstate_t state_bak; \ ++ \ ++ CONVFAIL = 0; \ ++ state_bak = *STATEP; \ ++ \ ++ MBLENGTH = mbrtowc (&WC, LP + POS, SIZE - POS, STATEP); \ ++ \ ++ switch (MBLENGTH) \ ++ { \ ++ case (size_t)-2: \ ++ case (size_t)-1: \ ++ *STATEP = state_bak; \ ++ CONVFAIL++; \ ++ /* Fall through */ \ ++ case 0: \ ++ MBLENGTH = 1; \ ++ } \ ++ } \ ++ while (0) ++ ++static char * ++find_field_multi (struct linebuffer *line) ++{ ++ size_t count; ++ char *lp = line->buffer; ++ size_t size = line->length - 1; ++ size_t pos; ++ size_t mblength; ++ wchar_t wc; ++ mbstate_t *statep; ++ int convfail = 0; ++ ++ pos = 0; ++ statep = &(line->state); ++ ++ /* skip fields. */ ++ for (count = 0; count < skip_fields && pos < size; count++) ++ { ++ while (pos < size) ++ { ++ MBCHAR_TO_WCHAR (wc, mblength, lp, pos, size, statep, convfail); ++ ++ if (convfail || !iswblank (wc)) ++ { ++ pos += mblength; ++ break; ++ } ++ pos += mblength; ++ } ++ ++ while (pos < size) ++ { ++ MBCHAR_TO_WCHAR (wc, mblength, lp, pos, size, statep, convfail); ++ ++ if (!convfail && iswblank (wc)) ++ break; ++ ++ pos += mblength; ++ } ++ } ++ ++ /* skip fields. */ ++ for (count = 0; count < skip_chars && pos < size; count++) ++ { ++ MBCHAR_TO_WCHAR (wc, mblength, lp, pos, size, statep, convfail); ++ pos += mblength; ++ } ++ ++ return lp + pos; ++} ++#endif ++ + /* Return false if two strings OLD and NEW match, true if not. + OLD and NEW point not to the beginnings of the lines + but rather to the beginnings of the fields to compare. +@@ -277,6 +381,8 @@ find_field (struct linebuffer const *lin + static bool + different (char *old, char *new, size_t oldlen, size_t newlen) + { ++ char *copy_old, *copy_new; ++ + if (check_chars < oldlen) + oldlen = check_chars; + if (check_chars < newlen) +@@ -284,14 +390,103 @@ different (char *old, char *new, size_t + + if (ignore_case) + { +- /* FIXME: This should invoke strcoll somehow. */ +- return oldlen != newlen || memcasecmp (old, new, oldlen); ++ size_t i; ++ ++ copy_old = xmalloc (oldlen + 1); ++ copy_new = xmalloc (oldlen + 1); ++ ++ for (i = 0; i < oldlen; i++) ++ { ++ copy_old[i] = toupper (old[i]); ++ copy_new[i] = toupper (new[i]); ++ } ++ bool rc = xmemcoll (copy_old, oldlen, copy_new, newlen); ++ free (copy_old); ++ free (copy_new); ++ return rc; + } +- else if (hard_LC_COLLATE) +- return xmemcoll (old, oldlen, new, newlen) != 0; + else +- return oldlen != newlen || memcmp (old, new, oldlen); ++ { ++ copy_old = (char *)old; ++ copy_new = (char *)new; ++ } ++ ++ return xmemcoll (copy_old, oldlen, copy_new, newlen); ++ ++} ++ ++#if HAVE_MBRTOWC ++static int ++different_multi (const char *old, const char *new, size_t oldlen, size_t newlen, mbstate_t oldstate, mbstate_t newstate) ++{ ++ size_t i, j, chars; ++ const char *str[2]; ++ char *copy[2]; ++ size_t len[2]; ++ mbstate_t state[2]; ++ size_t mblength; ++ wchar_t wc, uwc; ++ mbstate_t state_bak; ++ ++ str[0] = old; ++ str[1] = new; ++ len[0] = oldlen; ++ len[1] = newlen; ++ state[0] = oldstate; ++ state[1] = newstate; ++ ++ for (i = 0; i < 2; i++) ++ { ++ copy[i] = xmalloc (len[i] + 1); ++ memset (copy[i], '\0', len[i] + 1); ++ ++ for (j = 0, chars = 0; j < len[i] && chars < check_chars; chars++) ++ { ++ state_bak = state[i]; ++ mblength = mbrtowc (&wc, str[i] + j, len[i] - j, &(state[i])); ++ ++ switch (mblength) ++ { ++ case (size_t)-1: ++ case (size_t)-2: ++ state[i] = state_bak; ++ /* Fall through */ ++ case 0: ++ mblength = 1; ++ break; ++ ++ default: ++ if (ignore_case) ++ { ++ uwc = towupper (wc); ++ ++ if (uwc != wc) ++ { ++ mbstate_t state_wc; ++ size_t mblen; ++ ++ memset (&state_wc, '\0', sizeof(mbstate_t)); ++ mblen = wcrtomb (copy[i] + j, uwc, &state_wc); ++ assert (mblen != (size_t)-1); ++ } ++ else ++ memcpy (copy[i] + j, str[i] + j, mblength); ++ } ++ else ++ memcpy (copy[i] + j, str[i] + j, mblength); ++ } ++ j += mblength; ++ } ++ copy[i][j] = '\0'; ++ len[i] = j; ++ } ++ int rc = xmemcoll (copy[0], len[0], copy[1], len[1]); ++ free (copy[0]); ++ free (copy[1]); ++ return rc; ++ + } ++#endif + + /* Output the line in linebuffer LINE to standard output + provided that the switches say it should be output. +@@ -356,19 +551,38 @@ check_file (const char *infile, const ch + char *prevfield IF_LINT ( = NULL); + size_t prevlen IF_LINT ( = 0); + bool first_group_printed = false; ++#if HAVE_MBRTOWC ++ mbstate_t prevstate; ++ ++ memset (&prevstate, '\0', sizeof (mbstate_t)); ++#endif + + while (!feof (stdin)) + { + char *thisfield; + size_t thislen; + bool new_group; ++#if HAVE_MBRTOWC ++ mbstate_t thisstate; ++#endif + + if (readlinebuffer_delim (thisline, stdin, delimiter) == 0) + break; + + thisfield = find_field (thisline); + thislen = thisline->length - 1 - (thisfield - thisline->buffer); ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ { ++ thisstate = thisline->state; + ++ new_group = (prevline->length == 0 ++ || different_multi (thisfield, prevfield, ++ thislen, prevlen, ++ thisstate, prevstate)); ++ } ++ else ++#endif + new_group = (prevline->length == 0 + || different (thisfield, prevfield, thislen, prevlen)); + +@@ -386,6 +600,10 @@ check_file (const char *infile, const ch + SWAP_LINES (prevline, thisline); + prevfield = thisfield; + prevlen = thislen; ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ prevstate = thisstate; ++#endif + first_group_printed = true; + } + } +@@ -398,17 +616,26 @@ check_file (const char *infile, const ch + size_t prevlen; + uintmax_t match_count = 0; + bool first_delimiter = true; ++#if HAVE_MBRTOWC ++ mbstate_t prevstate; ++#endif + + if (readlinebuffer_delim (prevline, stdin, delimiter) == 0) + goto closefiles; + prevfield = find_field (prevline); + prevlen = prevline->length - 1 - (prevfield - prevline->buffer); ++#if HAVE_MBRTOWC ++ prevstate = prevline->state; ++#endif + + while (!feof (stdin)) + { + bool match; + char *thisfield; + size_t thislen; ++#if HAVE_MBRTOWC ++ mbstate_t thisstate = thisline->state; ++#endif + if (readlinebuffer_delim (thisline, stdin, delimiter) == 0) + { + if (ferror (stdin)) +@@ -417,6 +644,14 @@ check_file (const char *infile, const ch + } + thisfield = find_field (thisline); + thislen = thisline->length - 1 - (thisfield - thisline->buffer); ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ { ++ match = !different_multi (thisfield, prevfield, ++ thislen, prevlen, thisstate, prevstate); ++ } ++ else ++#endif + match = !different (thisfield, prevfield, thislen, prevlen); + match_count += match; + +@@ -449,6 +684,9 @@ check_file (const char *infile, const ch + SWAP_LINES (prevline, thisline); + prevfield = thisfield; + prevlen = thislen; ++#if HAVE_MBRTOWC ++ prevstate = thisstate; ++#endif + if (!match) + match_count = 0; + } +@@ -495,6 +733,19 @@ main (int argc, char **argv) + + atexit (close_stdout); + ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ { ++ find_field = find_field_multi; ++ } ++ else ++#endif ++ { ++ find_field = find_field_uni; ++ } ++ ++ ++ + skip_chars = 0; + skip_fields = 0; + check_chars = SIZE_MAX; +diff -urNp coreutils-8.22-orig/tests/local.mk coreutils-8.22/tests/local.mk +--- coreutils-8.22-orig/tests/local.mk 2014-01-08 13:55:24.524683837 +0100 ++++ coreutils-8.22/tests/local.mk 2014-01-08 13:55:56.129375241 +0100 +@@ -325,6 +325,8 @@ all_tests = \ + tests/misc/sort-discrim.sh \ + tests/misc/sort-files0-from.pl \ + tests/misc/sort-float.sh \ ++ tests/misc/sort-mb-tests.sh \ ++ tests/i18n/sort.sh \ + tests/misc/sort-merge.pl \ + tests/misc/sort-merge-fdlimit.sh \ + tests/misc/sort-month.sh \ +diff -urNp coreutils-8.22-orig/tests/misc/cut.pl coreutils-8.22/tests/misc/cut.pl +--- coreutils-8.22-orig/tests/misc/cut.pl 2013-12-04 15:48:30.000000000 +0100 ++++ coreutils-8.22/tests/misc/cut.pl 2014-01-08 13:55:56.130375231 +0100 +@@ -23,9 +23,11 @@ use strict; + # Turn off localization of executable's output. + @ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3; + +-my $mb_locale = $ENV{LOCALE_FR_UTF8}; ++my $mb_locale; ++# uncommented enable multibyte paths ++$mb_locale = $ENV{LOCALE_FR_UTF8}; + ! defined $mb_locale || $mb_locale eq 'none' +- and $mb_locale = 'C'; ++ and $mb_locale = 'C'; + + my $prog = 'cut'; + my $try = "Try '$prog --help' for more information.\n"; +@@ -225,6 +227,7 @@ if ($mb_locale ne 'C') + my @new_t = @$t; + my $test_name = shift @new_t; + ++ next if ($test_name =~ "newline-[12][0-9]"); + push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}]; + } + push @Tests, @new; +diff -urNp coreutils-8.22-orig/tests/misc/expand.pl coreutils-8.22/tests/misc/expand.pl +--- coreutils-8.22-orig/tests/misc/expand.pl 2013-12-04 15:48:30.000000000 +0100 ++++ coreutils-8.22/tests/misc/expand.pl 2014-01-08 13:55:56.135375181 +0100 +@@ -23,6 +23,15 @@ use strict; + # Turn off localization of executable's output. + @ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3; + ++#comment out next line to disable multibyte tests ++my $mb_locale = $ENV{LOCALE_FR_UTF8}; ++! defined $mb_locale || $mb_locale eq 'none' ++ and $mb_locale = 'C'; ++ ++my $prog = 'expand'; ++my $try = "Try \`$prog --help' for more information.\n"; ++my $inval = "$prog: invalid byte, character or field list\n$try"; ++ + my @Tests = + ( + ['t1', '--tabs=3', {IN=>"a\tb"}, {OUT=>"a b"}], +@@ -31,6 +40,37 @@ my @Tests = + ['i2', '--tabs=3 -i', {IN=>" \ta\tb"}, {OUT=>" a\tb"}], + ); + ++if ($mb_locale ne 'C') ++ { ++ # Duplicate each test vector, appending "-mb" to the test name and ++ # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we ++ # provide coverage for the distro-added multi-byte code paths. ++ my @new; ++ foreach my $t (@Tests) ++ { ++ my @new_t = @$t; ++ my $test_name = shift @new_t; ++ ++ # Depending on whether expand is multi-byte-patched, ++ # it emits different diagnostics: ++ # non-MB: invalid byte or field list ++ # MB: invalid byte, character or field list ++ # Adjust the expected error output accordingly. ++ if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval} ++ (@new_t)) ++ { ++ my $sub = {ERR_SUBST => 's/, character//'}; ++ push @new_t, $sub; ++ push @$t, $sub; ++ } ++ push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}]; ++ } ++ push @Tests, @new; ++ } ++ ++ ++@Tests = triple_test \@Tests; ++ + my $save_temps = $ENV{DEBUG}; + my $verbose = $ENV{VERBOSE}; + +diff -urNp coreutils-8.22-orig/tests/misc/fold.pl coreutils-8.22/tests/misc/fold.pl +--- coreutils-8.22-orig/tests/misc/fold.pl 2013-12-04 15:48:30.000000000 +0100 ++++ coreutils-8.22/tests/misc/fold.pl 2014-01-08 13:55:56.136375171 +0100 +@@ -20,9 +20,18 @@ use strict; + + (my $program_name = $0) =~ s|.*/||; + ++my $prog = 'fold'; ++my $try = "Try \`$prog --help' for more information.\n"; ++my $inval = "$prog: invalid byte, character or field list\n$try"; ++ + # Turn off localization of executable's output. + @ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3; + ++# uncommented to enable multibyte paths ++my $mb_locale = $ENV{LOCALE_FR_UTF8}; ++! defined $mb_locale || $mb_locale eq 'none' ++ and $mb_locale = 'C'; ++ + my @Tests = + ( + ['s1', '-w2 -s', {IN=>"a\t"}, {OUT=>"a\n\t"}], +@@ -31,9 +40,48 @@ my @Tests = + ['s4', '-w4 -s', {IN=>"abc ef\n"}, {OUT=>"abc \nef\n"}], + ); + ++# Add _POSIX2_VERSION=199209 to the environment of each test ++# that uses an old-style option like +1. ++if ($mb_locale ne 'C') ++ { ++ # Duplicate each test vector, appending "-mb" to the test name and ++ # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we ++ # provide coverage for the distro-added multi-byte code paths. ++ my @new; ++ foreach my $t (@Tests) ++ { ++ my @new_t = @$t; ++ my $test_name = shift @new_t; ++ ++ # Depending on whether fold is multi-byte-patched, ++ # it emits different diagnostics: ++ # non-MB: invalid byte or field list ++ # MB: invalid byte, character or field list ++ # Adjust the expected error output accordingly. ++ if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval} ++ (@new_t)) ++ { ++ my $sub = {ERR_SUBST => 's/, character//'}; ++ push @new_t, $sub; ++ push @$t, $sub; ++ } ++ push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}]; ++ } ++ push @Tests, @new; ++ } ++ ++@Tests = triple_test \@Tests; ++ ++# Remember that triple_test creates from each test with exactly one "IN" ++# file two more tests (.p and .r suffix on name) corresponding to reading ++# input from a file and from a pipe. The pipe-reading test would fail ++# due to a race condition about 1 in 20 times. ++# Remove the IN_PIPE version of the "output-is-input" test above. ++# The others aren't susceptible because they have three inputs each. ++@Tests = grep {$_->[0] ne 'output-is-input.p'} @Tests; ++ + my $save_temps = $ENV{DEBUG}; + my $verbose = $ENV{VERBOSE}; + +-my $prog = 'fold'; + my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose); + exit $fail; +diff -urNp coreutils-8.22-orig/tests/misc/join.pl coreutils-8.22/tests/misc/join.pl +--- coreutils-8.22-orig/tests/misc/join.pl 2013-12-04 15:48:30.000000000 +0100 ++++ coreutils-8.22/tests/misc/join.pl 2014-01-08 13:55:56.137375161 +0100 +@@ -25,6 +25,15 @@ my $limits = getlimits (); + + my $prog = 'join'; + ++my $try = "Try \`$prog --help' for more information.\n"; ++my $inval = "$prog: invalid byte, character or field list\n$try"; ++ ++my $mb_locale; ++#Comment out next line to disable multibyte tests ++$mb_locale = $ENV{LOCALE_FR_UTF8}; ++! defined $mb_locale || $mb_locale eq 'none' ++ and $mb_locale = 'C'; ++ + my $delim = chr 0247; + sub t_subst ($) + { +@@ -326,8 +335,49 @@ foreach my $t (@tv) + push @Tests, $new_ent; + } + ++# Add _POSIX2_VERSION=199209 to the environment of each test ++# that uses an old-style option like +1. ++if ($mb_locale ne 'C') ++ { ++ # Duplicate each test vector, appending "-mb" to the test name and ++ # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we ++ # provide coverage for the distro-added multi-byte code paths. ++ my @new; ++ foreach my $t (@Tests) ++ { ++ my @new_t = @$t; ++ my $test_name = shift @new_t; ++ ++ # Depending on whether join is multi-byte-patched, ++ # it emits different diagnostics: ++ # non-MB: invalid byte or field list ++ # MB: invalid byte, character or field list ++ # Adjust the expected error output accordingly. ++ if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval} ++ (@new_t)) ++ { ++ my $sub = {ERR_SUBST => 's/, character//'}; ++ push @new_t, $sub; ++ push @$t, $sub; ++ } ++ #Adjust the output some error messages including test_name for mb ++ if (grep {ref $_ eq 'HASH' && exists $_->{ERR}} ++ (@new_t)) ++ { ++ my $sub2 = {ERR_SUBST => "s/$test_name-mb/$test_name/"}; ++ push @new_t, $sub2; ++ push @$t, $sub2; ++ } ++ push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}]; ++ } ++ push @Tests, @new; ++ } ++ + @Tests = triple_test \@Tests; + ++#skip invalid-j-mb test, it is failing because of the format ++@Tests = grep {$_->[0] ne 'invalid-j-mb'} @Tests; ++ + my $save_temps = $ENV{DEBUG}; + my $verbose = $ENV{VERBOSE}; + +diff -urNp coreutils-8.22-orig/tests/misc/sort-mb-tests.sh coreutils-8.22/tests/misc/sort-mb-tests.sh +--- coreutils-8.22-orig/tests/misc/sort-mb-tests.sh 1970-01-01 01:00:00.000000000 +0100 ++++ coreutils-8.22/tests/misc/sort-mb-tests.sh 2014-01-08 13:55:56.138375151 +0100 +@@ -0,0 +1,45 @@ ++#!/bin/sh ++# Verify sort's multi-byte support. ++ ++. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src ++print_ver_ sort ++ ++export LC_ALL=en_US.UTF-8 ++locale -k LC_CTYPE | grep -q "charmap.*UTF-8" \ ++ || skip_ "No UTF-8 locale available" ++ ++ ++cat < exp ++Banana@5 ++Apple@10 ++Citrus@20 ++Cherry@30 ++EOF ++ ++cat < out || fail=1 ++Apple@10 ++Banana@5 ++Citrus@20 ++Cherry@30 ++EOF ++ ++compare exp out || { fail=1; cat out; } ++ ++ ++cat < exp ++Citrus@AA20@@5 ++Cherry@AA30@@10 ++Apple@AA10@@20 ++Banana@AA5@@30 ++EOF ++ ++cat < out || fail=1 ++Apple@AA10@@20 ++Banana@AA5@@30 ++Citrus@AA20@@5 ++Cherry@AA30@@10 ++EOF ++ ++compare exp out || { fail=1; cat out; } ++ ++Exit $fail +diff -urNp coreutils-8.22-orig/tests/misc/sort-merge.pl coreutils-8.22/tests/misc/sort-merge.pl +--- coreutils-8.22-orig/tests/misc/sort-merge.pl 2013-12-04 15:48:30.000000000 +0100 ++++ coreutils-8.22/tests/misc/sort-merge.pl 2014-01-08 13:55:56.139375141 +0100 +@@ -26,6 +26,15 @@ my $prog = 'sort'; + # Turn off localization of executable's output. + @ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3; + ++my $mb_locale; ++# uncommented according to upstream commit enabling multibyte paths ++$mb_locale = $ENV{LOCALE_FR_UTF8}; ++! defined $mb_locale || $mb_locale eq 'none' ++ and $mb_locale = 'C'; ++ ++my $try = "Try \`$prog --help' for more information.\n"; ++my $inval = "$prog: invalid byte, character or field list\n$try"; ++ + # three empty files and one that says 'foo' + my @inputs = (+(map{{IN=> {"empty$_"=> ''}}}1..3), {IN=> {foo=> "foo\n"}}); + +@@ -77,6 +86,39 @@ my @Tests = + {OUT=>$big_input}], + ); + ++# Add _POSIX2_VERSION=199209 to the environment of each test ++# that uses an old-style option like +1. ++if ($mb_locale ne 'C') ++ { ++ # Duplicate each test vector, appending "-mb" to the test name and ++ # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we ++ # provide coverage for the distro-added multi-byte code paths. ++ my @new; ++ foreach my $t (@Tests) ++ { ++ my @new_t = @$t; ++ my $test_name = shift @new_t; ++ ++ # Depending on whether sort is multi-byte-patched, ++ # it emits different diagnostics: ++ # non-MB: invalid byte or field list ++ # MB: invalid byte, character or field list ++ # Adjust the expected error output accordingly. ++ if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval} ++ (@new_t)) ++ { ++ my $sub = {ERR_SUBST => 's/, character//'}; ++ push @new_t, $sub; ++ push @$t, $sub; ++ } ++ next if ($test_name =~ "nmerge-."); ++ push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}]; ++ } ++ push @Tests, @new; ++ } ++ ++@Tests = triple_test \@Tests; ++ + my $save_temps = $ENV{DEBUG}; + my $verbose = $ENV{VERBOSE}; + +diff -urNp coreutils-8.22-orig/tests/misc/sort.pl coreutils-8.22/tests/misc/sort.pl +--- coreutils-8.22-orig/tests/misc/sort.pl 2013-12-04 15:48:30.000000000 +0100 ++++ coreutils-8.22/tests/misc/sort.pl 2014-01-08 13:55:56.140375131 +0100 +@@ -24,10 +24,15 @@ my $prog = 'sort'; + # Turn off localization of executable's output. + @ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3; + +-my $mb_locale = $ENV{LOCALE_FR_UTF8}; ++my $mb_locale; ++#Comment out next line to disable multibyte tests ++$mb_locale = $ENV{LOCALE_FR_UTF8}; + ! defined $mb_locale || $mb_locale eq 'none' + and $mb_locale = 'C'; + ++my $try = "Try \`$prog --help' for more information.\n"; ++my $inval = "$prog: invalid byte, character or field list\n$try"; ++ + # Since each test is run with a file name and with redirected stdin, + # the name in the diagnostic is either the file name or "-". + # Normalize each diagnostic to use '-'. +@@ -317,6 +322,10 @@ my @Tests = + ["22a", '-k 2,2fd -k 1,1r', {IN=>"3 b\n4 B\n"}, {OUT=>"4 B\n3 b\n"}], + ["22b", '-k 2,2d -k 1,1r', {IN=>"3 b\n4 b\n"}, {OUT=>"4 b\n3 b\n"}], + ++# This fails in Fedora 20, per Göran Uddeborg in: http://bugs.gnu.org/18540 ++["23", '-s -k1,1 -t/', {IN=>"a b/x\na-b-c/x\n"}, {OUT=>"a b/x\na-b-c/x\n"}, ++ {ENV => "LC_ALL=$mb_locale"}], ++ + ["no-file1", 'no-file', {EXIT=>2}, {ERR=>$no_file}], + # This test failed until 1.22f. Sort didn't give an error. + # From Will Edgington. +@@ -415,6 +424,38 @@ foreach my $t (@Tests) + } + } + ++if ($mb_locale ne 'C') ++ { ++ # Duplicate each test vector, appending "-mb" to the test name and ++ # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we ++ # provide coverage for the distro-added multi-byte code paths. ++ my @new; ++ foreach my $t (@Tests) ++ { ++ my @new_t = @$t; ++ my $test_name = shift @new_t; ++ ++ # Depending on whether sort is multi-byte-patched, ++ # it emits different diagnostics: ++ # non-MB: invalid byte or field list ++ # MB: invalid byte, character or field list ++ # Adjust the expected error output accordingly. ++ if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval} ++ (@new_t)) ++ { ++ my $sub = {ERR_SUBST => 's/, character//'}; ++ push @new_t, $sub; ++ push @$t, $sub; ++ } ++ #disable several failing tests until investigation, disable all tests with envvars set ++ next if (grep {ref $_ eq 'HASH' && exists $_->{ENV}} (@new_t)); ++ next if ($test_name =~ "18g" or $test_name =~ "sort-numeric" or $test_name =~ "08[ab]" or $test_name =~ "03[def]" or $test_name =~ "h4" or $test_name =~ "n1" or $test_name =~ "2[01]a"); ++ next if ($test_name =~ "11[ab]"); # avoid FP: expected result differs to MB result due to collation rules. ++ push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}]; ++ } ++ push @Tests, @new; ++ } ++ + @Tests = triple_test \@Tests; + + # Remember that triple_test creates from each test with exactly one "IN" +@@ -424,6 +465,7 @@ foreach my $t (@Tests) + # Remove the IN_PIPE version of the "output-is-input" test above. + # The others aren't susceptible because they have three inputs each. + @Tests = grep {$_->[0] ne 'output-is-input.p'} @Tests; ++@Tests = grep {$_->[0] ne 'output-is-input-mb.p'} @Tests; + + my $save_temps = $ENV{DEBUG}; + my $verbose = $ENV{VERBOSE}; +diff -urNp coreutils-8.22-orig/tests/misc/unexpand.pl coreutils-8.22/tests/misc/unexpand.pl +--- coreutils-8.22-orig/tests/misc/unexpand.pl 2013-12-04 15:48:30.000000000 +0100 ++++ coreutils-8.22/tests/misc/unexpand.pl 2014-01-08 13:55:56.140375131 +0100 +@@ -27,6 +27,14 @@ my $limits = getlimits (); + + my $prog = 'unexpand'; + ++# comment out next line to disable multibyte tests ++my $mb_locale = $ENV{LOCALE_FR_UTF8}; ++! defined $mb_locale || $mb_locale eq 'none' ++ and $mb_locale = 'C'; ++ ++my $try = "Try \`$prog --help' for more information.\n"; ++my $inval = "$prog: invalid byte, character or field list\n$try"; ++ + my @Tests = + ( + ['a1', {IN=> ' 'x 1 ."y\n"}, {OUT=> ' 'x 1 ."y\n"}], +@@ -92,6 +100,37 @@ my @Tests = + {EXIT => 1}, {ERR => "$prog: tab stop value is too large\n"}], + ); + ++if ($mb_locale ne 'C') ++ { ++ # Duplicate each test vector, appending "-mb" to the test name and ++ # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we ++ # provide coverage for the distro-added multi-byte code paths. ++ my @new; ++ foreach my $t (@Tests) ++ { ++ my @new_t = @$t; ++ my $test_name = shift @new_t; ++ ++ # Depending on whether unexpand is multi-byte-patched, ++ # it emits different diagnostics: ++ # non-MB: invalid byte or field list ++ # MB: invalid byte, character or field list ++ # Adjust the expected error output accordingly. ++ if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval} ++ (@new_t)) ++ { ++ my $sub = {ERR_SUBST => 's/, character//'}; ++ push @new_t, $sub; ++ push @$t, $sub; ++ } ++ next if ($test_name =~ 'b-1'); ++ push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}]; ++ } ++ push @Tests, @new; ++ } ++ ++@Tests = triple_test \@Tests; ++ + my $save_temps = $ENV{DEBUG}; + my $verbose = $ENV{VERBOSE}; + +diff -urNp coreutils-8.22-orig/tests/misc/uniq.pl coreutils-8.22/tests/misc/uniq.pl +--- coreutils-8.22-orig/tests/misc/uniq.pl 2013-12-04 15:48:30.000000000 +0100 ++++ coreutils-8.22/tests/misc/uniq.pl 2014-01-08 13:55:56.141375121 +0100 +@@ -23,9 +23,17 @@ my $limits = getlimits (); + my $prog = 'uniq'; + my $try = "Try '$prog --help' for more information.\n"; + ++my $inval = "$prog: invalid byte, character or field list\n$try"; ++ + # Turn off localization of executable's output. + @ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3; + ++my $mb_locale; ++#Comment out next line to disable multibyte tests ++$mb_locale = $ENV{LOCALE_FR_UTF8}; ++! defined $mb_locale || $mb_locale eq 'none' ++ and $mb_locale = 'C'; ++ + # When possible, create a "-z"-testing variant of each test. + sub add_z_variants($) + { +@@ -261,6 +269,53 @@ foreach my $t (@Tests) + and push @$t, {ENV=>'_POSIX2_VERSION=199209'}; + } + ++if ($mb_locale ne 'C') ++ { ++ # Duplicate each test vector, appending "-mb" to the test name and ++ # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we ++ # provide coverage for the distro-added multi-byte code paths. ++ my @new; ++ foreach my $t (@Tests) ++ { ++ my @new_t = @$t; ++ my $test_name = shift @new_t; ++ ++ # Depending on whether uniq is multi-byte-patched, ++ # it emits different diagnostics: ++ # non-MB: invalid byte or field list ++ # MB: invalid byte, character or field list ++ # Adjust the expected error output accordingly. ++ if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval} ++ (@new_t)) ++ { ++ my $sub = {ERR_SUBST => 's/, character//'}; ++ push @new_t, $sub; ++ push @$t, $sub; ++ } ++ # In test #145, replace the each ‘...’ by '...'. ++ if ($test_name =~ "145") ++ { ++ my $sub = { ERR_SUBST => "s/‘([^’]+)’/'\$1'/g"}; ++ push @new_t, $sub; ++ push @$t, $sub; ++ } ++ next if ( $test_name =~ "schar" ++ or $test_name =~ "^obs-plus" ++ or $test_name =~ "119"); ++ push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}]; ++ } ++ push @Tests, @new; ++ } ++ ++# Remember that triple_test creates from each test with exactly one "IN" ++# file two more tests (.p and .r suffix on name) corresponding to reading ++# input from a file and from a pipe. The pipe-reading test would fail ++# due to a race condition about 1 in 20 times. ++# Remove the IN_PIPE version of the "output-is-input" test above. ++# The others aren't susceptible because they have three inputs each. ++ ++@Tests = grep {$_->[0] ne 'output-is-input.p'} @Tests; ++ + @Tests = add_z_variants \@Tests; + @Tests = triple_test \@Tests; + +diff -urNp coreutils-8.22-orig/tests/pr/pr-tests.pl coreutils-8.22/tests/pr/pr-tests.pl +--- coreutils-8.22-orig/tests/pr/pr-tests.pl 2013-12-04 15:48:30.000000000 +0100 ++++ coreutils-8.22/tests/pr/pr-tests.pl 2014-01-08 13:55:56.144375092 +0100 +@@ -23,6 +23,15 @@ use strict; + + my $prog = 'pr'; + ++my $mb_locale; ++#Uncomment the following line to enable multibyte tests ++$mb_locale = $ENV{LOCALE_FR_UTF8}; ++! defined $mb_locale || $mb_locale eq 'none' ++ and $mb_locale = 'C'; ++ ++my $try = "Try \`$prog --help' for more information.\n"; ++my $inval = "$prog: invalid byte, character or field list\n$try"; ++ + my @tv = ( + + # -b option is no longer an official option. But it's still working to +@@ -466,8 +475,48 @@ push @Tests, + {IN=>{3=>"x\ty\tz\n"}}, + {OUT=>join("\t", qw(a b c m n o x y z)) . "\n"} ]; + ++# Add _POSIX2_VERSION=199209 to the environment of each test ++# that uses an old-style option like +1. ++if ($mb_locale ne 'C') ++ { ++ # Duplicate each test vector, appending "-mb" to the test name and ++ # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we ++ # provide coverage for the distro-added multi-byte code paths. ++ my @new; ++ foreach my $t (@Tests) ++ { ++ my @new_t = @$t; ++ my $test_name = shift @new_t; ++ ++ # Depending on whether pr is multi-byte-patched, ++ # it emits different diagnostics: ++ # non-MB: invalid byte or field list ++ # MB: invalid byte, character or field list ++ # Adjust the expected error output accordingly. ++ if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval} ++ (@new_t)) ++ { ++ my $sub = {ERR_SUBST => 's/, character//'}; ++ push @new_t, $sub; ++ push @$t, $sub; ++ } ++ #temporarily skip some failing tests ++ next if ($test_name =~ "col-0" or $test_name =~ "col-inval"); ++ push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}]; ++ } ++ push @Tests, @new; ++ } ++ + @Tests = triple_test \@Tests; + ++# Remember that triple_test creates from each test with exactly one "IN" ++# file two more tests (.p and .r suffix on name) corresponding to reading ++# input from a file and from a pipe. The pipe-reading test would fail ++# due to a race condition about 1 in 20 times. ++# Remove the IN_PIPE version of the "output-is-input" test above. ++# The others aren't susceptible because they have three inputs each. ++@Tests = grep {$_->[0] ne 'output-is-input.p'} @Tests; ++ + my $save_temps = $ENV{DEBUG}; + my $verbose = $ENV{VERBOSE}; + diff --git a/SOURCES/coreutils-overflow.patch b/SOURCES/coreutils-overflow.patch new file mode 100644 index 0000000..0d55a6d --- /dev/null +++ b/SOURCES/coreutils-overflow.patch @@ -0,0 +1,11 @@ +--- coreutils-5.2.1/src/who.c.overflow 2005-05-25 09:59:06.000000000 +0100 ++++ coreutils-5.2.1/src/who.c 2005-05-25 10:00:31.000000000 +0100 +@@ -75,7 +75,7 @@ + # define UT_TYPE_NEW_TIME(U) false + #endif + +-#define IDLESTR_LEN 6 ++#define IDLESTR_LEN 10 + + #if HAVE_STRUCT_XTMP_UT_PID + # define PIDSTR_DECL_AND_INIT(Var, Utmp_ent) \ diff --git a/SOURCES/coreutils-selinux.patch b/SOURCES/coreutils-selinux.patch new file mode 100644 index 0000000..928ef95 --- /dev/null +++ b/SOURCES/coreutils-selinux.patch @@ -0,0 +1,529 @@ +diff -urNp coreutils-8.21-orig/init.cfg coreutils-8.21/init.cfg +--- coreutils-8.21-orig/init.cfg 2013-01-31 01:46:24.000000000 +0100 ++++ coreutils-8.21/init.cfg 2013-02-15 14:31:58.957469955 +0100 +@@ -308,8 +308,8 @@ require_selinux_() + # Independent of whether SELinux is enabled system-wide, + # the current file system may lack SELinux support. + # Also the current build may have SELinux support disabled. +- case $(ls -Zd .) in +- '? .'|'unlabeled .') ++ case $(ls -Zd . | cut -f4 -d" ") in ++ '?'|'unlabeled') + test -z "$CONFIG_HEADER" \ + && framework_failure_ 'CONFIG_HEADER not defined' + grep '^#define HAVE_SELINUX_SELINUX_H 1' "$CONFIG_HEADER" > /dev/null \ +diff -urNp coreutils-8.21-orig/man/chcon.x coreutils-8.21/man/chcon.x +--- coreutils-8.21-orig/man/chcon.x 2011-08-23 15:44:01.000000000 +0200 ++++ coreutils-8.21/man/chcon.x 2013-02-15 14:31:58.937482694 +0100 +@@ -1,4 +1,4 @@ + [NAME] +-chcon \- change file security context ++chcon \- change file SELinux security context + [DESCRIPTION] + .\" Add any additional description here +diff -urNp coreutils-8.21-orig/man/runcon.x coreutils-8.21/man/runcon.x +--- coreutils-8.21-orig/man/runcon.x 2011-08-23 15:44:01.000000000 +0200 ++++ coreutils-8.21/man/runcon.x 2013-02-15 14:31:58.938486496 +0100 +@@ -1,5 +1,5 @@ + [NAME] +-runcon \- run command with specified security context ++runcon \- run command with specified SELinux security context + [DESCRIPTION] + Run COMMAND with completely-specified CONTEXT, or with current or + transitioned security context modified by one or more of LEVEL, +diff -urNp coreutils-8.21-orig/src/copy.c coreutils-8.21/src/copy.c +--- coreutils-8.21-orig/src/copy.c 2013-02-07 10:37:05.000000000 +0100 ++++ coreutils-8.21/src/copy.c 2013-02-15 14:31:58.941467872 +0100 +@@ -2410,6 +2410,17 @@ copy_internal (char const *src_name, cha + else + { + omitted_permissions = 0; ++ ++ /* For directories, the process global context could be reset for ++ descendents, so use it to set the context for existing dirs here. ++ This will also give earlier indication of failure to set ctx. */ ++ if (x->set_security_context || x->preserve_security_context) ++ if (! set_file_security_ctx (dst_name, x->preserve_security_context, ++ false, x)) ++ { ++ if (x->require_preserve_context) ++ goto un_backup; ++ } + } + + /* Decide whether to copy the contents of the directory. */ +@@ -2415,6 +2426,8 @@ copy_internal (char const *src_name, cha + { + /* Here, we are crossing a file system boundary and cp's -x option + is in effect: so don't copy the contents of this directory. */ ++ if (x->preserve_security_context) ++ restore_default_fscreatecon_or_die (); + } + else + { +@@ -2602,7 +2613,7 @@ copy_internal (char const *src_name, cha + + /* With -Z or --preserve=context, set the context for existing files. + Note this is done already for copy_reg() for reasons described therein. */ +- if (!new_dst && !x->copy_as_regular ++ if (!new_dst && !x->copy_as_regular && !S_ISDIR (src_mode) + && (x->set_security_context || x->preserve_security_context)) + { + if (! set_file_security_ctx (dst_name, x->preserve_security_context, +diff -urNp coreutils-8.21-orig/src/cp.c coreutils-8.21/src/cp.c +--- coreutils-8.21-orig/src/cp.c 2013-02-07 10:37:05.000000000 +0100 ++++ coreutils-8.21/src/cp.c 2013-02-15 14:31:58.945468929 +0100 +@@ -201,6 +202,9 @@ Copy SOURCE to DEST, or multiple SOURCE( + all\n\ + "), stdout); + fputs (_("\ ++ -c deprecated, same as --preserve=context\n\ ++"), stdout); ++ fputs (_("\ + --no-preserve=ATTR_LIST don't preserve the specified attributes\n\ + --parents use full source file name under DIRECTORY\n\ + "), stdout); +@@ -933,7 +939,7 @@ main (int argc, char **argv) + we'll actually use backup_suffix_string. */ + backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); + +- while ((c = getopt_long (argc, argv, "abdfHilLnprst:uvxPRS:TZ", ++ while ((c = getopt_long (argc, argv, "abcdfHilLnprst:uvxPRS:TZ", + long_opts, NULL)) + != -1) + { +@@ -981,6 +987,17 @@ main (int argc, char **argv) + copy_contents = true; + break; + ++ case 'c': ++ fprintf (stderr, "%s: warning: option '-c' is deprecated, please use '--preserve=context' instead\n", argv[0]); ++ if ( x.set_security_context ) { ++ (void) fprintf(stderr, "%s: cannot force target context and preserve it\n", argv[0]); ++ exit( 1 ); ++ } ++ else if (selinux_enabled) { ++ x.preserve_security_context = true; ++ x.require_preserve_context = true; ++ } ++ break; + case 'd': + x.preserve_links = true; + x.dereference = DEREF_NEVER; +diff -urNp coreutils-8.21-orig/src/id.c coreutils-8.21/src/id.c +--- coreutils-8.21-orig/src/id.c 2013-01-31 01:46:24.000000000 +0100 ++++ coreutils-8.21/src/id.c 2013-02-15 14:31:58.946469154 +0100 +@@ -106,7 +106,7 @@ int + main (int argc, char **argv) + { + int optc; +- int selinux_enabled = (is_selinux_enabled () > 0); ++ bool selinux_enabled = (is_selinux_enabled () > 0); + bool smack_enabled = is_smack_enabled (); + bool opt_zero = false; + char *pw_name = NULL; +diff -urNp coreutils-8.21-orig/src/install.c coreutils-8.21/src/install.c +--- coreutils-8.21-orig/src/install.c 2013-02-07 10:37:05.000000000 +0100 ++++ coreutils-8.21/src/install.c 2013-02-15 14:31:58.948469440 +0100 +@@ -639,7 +640,7 @@ In the 4th form, create all components o + -v, --verbose print the name of each directory as it is created\n\ + "), stdout); + fputs (_("\ +- --preserve-context preserve SELinux security context\n\ ++ -P, --preserve-context preserve SELinux security context (-P deprecated)\n\ + -Z, --context[=CTX] set SELinux security context of destination file to\n\ + default type, or to CTX if specified\n\ + "), stdout); +@@ -782,7 +783,7 @@ main (int argc, char **argv) + we'll actually use backup_suffix_string. */ + backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); + +- while ((optc = getopt_long (argc, argv, "bcCsDdg:m:o:pt:TvS:Z", long_options, ++ while ((optc = getopt_long (argc, argv, "bcCsDdg:m:o:pPt:TvS:Z", long_options, + NULL)) != -1) + { + switch (optc) +@@ -853,6 +854,8 @@ main (int argc, char **argv) + no_target_directory = true; + break; + ++ case 'P': ++ fprintf (stderr, "%s: warning: option '-P' is deprecated, please use '--preserve-context' instead\n", argv[0]); + case PRESERVE_CONTEXT_OPTION: + if (! selinux_enabled) + { +@@ -860,6 +862,10 @@ main (int argc, char **argv) + "this kernel is not SELinux-enabled")); + break; + } ++ if ( x.set_security_context ) { ++ (void) fprintf(stderr, "%s: cannot force target context and preserve it\n", argv[0]); ++ exit( 1 ); ++ } + x.preserve_security_context = true; + use_default_selinux_context = false; + break; +diff -urNp coreutils-8.21-orig/src/ls.c coreutils-8.21/src/ls.c +--- coreutils-8.21-orig/src/ls.c 2013-02-03 04:24:02.000000000 +0100 ++++ coreutils-8.21/src/ls.c 2013-02-15 14:31:58.953469008 +0100 +@@ -165,7 +165,8 @@ enum filetype + symbolic_link, + sock, + whiteout, +- arg_directory ++ arg_directory, ++ command_line + }; + + /* Display letters and indicators for each filetype. +@@ -281,6 +282,7 @@ static void queue_directory (char const + bool command_line_arg); + static void sort_files (void); + static void parse_ls_color (void); ++static void print_scontext_format (const struct fileinfo *f); + + /* Initial size of hash table. + Most hierarchies are likely to be shallower than this. */ +@@ -350,7 +352,7 @@ static struct pending *pending_dirs; + + static struct timespec current_time; + +-static bool print_scontext; ++static int print_scontext = 0; + static char UNKNOWN_SECURITY_CONTEXT[] = "?"; + + /* Whether any of the files has an ACL. This affects the width of the +@@ -390,7 +392,9 @@ enum format + one_per_line, /* -1 */ + many_per_line, /* -C */ + horizontal, /* -x */ +- with_commas /* -m */ ++ with_commas, /* -m */ ++ security_format, /* -Z */ ++ invalid_format + }; + + static enum format format; +@@ -793,6 +797,9 @@ enum + SHOW_CONTROL_CHARS_OPTION, + SI_OPTION, + SORT_OPTION, ++ CONTEXT_OPTION, ++ LCONTEXT_OPTION, ++ SCONTEXT_OPTION, + TIME_OPTION, + TIME_STYLE_OPTION + }; +@@ -839,7 +846,9 @@ static struct option const long_options[ + {"time-style", required_argument, NULL, TIME_STYLE_OPTION}, + {"color", optional_argument, NULL, COLOR_OPTION}, + {"block-size", required_argument, NULL, BLOCK_SIZE_OPTION}, +- {"context", no_argument, 0, 'Z'}, ++ {"context", no_argument, 0, CONTEXT_OPTION}, ++ {"lcontext", no_argument, 0, LCONTEXT_OPTION}, ++ {"scontext", no_argument, 0, SCONTEXT_OPTION}, + {"author", no_argument, NULL, AUTHOR_OPTION}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, +@@ -849,12 +858,12 @@ static struct option const long_options[ + static char const *const format_args[] = + { + "verbose", "long", "commas", "horizontal", "across", +- "vertical", "single-column", NULL ++ "vertical", "single-column", "context", NULL + }; + static enum format const format_types[] = + { + long_format, long_format, with_commas, horizontal, horizontal, +- many_per_line, one_per_line ++ many_per_line, one_per_line, security_format + }; + ARGMATCH_VERIFY (format_args, format_types); + +@@ -1296,7 +1305,8 @@ main (int argc, char **argv) + /* Avoid following symbolic links when possible. */ + if (is_colored (C_ORPHAN) + || (is_colored (C_EXEC) && color_symlink_as_referent) +- || (is_colored (C_MISSING) && format == long_format)) ++ || (is_colored (C_MISSING) && (format == long_format ++ || format == security_format))) + check_symlink_color = true; + + /* If the standard output is a controlling terminal, watch out +@@ -1343,7 +1353,7 @@ main (int argc, char **argv) + if (dereference == DEREF_UNDEFINED) + dereference = ((immediate_dirs + || indicator_style == classify +- || format == long_format) ++ || format == long_format || format == security_format) + ? DEREF_NEVER + : DEREF_COMMAND_LINE_SYMLINK_TO_DIR); + +@@ -1363,7 +1373,7 @@ main (int argc, char **argv) + + format_needs_stat = sort_type == sort_time || sort_type == sort_size + || format == long_format +- || print_scontext ++ || format == security_format || print_scontext + || print_block_size; + format_needs_type = (! format_needs_stat + && (recursive +@@ -1394,7 +1404,7 @@ main (int argc, char **argv) + } + else + do +- gobble_file (argv[i++], unknown, NOT_AN_INODE_NUMBER, true, ""); ++ gobble_file (argv[i++], command_line, NOT_AN_INODE_NUMBER, true, ""); + while (i < argc); + + if (cwd_n_used) +@@ -1565,7 +1575,7 @@ decode_switches (int argc, char **argv) + ignore_mode = IGNORE_DEFAULT; + ignore_patterns = NULL; + hide_patterns = NULL; +- print_scontext = false; ++ print_scontext = 0; + + /* FIXME: put this in a function. */ + { +@@ -1941,13 +1951,27 @@ decode_switches (int argc, char **argv) + break; + + case 'Z': +- print_scontext = true; ++ print_scontext = 1; ++ format = security_format; + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + ++ case CONTEXT_OPTION: /* default security context format */ ++ print_scontext = 1; ++ format = security_format; ++ break; ++ case LCONTEXT_OPTION: /* long format plus security context */ ++ print_scontext = 1; ++ format = long_format; ++ break; ++ case SCONTEXT_OPTION: /* short form of new security format */ ++ print_scontext = 0; ++ format = security_format; ++ break; ++ + default: + usage (LS_FAILURE); + } +@@ -2883,6 +2907,7 @@ gobble_file (char const *name, enum file + memset (f, '\0', sizeof *f); + f->stat.st_ino = inode; + f->filetype = type; ++ f->scontext = NULL; + + if (command_line_arg + || format_needs_stat +@@ -2995,7 +3020,7 @@ gobble_file (char const *name, enum file + && print_with_color && is_colored (C_CAP)) + f->has_capability = has_capability_cache (absolute_name, f); + +- if (format == long_format || print_scontext) ++ if (format == long_format || format == security_format || print_scontext) + { + bool have_scontext = false; + bool have_acl = false; +@@ -3016,7 +3041,7 @@ gobble_file (char const *name, enum file + err = 0; + } + +- if (err == 0 && format == long_format) ++ if (err == 0 && (format == long_format || format == security_format)) + { + int n = file_has_acl_cache (absolute_name, f); + err = (n < 0); +@@ -3035,7 +3060,8 @@ gobble_file (char const *name, enum file + } + + if (S_ISLNK (f->stat.st_mode) +- && (format == long_format || check_symlink_color)) ++ && (format == long_format || format == security_format ++ || check_symlink_color)) + { + struct stat linkstats; + +@@ -3054,6 +3080,7 @@ gobble_file (char const *name, enum file + command line are automatically traced if not being + listed as files. */ + if (!command_line_arg || format == long_format ++ || format == security_format + || !S_ISDIR (linkstats.st_mode)) + { + /* Get the linked-to file's mode for the filetype indicator +@@ -3087,7 +3114,7 @@ gobble_file (char const *name, enum file + block_size_width = len; + } + +- if (format == long_format) ++ if (format == long_format || format == security_format) + { + if (print_owner) + { +@@ -3591,6 +3618,13 @@ print_current_files (void) + print_long_format (sorted_file[i]); + DIRED_PUTCHAR ('\n'); + } ++ break; ++ case security_format: ++ for (i = 0; i < cwd_n_used; i++) ++ { ++ print_scontext_format (sorted_file[i]); ++ DIRED_PUTCHAR ('\n'); ++ } + break; + } + } +@@ -3753,6 +3787,67 @@ format_inode (char *buf, size_t buflen, + : (char *) "?"); + } + ++/* Print info about f in scontext format */ ++static void ++print_scontext_format (const struct fileinfo *f) ++{ ++ char modebuf[12]; ++ ++ /* 7 fields that may require LONGEST_HUMAN_READABLE bytes, ++ 1 10-byte mode string, ++ 9 spaces, one following each of these fields, and ++ 1 trailing NUL byte. */ ++ ++ char init_bigbuf[7 * LONGEST_HUMAN_READABLE + 10 + 9 + 1]; ++ char *buf = init_bigbuf; ++ char *p; ++ ++ p = buf; ++ ++ if ( print_scontext ) { /* zero means terse listing */ ++ filemodestring (&f->stat, modebuf); ++ if (! any_has_acl) ++ modebuf[10] = '\0'; ++ else if (f->acl_type == ACL_T_SELINUX_ONLY) ++ modebuf[10] = '.'; ++ else if (f->acl_type == ACL_T_YES) ++ modebuf[10] = '+'; ++ modebuf[11] = '\0'; ++ ++ /* print mode */ ++ ++ (void) sprintf (p, "%s ", modebuf); ++ p += strlen (p); ++ ++ /* print standard user and group */ ++ ++ DIRED_FPUTS (buf, stdout, p - buf); ++ format_user (f->stat.st_uid, owner_width, f->stat_ok); ++ format_group (f->stat.st_gid, group_width, f->stat_ok); ++ p = buf; ++ } ++ ++ (void) sprintf (p, "%-32s ", f->scontext ?: ""); ++ p += strlen (p); ++ ++ DIRED_INDENT (); ++ DIRED_FPUTS (buf, stdout, p - buf); ++ size_t w = print_name_with_quoting (f, false, &dired_obstack, p - buf); ++ ++ if (f->filetype == symbolic_link) { ++ if (f->linkname) { ++ DIRED_FPUTS_LITERAL (" -> ", stdout); ++ print_name_with_quoting (f, true, NULL, (p - buf) + w + 4); ++ if (indicator_style != none) ++ print_type_indicator (f->stat_ok, f->linkmode, f->filetype); ++ } ++ } ++ else { ++ if (indicator_style != none) ++ print_type_indicator (f->stat_ok, f->stat.st_mode, f->filetype); ++ } ++} ++ + /* Print information about F in long format. */ + static void + print_long_format (const struct fileinfo *f) +@@ -3844,9 +3939,15 @@ print_long_format (const struct fileinfo + The latter is wrong when nlink_width is zero. */ + p += strlen (p); + ++ if (print_scontext) ++ { ++ sprintf (p, "%-32s ", f->scontext ? f->scontext : ""); ++ p += strlen (p); ++ } ++ + DIRED_INDENT (); + +- if (print_owner || print_group || print_author || print_scontext) ++ if (print_owner || print_group || print_author) + { + DIRED_FPUTS (buf, stdout, p - buf); + +@@ -3859,9 +3960,6 @@ print_long_format (const struct fileinfo + if (print_author) + format_user (f->stat.st_author, author_width, f->stat_ok); + +- if (print_scontext) +- format_user_or_group (f->scontext, 0, scontext_width); +- + p = buf; + } + +@@ -4207,9 +4305,6 @@ print_file_name_and_frills (const struct + : human_readable (ST_NBLOCKS (f->stat), buf, human_output_opts, + ST_NBLOCKSIZE, output_block_size)); + +- if (print_scontext) +- printf ("%*s ", format == with_commas ? 0 : scontext_width, f->scontext); +- + size_t width = print_name_with_quoting (f, false, NULL, start_col); + + if (indicator_style != none) +@@ -4417,9 +4512,6 @@ length_of_file_name_and_frills (const st + output_block_size)) + : block_size_width); + +- if (print_scontext) +- len += 1 + (format == with_commas ? strlen (f->scontext) : scontext_width); +- + quote_name (NULL, f->name, filename_quoting_options, &name_width); + len += name_width; + +@@ -4856,9 +4948,16 @@ Sort entries alphabetically if none of - + -w, --width=COLS assume screen width instead of current value\n\ + -x list entries by lines instead of by columns\n\ + -X sort alphabetically by entry extension\n\ +- -Z, --context print any SELinux security context of each file\n\ + -1 list one file per line\n\ + "), stdout); ++ fputs(_("\nSELinux options:\n\n\ ++ --lcontext Display security context. Enable -l. Lines\n\ ++ will probably be too wide for most displays.\n\ ++ -Z, --context Display security context so it fits on most\n\ ++ displays. Displays only mode, user, group,\n\ ++ security context and file name.\n\ ++ --scontext Display only security context and file name.\n\ ++"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + emit_size_note (); +diff -urNp coreutils-8.21-orig/tests/misc/selinux.sh coreutils-8.21/tests/misc/selinux.sh +--- coreutils-8.21-orig/tests/misc/selinux.sh 2013-01-31 01:46:24.000000000 +0100 ++++ coreutils-8.21/tests/misc/selinux.sh 2013-02-15 14:31:58.957469955 +0100 +@@ -37,7 +37,7 @@ chcon $ctx f d p || + + # inspect that context with both ls -Z and stat. + for i in d f p; do +- c=$(ls -dogZ $i|cut -d' ' -f3); test x$c = x$ctx || fail=1 ++ c=$(ls -dogZ $i|cut -d' ' -f4); test x$c = x$ctx || fail=1 + c=$(stat --printf %C $i); test x$c = x$ctx || fail=1 + done + diff --git a/SOURCES/coreutils-selinuxmanpages.patch b/SOURCES/coreutils-selinuxmanpages.patch new file mode 100644 index 0000000..6bd7aaa --- /dev/null +++ b/SOURCES/coreutils-selinuxmanpages.patch @@ -0,0 +1,53 @@ +diff -urNp coreutils-6.10-orig/doc/coreutils.texi coreutils-6.10/doc/coreutils.texi +--- coreutils-6.10-orig/doc/coreutils.texi 2008-04-07 17:52:11.000000000 +0200 ++++ coreutils-6.10/doc/coreutils.texi 2008-04-07 18:01:43.000000000 +0200 +@@ -6981,6 +6981,11 @@ for i; do + exit $fail + @end example + ++@item -c ++@cindex SELinux security context information, preserving ++Preserve SELinux security context of the original files if possible. ++Some file systems don't support storing of SELinux security context. ++ + @item --copy-contents + @cindex directories, copying recursively + @cindex copying directories recursively +diff -urNp coreutils-8.22-orig/doc/coreutils.texi coreutils-8.22/doc/coreutils.texi +--- coreutils-8.22-orig/doc/coreutils.texi 2015-06-12 14:16:22.672832509 +0200 ++++ coreutils-8.22/doc/coreutils.texi 2015-06-12 14:43:02.646303224 +0200 +@@ -7311,13 +7311,32 @@ it also affects the HP-UX @command{ls} p + + @item -Z + @itemx --context ++@itemx --scontext ++@itemx --lcontext ++@itemx --format=context + @opindex -Z + @opindex --context ++@opindex --format=security ++@opindex --scontext ++@opindex --lcontext + @cindex SELinux + @cindex security context + Display the SELinux security context or @samp{?} if none is found. +-When used with the @option{-l} option, print the security context +-to the left of the size column. ++@option{-Z} counts as format option and enables displaying of SELinux ++context. ++@option{--scontext} prints SELinux context left to the file name. ++@option{--lcontext} prints long format with SELinux context in the middle. ++@option{--context} prints permissions, user/group, context and file name (in comparison to @option{--lcontext}, omits size, modification time and number of hardlinks). ++ ++Note: When multiple format options are used in @command{ls}, ++the last one is used. Therefore @samp{ls -lZ} (security format ++is last - same as @samp{ls --context}) differs from @samp{ls -Zl} ++(long format with selinux context is shown, same as @samp{ls --lcontext}) ++ ++Do not rely on @option{--scontext} and @option{--lcontext} ++options in your scripts. They will be removed in next major ++version of Red Hat Enterprise Linux. @option{--context} behaviour ++will change (just enabling displaying SELinux context). + + @end table + diff --git a/SOURCES/sh-utils-2.0.11-dateman.patch b/SOURCES/sh-utils-2.0.11-dateman.patch new file mode 100644 index 0000000..8684dc7 --- /dev/null +++ b/SOURCES/sh-utils-2.0.11-dateman.patch @@ -0,0 +1,12 @@ +diff -urNp coreutils-5.97-orig/man/date.x coreutils-5.97/man/date.x +--- coreutils-5.97-orig/man/date.x 1999-11-02 15:07:36.000000000 +0100 ++++ coreutils-5.97/man/date.x 2008-10-15 10:13:31.000000000 +0200 +@@ -11,3 +11,8 @@ + relative date, and numbers. An empty string indicates the beginning + of the day. The date string format is more complex than is easily + documented here but is fully described in the info documentation. ++[ENVIRONMENT] ++.TP ++TZ ++Specifies the timezone, unless overridden by command line parameters. ++If neither is specified, the setting from /etc/localtime is used. diff --git a/SPECS/coreutils.spec b/SPECS/coreutils.spec new file mode 100644 index 0000000..2573878 --- /dev/null +++ b/SPECS/coreutils.spec @@ -0,0 +1,2120 @@ +Summary: A set of basic GNU tools commonly used in shell scripts +Name: coreutils +Version: 8.22 +Release: 24%{?dist} +License: GPLv3+ +Group: System Environment/Base +Url: http://www.gnu.org/software/coreutils/ +Source0: ftp://ftp.gnu.org/gnu/%{name}/%{name}-%{version}.tar.xz +Source101: coreutils-DIR_COLORS +Source102: coreutils-DIR_COLORS.lightbgcolor +Source103: coreutils-DIR_COLORS.256color +Source105: coreutils-colorls.sh +Source106: coreutils-colorls.csh + +# From upstream +#Fix segfault in cp (in selinux context code) +Patch1: coreutils-8.22-cp-selinux.patch +#Mark veritas filesystem as remote (use polling) +Patch2: coreutils-8.22-vxfs-noinotify.patch +#Fix sparse test on xfs and btrfs filesystems +Patch3: coreutils-8.22-xfs-tests.patch +#Add dd option for progress reporting +Patch4: coreutils-8.22-dd-progress.patch +#Separate -Z and --context options where necessary in --help and manpage +Patch5: coreutils-8.22-selinux-optionsseparate.patch +#Handle du bindmount cycles more gracefully +Patch6: coreutils-8.22-du-bindmountcycles.patch +#Prevent possible race condition for hardlinks in mv +Patch7: coreutils-8.22-mv-hardlinksrace.patch +#Use new version of getdisk function in df (better results) +Patch8: coreutils-8.22-df-getdisk.patch +#Use new version of find_mount_list function +Patch9: coreutils-8.22-df-filtermountlistupdate.patch +#Prevent potential corruption of sparse files in cp +Patch10: coreutils-8.22-cp-sparsecorrupt.patch +#improve dirent d_type support verification (xfs build failure, #1263341) +Patch11: coreutils-8.22-xfsbuildfailure.patch +#Update filesystem magic lists from latest upstream (coreutils-8.25) +Patch12: coreutils-8.22-newfilesystems.patch +#Fix crash in date with empty TZ envvar +Patch13: coreutils-8.22-date-emptyTZ.patch +#df -l: do not hang on a dead autofs mount point (#1309247) +Patch14: coreutils-8.22-df-autofs.patch + +# ls: allow interruption when reading slow directories (#1421802) +Patch15: coreutils-8.22-ls-interruption.patch + +# df: do not stat file systems that do not satisfy the -t/-x args (#1511947) +Patch17: coreutils-8.22-df-stat.patch + +# mv -n: do not overwrite the destination (#1526265) +# http://git.savannah.gnu.org/cgit/coreutils.git/commit/?id=v8.29-9-g29baf25aa +Patch18: coreutils-8.22-mv-n-noreplace.patch + +# df: prioritize mounts nearer the device root (#1042840) +Patch19: coreutils-8.22-df-bind-mount.patch + +# df: avoid stat() for dummy file systems with -l (#1668137) +Patch20: coreutils-8.22-df-dummy-local.patch + +# doc: fix typo in date example (#1620624) +Patch21: coreutils-8.22-date-example-typo.patch + +# doc: improve description of the --kibibytes option of ls (#1527391) +Patch22: coreutils-8.22-doc-ls-kibibytes.patch + +# Our patches +#general patch to workaround koji build system issues +Patch100: coreutils-6.10-configuration.patch +#add note about no difference between binary/text mode on Linux - md5sum manpage +Patch101: coreutils-6.10-manpages.patch +#temporarily workaround probable kernel issue with TCSADRAIN(#504798) +Patch102: coreutils-7.4-sttytcsadrain.patch +#do display processor type for uname -p/-i based on uname(2) syscall +Patch103: coreutils-8.2-uname-processortype.patch +#df --direct +Patch104: coreutils-df-direct.patch +#add note about mkdir --mode behaviour into info documentation(#610559) +Patch107: coreutils-8.4-mkdir-modenote.patch +#fix gnulib tests on ppc64le +Patch108: coreutils-8.22-ppc64le.patch +#fix groups for session in id +Patch109: coreutils-8.22-id-groups.patch +#fix some non-default tests failing in beaker environment(#1247641) +Patch110: coreutils-8.22-non-defaulttests.patch +#Fix sort -h for other than first field +Patch111: coreutils-8.22-sort-blanks.patch + +# sh-utils +#add info about TZ envvar to date manpage +Patch703: sh-utils-2.0.11-dateman.patch +Patch713: coreutils-4.5.3-langinfo.patch + +# (sb) lin18nux/lsb compliance - multibyte functionality patch +Patch800: coreutils-i18n.patch + +# fold: preserve new-lines in mutlibyte text (#1418505) +Patch801: coreutils-i18n-fold-newline.patch + +# sort -M: fix memory leak when using multibyte locale (#1540059) +Patch802: coreutils-i18n-sort-memleak.patch + +#getgrouplist() patch from Ulrich Drepper. +Patch908: coreutils-getgrouplist.patch +#Prevent buffer overflow in who(1) (bug #158405). +Patch912: coreutils-overflow.patch +#Temporarily disable df symlink test, failing +Patch913: coreutils-8.22-temporarytestoff.patch +#Disable id/setgid.sh test, fix false positive failure of cp-a-selinux test +# (#1266501, #1266500) +Patch914: coreutils-8.22-failingtests.patch + +#SELINUX Patch - implements Redhat changes +#(upstream did some SELinux implementation unlike with RedHat patch) +Patch950: coreutils-selinux.patch +Patch951: coreutils-selinuxmanpages.patch + +Conflicts: filesystem < 3 +Provides: /bin/basename +Provides: /bin/cat +Provides: /bin/chgrp +Provides: /bin/chmod +Provides: /bin/chown +Provides: /bin/cp +Provides: /bin/cut +Provides: /bin/date +Provides: /bin/dd +Provides: /bin/df +Provides: /bin/echo +Provides: /bin/env +Provides: /bin/false +Provides: /bin/ln +Provides: /bin/ls +Provides: /bin/mkdir +Provides: /bin/mknod +Provides: /bin/mktemp +Provides: /bin/mv +Provides: /bin/nice +Provides: /bin/pwd +Provides: /bin/readlink +Provides: /bin/rm +Provides: /bin/rmdir +Provides: /bin/sleep +Provides: /bin/sort +Provides: /bin/stty +Provides: /bin/sync +Provides: /bin/touch +Provides: /bin/true +Provides: /bin/uname + +BuildRequires: bison +BuildRequires: gettext-devel +BuildRequires: libselinux-devel +BuildRequires: libacl-devel +BuildRequires: texinfo +BuildRequires: autoconf +BuildRequires: automake +BuildRequires: libcap-devel +BuildRequires: libattr-devel +BuildRequires: openssl-devel +BuildRequires: gmp-devel +BuildRequires: attr +BuildRequires: strace + +Requires(pre): /sbin/install-info +Requires(preun): /sbin/install-info +Requires(post): /sbin/install-info +Requires(post): grep +Requires: ncurses +Requires: gmp + +Provides: fileutils = %{version}-%{release} +Provides: sh-utils = %{version}-%{release} +Provides: stat = %{version}-%{release} +Provides: textutils = %{version}-%{release} +#old mktemp package had epoch 3, so we have to use 4 for coreutils +Provides: mktemp = 4:%{version}-%{release} +Provides: bundled(gnulib) +Obsoletes: mktemp < 4:%{version}-%{release} +Obsoletes: fileutils <= 4.1.9 +Obsoletes: sh-utils <= 2.0.12 +Obsoletes: stat <= 3.3 +Obsoletes: textutils <= 2.0.21 +#coreutils-libs dropped in f17 +Obsoletes: coreutils-libs < 8.13 + +%description +These are the GNU core utilities. This package is the combination of +the old GNU fileutils, sh-utils, and textutils packages. + +%prep +%setup -q + +# From upstream +%patch1 -p1 -b .nullcontext +%patch2 -p1 -b .vxfs +%patch3 -p1 -b .xfs +%patch4 -p1 -b .progress +%patch6 -p1 -b .bindmount +%patch7 -p1 -b .race +%patch8 -p1 -b .getdisk +%patch9 -p1 -b .findmnt +%patch10 -p1 -b .sparse +%patch11 -p1 -b .d_type +%patch12 -p1 -b .newfs +%patch13 -p1 -b .emptytz +%patch14 -p1 -b .df-autofs + +# Our patches +%patch100 -p1 -b .configure +%patch101 -p1 -b .manpages +%patch102 -p1 -b .tcsadrain +%patch103 -p1 -b .sysinfo +%patch104 -p1 -b .dfdirect +%patch107 -p1 -b .mkdirmode +%patch108 -p1 -b .ppc64le +%patch109 -p1 -b .groups +%patch110 -p1 -b .nondefault +%patch111 -p1 -b .blanks + +# sh-utils +%patch703 -p1 -b .dateman +%patch713 -p1 -b .langinfo + +# li18nux/lsb +%patch800 -p1 -b .i18n + +# Coreutils +%patch908 -p1 -b .getgrouplist +%patch912 -p1 -b .overflow +%patch913 -p1 -b .testoff +%patch914 -p1 -b .testfail + +#SELinux +%patch950 -p1 -b .selinux +%patch951 -p1 -b .selinuxman +%patch5 -p1 -b .separate + +# patches added in RHEL-7.5 +%patch801 -p1 +%patch15 -p1 +%patch17 -p1 + +# patches added in RHEL-7.6 +%patch18 -p1 +%patch802 -p1 + +# patches added in RHEL-7.7 +%patch19 -p1 +%patch20 -p1 +%patch21 -p1 +%patch22 -p1 + +chmod a+x tests/misc/sort-mb-tests.sh tests/df/direct.sh tests/cp/no-ctx.sh tests/dd/stats.sh || : + +#fix typos/mistakes in localized documentation(#439410, #440056) +find ./po/ -name "*.p*" | xargs \ + sed -i \ + -e 's/-dpR/-cdpR/' + +%build +export CFLAGS="$RPM_OPT_FLAGS -fno-strict-aliasing -fpic" +%{expand:%%global optflags %{optflags} -D_GNU_SOURCE=1} + +# needed to properly include the renameat2 gnulib module +autoreconf -fiv + +%configure --enable-largefile \ + --with-openssl=optional ac_cv_lib_crypto_MD5=no \ + --enable-install-program=hostname,arch \ + --with-tty-group \ + DEFAULT_POSIX2_VERSION=200112 alternative=199209 || : + +# Regenerate manpages +touch man/*.x +# Do not regenerate fs-is-local.h +touch src/fs-is-local.h + +make all %{?_smp_mflags} + +# XXX docs should say /var/run/[uw]tmp not /etc/[uw]tmp +sed -i -e 's,/etc/utmp,/var/run/utmp,g;s,/etc/wtmp,/var/run/wtmp,g' doc/coreutils.texi + +%check +make check + +%install +make DESTDIR=$RPM_BUILD_ROOT install + +# man pages are not installed with make install +make mandir=$RPM_BUILD_ROOT%{_mandir} install-man + +# fix japanese catalog file +if [ -d $RPM_BUILD_ROOT%{_datadir}/locale/ja_JP.EUC/LC_MESSAGES ]; then + mkdir -p $RPM_BUILD_ROOT%{_datadir}/locale/ja/LC_MESSAGES + mv $RPM_BUILD_ROOT%{_datadir}/locale/ja_JP.EUC/LC_MESSAGES/*mo \ + $RPM_BUILD_ROOT%{_datadir}/locale/ja/LC_MESSAGES + rm -rf $RPM_BUILD_ROOT%{_datadir}/locale/ja_JP.EUC +fi + +bzip2 -9f ChangeLog + +# let be compatible with old fileutils, sh-utils and textutils packages : +mkdir -p $RPM_BUILD_ROOT{%{_bindir},%{_sbindir}} + +# chroot was in /usr/sbin : +mv $RPM_BUILD_ROOT{%_bindir,%_sbindir}/chroot + +mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/profile.d +install -p -c -m644 %SOURCE101 $RPM_BUILD_ROOT%{_sysconfdir}/DIR_COLORS +install -p -c -m644 %SOURCE102 $RPM_BUILD_ROOT%{_sysconfdir}/DIR_COLORS.lightbgcolor +install -p -c -m644 %SOURCE103 $RPM_BUILD_ROOT%{_sysconfdir}/DIR_COLORS.256color +install -p -c -m644 %SOURCE105 $RPM_BUILD_ROOT%{_sysconfdir}/profile.d/colorls.sh +install -p -c -m644 %SOURCE106 $RPM_BUILD_ROOT%{_sysconfdir}/profile.d/colorls.csh + +# These come from util-linux and/or procps. +for i in hostname uptime kill ; do + rm $RPM_BUILD_ROOT{%{_bindir}/$i,%{_mandir}/man1/$i.1} +done + +# Compress ChangeLogs from before the fileutils/textutils/etc merge +bzip2 -f9 old/*/C* + +# Use hard links instead of symbolic links for LC_TIME files (bug #246729). +find %{buildroot}%{_datadir}/locale -type l | \ +(while read link + do + target=$(readlink "$link") + rm -f "$link" + ln "$(dirname "$link")/$target" "$link" + done) + +%find_lang %name + +# (sb) Deal with Installed (but unpackaged) file(s) found +rm -f $RPM_BUILD_ROOT%{_infodir}/dir + +%pre +# We must deinstall these info files since they're merged in +# coreutils.info. else their postun'll be run too late +# and install-info will fail badly because of duplicates +for file in sh-utils textutils fileutils; do + if [ -f %{_infodir}/$file.info.gz ]; then + /sbin/install-info --delete %{_infodir}/$file.info.gz --dir=%{_infodir}/dir &> /dev/null || : + fi +done + +%preun +if [ $1 = 0 ]; then + if [ -f %{_infodir}/%{name}.info.gz ]; then + /sbin/install-info --delete %{_infodir}/%{name}.info.gz %{_infodir}/dir || : + fi +fi + +%post +%{_bindir}/grep -v '(sh-utils)\|(fileutils)\|(textutils)' %{_infodir}/dir > \ + %{_infodir}/dir.rpmmodify || exit 0 + /bin/mv -f %{_infodir}/dir.rpmmodify %{_infodir}/dir +if [ -f %{_infodir}/%{name}.info.gz ]; then + /sbin/install-info %{_infodir}/%{name}.info.gz %{_infodir}/dir || : +fi + +%files -f %{name}.lang +%defattr(-,root,root,-) +%dir %{_datadir}/locale/*/LC_TIME +%config(noreplace) %{_sysconfdir}/DIR_COLORS* +%config(noreplace) %{_sysconfdir}/profile.d/* +%doc COPYING ABOUT-NLS ChangeLog.bz2 NEWS README THANKS TODO old/* +%{_bindir}/arch +%{_bindir}/basename +%{_bindir}/cat +%{_bindir}/chgrp +%{_bindir}/chmod +%{_bindir}/chown +%{_bindir}/cp +%{_bindir}/cut +%{_bindir}/date +%{_bindir}/dd +%{_bindir}/df +%{_bindir}/echo +%{_bindir}/env +%{_bindir}/false +%{_bindir}/link +%{_bindir}/ln +%{_bindir}/ls +%{_bindir}/mkdir +%{_bindir}/mknod +%{_bindir}/mv +%{_bindir}/nice +%{_bindir}/pwd +%{_bindir}/readlink +%{_bindir}/rm +%{_bindir}/rmdir +%{_bindir}/sleep +%{_bindir}/sort +%{_bindir}/stty +%{_bindir}/sync +%{_bindir}/mktemp +%{_bindir}/touch +%{_bindir}/true +%{_bindir}/uname +%{_bindir}/unlink +%{_bindir}/[ +%{_bindir}/base64 +%{_bindir}/chcon +%{_bindir}/cksum +%{_bindir}/comm +%{_bindir}/csplit +%{_bindir}/dir +%{_bindir}/dircolors +%{_bindir}/dirname +%{_bindir}/du +%{_bindir}/expand +%{_bindir}/expr +%{_bindir}/factor +%{_bindir}/fmt +%{_bindir}/fold +%{_bindir}/groups +%{_bindir}/head +%{_bindir}/hostid +%{_bindir}/id +%{_bindir}/install +%{_bindir}/join +%{_bindir}/logname +%{_bindir}/md5sum +%{_bindir}/mkfifo +%{_bindir}/nl +%{_bindir}/nohup +%{_bindir}/nproc +%{_bindir}/numfmt +%{_bindir}/od +%{_bindir}/paste +%{_bindir}/pathchk +%{_bindir}/pinky +%{_bindir}/pr +%{_bindir}/printenv +%{_bindir}/printf +%{_bindir}/ptx +%{_bindir}/realpath +%{_bindir}/runcon +%{_bindir}/seq +%{_bindir}/sha1sum +%{_bindir}/sha224sum +%{_bindir}/sha256sum +%{_bindir}/sha384sum +%{_bindir}/sha512sum +%{_bindir}/shred +%{_bindir}/shuf +%{_bindir}/split +%{_bindir}/stat +%{_bindir}/stdbuf +%{_bindir}/sum +%{_bindir}/tac +%{_bindir}/tail +%{_bindir}/tee +%{_bindir}/test +%{_bindir}/timeout +%{_bindir}/tr +%{_bindir}/truncate +%{_bindir}/tsort +%{_bindir}/tty +%{_bindir}/unexpand +%{_bindir}/uniq +%{_bindir}/users +%{_bindir}/vdir +%{_bindir}/wc +%{_bindir}/who +%{_bindir}/whoami +%{_bindir}/yes +%{_infodir}/coreutils* +%{_libexecdir}/coreutils* +%{_mandir}/man*/* +%{_sbindir}/chroot + +%changelog +* Fri Mar 15 2019 Kamil Dudka - 8.22-24 +- doc: improve description of the --kibibytes option of ls (#1527391) +- doc: fix typo in date example (#1620624) +- stat,tail: sync the list of file systems with coreutils-8.31 (#1659530) +- df: avoid stat() for dummy file systems with -l (#1668137) +- df: prioritize mounts nearer the device root (#1042840) + +* Fri Jun 15 2018 Kamil Dudka - 8.22-23 +- update description of the -a/--all option in df.1 man page (#1553212) +- sort -M: fix memory leak when using multibyte locale (#1540059) + +* Wed Jan 24 2018 Kamil Dudka - 8.22-22 +- mv -n: do not overwrite the destination (#1526265) + +* Mon Dec 04 2017 Kamil Dudka - 8.22-21 +- timeout: revert the last fix for a possible race (#1439465) + +* Thu Nov 23 2017 Kamil Dudka - 8.22-20 +- df: do not stat file systems that do not satisfy the -t/-x args (#1511947) + +* Thu Sep 21 2017 Kamil Dudka - 8.22-19 +- timeout: fix race possibly terminating wrong process (#1439465) +- ls: allow interruption when reading slow directories (#1421802) +- fold: preserve new-lines in mutlibyte text (#1418505) + +* Fri Jul 01 2016 Ondrej Vasik - 8.22-18 +- fix xfs build failure in chrooted environment (#1263341) +- update filesystem lists for stat and tail from latest upstream + (#1327881, #1280357) +- disable id/setgid.sh test(missing chroot feature), fix + cp-a-selinux test (#1266500,#1266501) +- colorls.sh - change detection of interactive shell for ksh + compatibility (#1321648) +- fix date --date crash with empty or invalid TZ envvar (#1325786) +- df -l: do not hang on a dead autofs mount point (#1309247) +- sort -h: fix functionality of human readable numeric sort for other + than first field (#1328360) + +* Wed Nov 25 2015 Ondrej Vasik - 8.22-16 +- cp: prevent potential sparse file corruption (#1284906) + +* Sat Sep 12 2015 Ondrej Vasik - 8.22-15 +- fix one more occurance of non-full path in colorls.sh (#1222223) + +* Mon Aug 17 2015 Ondrej Vasik - 8.22-14 +- fix several failing non-default(root,expensive) tests (#1247641) + +* Mon Jul 06 2015 Ondrej Vasik - 8.22-13 +- call utilities in colorls.* scripts with full path (#1222223) +- tail: disable inotify in --follow for vxfs (#1109083) +- remove circular dependency for util-linux (not relevant for RHEL 7 - #1155963) +- sort: do not look at more than specified keys for mb locales (#1148347) +- i18n patch: fix buffer overruns and compiler warnings (#1148347) +- xfs: fix dd sparse false test failure on btrfs and xfs (#1223041) +- dd: new status=progress level to print stats periodically (#1147701) +- id/groups - print correct group for session (#1115430) +- cp,install,mknod,mkfifo,mkdir: separate -Z and --context options + in --help and manpage (#1084471) +- ls: clarify --scontext/--context/--lcontext options behaviour + in info documentation, mention deprecation (#1099508) +- du: handle bindmount cycles more gracefully (#1238191) +- mv: prevent possible race condition for hardlinks (#1166570) +- df: improve filtering of NFS mounts and bind mounts + (#1197463, #1100026, #1129661) + +* Tue Aug 05 2014 Ondrej Vasik - 8.22-12 +- fix test failure on ppc64le (#1112687) + +* Fri Jan 24 2014 Daniel Mach - 8.22-11 +- Mass rebuild 2014-01-24 + +* Mon Jan 13 2014 Ondrej Vasik 8.22-10 +- cp/mv/install: do not crash when getfscreatecon() is + returning a NULL context +- fix the cut optimizations to UTF-8 locales only +- unset the unnecessary envvars after colorls scripts + +* Fri Jan 10 2014 Ondrej Oprala 8.22-9 +- Only use cut optimizations for UTF-8 locales (#1021403) + +* Mon Jan 06 2014 Ondrej Oprala 8.22-8 +- Don't use cut mb path if not necessary (#1021403) + +* Mon Jan 06 2014 Ondrej Oprala 8.22-7 +- Fix sorting by non-first field (#1003544) + +* Fri Jan 03 2014 Ondrej Vasik 8.22-5 +- do not modify SELinux contexts of existing parent + directories when copying files (fix by P.Brady, #1045122) + +* Fri Jan 03 2014 Ondrej Oprala 8.22-4 +- revert an old sort change and constrict it's condition + +* Thu Jan 02 2014 Ondrej Vasik 8.22-3 +- mark deprecated SELinux related downstream options as + deprecated in usage/man +- temporarily disable setting SELinux contexts recursively + for existing directories - broken (#1045122) + +* Fri Dec 27 2013 Daniel Mach - 8.22-2 +- Mass rebuild 2013-12-27 + +* Tue Dec 17 2013 Ondrej Vasik 8.22-1 +- new upstream version 8.22 (#1043552) +- temporarily df symlink test (incomplete upstream fix, not + regression) +- enable build with openssl for better performance of + HASHsum utilities (not for md5sum because of FIPS) +- turn on the multibyte path in the testsuite to cover + i18n regressions +- fix possible colorls.csh script errors for tcsh with + noclobber set and entered include file + +* Thu Nov 28 2013 Ondrej Vasik 8.21-14 +- mv: fails to overwrite directory on cross-filesystem + copy with EISDIR (#1035224) +- tail -F does not handle dead symlinks gracefully + (#1035219) + +* Mon Oct 14 2013 Ondrej Vasik 8.21-13 +- cp: correct error message for invalid arguments + of '--no-preserve' (#1018206) + +* Thu Aug 15 2013 Ondrej Vasik 8.21-12 +- pr -e, with a mix of backspaces and TABs, could corrupt the heap + in multibyte locales (analyzed by J.Koncicky) +- Fix sort multibyte incompatibilities (by O.Oprala) +- change the TMP variable name in colorls.csh to _tmp (#981373) +- optimization of colorls scripts by Ville Skytta (#961012) + +* Fri Apr 05 2013 Ondrej Oprala 8.21-10 +- DIR_COLORS.$TERM should have higher priority than + DIR_COLORS.256color (#921651) + +* Mon Mar 11 2013 Ondrej Oprala 8.21-9 +- add support for INCLUDE in colorls scripts (#818069) + +* Mon Mar 04 2013 Ondrej Vasik 8.21-8 +- fix factor on AArch64 (M.Salter, #917735) + +* Fri Mar 01 2013 Ondrej Vasik 8.21-7 +- ls: colorize several new archive/compressed types (#868510) + +* Sat Feb 23 2013 Ondrej Vasik 8.21-6 +- install: do proper cleanup when strip fails + (O.Oprala, B.Voekler, #632444) + +* Wed Feb 20 2013 Ondrej Vasik 8.21-5 +- fix multibyte issue in unexpand(by R.Kollar, #821262) + +* Mon Feb 18 2013 Ondrej Oprala 8.21-4 +- fix sort-mb-tests.sh test (B.Voelker) + +* Mon Feb 18 2013 Mark Wielaard 8.21-3 +- fix coreutils-i18n.patch to terminate mbdelim string (#911929) + +* Mon Feb 18 2013 Ondrej Vasik 8.21-2 +- remove unnecessary powerpc factor patch + +* Fri Feb 15 2013 Ondrej Vasik 8.21-1 +- new upstream release 8.21, update patches + +* Thu Feb 07 2013 Ondrej Oprala 8.20-8 +- add missing sort-mb-tests.sh to local.mk + +* Tue Feb 05 2013 Ondrej Vasik 8.20-7 +- add support for DTR/DSR control flow in stty(#445213) + +* Wed Jan 23 2013 Ondrej Vasik 8.20-6 +- fix multiple segmantation faults in i18n patch (by SUSE) + (#869442, #902917) + +* Thu Dec 20 2012 Ondrej Vasik 8.20-5 +- seq: fix newline output when -s specified (upstream) + +* Mon Dec 10 2012 Ondrej Vasik 8.20-4 +- fix showing duplicates in df (#709351, O.Oprala, B.Voelker) + +* Thu Dec 06 2012 Ondrej Vasik 8.20-3 +- fix factor on 32bit powerpc (upstream, #884715) + +* Mon Nov 05 2012 Ondrej Vasik 8.20-2 +- disable the temporary O_SYNC fix (glibc is fixed - #872366) + +* Sat Oct 27 2012 Ondrej Vasik 8.20-1 +- new upstream release 8.20 +- Temporarily require util-linux >= 2.22.1-3 (to prevent missing + su/runuser on system) + +* Mon Aug 20 2012 Ondrej Vasik 8.19-1 +- new upstream release 8.19 +- fix multibyte issues in cut and expand (M.Briza, #821260) + +* Sun Aug 12 2012 Ondrej Vasik 8.18-1 +- new upstream release 8.18 +- su/runuser moved to util-linux + +* Wed Jul 18 2012 Fedora Release Engineering - 8.17-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Tue May 15 2012 Ondrej Vasik 8.17-3 +- add virtual provides for bundled(gnulib) copylib (#821748) + +* Fri May 11 2012 Ondrej Vasik 8.17-2 +- ls: upstream fix - correctly show symlinks in / + +* Fri May 11 2012 Ondrej Vasik 8.17-1 +- new upstream release 8.17 + +* Fri May 04 2012 Ondrej Vasik 8.16-3 +- add .htm and .shtml to colorized DIR_COLORS document + type (#817218) + +* Mon Apr 16 2012 Ondrej Vasik 8.16-2 +- fix the tcsh colorls.csh behaviour in non-interactive + mode (#804604) + +* Mon Mar 26 2012 Ondrej Vasik 8.16-1 +- new upstream release 8.16 +- defuzz patches, remove already applied patches + +* Thu Mar 08 2012 Ondrej Vasik 8.15-8 +- fix regression in du -x with nondir argument (by J.Meyering) + +* Wed Mar 07 2012 Ondrej Vasik 8.15-7 +- fix sort segfault with multibyte locales (by P.Brady) + +* Fri Feb 10 2012 Harald Hoyer 8.15-6 +- turn on testsuite again + +* Wed Jan 25 2012 Harald Hoyer 8.15-5 +- add filesystem guard + +* Wed Jan 25 2012 Harald Hoyer 8.15-4 +- add missing provides for the /usr-move + +* Wed Jan 25 2012 Harald Hoyer 8.15-3 +- install everything in /usr + https://fedoraproject.org/wiki/Features/UsrMove + +* Mon Jan 16 2012 Kamil Dudka - 8.15-2 +- fix stack smashing, buffer overflow, and invalid output of pr (#772172) + +* Sat Jan 07 2012 Ondrej Vasik - 8.15-1 +- new upstream release 8.15 + +* Thu Jan 05 2012 Ondrej Vasik - 8.14-6 +- do not use shebang in sourced colorls.csh + +* Thu Jan 05 2012 Ondrej Vasik - 8.14-5 +- fix pr -c and pr -v segfault with multibyte locales + +* Mon Oct 31 2011 Rex Dieter 8.14-4 +- rebuild (gmp), last time, I promise + +* Mon Oct 24 2011 Ondrej Vasik - 8.14-3 +- require at least pam 1.1.3-7 (#748215) + +* Thu Oct 20 2011 Ondrej Vasik - 8.14-2 +- rebuild for gmp + +* Wed Oct 12 2011 Ondrej Vasik - 8.14-1 +- new upstream release 8.14 + +* Mon Sep 26 2011 Peter Schiffer - 8.13-2.2 +- rebuild with new gmp + +* Mon Sep 12 2011 Ondrej Vasik - 8.13-2 +- Obsolete coreutils-libs (#737287) + +* Fri Sep 09 2011 Ondrej Vasik - 8.13-1 +- new upstream release 8.13 +- temporarily disable recently added multibyte checks in + misc/cut test +- fix the SUSE fix for cut output-delimiter +- drop coreutils-libs subpackage, no longer needed + +* Mon Sep 05 2011 Ondrej Vasik - 8.12-7 +- incorporate some i18n patch fixes from OpenSUSE: + - fix cut output-delimiter option + - prevent infinite loop in sort when ignoring chars + - prevent using unitialized variable in cut + +* Tue Aug 23 2011 Ondrej Vasik - 8.12-6 +- su: fix shell suspend in tcsh (#597928) + +* Thu Aug 18 2011 Ondrej Vasik - 8.12-5 +- variable "u" should be static in uname processor type patch + +* Thu Aug 11 2011 Ondrej Vasik - 8.12-4 +- deprecate non-upstream cp -Z/--context (install should be + used instead of it), make it working if destination exists + (#715557) + +* Fri Jul 29 2011 Ondrej Vasik - 8.12-3 +- use acl_extended_file_nofollow() if available (#692823) + +* Fri Jul 15 2011 Ondrej Vasik - 8.12-2 +- support ecryptfs mount of Private (postlogin into su.pamd) + (#722323) + +* Wed Apr 27 2011 Ondrej Vasik - 8.12-1 +- new upstream release 8.12 + +* Thu Apr 14 2011 Ondrej Vasik - 8.11-2 +- fix issue with df --direct(extra new line) + +* Thu Apr 14 2011 Ondrej Vasik - 8.11-1 +- new upstream release 8.11, defuzz patches + +* Tue Mar 22 2011 Ondrej Vasik - 8.10-7 +- add note about mkdir mode behaviour into info + documentation (#610559) + +* Mon Mar 14 2011 Ondrej Vasik - 8.10-6 +- fix possible uninitalized variables usage caused by i18n + patch(#683799) + +* Fri Mar 4 2011 Ondrej Vasik - 8.10-5 +- make coreutils build even without patches (with + nopam, norunuser and noselinux variables) + +* Thu Feb 17 2011 Ondrej Vasik - 8.10-4 +- colorize documents by DIR_COLORS files(brown like mc) + +* Thu Feb 17 2011 Ondrej Vasik - 8.10-3 +- add several new TERMs to DIR_COLORS files(#678147) + +* Tue Feb 08 2011 Fedora Release Engineering - 8.10-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Fri Feb 04 2011 Ondrej Vasik - 8.10-1 +- new upstream release coreutils-8.10 + +* Sat Jan 08 2011 Dennis Gilmore - 8.9-2 +- drop no longer needed mkstemp patch for sparc + +* Tue Jan 04 2011 Ondrej Vasik - 8.9-1 +- new upstream release coreutils-8.9 + +* Fri Dec 31 2010 Ondrej Vasik - 8.8-2 +- The suffix length was dependent on the number of bytes + or lines per file (#666293) + +* Thu Dec 23 2010 Ondrej Vasik - 8.8-1 +- fix parallel sorting issue (#655096) +- new upstream release coreutils-8.8 (#665164) + +* Thu Nov 18 2010 Ondrej Vasik - 8.7-2 +- don't prompt for password with runuser(#654367) + +* Mon Nov 15 2010 Ondrej Vasik - 8.7-1 +- new upstream release coreutils-8.7 +- pam support in su consolidation with SUSE(#622700) + +* Wed Nov 03 2010 Kamil Dudka - 8.6-3 +- prevent sort from assertion failure in case LC_CTYPE does not match LC_TIME + (#647938) + +* Tue Oct 26 2010 Kamil Dudka - 8.6-2 +- improve i18n support in sort (debug-keys test is now back) + +* Wed Oct 20 2010 Ondrej Vasik - 8.6-1 +- new upstream release 8.6 +- remove applied patches, temporarily disable sort + debug-keys test for multibyte locales (failing + because of i18n patch) + +* Thu Sep 30 2010 Ondrej Vasik - 8.5-10 +- various fixes for case conversion in tr(#611274) + +* Wed Sep 29 2010 jkeating - 8.5-9 +- Rebuilt for gcc bug 634757 + +* Mon Sep 20 2010 Ondrej Vasik - 8.5-8 +- change assertion failure for invalid multibyte input + in sort to less confusing error message(#591352) + +* Wed Sep 08 2010 Ondrej Vasik - 8.5-7 +- add RELRO protection to su as well (#630017) + +* Mon Sep 06 2010 Ondrej Vasik - 8.5-6 +- compile su with pie again (#630017) + +* Mon Aug 30 2010 Ondrej Vasik - 8.5-5 +- fix double free abort in tac (#628213) + +* Thu Jul 22 2010 Ondrej Vasik - 8.5-4 +- Add .ear, .war, .sar , for Java jar-like archives to + dircolors (#616497) + +* Fri Jul 2 2010 Dan Horák - 8.5-3 +- rebuilt with the updated configuration patch +- drop the old -O1 exception for s390(x) +- updated the getgrouplist patch (Kamil Dudka) + +* Tue Apr 27 2010 Ondrej Vasik - 8.5-2 +- doublequote LS_COLORS in colorls.*sh scripts to speedup + shell start(#586029) +- add patch for mkstemp on sparc64(Dennis Gilmore) +- update /etc/DIR_COLORS* files + +* Mon Apr 26 2010 Ondrej Vasik - 8.5-1 +- new upstream release 8.5 + +* Thu Apr 15 2010 Ondrej Vasik - 8.4-8 +- move readlink from /usr/bin to bin, keep symlink in + /usr/bin(#580682) + +* Mon Mar 29 2010 Kamil Dudka - 8.4-7 +- a new option df --direct + +* Sat Mar 20 2010 Ondrej Vasik - 8.4-6 +- run tput colors in colorls profile.d scripts only + in the interactive mode(#450424) + +* Fri Feb 12 2010 Ondrej Vasik - 8.4-5 +- fix exit status of terminated child processes in su with + pam(#559098) + +* Fri Feb 05 2010 Ondrej Vasik - 8.4-4 +- do not depend on selinux patch application in + _require_selinux tests(#556350) + +* Fri Jan 29 2010 Ondrej Vasik - 8.4-3 +- do not fail tests if there are no loopdevices left + (#558898) + +* Tue Jan 26 2010 Ondrej Vasik - 8.4-2 +- who doesn't determine user's message status correctly + (#454261) + +* Thu Jan 14 2010 Ondrej Vasik - 8.4-1 +- new upstream release 8.4 + +* Fri Jan 08 2010 Ondrej Vasik - 8.3-1 +- new upstream release 8.3 + +* Wed Jan 06 2010 Ondrej Vasik - 8.2-6 +- require gmp-devel/gmp for large numbers support(#552846) + +* Sun Dec 27 2009 Ondrej Vasik - 8.2-5 +- fix misc/selinux root-only test(#550494) + +* Sat Dec 19 2009 Ondrej Vasik - 8.2-4 +- bring back uname -p/-i functionality except of the + athlon hack(#548834) +- comment patches + +* Wed Dec 16 2009 Ondrej Vasik - 8.2-3 +- use grep instead of deprecated egrep in colorls.sh script + (#548174) +- remove unnecessary versioned requires/conflicts +- remove non-upstream hack for uname -p + +* Wed Dec 16 2009 Ondrej Vasik - 8.2-2 +- fix DIR_COLORS.256color file + +* Fri Dec 11 2009 Ondrej Vasik - 8.2-1 +- new upstream release 8.2 +- removed applied patches, temporarily do not run dup_cloexec() + dependent gnulib tests failing in koji + +* Fri Nov 27 2009 Ondrej Vasik - 8.1-1 +- new upstream release 8.1 +- fix build under koji (no test failures with underlying + RHEL-5 XEN kernel due to unsearchable path and lack of + futimens functionality) + +* Wed Oct 07 2009 Ondrej Vasik - 8.0-2 +- update /etc/DIR_COLORS* files + +* Wed Oct 07 2009 Ondrej Vasik - 8.0-1 +- New upstream release 8.0 (beta), defuzz patches, + remove applied patches + +* Mon Oct 05 2009 Ondrej Vasik - 7.6-7 +- chcon no longer aborts on a selinux disabled system + (#527142) + +* Fri Oct 02 2009 Ondrej Vasik - 7.6-6 +- ls -LR exits with status 2, not 0, when it encounters + a cycle(#525402) +- ls: print "?", not "0" as inode of dereferenced dangling + symlink(#525400) +- call the install-info on .gz info files + +* Tue Sep 22 2009 Ondrej Vasik - 7.6-5 +- improve and correct runuser documentation (#524805) + +* Mon Sep 21 2009 Ondrej Vasik - 7.6-4 +- add dircolors color for GNU lzip (#516897) + +* Fri Sep 18 2009 Ondrej Vasik - 7.6-3 +- fixed typo in DIR_COLORS.256color causing no color for + multihardlink + +* Wed Sep 16 2009 Ondrej Vasik - 7.6-2 +- fix copying of extended attributes for read only source + files + +* Sat Sep 12 2009 Ondrej Vasik - 7.6-1 +- new upstream bugfix release 7.6, removed applied patches, + defuzzed the rest + +* Thu Sep 10 2009 Ondrej Vasik - 7.5-6 +- fix double free error in fold for singlebyte locales + (caused by multibyte patch) + +* Tue Sep 08 2009 Ondrej Vasik - 7.5-5 +- fix sort -h for multibyte locales (reported via + http://bugs.archlinux.org/task/16022) + +* Thu Sep 03 2009 Ondrej Vasik - 7.5-4 +- fixed regression where df -l as regular user + cause "Permission denied" (#520630, introduced by fix for + rhbz #497830) + +* Fri Aug 28 2009 Ondrej Vasik - 7.5-3 +- ls -i: print consistent inode numbers also for mount points + (#453709) + +* Mon Aug 24 2009 Ondrej Vasik - 7.5-2 +- Better fix than workaround the koji insufficient utimensat + support issue to prevent failures in other packages + +* Fri Aug 21 2009 Ondrej Vasik - 7.5-1 +- New upstream release 7.5, remove already applied patches, + defuzz few others, xz in default set(by dependencies), + so no explicit br required +- skip two new tests on system with insufficient utimensat + support(e.g. koji) +- libstdbuf.so in separate coreutils-libs subpackage +- update /etc/DIRCOLORS* + +* Thu Aug 06 2009 Ondrej Vasik - 7.4-6 +- do process install-info only with info files present(#515970) +- BuildRequires for xz, use xz tarball + +* Wed Aug 05 2009 Kamil Dudka - 7.4-5 +- ls -1U with two or more arguments (or with -R or -s) works properly again +- install runs faster again with SELinux enabled (#479502) + +* Fri Jul 24 2009 Fedora Release Engineering - 7.4-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Mon Jul 06 2009 Ondrej Vasik 7.4-3 +- do not ignore sort's version sort for multibyte locales + (#509688) + +* Thu Jun 18 2009 Ondrej Vasik 7.4-2 +- temporarily workaround probable kernel issue with + TCSADRAIN(#504798) + +* Mon May 25 2009 Ondrej Vasik 7.4-1 +- new upstream release 7.4, removed applied patches + +* Thu Apr 23 2009 Ondrej Vasik 7.2-3 +- fix segfaults in join (i18n patch) when using multibyte + locales(#497368) + +* Fri Apr 17 2009 Ondrej Vasik 7.2-2 +- make mv xattr support failures silent (as is done for + cp -a) - #496142 + +* Tue Mar 31 2009 Ondrej Vasik 7.2-1 +- New upstream bugfix release 7.2 +- removed applied patches +- temporarily disable strverscmp failing gnulib test + +* Thu Mar 19 2009 Ondrej Vasik 7.1-7 +- do not ship /etc/DIR_COLORS.xterm - as many terminals + use TERM xterm and black background as default - making + ls color output unreadable +- shipping /etc/DIR_COLORS.lightbgcolor instead of it for + light(white/gray) backgrounds +- try to preserve xattrs in cp -a when possible + +* Mon Mar 02 2009 Ondrej Vasik 7.1-6 +- fix sort bugs (including #485715) for multibyte locales + as well + +* Fri Feb 27 2009 Ondrej Vasik 7.1-5 +- fix infinite loop in recursive cp (upstream, introduced + by 7.1) + +* Thu Feb 26 2009 Ondrej Vasik 7.1-4 +- fix showing ACL's for ls -Z (#487374), fix automatic + column width for it as well + +* Wed Feb 25 2009 Ondrej Vasik 7.1-3 +- fix couple of bugs (including #485715) in sort with + determining end of fields(upstream) + +* Wed Feb 25 2009 Ondrej Vasik 7.1-2 +- workaround libcap issue with broken headers (#483548) +- fix gnulib testsuite failure (4x77 (skip) is not + 77(skip) ;) ) + +* Tue Feb 24 2009 Ondrej Vasik - 7.1-1 +- New upstream release 7.1 (temporarily using tar.gz tarball + as there are no xz utils in Fedora), removed applied + patches, amended patches and LS_COLORS files + +* Tue Feb 24 2009 Fedora Release Engineering - 7.0-8 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Wed Jan 28 2009 Kamil Dudka - 7.0-7 +- added BuildRequires for libattr-devel and attr + +* Wed Jan 28 2009 Kamil Dudka - 7.0-6 +- cp/mv: add --no-clobber (-n) option to not overwrite target +- cp/mv: add xattr support (#202823) + +* Thu Dec 04 2008 Ondrej Vasik - 7.0-5 +- fix info documentation for expr command as well(#474434) + +* Thu Dec 04 2008 Ondrej Vasik - 7.0-4 +- fixed syntax error w/ "expr" command using negative + string/integer as first (i.e expr -125) - due to + complexity of changes used diff against upstream git-head + (#474434) +- enable total-awk test again (and skip it when df not working) + +* Tue Nov 25 2008 Ondrej Vasik - 7.0-3 +- package summary tuning + +* Fri Nov 21 2008 Ondrej Vasik - 7.0-2 +- added requirements for util-linux-ng >= 2.14 + because of file conflict in update from F-8/F-9(#472445) +- some sed cleanup, df totaltests patch changes (not working + correctly yet :( ) + +* Wed Nov 12 2008 Ondrej Vasik - 7.0-1 +- new upstream release +- modification/removal of related patches +- use automake 1.10.1 instead of 1.10a +- temporarily skip df --total tests (failures), + timeout-paramaters (failure on ppc64) + +* Mon Nov 03 2008 Ondrej Vasik - 6.12-17 +- Requires: ncurses (#469277) + +* Wed Oct 22 2008 Ondrej Vasik - 6.12-16 +- make possible to disable capability in ls due to + performance impact when not cached(#467508) +- do not patch generated manpages - generate them at build + time +- do not mistakenly display -g and -G runuser option in su + --help output + +* Mon Oct 13 2008 Ondrej Vasik - 6.12-15 +- fix several date issues(e.g. countable dayshifts, ignoring + some cases of relative offset, locales conversions...) +- clarify ls exit statuses documentation (#446294) + +* Sun Oct 12 2008 Ondrej Vasik - 6.12-14 +- cp -Z now correctly separated in man page (#466646) +- cp -Z works again (#466653) +- make preservation of SELinux CTX non-mandatory for + preserve=all cp option + +* Wed Oct 08 2008 Ondrej Vasik - 6.12-13 +- remove unimplemented (never accepted by upstream) option + for chcon changes only. Removed from help and man. +- remove ugly lzma hack as lzma is now supported by setup + macro + +* Mon Oct 06 2008 Jarod Wilson - 6.12-12 +- fix up potential test failures when building in certain + slightly quirky environments (part of bz#442352) + +* Mon Oct 06 2008 Ondrej Vasik - 6.12-11 +- added requires for libattr (#465569) + +* Mon Sep 29 2008 Ondrej Vasik - 6.12-10 +- seq should no longer fail to display final number of some + float usages of seq with utf8 locales(#463556) + +* Wed Aug 13 2008 Ondrej Vasik - 6.12-9 +- mention that DISPLAY and XAUTHORITY envvars are preserved + for pam_xauth in su -l (#450505) + +* Mon Aug 04 2008 Kamil Dudka - 6.12-8 +- ls -U1 now uses constant memory + +* Wed Jul 23 2008 Kamil Dudka - 6.12-7 +- dd: iflag=fullblock now read full blocks if possible + (#431997, #449263) +- ls: --color now highlights files with capabilities (#449985) + +* Wed Jul 16 2008 Ondrej Vasik - 6.12-6 +- Get rid off fuzz in patches + +* Fri Jul 04 2008 Ondrej Vasik - 6.12-5 +- fix authors for basename and echo +- fix who info pages, print last runlevel only for printable + chars + +* Mon Jun 16 2008 Ondrej Vasik - 6.12-4 +- print verbose output of chcon with newline after each + message (#451478) + +* Fri Jun 06 2008 Ondrej Vasik - 6.12-3 +- workaround for koji failures(#449910, #442352) now + preserves timestamps correctly - fallback to supported + functions, added test case +- runuser binary is no longer doubled in /usr/bin/runuser + +* Wed Jun 04 2008 Ondrej Vasik - 6.12-2 +- workaround for strange koji failures(#449910,#442352) +- fixed ls -ZC segfault(#449866, introduced by 6.10-1 + SELinux patch reworking) + +* Mon Jun 02 2008 Ondrej Vasik - 6.12-1 +- New upstream release 6.12, adapted patches + +* Thu May 29 2008 Tom "spot" Callaway - 6.11-5 +- fix SHA256/SHA512 to work on sparc + +* Tue May 20 2008 Ondrej Vasik - 6.11-4 +- fixed a HUGE memory leak in install binary(#447410) + +* Mon May 19 2008 Ondrej Vasik - 6.11-3 +- added arch utility (from util-linux-ng) +- do not show executable file types without executable bit + in colored ls as executable + +* Wed Apr 23 2008 Ondrej Vasik - 6.11-2 +- Do not show misleading scontext in id command when user + is specified (#443485) +- Avoid possible test failures on non-english locales + +* Mon Apr 21 2008 Ondrej Vasik - 6.11-1 +- New upstream release 6.11 +- removed accepted patches + few minor patch changes + +* Fri Apr 18 2008 Ondrej Vasik - 6.10-21 +- fix wrong checksum line handling in sha1sum -c + command(#439531) + +* Tue Apr 15 2008 Ondrej Vasik - 6.10-20 +- fix possible segfault in sha1sum/md5sum command + +* Mon Apr 14 2008 Ondrej Vasik - 6.10-19 +- fix possible build-failure typo in i18n patch(#442205) + +* Mon Apr 7 2008 Ondrej Vasik - 6.10-18 +- fix colorls.sh syntax with Zsh (#440652) +- mention that cp -a includes -c option + mention cp -c + option in manpages (#440056) +- fix typo in runuser manpages (#439410) + +* Sat Mar 29 2008 Ondrej Vasik - 6.10-17 +- better workaround of glibc getoptc change(factor test) +- don't segfault mknod, mkfifo with invalid-selinux-context + +* Thu Mar 27 2008 Ondrej Vasik - 6.10-16 +- keep LS_COLORS when USER_LS_COLORS defined +- someupstream fixes: +- mkdir -Z invalid-selinux-context dir no longer segfaults +- ptx with odd number of backslashes no longer leads to buffer + overflow +- paste -d'\' file" no longer ovveruns memory + +* Wed Mar 26 2008 Ondrej Vasik - 6.10-15 +- covered correct handling for some test conditions failures + e.g. root build+selinux active and not running mcstrans(d) + or selinux enforcing (#436717) + +* Wed Mar 19 2008 Ondrej Vasik - 6.10-14 +- mv: never unlink a destination file before calling rename + (upstream, #438076) + +* Mon Mar 17 2008 Ondrej Vasik - 6.10-13 +- disable echo option separator behavior(added by #431005, + request for removal #437653 + upstream) +- temporarily disabled longoptions change until full + clarification upstreamery (#431005) + +* Tue Mar 11 2008 Ondrej Vasik - 6.10-12 +- fixed harmless double close of stdout in dd(#436368) + +* Thu Mar 6 2008 Ondrej Vasik - 6.10-11 +- fixed broken order of params in stat(#435669) + +* Tue Mar 4 2008 Ondrej Vasik - 6.10-10 +- colorls.csh missing doublequotes (#435789) +- fixed possibility to localize verbose outputs + +* Mon Mar 3 2008 Ondrej Vasik - 6.10-9 +- consolidation of verbose output to stdout (upstream) + +* Mon Feb 18 2008 Ondrej Vasik - 6.10-8 +- use default security context in install - broken by + coreutils-6.10 update(#319231) +- some sh/csh scripts optimalizations(by ville.skytta@iki.fi, + - #433189, #433190) + +* Mon Feb 11 2008 Ondrej Vasik - 6.10-7 +- keep old csh/sh usermodified colorls shell scripts + but use the new ones(#432154) + +* Thu Feb 7 2008 Ondrej Vasik - 6.10-6 +- better 256-color support in colorls shell scripts +- color tuning(based on feedback in #429121) + +* Mon Feb 4 2008 Ondrej Vasik - 6.10-5 +- enabled 256-color support in colorls shell scripts(#429121) +- fixed syntax error in csh script(#431315) + +* Thu Jan 31 2008 Ondrej Vasik - 6.10-4 +- forgotten return in colorls.sh change + +* Thu Jan 31 2008 Ondrej Vasik - 6.10-3 +- fix unability of echo to display certain strings(added -- + separator, #431005) +- do not require only one long_opt for certain commands + e.g. sleep, yes - but use first usable (#431005) +- do not override userspecified LS_COLORS variable, but + use it for colored ls(#430827) +- discard errors from dircolors to /dev/null + some tuning + of lscolor sh/csh scripts(#430823) +- do not consider files with SELinux security context as + files having ACL in ls long format(#430779) + +* Mon Jan 28 2008 Ondrej Vasik - 6.10-2 +- some manpages improvements(#406981,#284881) +- fix non-versioned obsoletes of mktemp(#430407) + +* Fri Jan 25 2008 Ondrej Vasik - 6.10-1 +- New upstream release(changed %%prep because of lack of lzma + support in %%setup macro) +- License GPLv3+ +- removed patches cp-i-u,du-ls-upstream,statsecuritycontext, + futimens,getdateYYYYMMDD,ls-x +- modified patches to be compilable after upstream changes +- selinux patch reworked to have backward compatibility with + F8(cp,ls and stat behaviour differ from upstream in SELinux + options) +- su-l/runuser-l pam file usage a bit documented(#368721) +- more TERMs for DIR_COLORS, added colors for audio files, + more image/compress file types(taken from upstream + dircolors.hin) +- new file DIR_COLORS.256color which takes advantage from + 256color term types-not really used yet(#429121) + +* Wed Jan 16 2008 Ondrej Vasik - 6.9-17 +- added several missing colored TERMs(including rxvt-unicode, + screen-256color and xterm-256color) to DIR_COLORS and + DIR_COLORS.xterm(#239266) + +* Wed Dec 05 2007 Ondrej Vasik - 6.9-16 +- fix displaying of security context in stat(#411181) + +* Thu Nov 29 2007 Ondrej Vasik - 6.9-15 +- completed fix of wrong colored broken symlinks in ls(#404511) + +* Fri Nov 23 2007 Ondrej Vasik - 6.9-14 +- fixed bug in handling YYYYMMDD date format with relative + signed offset(#377821) + +* Tue Nov 13 2007 Ondrej Vasik - 6.9-13 +- fixed bug in selinux patch which caused bad preserving + of security context in install(#319231) + +* Fri Nov 02 2007 Ondrej Vasik - 6.9-12 +- added some upstream supported dircolors TERMs(#239266) +- fixed du output for unaccesible dirs(#250089) +- a bit of upstream tunning for symlinks + +* Tue Oct 30 2007 Ondrej Vasik - 6.9-11 +- allow cp -a to rewrite file on different filesystem(#219900) + (based on upstream patch) + +* Mon Oct 29 2007 Ondrej Vasik - 6.9-10 +- modified coreutils-i18n.patch because of sort -R in + a non C locales(fix by Andreas Schwab) (#249315) + +* Mon Oct 29 2007 Ondrej Vasik - 6.9-9 +- applied upstream patch for runuser to coreutils-selinux.patch(#232652) +- License tag to GPLv2+ + +* Thu Oct 25 2007 Ondrej Vasik - 6.9-8 +- applied upstream patch for cp and mv(#248591) + +* Thu Aug 23 2007 Pete Graner - 6.9-7 +- Fix typo in spec file. (CVS merge conflict leftovers) + +* Thu Aug 23 2007 Pete Graner - 6.9-6 +- Remove --all-name from spec file its now provided in the upstream rpm's find-lang.sh +- Rebuild + +* Tue Aug 14 2007 Tim Waugh 6.9-5 +- Don't generate runuser.1 since we ship a complete manpage for it + (bug #241662). + +* Wed Jul 4 2007 Tim Waugh 6.9-4 +- Use hard links instead of symbolic links for LC_TIME files (bug #246729). + +* Wed Jun 13 2007 Tim Waugh 6.9-3 +- Fixed 'ls -x' output (bug #240298). +- Disambiguate futimens() from the glibc implementation (bug #242321). + +* Mon Apr 02 2007 Karsten Hopp 6.9-2 +- /bin/mv in %%post requires libselinux + +* Mon Mar 26 2007 Tim Waugh 6.9-1 +- 6.9. + +* Fri Mar 9 2007 Tim Waugh +- Better install-info scriptlets (bug #225655). + +* Thu Mar 1 2007 Tim Waugh 6.8-1 +- 6.8+, in preparation for 6.9. + +* Thu Feb 22 2007 Tim Waugh 6.7-9 +- Use sed instead of perl for text replacement (bug #225655). +- Use install-info scriptlets from the guidelines (bug #225655). + +* Tue Feb 20 2007 Tim Waugh 6.7-8 +- Don't mark profile scripts as config files (bug #225655). +- Avoid extra directory separators (bug #225655). + +* Mon Feb 19 2007 Tim Waugh 6.7-7 +- Better Obsoletes/Provides versioning (bug #225655). +- Use better defattr (bug #225655). +- Be info file compression tolerant (bug #225655). +- Moved changelog compression to %%install (bug #225655). +- Prevent upstream changes being masked (bug #225655). +- Added a comment (bug #225655). +- Use install -p for non-compiled files (bug #225655). +- Use sysconfdir macro for /etc (bug #225655). +- Use Requires(pre) etc for install-info (bug #225655). + +* Fri Feb 16 2007 Tim Waugh 6.7-6 +- Provide version for stat (bug #225655). +- Fixed permissions on profile scripts (bug #225655). + +* Wed Feb 14 2007 Tim Waugh 6.7-5 +- Removed unnecessary stuff in pre scriptlet (bug #225655). +- Prefix sources with 'coreutils-' (bug #225655). +- Avoid %%makeinstall (bug #225655). + +* Tue Feb 13 2007 Tim Waugh 6.7-4 +- Ship COPYING file (bug #225655). +- Use datadir and infodir macros in %%pre scriptlet (bug #225655). +- Use spaces not tabs (bug #225655). +- Fixed build root. +- Change prereq to requires (bug #225655). +- Explicitly version some obsoletes tags (bug #225655). +- Removed obsolete pl translation fix. + +* Mon Jan 22 2007 Tim Waugh 6.7-3 +- Make scriptlet unconditionally succeed (bug #223681). + +* Fri Jan 19 2007 Tim Waugh 6.7-2 +- Build does not require libtermcap-devel. + +* Tue Jan 9 2007 Tim Waugh 6.7-1 +- 6.7. No longer need sort-compatibility, rename, newhashes, timestyle, + acl, df-cifs, afs or autoconf patches. + +* Tue Jan 2 2007 Tim Waugh +- Prevent 'su --help' showing runuser-only options such as --group. + +* Fri Nov 24 2006 Tim Waugh 5.97-16 +- Unbreak id (bug #217177). + +* Thu Nov 23 2006 Tim Waugh 5.97-15 +- Fixed stat's 'C' format specifier (bug #216676). +- Misleading 'id -Z root' error message (bug #211089). + +* Fri Nov 10 2006 Tim Waugh 5.97-14 +- Clarified runcon man page (bug #213846). + +* Tue Oct 17 2006 Tim Waugh 5.97-13 +- Own LC_TIME locale directories (bug #210751). + +* Wed Oct 4 2006 Tim Waugh 5.97-12 +- Fixed 'cp -Z' when destination exists, again (bug #189967). + +* Thu Sep 28 2006 Tim Waugh 5.97-11 +- Back-ported rename patch (bug #205744). + +* Tue Sep 12 2006 Tim Waugh 5.97-10 +- Ignore 'cifs' filesystems for 'df -l' (bug #183703). +- Include -g/-G in runuser man page (part of bug #199344). +- Corrected runuser man page (bug #200620). + +* Thu Aug 24 2006 Tim Waugh 5.97-9 +- Fixed warnings in pam, i18n, sysinfo, selinux and acl patches (bug #203166). + +* Wed Aug 23 2006 Tim Waugh 5.97-8 +- Don't chdir until after PAM bits in su (bug #197659). + +* Tue Aug 15 2006 Tim Waugh 5.97-7 +- Fixed 'sort -b' multibyte problem (bug #199986). + +* Fri Jul 21 2006 Tim Waugh 5.97-6 +- Added runuser '-g' and '-G' options (bug #199344). +- Added su '--session-command' option (bug #199066). + +* Tue Jul 18 2006 Tomas Mraz 5.97-5 +- 'include' su and runuser scripts in su-l and runuser-l scripts + +* Thu Jul 13 2006 David Howells 5.97-4 +- split the PAM scripts for "su -l"/"runuser -l" from that of normal "su" and + "runuser" (#198639) +- add keyinit instructions to PAM scripts + +* Wed Jul 12 2006 Jesse Keating - 5.97-3.1 +- rebuild + +* Tue Jul 11 2006 Tomas Mraz 5.97-3 +- allow root to su to expired user (#152420) + +* Thu Jun 29 2006 Tim Waugh 5.97-2 +- Allow 'sort +1 -2' (patch from upstream). + +* Sun Jun 25 2006 Tim Waugh 5.97-1 +- 5.97. No longer need tempname or tee patches, or pl translation. + +* Sun Jun 25 2006 Tim Waugh 5.96-4 +- Include new hashes (bug #196369). Patch from upstream. +- Build at -O1 on s390 for the moment (bug #196369). + +* Fri Jun 9 2006 Tim Waugh +- Fix large file support for temporary files. + +* Mon Jun 5 2006 Tim Waugh 5.96-3 +- Fixed Polish translation. + +* Mon May 22 2006 Tim Waugh 5.96-2 +- 5.96. No longer need proc patch. + +* Fri May 19 2006 Tim Waugh +- Fixed pr properly in multibyte locales (bug #192381). + +* Tue May 16 2006 Tim Waugh 5.95-3 +- Upstream patch to fix cp -p when proc is not mounted (bug #190601). +- BuildRequires libacl-devel. + +* Mon May 15 2006 Tim Waugh +- Fixed pr in multibyte locales (bug #189663). + +* Mon May 15 2006 Tim Waugh 5.95-2 +- 5.95. + +* Wed Apr 26 2006 Tim Waugh 5.94-4 +- Avoid redeclared 'tee' function. +- Fix 'cp -Z' when the destination exists (bug #189967). + +* Thu Apr 20 2006 Tim Waugh 5.94-3 +- Make 'ls -Z' output more consistent with other output formats. + +* Fri Mar 24 2006 Tim Waugh 5.94-2 +- 5.94. + +* Fri Feb 10 2006 Jesse Keating - 5.93-7.2 +- bump again for double-long bug on ppc(64) + +* Tue Feb 07 2006 Jesse Keating - 5.93-7.1 +- rebuilt for new gcc4.1 snapshot and glibc changes + +* Mon Jan 23 2006 Tim Waugh +- Fixed chcon(1) bug reporting address (bug #178523). + +* Thu Jan 5 2006 Tim Waugh 5.93-7 +- Don't suppress chown/chgrp errors in install(1) (bug #176708). + +* Mon Jan 2 2006 Dan Walsh 5.93-6 +- Remove pam_selinux.so from su.pamd, not needed for targeted and Strict/MLS + will have to newrole before using. + +* Fri Dec 23 2005 Tim Waugh 5.93-5 +- Fix "sort -n" (bug #176468). + +* Fri Dec 16 2005 Tim Waugh +- Explicitly set default POSIX2 version during configure stage. + +* Fri Dec 09 2005 Jesse Keating +- rebuilt + +* Fri Dec 2 2005 Tim Waugh +- Parametrize SELinux (bug #174067). +- Fix runuser.pamd (bug #173807). + +* Thu Nov 24 2005 Tim Waugh 5.93-4 +- Rebuild to pick up new glibc *at functions. +- Apply runuser PAM patch from bug #173807. Ship runuser PAM file. + +* Tue Nov 15 2005 Dan Walsh 5.93-3 +- Remove multiple from su.pamd + +* Mon Nov 14 2005 Tim Waugh 5.93-2 +- Call setsid() in su under some circumstances (bug #173008). +- Prevent runuser operating when setuid (bug #173113). + +* Tue Nov 8 2005 Tim Waugh 5.93-1 +- 5.93. +- No longer need alt-md5sum-binary, dircolors, mkdir, mkdir2 or tac patches. + +* Fri Oct 28 2005 Tim Waugh 5.92-1 +- Finished porting i18n patch to sort.c. +- Fixed for sort-mb-tests (avoid +n syntax). + +* Fri Oct 28 2005 Tim Waugh 5.92-0.2 +- Fix chgrp basic test. +- Include md5sum patch from ALT. + +* Mon Oct 24 2005 Tim Waugh 5.92-0.1 +- 5.92. +- No longer need afs, dircolors, utmp, gcc4, brokentest, dateseconds, + chown, rmaccess, copy, stale-utmp, no-sign-extend, fchown patches. +- Updated acl, dateman, pam, langinfo, i18n, getgrouplist, selinux patches. +- Dropped printf-ll, allow_old_options, jday, zh_CN patches. +- NOTE: i18n patch not ported for sort(1) yet. + +* Fri Sep 30 2005 Tomas Mraz - 5.2.1-56 +- use include instead of pam_stack in pam config + +* Fri Sep 9 2005 Dan Walsh 5.2.1-55 +- Reverse change to use raw functions + +* Thu Sep 8 2005 Tim Waugh 5.2.1-54 +- Explicit setuid bit for /bin/su in file manifest (bug #167745). + +* Tue Sep 6 2005 Dan Walsh 5.2.1-53 +- Allow id to run even when SELinux security context can not be run +- Change chcon to use raw functions. + +* Tue Jun 28 2005 Tim Waugh +- Corrected comments in DIR_COLORS.xterm (bug #161711). + +* Wed Jun 22 2005 Tim Waugh 5.2.1-52 +- Fixed stale-utmp patch so that 'who -r' and 'who -b' work + again (bug #161264). + +* Fri Jun 17 2005 Tim Waugh 5.2.1-51 +- Use upstream hostid fix. + +* Thu Jun 16 2005 Tim Waugh 5.2.1-50 +- Don't display the sign-extended part of the host id (bug #160078). + +* Tue May 31 2005 Dan Walsh 5.2.1-49 +- Eliminate bogus "can not preserve context" message when moving files. + +* Wed May 25 2005 Tim Waugh 5.2.1-48 +- Prevent buffer overflow in who(1) (bug #158405). + +* Fri May 20 2005 Tim Waugh 5.2.1-47 +- Better error checking in the pam patch (bug #158189). + +* Mon May 16 2005 Dan Walsh 5.2.1-46 +- Fix SELinux patch to better handle MLS integration + +* Mon May 16 2005 Tim Waugh 5.2.1-45 +- Applied Russell Coker's selinux changes (bug #157856). + +* Fri Apr 8 2005 Tim Waugh +- Fixed pam patch from Steve Grubb (bug #154946). +- Use better upstream patch for "stale utmp". + +* Tue Mar 29 2005 Tim Waugh 5.2.1-44 +- Added "stale utmp" patch from upstream. + +* Thu Mar 24 2005 Tim Waugh 5.2.1-43 +- Removed patch that adds -C option to install(1). + +* Wed Mar 16 2005 Tim Waugh 5.2.1-42 +- Fixed pam patch. +- Fixed broken configure test. +- Fixed build with GCC 4 (bug #151045). + +* Wed Feb 9 2005 Tim Waugh 5.2.1-41 +- Jakub Jelinek's sort -t multibyte fixes (bug #147567). + +* Sat Feb 5 2005 Tim Waugh 5.2.1-40 +- Undo last change (bug #145266). + +* Fri Feb 4 2005 Tim Waugh 5.2.1-38 +- Special case for ia32e in uname (bug #145266). + +* Thu Jan 13 2005 Tim Waugh 5.2.1-37 +- Fixed zh_CN translation (bug #144845). Patch from Mitrophan Chin. + +* Tue Dec 28 2004 Dan Walsh 5.2.1-36 +- Fix to only setdefaultfilecon if not overridden by command line + +* Mon Dec 27 2004 Dan Walsh 5.2.1-35 +- Change install to restorecon if it can + +* Wed Dec 15 2004 Tim Waugh +- Fixed small bug in i18n patch. + +* Mon Dec 6 2004 Tim Waugh 5.2.1-34 +- Don't set fs uid until after pam_open_session (bug #77791). + +* Thu Nov 25 2004 Tim Waugh 5.2.1-33 +- Fixed colorls.csh (bug #139988). Patch from Miloslav Trmac. + +* Mon Nov 8 2004 Tim Waugh +- Updated URL (bug #138279). + +* Mon Oct 25 2004 Steve Grubb 5.2.1-32 +- Handle the return code of function calls in runcon. + +* Mon Oct 18 2004 Tim Waugh +- Prevent compiler warning in coreutils-i18n.patch (bug #136090). + +* Tue Oct 5 2004 Tim Waugh 5.2.1-31 +- getgrouplist() patch from Ulrich Drepper. +- The selinux patch should be applied last. + +* Mon Oct 4 2004 Dan Walsh 5.2.1-30 +- Mv runuser to /sbin + +* Mon Oct 4 2004 Dan Walsh 5.2.1-28 +- Fix runuser man page. + +* Mon Oct 4 2004 Tim Waugh +- Fixed build. + +* Fri Sep 24 2004 Dan Walsh 5.2.1-26 +- Add runuser as similar to su, but only runable by root + +* Fri Sep 24 2004 Tim Waugh 5.2.1-25 +- chown(1) patch from Ulrich Drepper. + +* Tue Sep 14 2004 Tim Waugh 5.2.1-24 +- SELinux patch fix: don't display '(null)' if getfilecon() fails + (bug #131196). + +* Fri Aug 20 2004 Tim Waugh 5.2.1-23 +- Fixed colorls.csh quoting (bug #102412). +- Fixed another join LSB test failure (bug #121153). + +* Mon Aug 16 2004 Tim Waugh 5.2.1-22 +- Fixed sort -t LSB test failure (bug #121154). +- Fixed join LSB test failure (bug #121153). + +* Wed Aug 11 2004 Tim Waugh 5.2.1-21 +- Apply upstream patch to fix 'cp -a' onto multiply-linked files (bug #128874). +- SELinux patch fix: don't error out if lgetfilecon() returns ENODATA. + +* Tue Aug 10 2004 Tim Waugh 5.2.1-20 +- Added 'konsole' TERM to DIR_COLORS (bug #129544). + +* Wed Aug 4 2004 Tim Waugh 5.2.1-19 +- Added 'gnome' TERM to DIR_COLORS (bug #129112). +- Worked around a bash bug #129128. +- Fixed an i18n patch bug in cut (bug #129114). + +* Tue Aug 3 2004 Tim Waugh +- Fixed colorls.{sh,csh} so that the l. and ll aliases are always defined + (bug #128948). + +* Tue Jul 13 2004 Tim Waugh 5.2.1-18 +- Fixed field extraction in sort (bug #127694). + +* Fri Jun 25 2004 Tim Waugh +- Added 'TERM screen.linux' to DIR_COLORS (bug #78816). + +* Wed Jun 23 2004 Dan Walsh 5.2.1-17 +- Move pam-xauth to after pam-selinux + +* Tue Jun 15 2004 Elliot Lee +- rebuilt + +* Mon Jun 7 2004 Tim Waugh 5.2.1-15 +- Fix ls -Z (bug #125447). + +* Fri Jun 4 2004 Tim Waugh +- Build requires bison (bug #125290). + +* Fri Jun 4 2004 Tim Waugh 5.2.1-14 +- Fix selinux patch causing problems with ls --format=... (bug #125238). + +* Thu Jun 3 2004 Dan Walsh 5.2.1-13 +- Change su to use pam_selinux open and pam_selinux close + +* Wed Jun 2 2004 Tim Waugh 5.2.1-12 +- Don't call access() on symlinks about to be removed (bug #124699). + +* Wed Jun 2 2004 Tim Waugh 5.2.1-11 +- Fix ja translation (bug #124862). + +* Tue May 18 2004 Jeremy Katz 5.2.1-10 +- rebuild + +* Mon May 17 2004 Tim Waugh 5.2.1-9 +- Mention pam in the info for su (bug #122592). +- Remove wheel group rant again (bug #122886). +- Change default behaviour for chgrp/chown (bug #123263). Patch from + upstream. + +* Mon May 17 2004 Thomas Woerner 5.2.1-8 +- compiling su PIE + +* Wed May 12 2004 Tim Waugh +- Build requires new versions of autoconf and automake (bug #123098). + +* Tue May 4 2004 Tim Waugh 5.2.1-7 +- Fix join -t (bug #122435). + +* Tue Apr 20 2004 Tim Waugh 5.2.1-6 +- Fix 'ls -Z' displaying users/groups if stat() failed (bug #121292). + +* Fri Apr 9 2004 Dan Walsh 5.2.1-5 +- Add ls -LZ fix +- Fix chcon to handle "." + +* Wed Mar 17 2004 Tim Waugh +- Apply upstream fix for non-zero seconds for --date="10:00 +0100". + +* Tue Mar 16 2004 Dan Walsh 5.2.1-3 +- If preserve fails, report as warning unless user requires preserve + +* Tue Mar 16 2004 Dan Walsh 5.2.1-2 +- Make mv default to preserve on context + +* Sat Mar 13 2004 Tim Waugh 5.2.1-1 +- 5.2.1. + +* Fri Mar 12 2004 Tim Waugh 5.2.0-9 +- Add '-Z' to 'ls --help' output (bug #118108). + +* Fri Mar 5 2004 Tim Waugh +- Fix deref-args test case for rebuilding under SELinux (bug #117556). + +* Wed Feb 25 2004 Tim Waugh 5.2.0-8 +- kill(1) offloaded to util-linux altogether. + +* Tue Feb 24 2004 Tim Waugh 5.2.0-7 +- Ship the real '[', not a symlink. + +* Mon Feb 23 2004 Tim Waugh 5.2.0-6 +- Apply Paul Eggert's chown patch (bug #116536). +- Merged chdir patch into pam patch where it belongs. + +* Mon Feb 23 2004 Tim Waugh 5.2.0-5 +- Fixed i18n patch bug causing sort -M not to work (bug #116575). + +* Sat Feb 21 2004 Tim Waugh 5.2.0-4 +- Reinstate kill binary, just not its man page (bug #116463). + +* Sat Feb 21 2004 Tim Waugh 5.2.0-3 +- Updated ls-stat patch. + +* Fri Feb 20 2004 Dan Walsh 5.2.0-2 +- fix chcon to ignore . and .. directories for recursing + +* Fri Feb 20 2004 Tim Waugh 5.2.0-1 +- Patch ls so that failed stat() is handled gracefully (Ulrich Drepper). +- 5.2.0. + +* Thu Feb 19 2004 Tim Waugh +- More AFS patch tidying. + +* Wed Feb 18 2004 Dan Walsh 5.1.3-0.2 +- fix chcon to handle -h qualifier properly, eliminate potential crash + +* Wed Feb 18 2004 Tim Waugh +- Stop 'sort -g' leaking memory (i18n patch bug #115620). +- Don't ship kill, since util-linux already does. +- Tidy AFS patch. + +* Mon Feb 16 2004 Tim Waugh 5.1.3-0.1 +- 5.1.3. +- Patches ported forward or removed. + +* Fri Feb 13 2004 Elliot Lee 5.0-40 +- rebuilt + +* Tue Jan 20 2004 Dan Walsh 5.0-39 +- Change /etc/pam.d/su to remove preservuser and add multiple + +* Tue Jan 20 2004 Dan Walsh 5.0-38 +- Change is_selinux_enabled to is_selinux_enabled > 0 + +* Tue Jan 20 2004 Dan Walsh 5.0-37 +- Add pam_selinux to pam file to allow switching of roles within selinux + +* Fri Jan 16 2004 Tim Waugh +- The textutils-2.0.17-mem.patch is no longer needed. + +* Thu Jan 15 2004 Tim Waugh 5.0-36 +- Fixed autoconf test causing builds to fail. + +* Tue Dec 9 2003 Dan Walsh 5.0-35 +- Fix copying to non xattr files + +* Thu Dec 4 2003 Tim Waugh 5.0-34.sel +- Fix column widths problems in ls. + +* Tue Dec 2 2003 Tim Waugh 5.0-33.sel +- Speed up md5sum by disabling speed-up asm. + +* Wed Nov 19 2003 Dan Walsh 5.0-32.sel +- Try again + +* Wed Nov 19 2003 Dan Walsh 5.0-31.sel +- Fix move on non SELinux kernels + +* Fri Nov 14 2003 Tim Waugh 5.0-30.sel +- Fixed useless acl dependencies (bug #106141). + +* Fri Oct 24 2003 Dan Walsh 5.0-29.sel +- Fix id -Z + +* Tue Oct 21 2003 Dan Walsh 5.0-28.sel +- Turn on SELinux +- Fix chcon error handling + +* Wed Oct 15 2003 Dan Walsh 5.0-28 +- Turn off SELinux + +* Mon Oct 13 2003 Dan Walsh 5.0-27.sel +- Turn on SELinux + +* Mon Oct 13 2003 Dan Walsh 5.0-27 +- Turn off SELinux + +* Mon Oct 13 2003 Dan Walsh 5.0-26.sel +- Turn on SELinux + +* Sun Oct 12 2003 Florian La Roche +- allow compiling without pam support + +* Fri Oct 10 2003 Tim Waugh 5.0-23 +- Make split(1) handle large files (bug #106700). + +* Thu Oct 9 2003 Dan Walsh 5.0-22 +- Turn off SELinux + +* Wed Oct 8 2003 Dan Walsh 5.0-21.sel +- Cleanup SELinux patch + +* Fri Oct 3 2003 Tim Waugh 5.0-20 +- Restrict ACL support to only those programs needing it (bug #106141). +- Fix default PATH for LSB (bug #102567). + +* Thu Sep 11 2003 Dan Walsh 5.0-19 +- Turn off SELinux + +* Wed Sep 10 2003 Dan Walsh 5.0-18.sel +- Turn on SELinux + +* Fri Sep 5 2003 Dan Walsh 5.0-17 +- Turn off SELinux + +* Tue Sep 2 2003 Dan Walsh 5.0-16.sel +- Only call getfilecon if the user requested it. +- build with selinux + +* Wed Aug 20 2003 Tim Waugh 5.0-14 +- Documentation fix (bug #102697). + +* Tue Aug 12 2003 Tim Waugh 5.0-13 +- Made su use pam again (oops). +- Fixed another i18n bug causing sort --month-sort to fail. +- Don't run dubious stty test, since it fails when backgrounded + (bug #102033). +- Re-enable make check. + +* Fri Aug 8 2003 Tim Waugh 5.0-12 +- Don't run 'make check' for this build (build environment problem). +- Another uninitialized variable in i18n (from bug #98683). + +* Wed Aug 6 2003 Dan Walsh 5.0-11 +- Internationalize runcon +- Update latest chcon from NSA + +* Wed Jul 30 2003 Tim Waugh +- Re-enable make check. + +* Wed Jul 30 2003 Tim Waugh 5.0-9 +- Don't run 'make check' for this build (build environment problem). + +* Mon Jul 28 2003 Tim Waugh 5.0-8 +- Actually use the ACL patch (bug #100519). + +* Wed Jul 16 2003 Dan Walsh 5.0-7 +- Convert to SELinux + +* Mon Jun 9 2003 Tim Waugh +- Removed samefile patch. Now the test suite passes. + +* Wed Jun 04 2003 Elliot Lee +- rebuilt + +* Wed May 28 2003 Tim Waugh 5.0-5 +- Both kon and kterm support colours (bug #83701). +- Fix 'ls -l' alignment in zh_CN locale (bug #88346). + +* Mon May 12 2003 Tim Waugh 5.0-4 +- Prevent file descriptor leakage in du (bug #90563). +- Build requires recent texinfo (bug #90439). + +* Wed Apr 30 2003 Tim Waugh 5.0-3 +- Allow obsolete options unless POSIXLY_CORRECT is set. + +* Sat Apr 12 2003 Tim Waugh +- Fold bug was introduced by i18n patch; fixed there instead. + +* Fri Apr 11 2003 Matt Wilson 5.0-2 +- fix segfault in fold (#88683) + +* Sat Apr 5 2003 Tim Waugh 5.0-1 +- 5.0. + +* Mon Mar 24 2003 Tim Waugh +- Use _smp_mflags. + +* Mon Mar 24 2003 Tim Waugh 4.5.11-2 +- Remove overwrite patch. +- No longer seem to need nolibrt, errno patches. + +* Thu Mar 20 2003 Tim Waugh +- No longer seem to need danglinglink, prompt, lug, touch_errno patches. + +* Thu Mar 20 2003 Tim Waugh 4.5.11-1 +- 4.5.11. +- Use packaged readlink. + +* Wed Mar 19 2003 Tim Waugh 4.5.10-1 +- 4.5.10. +- Update lug, touch_errno, acl, utmp, printf-ll, i18n, test-bugs patches. +- Drop fr_fix, LC_TIME, preserve, regex patches. + +* Wed Mar 12 2003 Tim Waugh 4.5.3-21 +- Fixed another i18n patch bug (bug #82032). + +* Tue Mar 11 2003 Tim Waugh 4.5.3-20 +- Fix sort(1) efficiency in multibyte encoding (bug #82032). + +* Tue Feb 18 2003 Tim Waugh 4.5.3-19 +- Ship readlink(1) (bug #84200). + +* Thu Feb 13 2003 Tim Waugh 4.5.3-18 +- Deal with glibc < 2.2 in %%pre scriplet (bug #84090). + +* Wed Feb 12 2003 Tim Waugh 4.5.3-16 +- Require glibc >= 2.2 (bug #84090). + +* Tue Feb 11 2003 Bill Nottingham 4.5.3-15 +- fix group (#84095) + +* Wed Jan 22 2003 Tim Powers 4.5.3-14 +- rebuilt + +* Thu Jan 16 2003 Tim Waugh +- Fix rm(1) man page. + +* Thu Jan 16 2003 Tim Waugh 4.5.3-13 +- Fix re_compile_pattern check. +- Fix su hang (bug #81653). + +* Tue Jan 14 2003 Tim Waugh 4.5.3-11 +- Fix memory size calculation. + +* Tue Dec 17 2002 Tim Waugh 4.5.3-10 +- Fix mv error message (bug #79809). + +* Mon Dec 16 2002 Tim Powers 4.5.3-9 +- added PreReq on grep + +* Fri Dec 13 2002 Tim Waugh +- Fix cp --preserve with multiple arguments. + +* Thu Dec 12 2002 Tim Waugh 4.5.3-8 +- Turn on colorls for screen (bug #78816). + +* Mon Dec 9 2002 Tim Waugh 4.5.3-7 +- Fix mv (bug #79283). +- Add patch27 (nogetline). + +* Sun Dec 1 2002 Tim Powers 4.5.3-6 +- use the su.pamd from sh-utils since it works properly with multilib systems + +* Fri Nov 29 2002 Tim Waugh 4.5.3-5 +- Fix test suite quoting problems. + +* Fri Nov 29 2002 Tim Waugh 4.5.3-4 +- Fix scriplets. +- Fix i18n patch so it doesn't break uniq. +- Fix several other patches to either make the test suite pass or + not run the relevant tests. +- Run 'make check'. +- Fix file list. + +* Thu Nov 28 2002 Tim Waugh 4.5.3-3 +- Adapted for Red Hat Linux. +- Self-host for help2man. +- Don't ship readlink just yet (maybe later). +- Merge patches from fileutils and sh-utils (textutils ones are already + merged it seems). +- Keep the binaries where the used to be (in particular, id and stat). + +* Sun Nov 17 2002 Stew Benedict 4.5.3-2mdk +- LI18NUX/LSB compliance (patch800) +- Installed (but unpackaged) file(s) - /usr/share/info/dir + +* Thu Oct 31 2002 Thierry Vignaud 4.5.3-1mdk +- new release +- rediff patch 180 +- merge patch 150 into 180 + +* Mon Oct 14 2002 Thierry Vignaud 4.5.2-6mdk +- move su back to /bin + +* Mon Oct 14 2002 Thierry Vignaud 4.5.2-5mdk +- patch 0 : lg locale is illegal and must be renamed lug (pablo) + +* Mon Oct 14 2002 Thierry Vignaud 4.5.2-4mdk +- fix conflict with procps + +* Mon Oct 14 2002 Thierry Vignaud 4.5.2-3mdk +- patch 105 : fix install -s + +* Mon Oct 14 2002 Thierry Vignaud 4.5.2-2mdk +- fix build +- don't chmode two times su +- build with large file support +- fix description +- various spec cleanups +- fix chroot installation +- fix missing /bin/env +- add old fileutils, sh-utils & textutils ChangeLogs + +* Fri Oct 11 2002 Thierry Vignaud 4.5.2-1mdk +- initial release (merge fileutils, sh-utils & textutils) +- obsoletes/provides: sh-utils/fileutils/textutils +- fileutils stuff go in 1xx range +- sh-utils stuff go in 7xx range +- textutils stuff go in 5xx range +- drop obsoletes patches 1, 2, 10 (somes files're gone but we didn't ship + most of them) +- rediff patches 103, 105, 111, 113, 180, 706 +- temporary disable patch 3 & 4 +- fix fileutils url