Compare commits

...

74 Commits
v8.10 ... v8.11

Author SHA1 Message Date
Jim Meyering
8dc5394183 version 8.11
* NEWS: Record release date.
2011-04-13 21:13:50 +02:00
Pádraig Brady
ace9ef2a94 maint: mention dd's new partial read warning in NEWS
* NEWS: Mention the new feature, from commits e1788d9e and 194c1e89
2011-04-13 15:38:36 +01:00
Pádraig Brady
403e8e3b89 tests: fix a false positive fiemap test on some file systems
* tests/filefrag-extent-compare: Don't check the length of the
last extent, as this was seen to vary on XFS, where it leaves
trailing blocks allocated for performance reasons.
* tests/cp/fiemap-empty: Though not seen as an issue in practise,
try to avoid possible issues with the allocator in file systems,
by requesting to allocate a power of 2.
2011-04-13 11:18:48 +01:00
Pádraig Brady
501ce81b6a maint: correct kernel version in test comment 2011-04-12 11:30:33 +01:00
Jim Meyering
53ee267945 maint: remove unnecessary inclusion of <stdio.h>
* src/extent-scan.c: Don't include <stdio.h>.  It was not used.
2011-04-12 12:14:26 +02:00
Jim Meyering
ce0f286cce build: update gnulib submodule to latest 2011-04-11 14:33:23 +02:00
Jim Meyering
1487204385 cfg.mk: remove useless semicolon and backslash
* cfg.mk (sc_NEWS_two_empty_lines): Remove semicolon and backslash.
2011-04-11 14:32:56 +02:00
Jim Meyering
4db3c6b5ea doc: tweak NEWS
* NEWS: Slightly obfuscate a line to avoid a false-positive
doubled-word ("is-is") match.
Fix a grammar error in news for 8.2.
* cfg.mk (old_NEWS_hash): Resync.
2011-04-11 14:32:56 +02:00
Jim Meyering
b80e2c7c25 maint: install: remove support for --preserve_context ("_", not "-")
* src/install.c: Its use has elicited a warning for two years.
Use --preserve-context instead.
* NEWS (changes in behavior): Mention this.
2011-04-11 14:32:56 +02:00
Jim Meyering
9288068ff8 maint: reorder install.c to eliminate declarations of static functions
* src/install.c: Remove static function declarations.
2011-04-11 14:32:56 +02:00
Jim Meyering
e6f4c34167 maint: rename variables for clarity...
and to avoid a false-positive "TO to" in new doubled word check.
* src/install.c (change_timestamps): Rename parameters for
readability.  Make the comment match the code.
2011-04-11 14:32:55 +02:00
Jim Meyering
b2dfc3b5e5 maint: remove doubled words in comments, e.g., s/to to/to/
* tests/ls/color-norm: s/to to/to/
* gl/lib/mbsalign.h (mbs_align_t): s/or or/or/
* src/extent-scan.c (extent_scan_read): s/the the/the/
* src/libstdbuf.c: s/the the/the/
* tests/misc/stdbuf: s/on on/on/
* ChangeLog-2005: s/for\n\tfor /for\n\t/
2011-04-11 14:32:55 +02:00
Pádraig Brady
80be785c95 maint: misc typo fixes
* src/fiemap.h: s/can not/cannot/
* NEWS: s/in/is/
* doc/coreutils.texi: Remove spurious "and".
s/effect/affect/
Use matched ``...'' quotes.
2011-04-11 11:13:14 +02:00
Pádraig Brady
324571ea4a maint: correct kernel version in NEWS
* NEWS: Adjust to match commit 1c3654cb, 2011-04-02,
"copy: require fiemap sync also for 2.6.38 kernels"
2011-04-07 00:23:00 +01:00
Pádraig Brady
18f5a8537c copy: handle mergeable extents across fiemap scans
* extent-scan.h (extent_scan_free): Init the pointer to NULL,
and reset the count to 0, so that we can realloc the buffer.
* src/extent-scan.c (extent_scan_init): Likewise.
(extent_scan_read): Loop over multiple fiemap scans, so we handle
mergeable extents that span across fiemap scan boundaries.  Once
we have enough unique extents, return so as to minimize memory use.
2011-04-06 23:15:19 +01:00
Pádraig Brady
8b2bedadb5 copy: fix an unlikely memory leak when a fiemap copy fails
* src/copy.c (extent_copy): Free the extents array when
sparse_copy() fails.
2011-04-06 23:08:54 +01:00
Jim Meyering
a71537366e tests: avoid spurious parallel failure due to temporary disk full
Running the new fiemap-empty test uses 600MB of disk space via
fallocate, and in so doing caused failure in unrelated tests that
were running in parallel on a small file system.  Rather than
simply running fallocate (which allocates the space, inducing
disk full when it fails), skip the test if there is less than
800MB of free space, as computed via stat and awk.
* tests/init.cfg (require_file_system_bytes_free_): New function.
* tests/cp/fiemap-empty: Use it.
2011-04-04 18:21:32 +02:00
Jim Meyering
4e23ca47ac tests: don't ever leave a backgrounded "sleep 10m" process
* tests/misc/help-version: Sleep only ~30s, not 10m.
The latter was a problem when somehow that sleep process would
hang around and thereby prevent (for up to 10m) a normal unmount
of the temporary partition in which I'd run the tests.
2011-04-04 18:21:32 +02:00
Jim Meyering
aec3e1e107 tests: preserve-gid: don't chown temporary PATH dir to a nameless UID
* tests/cp/preserve-gid: Simply chmod a+rx instead.
That is safer, in case the nameless UID actually has an account,
and might take advantage of root running a program in a directory
under its control
2011-04-04 18:21:32 +02:00
Jim Meyering
40f71538b6 tests: preserve-gid: remove useless use of "env"
* tests/cp/preserve-gid: Remove useless use of "env".
2011-04-04 18:21:32 +02:00
Jim Meyering
1bc76356d2 tests: convert common root-build test failure to a "skip"
* tests/mv/sticky-to-xpart: Skip rather than failing this test
when run as root and the binaries are not accessible by "nobody".
2011-04-04 18:21:31 +02:00
Jim Meyering
6227c8e8de tests: minor improvement of sc_tight_scope rule
* src/Makefile.am (sc_tight_scope): Adjust rule to use an eval-based
trap-setting for-loop rather than 4x hard-coded 128+N constants.
Also catch SIGQUIT (3).  Tweak comments.
2011-04-04 18:21:31 +02:00
Eric Blake
8d0b79afa5 docs: mention POSIX 2008
* doc/coreutils.texi (Standards conformance): Give value of
_POSIX2_VERSION matching the _POSIX_C_SOURCE of POSIX 2008.
2011-04-04 09:45:28 -06:00
Jim Meyering
03583f8d64 maint: prohibit direct use of strncmp: prefer STREQ_LEN, STRNCMP_LIT
* cfg.mk (sc_prohibit_strncmp): New rule, mostly from libvirt.
* src/system.h (STREQ_LEN, STRPREFIX, STRNCMP_LIT): Define.
* src/df.c (get_dev, get_point): Convert.
* src/extent-scan.c (extent_need_sync): Likewise.
* src/ls.c (is_colored, decode_switches): Likewise.
(parse_ls_color, (print_color_indicator): Likewise.
* src/md5sum.c (split_3): Likewise.
* src/split.c (main, emit_ancillary_info): Likewise.
* src/tr.c (look_up_char_class): Likewise.
* src/uname.c (main): Likewise.
* src/who.c (scan_entries): Likewise.
2011-04-03 21:55:27 +02:00
Jim Meyering
1c3654cb1f copy: require fiemap sync also for 2.6.38 kernels
* src/extent-scan.c (extent_need_sync): Require sync also for 2.6.38.
Without this, part of the cp/fiemap-empty test would fail both on
F15-to-be (2.6.38.1-6.fc15.x86_64) and rawhide.  For details, see
http://thread.gmane.org/gmane.comp.gnu.coreutils.bugs/22190
2011-04-03 12:16:27 +02:00
Jim Meyering
45b332f7ab cp: always detect copy-into-self: avoid infloop w/large PATH_MAX
When running the erroneous command, cp -rl A D D, and depending on the
structure of directories A and D and the file system type (because that
changes order of dir. entry traversal), cp would sometimes fail to
detect that D was being copied into D, and would create D/D/D/D/D/...
until it hit PATH_MAX or exhausted some resource.
I noticed this via the occasional failure of the cp/into-self test
when run using a ZFS file system.  It is occasional because the bug
is dependent on the order in which directory entries are traversed,
and that is apparently indeterminate with ZFS.
Technically, with the current recursive implementation, there is no
risk of an infinite loop, due to stack limitations, but with an
eventual fts-based implementation, it might have iterated until
disk space or inodes are exhausted.
* src/copy.c (copy_dir): Avoid copy-into-self interminable loop on
systems with large PATH_MAX.  On other systems, diagnose the copy-into-
self error consistently.  Handle the parameter,
first_dir_created_per_command_line_arg, correctly when there are two
or more sub-directories.
2011-04-02 16:14:47 +02:00
Jim Meyering
e08b3e7c08 maint: fix a comment typo
* tests/cp/fiemap-empty: Correct typo in comment.  Add "FIXME".
2011-04-02 14:22:55 +02:00
Pádraig Brady
bfdb6b585b copy: process empty extents more efficiently
* src/copy.c (extent_copy): Treat an allocated but empty extent
much like a hole.  I.E. don't read data we know is going to be NUL.
Also we convert the empty extent to a hole only when SPARSE_ALWAYS
so that the source and dest have the same allocation.  This will
be improved soon, when we use fallocate() to do the allocation.
* tests/cp/fiemap-empty: A new test for efficiency and correctness
of copying empty extents.
* tests/Makefile.am: Reference the new test.
* NEWS: Mention the change in behavior.
2011-04-01 15:04:18 +01:00
Pádraig Brady
b56b53bd70 copy: protect against overlapping extents
* src/extent-scan.c (extent_scan_read): Add a more stringent check
for OFF_T overflow, to ensure subsequent code is immune.
Detect overlapping extents and adjust, so as files always copied.
Detection using a single scan with fallback to a standard copy
was thought too expensive in memory or time.
* NEWS: Mention the fix
2011-04-01 14:42:46 +01:00
Pádraig Brady
594292a1d8 copy: link rather than copy symlinks, when --link used
This bug was introduced in commit ca9e212c, 2009-09-24,
"cp, mv: use linkat to guarantee semantics", which
inadvertently disabled the creation of hardlinks to symlinks.
However rather than implementing the intention of that commit
and relying on gnulib linkat emulation, we'll revert to the
previous emulation as that maintains ownership and timestamps.

* src/copy.c (copy_internal): Use our existing hardlink to
symlink emulation when link() might dereference the symlink.
Also ensure that we copy the timestamps of the original symlink
when we use the emulation.
* tests/cp/link-symlink: Add a test to ensure timestamps copied.
* tests/Makefile.am: Reference the new test.
* NEWS: Mention the fix.
Reported by Ruediger Meier
2011-04-01 14:17:27 +01:00
Jim Meyering
0ec711b5c4 tests: inotify-rotate: avoid race condition with overloaded disk
* tests/tail-2/inotify-rotate: Wait 50% longer for grep to succeed.
Without this change, this test would fail consistently when using
"make -j25 check" with F15 in a virtio- and spinning-rust-backed
virtual machine.
2011-03-31 18:58:38 +02:00
Pádraig Brady
f69876e558 copy: with fiemap copy, only sync when needed
* src/extent-scan.h (struct extent_scan): Add the fm_flags member to
pass to the fiemap scan.
* src/extent-scan.c (extent_need_sync): A new function used to
detect Linux kernels before 2.6.38.
(extent_scan_init): Add FIEMAP_FLAG_SYNC when needed.
* tests/cp/sparse-fiemap: Adjust comment.
* NEWS: Mention the change in behavior.
Indirectly suggested by Mike Frysinger
2011-03-31 16:46:42 +01:00
Mathieu Bridon
17a7e45927 tests: avoid unwarranted failure in mock-simulated non-SELinux env.
* tests/init.cfg (require_selinux_): Skip the test also when
/proc/filesystems does not list selinuxfs.
Add comments.
* cfg.mk (exclude_file_name_regexp--sc_file_system): Exempt
tests/init.cfg, with its use of /proc/filesystems.
Based on the patch by Mathieu Bridon in http://debbugs.gnu.org/8359.
More discussion in http://bugzilla.redhat.com/573111
2011-03-28 12:00:12 +02:00
Jim Meyering
fde07ff436 maint: correct formatting style in a header
* src/find-mount-point.h: Move "*" to where it belongs.
Move "const", too.
* src/find-mount-point.c: Move "const" to conform.
* src/Makefile.am (sc_tight_scope): Allow `*'s before the function name.
Use perl's -l option and drop the \n after (and quotes around) $1.
2011-03-28 11:51:35 +02:00
Pádraig Brady
99679fff62 df: fix alignment of columns
* src/df.c (alloc_table_row): A new function to allocate storage
for a row of strings.
(print_table): A new function to interate over all stored strings in
the table, and apply alignment honoring the max width of each column.
(get_header): Renamed from print_header, and adjusted accordingly.
(get_dev): Renamed from show_dev.  Also we no longer wrap longer
device names over two lines, which can be an unexpected issue for
scripts parsing the output from df.
(get_disk): s/show_/get_/
(get_point): Likewise.
(get_entry): Likewise.
(get_all_entries): Likewise.
* NEWS: Mention the change.
2011-03-23 16:44:49 +00:00
Jim Meyering
437fcf713c build: update gnulib submodule to latest 2011-03-22 07:13:59 +01:00
Jim Meyering
b3f6b33e4b tests: exercise tests new "==" operator
* tests/misc/test: Exercise the new operator.
* NEWS (Changes in behavior): Mention it.
2011-03-22 07:13:59 +01:00
David A. Wheeler
3f31ec950b test: accept "==" as a synonym for "="
Make GNU coreutils' test recognize "==" as a synonym for "=".
This is already the case in GNU coreutils' expr, bash, ksh,
busybox ash, FreeBSD-current /bin/sh and /bin/test, and
OpenBSD's /bin/sh.

Before, env test a '==' a would fail with this diagnostic:
"test: ==: binary operator expected".  Now, it succeeds.
* src/test.c: Accept "==" as a synonym for "=".
* doc/coreutils.texi (String tests): Document it.
Reported as http://debbugs.gnu.org/8263
Also see http://austingroupbugs.net/view.php?id=375
2011-03-22 07:12:01 +01:00
Jim Meyering
2a3a094e0d tests: fix a bug in the cp/preserve-gid test
* tests/cp/preserve-gid: Ensure that every process under test uses
the cp binary we've just built.  Before this fix, with a restrictive
umask or build-dir permissions, the UID-changing tests would end up
using whatever cp happened to be available through $PATH
Analysis by arbogast.cedric@gmail.com in http://debbugs.gnu.org/8292.
2011-03-21 07:37:20 +01:00
Paul Eggert
c20d0e17c3 bootstrap: do not exclude m4/message.m4
* bootstrap.conf (excluded_files): Don't exclude m4/lcmessage.m4,
as it's needed with the latest gnulib.
2011-03-20 12:25:26 -07:00
Jim Meyering
8e5292dfb8 maint: remove a name from THANKS.in that is derived from git log
The names in THANKS are generated from two sources: the hard-coded
list, THANKS.in, and the names of committers from the git log.
When a contributor on the hard-coded list commits a change,
we remove their now-redundant name from THANKS.in.
* THANKS.in: Remove a now-duplicate name.
2011-03-20 16:05:23 +01:00
Pádraig Brady
7a804b9af4 tests: fix the sparse-fiemap test
* tests/filefrag-extent-compare: Merge adjacent extents in
each list before processing, so we correctly account for
split extents in either list.
* tests/cp/sparse-fiemap: Remove the explicit syncing,
which was only changing the way extents were arranged,
and thus working around the extent comparison issue
that was seen on ext4 loop back.
2011-03-19 23:58:49 +00:00
Jim Meyering
4f591fdd0b sort: avoid memory pressure of 130MB/thread when reading from pipe
* src/sort.c (INPUT_FILE_SIZE_GUESS): Decrease initial allocation
factor used to size buffer used when reading a non-regular file.
For motivation, see discussion here:
http://thread.gmane.org/gmane.comp.gnu.coreutils.general/878/focus=887
2011-03-16 16:30:02 +01:00
Jim Meyering
8e4e1d484f maint: stop using .x-sc_* files to list syntax-check exemptions
Instead, use the brand new mechanism with which you merely use a
variable (derived from the rule name) defined in cfg.mk to an ERE
matching the exempted file names.
* gnulib: Update to latest, to get maint.mk that implements this.
* Makefile.am (syntax_check_exceptions): Remove variable.
(EXTRA_DIST): Remove use of the variable.
* cfg.mk (sc_x_sc_dist_check): Remove rule, no longer useful.
(exclude_file_name_regexp--sc_space_tab): Define variable.
(exclude_file_name_regexp--sc_bindtextdomain): Likewise.
(exclude_file_name_regexp--sc_unmarked_diagnostics): Likewise.
(exclude_file_name_regexp--sc_error_message_uppercase): Likewise.
(exclude_file_name_regexp--sc_trailing_blank): Likewise.
(exclude_file_name_regexp--sc_system_h_headers): Likewise.
(exclude_file_name_regexp--sc_require_config_h_first): Likewise.
(exclude_file_name_regexp--sc_require_config_h): Likewise.
(exclude_file_name_regexp--sc_po_check): Likewise.
(exclude_file_name_regexp--sc_prohibit_always-defined_macros): Likewise.
(exclude_file_name_regexp--sc_prohibit_empty_lines_at_EOF): Likewise.
(exclude_file_name_regexp--sc_program_name): Likewise.
(exclude_file_name_regexp--sc_file_system): Likewise.
(exclude_file_name_regexp--sc_prohibit_always_true_header_tests):
Likewise.
(exclude_file_name_regexp--sc_prohibit_fail_0): Likewise.
(exclude_file_name_regexp--sc_prohibit_atoi_atof): Likewise.
(exclude_file_name_regexp--sc_prohibit_tab_based_indentation): Likewise.
(exclude_file_name_regexp--sc_prohibit_stat_st_blocks): Likewise.
* configure.ac [whether localtime caches TZ]: Use return 0/1, not
exit (0/1) to avoid triggering a sc_prohibit_magic_number_exit failure.
* .x-sc_GPL_version: Remove file.
* .x-sc_bindtextdomain: Likewise.
* .x-sc_error_message_uppercase: Likewise.
* .x-sc_file_system: Likewise.
* .x-sc_obsolete_symbols: Likewise.
* .x-sc_po_check: Likewise.
* .x-sc_program_name: Likewise.
* .x-sc_prohibit_always-defined_macros: Likewise.
* .x-sc_prohibit_always_true_header_tests: Likewise.
* .x-sc_prohibit_atoi_atof: Likewise.
* .x-sc_prohibit_empty_lines_at_EOF: Likewise.
* .x-sc_prohibit_fail_0: Likewise.
* .x-sc_prohibit_magic_number_exit: Likewise.
* .x-sc_prohibit_stat_st_blocks: Likewise.
* .x-sc_prohibit_strcmp: Likewise.
* .x-sc_prohibit_tab_based_indentation: Likewise.
* .x-sc_require_config_h: Likewise.
* .x-sc_require_config_h_first: Likewise.
* .x-sc_space_tab (config): Likewise.
* .x-sc_sun_os_names: Likewise.
* .x-sc_system_h_headers: Likewise.
* .x-sc_trailing_blank: Likewise.
* .x-sc_unmarked_diagnostics: Likewise.
* .x-sc_useless_cpp_parens: Likewise.
2011-03-16 12:22:22 +01:00
Pádraig Brady
0ddfd54b08 maint: use wcswidth from gnulib
* gl/lib/mbsalign.c (rpl_wcswidth): Remove this in favor
of the equivalent wcswidth replacement in gnulib.
* bootstrap.conf: Depend on the wcswidth module.
Suggested by Bruno Haible.
2011-03-13 23:55:17 +00:00
Jim Meyering
56e8714e2b touch: update to latest gnulib to fix Solaris 10 touch segfault
* gnulib: Update to latest, to address http://debbugs.gnu.org/8230.
When built on Solaris 9 and run on Solaris 10, touch would segfault.
Reported by Ben Walton.
* bootstrap: Update from gnulib.
* tests/init.sh: Likewise.
* NEWS (Bug fixes): Mention this.
2011-03-13 18:41:44 +01:00
Jim Meyering
e0245ae0ae sort: spawn fewer threads for small inputs
* src/sort.c (SUBTHREAD_LINES_HEURISTIC): Do not spawn a new thread
for every 4 lines.  Increase this from 4 to 128K.  128K lines seems
appropriate for a 5-year-old dual-core laptop, but it is too low for
some common combinations of short lines and/or newer systems.
* NEWS (Bug fixes): Mention it.
2011-03-13 18:13:17 +01:00
Pádraig Brady
3ed0384c41 copy: merge similar extents before processing
* src/extent-scan.c (extent_scan_read):  Merge adjacent extents
that vary only in size, so that we may process them more efficiently.
This will be especially useful when we introduce fallocate()
so that we don't reproduce fragmentation in the destination.
2011-03-11 00:50:10 +00:00
Paul Eggert
194c1e89a4 dd: avoid or diagnose some problems with short reads
* src/dd.c (warn_partial_read): New static var.
(iread): Diagnose partial reads if needed.
(iwrite): Don't diagnose them here; not needed any more.
(scanargs): Determine whether partial reads should be diagnosted.
2011-03-05 16:06:34 -08:00
Pádraig Brady
5bf48c1186 maint: fix dd nocache test to be independent of current stdin
* tests/dd/nocache: Don't assume stdin is a pipe
2011-03-05 09:53:00 +00:00
Pádraig Brady
5f3115535b dd: add a flag to discard cached data
* src/dd.c (FFS_MASK): A new macro (Find First Set) refactored
from the following enum as it's now used twice.
(usage): Mention the new 'nocache' flag.
(cache_round): A new function to help ignore requests
to drop cache, that are less than page_size.
(invalidate_cache): A new function to call posix_fadvise()
with the appropriate offset and length.  Note we don't
use fdadvise() so we can detect errors when count=0.
(dd_copy): Call invalidate_cache() for the portions read.
(iwrite): Likewise for the portions written.
(main): Call invalidate_cache for page_size slop or
for full file when count=0.
* cfg.mk (sc_dd_O_FLAGS): Adjust to pass.
* doc/coreutils.texi (dd invocation): Describe the 'nocache' flag,
and give some examples of how it can be used.
* tests/dd/nocache: A new test.
* tests/Makefile.am: Reference the new test.
* NEWS: Mention the new feature.
2011-03-05 02:33:53 +00:00
Pádraig Brady
433a7c614f doc: clarify that dd bs= can immediately output short reads
* doc/coreutils.texi (dd invocation): Clarify that bs= can
cause parital reads to be immediately written to output.
* src/dd.c (usage): Hint that bs= can cause partial writes.
See http://debbugs.gnu.org/cgi/bugreport.cgi?bug=8171
2011-03-05 02:21:45 +00:00
Pádraig Brady
7525860fb9 doc: group dd conv= options that are actually flags
* src/dd.c (usage): Move 'sync' up with other data transformation
options.  Having it alongside 'fsync' and 'fdatasync' is
particularly confusing.  Also the double line description of
the 'sync' option, serves as a visual break from the "flag"
type options that follow.
* doc/coreutils.texi (dd invocation):  Apply the same grouping
as above, by splitting the "conv=" table in two.
2011-03-05 02:01:16 +00:00
Pádraig Brady
e1788d9ed9 dd: warn when we disable oflag=direct not at EOF
An alternative to this is to auto enable iflag=fullblock
when oflag=direct and bs= is specified.
It was thought better though, to warn about the specific issue,
and give full control of dd's options to the user.

* src/dd.c (iwrite): Warn, when we write after having
disabled O_DIRECT.
See https://bugzilla.redhat.com/show_bug.cgi?id=614605
2011-03-05 01:48:55 +00:00
Jim Meyering
caaf2899f6 du: don't infloop for --files0-from=DIR
* src/du.c (main): Fail on AI_ERR_READ error, rather than merely
diagnosing and continuing.  Based on a patch by Stefan Vargyas.
Also move the handling of AI_ERR_EOF into the case stmt.
Do not report ferror/fclose(stdin) failure when we've
already diagnosed e.g., failure to read the DIR, above.
Bug introduced by 2008-11-24 commit 031e2fb5, "du: read and
process --files0-from= input a name at a time,".
* src/wc.c: Handle read failure as with du: do not exit
immediately, but rather go on to print any total and to clean-up.
As above, move the handling of AI_ERR_EOF into the case stmt.
* tests/du/files0-from-dir: New file, to test both du and wc.
* tests/Makefile.am (TESTS): Add it.
* NEWS (Bug fixes): Mention it.
2011-03-03 09:05:44 +01:00
Jim Meyering
7cfd12c78e wc: avoid NULL dereference on out-of-memory error
* src/wc.c (main): Diagnose failed argv_iter_init_* failure,
rather than falling through and dereferencing NULL.
Bug introduced by 2008-11-25 commit c2e56e0d,
"wc: read and process --files0-from= input a name at a time,".
* NEWS (Bug fixes): Mention it.
2011-03-03 09:01:17 +01:00
Pádraig Brady
a132e03507 tests: without filefrag, only skip part of sparse-fiemap
* tests/cp/sparse-fiemap: Move the PERL check to the top,
since we don't test anything without it.  In the loop,
don't use skip_test_ as it exits the test completely.
2011-02-25 07:30:09 +00:00
Gilles Espinasse
269665866d maint: replace spaces with tab in tests/Makefile.am
* tests/Makefile.am: Replace spaces with tabs for consistency
2011-02-19 23:09:09 +00:00
Jim Meyering
2895f44e89 stdbuf: avoid even the appearance of a possible use-after-free
There was an execution path by which "libstdbuf" could be used after
being freed, but that would happen only if there were no libstdbuf.so
alongside the stdbuf program and there had been an installation error
leading to absence of the file, PKGLIBDIR/libstdbuf.so.
* src/stdbuf.c (set_LD_PRELOAD): Rearrange loop to make it perfectly
clear that there is no possibility of use-after-free.
Steve Grubb reported this possible use-after-free of "libstdbuf".
2011-02-18 23:31:29 +01:00
Gilles Espinasse
e6067bcb04 tests: correct racy sparse-to-pipe test
* tests/cp/sparse-to-pipe: Wait for backgrounded "cat" to complete
before comparing the results.
2011-02-18 13:52:21 +01:00
Paul Eggert
43066fe2ca uptime: omit unnecessary #if
* src/uptime.c (print_uptime): Omit unnecessary "#if defined
HAVE_GETLOADAVG || defined C_GETLOADAVG".  This #if is always
true, and removing it will help us simplify the gnulib getloadavg
module.
2011-02-14 21:05:55 -08:00
Pádraig Brady
0f56019db8 tests: support more file systems in the cp fiemap tests
* tests/cp/sparse-fiemap: Check for fiemap support against a file
rather than a directory to enable tests on BTRFS for example.
Explicity disable the test on ext3 or file systems where we
can't determine the type.
* tests/cp/fiemap-perf: Likewise.  Also disable the test on older
BTRFS (like in Fedora 14), where extents are returned for holes.
* tests/init.cfg: Comment that BTRFS only supports fiemap
for regular files.
2011-02-15 00:02:29 +00:00
Pádraig Brady
275c831a3c copy: adjust fiemap handling of sparse files
Don't depend on heuristics to detect sparse files
if fiemap is available.  Also don't scan for new
holes unless --sparse=always has been specified.

* src/copy.c (extent_copy): Pass the user specified
sparse mode, and handle as described above.
2011-02-11 00:13:31 +00:00
Pádraig Brady
6f95025c9d copy: suppress redundant lseeks when using fiemap
* src/copy.c (extent_copy): Suppress redundant lseek()s in both
the source and dest files, when there is no hole between extents.
2011-02-11 00:13:31 +00:00
Jim Meyering
15571e0c8f tests: fix bug in preceding check.mk change
* tests/check.mk (.built-programs): Run cd'd submake in a subshell
so the redirected output ends up in the current directory, not ../src.
2011-02-10 10:01:23 +01:00
Jim Meyering
c91b2a3c3b tests: print "python missing:..." diagnostic where more will see it
* tests/init.cfg (fiemap_capable_): Print with warn_, so that the
diagnostic shows up alongside the corresponding SKIP message.
2011-02-10 08:57:12 +01:00
Jim Meyering
ee6c466ba8 tests: avoid gross inefficiency in "make test"
Do not run a sub-make to set up the environment for each
and every test script.  Instead, run it just once and store
the result in a file.
* tests/check.mk (built_programs): Remove definition.
(.built-programs): New rule to create the temporary file.
(CLEANFILES): Arrange to remove it.
(TESTS_ENVIRONMENT): Simply cat .built-programs, rather than
running the sub-make.
* .gitignore: Ignore it.
2011-02-10 08:50:14 +01:00
Pádraig Brady
5c3fd50a75 test: improve the cp fiemap tests
* tests/cp/fiemap-2: Enable the fiemap check for files, which
will enable the test for files on ext3.
* tests/cp/fiemap-perf: Comment why we're not enabling for ext3.
* tests/cp/sparse-fiemap: Ditto.  Also sync the files before
doing a fiemap which was needed for ext4 loop back at least.
Add a comment that FIEMAP_FLAG_SYNC is ineffective, thus
requiring the explicit syncs.
* tests/fiemap-capable: A new python script to determine
if a specified path supports fiemap.
* tests/init.cfg (fiemap_capable_): Use the new python script.
* tests/Makefile.am (EXTRA_DIST): Include the new python script.
2011-02-08 22:46:25 +00:00
Jim Meyering
480c0dc9e7 tests: randread-tests: use macro.h not "#define ASSERT..."
* gl/modules/randread-tests (Files): Add tests/macros.h
* gl/tests/test-rand-isaac.c: Remove now-unneeded #include directives.
(ASSERT): Remove definition.
Instead, include "macros.h".
Prompted by suggestions from Bruno Haible.
2011-02-08 08:30:19 +01:00
Jim Meyering
beaf631292 maint: move di-set and ino-map modules from ./gl to gnulib
* gl/lib/di-set.c: Remove file.
* gl/lib/di-set.h: Likewise.
* gl/lib/ino-map.c: Likewise.
* gl/lib/ino-map.h: Likewise.
* gl/modules/di-set: Likewise.
* gl/modules/di-set-tests: Likewise.
* gl/modules/ino-map: Likewise.
* gl/modules/ino-map-tests: Likewise.
* gl/tests/test-di-set.c: Likewise.
* gl/tests/test-ino-map.c: Likewise.
* gnulib: Update to latest, now that these two modules are there.
2011-02-07 16:24:14 +01:00
Jim Meyering
b9fc790ddc di-set: provide a lookup method
This is required for patch, and hence is about to move to gnulib.
* gl/lib/di-set.c (di_set_lookup): New function.
* gl/lib/di-set.h: Declare it.
* gl/tests/test-di-set.c (main): Exercise it.

The bug was introduced on 2004-12-04 via commit 7380cf79.
2011-02-07 15:50:44 +01:00
Jim Meyering
2e636af1ef cut: don't segfault for large unbounded range
* src/cut.c (set_fields): When computing the maximum range endpoint,
take into consideration the start of any unbounded range, like "999-".
* NEWS (Bug fixes): Mention it.
* tests/misc/cut (big-unbounded-b,c,f): Add tests.
Reported by Paul Marinescu in http://debbugs.gnu.org/7993
The bug was introduced on 2004-12-04 via commit 7380cf79.
2011-02-07 09:25:51 +01:00
Jim Meyering
9f61806875 copy: don't let a failed lseek go undiagnosed
Upon failed lseek, sparse_copy_finalize would mistakenly return true.
Admittedly, that is very unlikely, since that particular lseek
is attempted only if the preceding call to sparse_copy induced
a hole at EOF (via lseek on the destination FD).  However, now
that sparse_copy has an output parameter, N_READ, there is no
longer any reason to call lseek (fd, 0, SEEK_CUR), so...
* src/copy.c (sparse_copy_finalize): Remove the function.
(copy_reg): Call ftruncate with n_read, rather than
sparse_copy_finalize with its now-unnecessary lseek.
Lasse Collin spotted the bug in sparse_copy_finalize.
2011-02-05 22:40:57 +01:00
Jim Meyering
661413d8c3 post-release administrivia
* NEWS: Add header line for next release.
* .prev-version: Record previous version.
* cfg.mk (old_NEWS_hash): Auto-update.
2011-02-04 18:19:36 +01:00
97 changed files with 1842 additions and 1672 deletions

1
.gitignore vendored
View File

@@ -75,6 +75,7 @@
/src/version.h
/stamp-h1
/tests/*/*.log
/tests/.built-programs
/tests/t?
/tests/test-suite.log
ID

View File

@@ -1 +1 @@
8.9
8.10

View File

@@ -1 +0,0 @@
^build-aux/check\.mk$

View File

@@ -1,7 +0,0 @@
^gl/lib/randint\.c$
^gl/tests/test-di-set\.c$
^gl/tests/test-fadvise\.c$
^gl/tests/test-ino-map\.c$
^gl/tests/test-mbsalign\.c$
^gl/tests/test-rand-isaac\.c$
^lib/euidaccess-stat\.c$

View File

@@ -1 +0,0 @@
build-aux/cvsu

View File

@@ -1,5 +0,0 @@
ChangeLog
NEWS
src/df.c
src/stat.c
tests/misc/df-P

View File

@@ -1 +0,0 @@
ChangeLog

View File

@@ -1 +0,0 @@
^gl/

View File

@@ -1,3 +0,0 @@
gl/lib/randint.c
lib/euidaccess-stat.c
gl/tests/.*\.c

View File

@@ -1 +0,0 @@
src/seq.c

View File

@@ -1,2 +0,0 @@
^m4/stat-prog\.m4$
ChangeLog

View File

@@ -1 +0,0 @@
^lib/euidaccess-stat\.c$

View File

@@ -1 +0,0 @@
^tests/pr/

View File

@@ -1,4 +0,0 @@
\.mk$
/Makefile\.am$
^tests/init\.sh$
^tests/test-lib\.sh$

View File

@@ -1,2 +0,0 @@
configure.ac
ChangeLog*

View File

@@ -1,4 +0,0 @@
src/system.h
tests/du/2g
old/fileutils/ChangeLog-1997
ChangeLog-2005

View File

@@ -1 +0,0 @@
ChangeLog

View File

@@ -1,7 +0,0 @@
^GNUMakefile$
Makefile\.am$
\.mk$
^tests/pr/
ChangeLog.*
^man/help2man$
^gl/lib/.*\.c\.diff$

View File

@@ -1,9 +0,0 @@
^lib/buffer-lcm\.c$
^src/false\.c$
^src/lbracket\.c$
^src/ls-dir\.c$
^src/ls-ls\.c$
^src/ls-vdir\.c$
^src/tac-pipe\.c$
^src/uname-arch\.c$
^src/uname-uname\.c$

View File

@@ -1,9 +0,0 @@
^lib/buffer-lcm\.c$
^src/false\.c$
^src/lbracket\.c$
^src/ls-dir\.c$
^src/ls-ls\.c$
^src/ls-vdir\.c$
^src/tac-pipe\.c$
^src/uname-arch\.c$
^src/uname-uname\.c$

View File

@@ -1,12 +0,0 @@
config(ure|\.(guess|sub))
tests/pr
lib/regex.c
config-log
tests/misc/nl
po/de.po
m4/lib-ld.m4
m4/lib-prefix.m4
m4/po.m4
aclocal.m4
src/c99-to-c89.diff
^gl/lib/.*\.c\.diff$

View File

@@ -1,2 +0,0 @@
config-log
build-aux/config.guess

View File

@@ -1,3 +0,0 @@
^src/libstdbuf\.c$
^src/system\.h$
^src/copy\.h$

View File

@@ -1 +0,0 @@
^tests/pr/

View File

@@ -1,2 +0,0 @@
^lib/xstrtol\.h$
^build-aux/cvsu$

View File

@@ -1,13 +0,0 @@
^build-aux/config.guess
^configure
^lib/alloca.c
^lib/fts.c
^lib/getdate.c
^lib/getloadavg.c
^lib/gettext.h
^lib/getusershell.c
^lib/mbswidth.c
^lib/strtod.c
^lib/xstrtol.c
^m4/
^tests/misc/pwd-unreadable-parent

View File

@@ -9086,7 +9086,7 @@
split's --verbose option did nothing [broken in 4.5.10 and 5.0]
* src/split.c (longopts): Use `1', not `0' as the value for
for &verbose. Reported by Keith Thompson.
&verbose. Reported by Keith Thompson.
Test for the above fix.
* tests/misc/split-a: Also use --verbose and compare stderr

View File

@@ -39,35 +39,8 @@ changelog_etc = \
old/textutils/NEWS \
po/ChangeLog-2007
syntax_check_exceptions = \
.x-sc_GPL_version \
.x-sc_bindtextdomain \
.x-sc_error_message_uppercase \
.x-sc_file_system \
.x-sc_obsolete_symbols \
.x-sc_po_check \
.x-sc_program_name \
.x-sc_prohibit_always-defined_macros \
.x-sc_prohibit_atoi_atof \
.x-sc_prohibit_empty_lines_at_EOF \
.x-sc_prohibit_fail_0 \
.x-sc_prohibit_magic_number_exit \
.x-sc_prohibit_stat_st_blocks \
.x-sc_prohibit_strcmp \
.x-sc_prohibit_tab_based_indentation \
.x-sc_require_config_h \
.x-sc_require_config_h_first \
.x-sc_space_tab \
.x-sc_sun_os_names \
.x-sc_system_h_headers \
.x-sc_trailing_blank \
.x-sc_prohibit_always_true_header_tests \
.x-sc_unmarked_diagnostics \
.x-sc_useless_cpp_parens
EXTRA_DIST = \
$(changelog_etc) \
$(syntax_check_exceptions) \
.mailmap \
.prev-version \
.version \

60
NEWS
View File

@@ -1,5 +1,61 @@
GNU coreutils NEWS -*- outline -*-
* Noteworthy changes in release 8.11 (2011-04-13) [stable]
** Bug fixes
cp -a --link would not create a hardlink to a symlink, instead
copying the symlink and then not preserving its timestamp.
[bug introduced in coreutils-8.0]
cp now avoids FIEMAP issues with BTRFS before Linux 2.6.38,
which could result in corrupt copies of sparse files.
[bug introduced in coreutils-8.10]
cut could segfault when invoked with a user-specified output
delimiter and an unbounded range like "-f1234567890-".
[bug introduced in coreutils-5.3.0]
du would infloop when given --files0-from=DIR
[bug introduced in coreutils-7.1]
sort no longer spawns 7 worker threads to sort 16 lines
[bug introduced in coreutils-8.6]
touch built on Solaris 9 would segfault when run on Solaris 10
[bug introduced in coreutils-8.8]
wc would dereference a NULL pointer upon an early out-of-memory error
[bug introduced in coreutils-7.1]
** New features
dd now accepts the 'nocache' flag to the iflag and oflag options,
which will discard any cache associated with the files, or
processed portion thereof.
dd now warns that 'iflag=fullblock' should be used,
in various cases where partial reads can cause issues.
** Changes in behavior
cp now avoids syncing files when possible, when doing a FIEMAP copy.
The sync is only needed on Linux kernels before 2.6.39.
[The sync was introduced in coreutils-8.10]
cp now copies empty extents efficiently, when doing a FIEMAP copy.
It no longer reads the zero bytes from the input, and also can efficiently
create a hole in the output file when --sparse=always is specified.
df now aligns columns consistently, and no longer wraps entries
with longer device identifiers, over two lines.
install now rejects its long-deprecated --preserve_context option.
Use --preserve-context instead.
test now accepts "==" as a synonym for "="
* Noteworthy changes in release 8.10 (2011-02-04) [stable]
** Bug fixes
@@ -367,7 +423,7 @@ GNU coreutils NEWS -*- outline -*-
if it uses helper processes for compression and its parent
ignores CHLD signals. [bug introduced in coreutils-6.9]
tail without -f no longer access uninitialized memory
tail without -f no longer accesses uninitialized memory
[bug introduced in coreutils-7.6]
timeout is now immune to the signal handling of its parent.
@@ -496,7 +552,7 @@ GNU coreutils NEWS -*- outline -*-
ls -LR exits with status 2, not 0, when it encounters a cycle
ls -is is now consistent with ls -lis in ignoring values returned
"ls -is" is now consistent with ls -lis in ignoring values returned
from a failed stat/lstat. For example ls -Lis now prints "?", not "0",
for the inode number and allocated size of a dereferenced dangling symlink.

View File

@@ -71,6 +71,7 @@ Barry Kelly http://barrkel.blogspot.com/
Bauke Jan Douma bjdouma@xs4all.nl
Ben Elliston bje@air.net.au
Ben Harris bjh21@netbsd.org
Ben Walton bwalton@artsci.utoronto.ca
Bengt Martensson bengt@mathematik.uni-Bremen.de
Benjamin Cutler cutlerbc@simla.colostate.edu
Bernard Giroud bernard.giroud@creditlyonnais.ch
@@ -206,7 +207,6 @@ Geoff Whale geoffw@cse.unsw.EDU.AU
Gerald Pfeifer gerald@pfeifer.com
Gerhard Poul gpoul@gnu.org
Germano Leichsenring germano@jedi.cs.kobe-u.ac.jp
Gilles Espinasse g.esp@free.fr
Glen Lenker glen.lenker@gmail.com
Göran Uddeborg goeran@uddeborg.se
Guochun Shi gshi@ncsa.uiuc.edu
@@ -524,6 +524,7 @@ Soeren Sonnenburg sonnenburg@informatik.hu-berlin.de
Solar Designer solar@owl.openwall.com
Stanislav Ievlev inger@altlinux.ru
Stavros Passas stabat@ics.forth.gr
Stefan Vargyas stvar@yahoo.com
Stéphane Chazelas Stephane_CHAZELAS@yahoo.fr
Stephen Depooter sbdep@myrealbox.com
Stephen Eglen eglen@pcg.wustl.edu

View File

@@ -1,6 +1,6 @@
#! /bin/sh
# Print a version string.
scriptversion=2010-11-20.03; # UTC
scriptversion=2011-03-03.12; # UTC
# Bootstrap this package from checked-out sources.
@@ -42,30 +42,32 @@ local_gl_dir=gl
bt='._bootmp'
bt_regex=`echo "$bt"| sed 's/\./[.]/g'`
bt2=${bt}2
me=$0
usage() {
cat <<EOF
Usage: $0 [OPTION]...
Usage: $me [OPTION]...
Bootstrap this package from the checked-out sources.
Options:
--gnulib-srcdir=DIRNAME Specify the local directory where gnulib
--gnulib-srcdir=DIRNAME specify the local directory where gnulib
sources reside. Use this if you already
have gnulib sources on your machine, and
do not want to waste your bandwidth downloading
them again. Defaults to \$GNULIB_SRCDIR.
--bootstrap-sync If this bootstrap script is not identical to
them again. Defaults to \$GNULIB_SRCDIR
--bootstrap-sync if this bootstrap script is not identical to
the version in the local gnulib sources,
update this script, and then restart it with
/bin/sh or the shell \$CONFIG_SHELL if
defined.
--no-bootstrap-sync Do not check whether bootstrap is out of sync.
--copy Copy files instead of creating symbolic links.
--force Attempt to bootstrap even if the sources seem
not to have been checked out.
--skip-po Do not download po files.
/bin/sh or the shell \$CONFIG_SHELL
--no-bootstrap-sync do not check whether bootstrap is out of sync
--copy copy files instead of creating symbolic links
--force attempt to bootstrap even if the sources seem
not to have been checked out
--no-git do not use git to update gnulib. Requires that
--gnulib-srcdir point to a correct gnulib snapshot
--skip-po do not download po files
If the file $0.conf exists in the same directory as this script, its
If the file $me.conf exists in the same directory as this script, its
contents are read as shell variables to configure the bootstrap.
For build prerequisites, environment variables like \$AUTOCONF and \$AMTAR
@@ -178,6 +180,9 @@ vc_ignore=auto
# default.
bootstrap_sync=false
# Use git to update gnulib sources
use_git=true
# find_tool ENVVAR NAMES...
# -------------------------
# Search for a required program. Use the value of ENVVAR, if set,
@@ -202,11 +207,11 @@ find_tool ()
find_tool_error_prefix="\$$find_tool_envvar: "
fi
if test x"$find_tool_res" = x; then
echo >&2 "$0: one of these is required: $find_tool_names"
echo >&2 "$me: one of these is required: $find_tool_names"
exit 1
fi
($find_tool_res --version </dev/null) >/dev/null 2>&1 || {
echo >&2 "$0: ${find_tool_error_prefix}cannot run $find_tool_res --version"
echo >&2 "$me: ${find_tool_error_prefix}cannot run $find_tool_res --version"
exit 1
}
eval "$find_tool_envvar=\$find_tool_res"
@@ -253,12 +258,21 @@ do
bootstrap_sync=true;;
--no-bootstrap-sync)
bootstrap_sync=false;;
--no-git)
use_git=false;;
*)
echo >&2 "$0: $option: unknown option"
exit 1;;
esac
done
if $use_git || test -d "$GNULIB_SRCDIR"; then
:
else
echo "$0: Error: --no-git requires --gnulib-srcdir" >&2
exit 1
fi
if test -n "$checkout_only_file" && test ! -r "$checkout_only_file"; then
echo "$0: Bootstrapping from a non-checked-out distribution is risky." >&2
exit 1
@@ -384,18 +398,22 @@ check_versions() {
if test "$app" = libtool; then
app=libtoolize
fi
# Exempt git if --no-git is in effect.
if test "$app" = git; then
$use_git || continue
fi
# Honor $APP variables ($TAR, $AUTOCONF, etc.)
appvar=`echo $app | tr '[a-z]-' '[A-Z]_'`
test "$appvar" = TAR && appvar=AMTAR
eval "app=\${$appvar-$app}"
inst_ver=$(get_version $app)
if [ ! "$inst_ver" ]; then
echo "Error: '$app' not found" >&2
echo "$me: Error: '$app' not found" >&2
ret=1
elif [ ! "$req_ver" = "-" ]; then
latest_ver=$(sort_ver $req_ver $inst_ver | cut -d' ' -f2)
if [ ! "$latest_ver" = "$inst_ver" ]; then
echo "Error: '$app' version == $inst_ver is too old" >&2
echo "$me: Error: '$app' version == $inst_ver is too old" >&2
echo " '$app' version >= $req_ver is required" >&2
ret=1
fi
@@ -428,9 +446,9 @@ fi
if ! printf "$buildreq" | check_versions; then
echo >&2
if test -f README-prereq; then
echo "See README-prereq for how to get the prerequisite programs" >&2
echo "$0: See README-prereq for how to get the prerequisite programs" >&2
else
echo "Please install the prerequisite programs" >&2
echo "$0: Please install the prerequisite programs" >&2
fi
exit 1
fi
@@ -442,11 +460,11 @@ if test -d .git && (git --version) >/dev/null 2>/dev/null ; then
if git config merge.merge-changelog.driver >/dev/null ; then
:
elif (git-merge-changelog --version) >/dev/null 2>/dev/null ; then
echo "initializing git-merge-changelog driver"
echo "$0: initializing git-merge-changelog driver"
git config merge.merge-changelog.name 'GNU-style ChangeLog merge driver'
git config merge.merge-changelog.driver 'git-merge-changelog %O %A %B'
else
echo "consider installing git-merge-changelog from gnulib"
echo "$0: consider installing git-merge-changelog from gnulib"
fi
fi
@@ -462,7 +480,7 @@ git_modules_config () {
}
gnulib_path=`git_modules_config submodule.gnulib.path`
: ${gnulib_path=gnulib}
test -z "$gnulib_path" && gnulib_path=gnulib
# Get gnulib files.
@@ -533,7 +551,7 @@ gnulib_tool=$GNULIB_SRCDIR/gnulib-tool
download_po_files() {
subdir=$1
domain=$2
echo "$0: getting translations into $subdir for $domain..."
echo "$me: getting translations into $subdir for $domain..."
cmd=`printf "$po_download_command_format" "$domain" "$subdir"`
eval "$cmd"
}
@@ -567,7 +585,7 @@ update_po_files() {
! test -f "$po_dir/$po.po" ||
! $SHA1SUM -c --status "$cksum_file" \
< "$new_po" > /dev/null; then
echo "updated $po_dir/$po.po..."
echo "$me: updated $po_dir/$po.po..."
cp "$new_po" "$po_dir/$po.po" \
&& $SHA1SUM < "$new_po" > "$cksum_file"
fi
@@ -612,13 +630,13 @@ symlink_to_dir()
if $copy; then
{
test ! -h "$dst" || {
echo "$0: rm -f $dst" &&
echo "$me: rm -f $dst" &&
rm -f "$dst"
}
} &&
test -f "$dst" &&
cmp -s "$src" "$dst" || {
echo "$0: cp -fp $src $dst" &&
echo "$me: cp -fp $src $dst" &&
cp -fp "$src" "$dst"
}
else
@@ -632,7 +650,7 @@ symlink_to_dir()
*)
case /$dst/ in
*//* | */../* | */./* | /*/*/*/*/*/)
echo >&2 "$0: invalid symlink calculation: $src -> $dst"
echo >&2 "$me: invalid symlink calculation: $src -> $dst"
exit 1;;
/*/*/*/*/) dot_dots=../../../;;
/*/*/*/) dot_dots=../../;;
@@ -640,7 +658,7 @@ symlink_to_dir()
esac;;
esac
echo "$0: ln -fs $dot_dots$src $dst" &&
echo "$me: ln -fs $dot_dots$src $dst" &&
ln -fs "$dot_dots$src" "$dst"
}
fi
@@ -673,7 +691,7 @@ cp_mark_as_generated()
cmp -s "$cp_src" "$cp_dst" || {
# Copy the file first to get proper permissions if it
# doesn't already exist. Then overwrite the copy.
echo "$0: cp -f $cp_src $cp_dst" &&
echo "$me: cp -f $cp_src $cp_dst" &&
rm -f "$cp_dst" &&
cp "$cp_src" "$cp_dst-t" &&
sed "s!$bt_regex/!!g" "$cp_src" > "$cp_dst-t" &&
@@ -691,7 +709,7 @@ cp_mark_as_generated()
if cmp -s "$cp_dst-t" "$cp_dst"; then
rm -f "$cp_dst-t"
else
echo "$0: cp $cp_src $cp_dst # with edits" &&
echo "$me: cp $cp_src $cp_dst # with edits" &&
mv -f "$cp_dst-t" "$cp_dst"
fi
fi
@@ -710,7 +728,7 @@ version_controlled_file() {
elif test -d .svn; then
svn log -r HEAD "$dir/$file" > /dev/null 2>&1 && found=yes
else
echo "$0: no version control for $dir/$file?" >&2
echo "$me: no version control for $dir/$file?" >&2
fi
test $found = yes
}
@@ -734,18 +752,18 @@ slurp() {
remove_intl='/^[^#].*\/intl/s/^/#/;'"s!$bt_regex/!!g"
sed "$remove_intl" $1/$dir/$file |
cmp - $dir/$gnulib_mk > /dev/null || {
echo "$0: Copying $1/$dir/$file to $dir/$gnulib_mk ..." &&
echo "$me: Copying $1/$dir/$file to $dir/$gnulib_mk ..." &&
rm -f $dir/$gnulib_mk &&
sed "$remove_intl" $1/$dir/$file >$dir/$gnulib_mk &&
gnulib_mk_hook $dir/$gnulib_mk
}
elif { test "${2+set}" = set && test -r $2/$dir/$file; } ||
version_controlled_file $dir $file; then
echo "$0: $dir/$file overrides $1/$dir/$file"
echo "$me: $dir/$file overrides $1/$dir/$file"
else
copied=$copied$sep$file; sep=$nl
if test $file = gettext.m4; then
echo "$0: patching m4/gettext.m4 to remove need for intl/* ..."
echo "$me: patching m4/gettext.m4 to remove need for intl/* ..."
rm -f $dir/$file
sed '
/^AC_DEFUN(\[AM_INTL_SUBDIR],/,/^]/c\
@@ -856,7 +874,7 @@ grep -E '^[ ]*AC_CONFIG_HEADERS?\>' configure.ac >/dev/null ||
for command in \
libtool \
"${ACLOCAL-aclocal} --force -I m4 $ACLOCAL_FLAGS" \
"${ACLOCAL-aclocal} --force -I '$m4_base' $ACLOCAL_FLAGS" \
"${AUTOCONF-autoconf} --force" \
"${AUTOHEADER-autoheader} --force" \
"${AUTOMAKE-automake} --add-missing --copy --force-missing"
@@ -867,7 +885,7 @@ do
command="${LIBTOOLIZE-libtoolize} -c -f"
fi
echo "$0: $command ..."
$command || exit
eval "$command" || exit
done

View File

@@ -232,6 +232,7 @@ gnulib_modules="
verror
version-etc-fsf
wcwidth
wcswidth
winsz-ioctl
winsz-termios
write-any-file
@@ -299,7 +300,6 @@ if test $gettext_external = 1; then
excluded_files='
m4/glibc2.m4
m4/intdiv0.m4
m4/lcmessage.m4
m4/uintmax_t.m4
m4/ulonglong.m4
m4/visibility.m4

63
cfg.mk
View File

@@ -27,7 +27,7 @@ bootstrap-tools = autoconf,automake,gnulib,bison
# Now that we have better tests, make this the default.
export VERBOSE = yes
old_NEWS_hash = f2ebf9f1f16209f7a4b9927a755956fa
old_NEWS_hash = 99b06e7bb289add96b10127fceced4e9
# Add an exemption for sc_makefile_at_at_check.
_makefile_at_at_check_exceptions = ' && !/^cu_install_program =/'
@@ -39,8 +39,8 @@ _hv_file ?= $(srcdir)/tests/misc/help-version
dd = $(srcdir)/src/dd.c
sc_dd_O_FLAGS:
@rm -f $@.1 $@.2
@{ echo O_FULLBLOCK; perl -nle '/^ +\| (O_\w*)$$/ and print $$1' \
$(dd); } | sort > $@.1
@{ echo O_FULLBLOCK; echo O_NOCACHE; \
perl -nle '/^ +\| (O_\w*)$$/ and print $$1' $(dd); } | sort > $@.1
@{ echo O_NOFOLLOW; perl -nle '/{"[a-z]+",\s*(O_\w+)},/ and print $$1' \
$(dd); } | sort > $@.2
@diff -u $@.1 $@.2 || diff=1 || diff=; \
@@ -93,19 +93,6 @@ sc_root_tests:
exit 1; } || :; \
fi
# Ensure that the syntax_check_exceptions file list in Makefile.am
# stays in sync with corresponding files in the repository.
sce = syntax_check_exceptions
sc_x_sc_dist_check:
@test "$$( ($(VC_LIST) | sed -n '/\.x-sc_/p' \
| sed 's|^$(_dot_escaped_srcdir)/||'; \
sed -n '/^$(sce) =[ ]*\\$$/,/[^\]$$/p' \
$(srcdir)/Makefile.am \
| sed 's/^ *//;/^$(sce) =/d' \
| tr -s '\012\\' ' ' | fmt -1 \
) | sort | uniq -u)" \
&& { echo 'Makefile.am: $(sce) mismatch' >&2; exit 1; } || :;
# Create a list of regular expressions matching the names
# of files included from system.h. Exclude a couple.
.re-list:
@@ -186,7 +173,7 @@ sc_NEWS_two_empty_lines:
@sed -n 4,/Noteworthy/p $(srcdir)/NEWS \
| perl -n0e '/(^|\n)\n\n\* Noteworthy/ or exit 1' \
|| { echo '$(ME): use two empty lines to separate NEWS sections' \
1>&2; exit 1; } || :; \
1>&2; exit 1; } || :
# Perl-based tests used to exec perl from a #!/bin/sh script.
# Now they all start with #!/usr/bin/perl and the portability
@@ -328,6 +315,15 @@ sc_space_before_open_paren:
else :; \
fi
# Similar to the gnulib maint.mk rule for sc_prohibit_strcmp
# Use STREQ_LEN or STRPREFIX rather than comparing strncmp == 0, or != 0.
sc_prohibit_strncmp:
@grep -nE '! *str''ncmp *\(|\<str''ncmp *\(.+\) *[!=]=' \
$$($(VC_LIST_EXCEPT)) \
| grep -vE ':# *define STR(N?EQ_LEN|PREFIX)\(' && \
{ echo '$(ME): use STREQ_LEN or STRPREFIX instead of str''ncmp' \
1>&2; exit 1; } || :
# Override the default Cc: used in generating an announcement.
announcement_Cc_ = $(translation_project_), \
coreutils@gnu.org, coreutils-announce@gnu.org
@@ -337,3 +333,36 @@ include $(srcdir)/dist-check.mk
update-copyright-env = \
UPDATE_COPYRIGHT_USE_INTERVALS=1 \
UPDATE_COPYRIGHT_MAX_LINE_LENGTH=79
# List syntax-check exemptions.
exclude_file_name_regexp--sc_space_tab = \
^(tests/pr/|tests/misc/nl$$|gl/.*\.diff$$)
exclude_file_name_regexp--sc_bindtextdomain = ^(gl/.*|lib/euidaccess-stat)\.c$$
exclude_file_name_regexp--sc_unmarked_diagnostics = ^build-aux/cvsu$$
exclude_file_name_regexp--sc_error_message_uppercase = ^build-aux/cvsu$$
exclude_file_name_regexp--sc_trailing_blank = ^tests/pr/
exclude_file_name_regexp--sc_system_h_headers = \
^src/((system|copy)\.h|libstdbuf\.c)$$
_src = (false|lbracket|ls-(dir|ls|vdir)|tac-pipe|uname-(arch|uname))
exclude_file_name_regexp--sc_require_config_h_first = \
(^lib/buffer-lcm\.c|src/$(_src)\.c)$$
exclude_file_name_regexp--sc_require_config_h = \
$(exclude_file_name_regexp--sc_require_config_h_first)
exclude_file_name_regexp--sc_po_check = ^gl/
exclude_file_name_regexp--sc_prohibit_always-defined_macros = ^src/seq\.c$$
exclude_file_name_regexp--sc_prohibit_empty_lines_at_EOF = ^tests/pr/
exclude_file_name_regexp--sc_program_name = ^(gl/.*|lib/euidaccess-stat)\.c$$
exclude_file_name_regexp--sc_file_system = \
NEWS|^(tests/init\.cfg|src/df\.c|tests/misc/df-P)$$
exclude_file_name_regexp--sc_prohibit_always_true_header_tests = \
^m4/stat-prog\.m4$$
exclude_file_name_regexp--sc_prohibit_fail_0 = \
(^tests/init\.sh|Makefile\.am|\.mk)$$
exclude_file_name_regexp--sc_prohibit_atoi_atof = ^lib/euidaccess-stat\.c$$
exclude_file_name_regexp--sc_prohibit_tab_based_indentation = \
^tests/pr/|(^gl/lib/reg.*\.c\.diff|Makefile(\.am)?|\.mk|^man/help2man)$$
exclude_file_name_regexp--sc_prohibit_stat_st_blocks = \
^(src/system\.h|tests/du/2g)$$

View File

@@ -162,18 +162,18 @@ int main()
time_t now = time ((time_t *) 0);
int hour_GMT0, hour_unset;
if (putenv ("TZ=GMT0") != 0)
exit (1);
return 1;
hour_GMT0 = localtime (&now)->tm_hour;
unset_TZ ();
hour_unset = localtime (&now)->tm_hour;
if (putenv ("TZ=PST8") != 0)
exit (1);
return 1;
if (localtime (&now)->tm_hour == hour_GMT0)
exit (1);
return 1;
unset_TZ ();
if (localtime (&now)->tm_hour != hour_unset)
exit (1);
exit (0);
return 1;
return 0;
}]])],
[utils_cv_localtime_cache=no],
[utils_cv_localtime_cache=yes],

View File

@@ -1455,10 +1455,11 @@ The @sc{gnu} utilities normally conform to the version of @acronym{POSIX}
that is standard for your system. To cause them to conform to a
different version of @acronym{POSIX}, define the @env{_POSIX2_VERSION}
environment variable to a value of the form @var{yyyymm} specifying
the year and month the standard was adopted. Two values are currently
the year and month the standard was adopted. Three values are currently
supported for @env{_POSIX2_VERSION}: @samp{199209} stands for
@acronym{POSIX} 1003.2-1992, and @samp{200112} stands for @acronym{POSIX}
1003.1-2001. For example, if you have a newer system but are running software
@acronym{POSIX} 1003.2-1992, @samp{200112} stands for @acronym{POSIX}
1003.1-2001, and @samp{200809} stands for @acronym{POSIX} 1003.1-2008.
For example, if you have a newer system but are running software
that assumes an older version of @acronym{POSIX} and uses @samp{sort +1}
or @samp{tail +10}, you can work around any compatibility problems by setting
@samp{_POSIX2_VERSION=199209} in your environment.
@@ -7971,8 +7972,8 @@ Set both input and output block sizes to @var{bytes}.
This makes @command{dd} read and write @var{bytes} per block,
overriding any @samp{ibs} and @samp{obs} settings.
In addition, if no data-transforming @option{conv} option is specified,
each input block is copied to the output as a single block,
without aggregating short reads.
input is copied to the output as soon as it's read,
even if it is smaller than the block size.
@item cbs=@var{bytes}
@opindex cbs
@@ -8062,22 +8063,29 @@ Swap every pair of input bytes. @sc{gnu} @command{dd}, unlike others, works
when an odd number of bytes are read---the last byte is simply copied
(since there is nothing to swap it with).
@item noerror
@opindex noerror
@cindex read errors, ignoring
Continue after read errors.
@item sync
@opindex sync @r{(padding with @acronym{ASCII} @sc{nul}s)}
Pad every input block to size of @samp{ibs} with trailing zero bytes.
When used with @samp{block} or @samp{unblock}, pad with spaces instead of
zero bytes.
@item nocreat
@opindex nocreat
@cindex creating output file, avoiding
Do not create the output file; the output file must already exist.
@end table
The following ``conversions'' are really file flags
and don't affect internal processing:
@table @samp
@item excl
@opindex excl
@cindex creating output file, requiring
Fail if the output file already exists; @command{dd} must create the
output file itself.
@item nocreat
@opindex nocreat
@cindex creating output file, avoiding
Do not create the output file; the output file must already exist.
The @samp{excl} and @samp{nocreat} conversions are mutually exclusive.
@item notrunc
@@ -8085,11 +8093,10 @@ The @samp{excl} and @samp{nocreat} conversions are mutually exclusive.
@cindex truncating output file, avoiding
Do not truncate the output file.
@item sync
@opindex sync @r{(padding with @acronym{ASCII} @sc{nul}s)}
Pad every input block to size of @samp{ibs} with trailing zero bytes.
When used with @samp{block} or @samp{unblock}, pad with spaces instead of
zero bytes.
@item noerror
@opindex noerror
@cindex read errors, ignoring
Continue after read errors.
@item fdatasync
@opindex fdatasync
@@ -8168,6 +8175,31 @@ last-access and last-modified time) is not necessarily synchronized.
@cindex synchronized data and metadata I/O
Use synchronized I/O for both data and metadata.
@item nocache
@opindex nocache
@cindex discarding file cache
Discard the data cache for a file.
When count=0 all cache is discarded,
otherwise the cache is dropped for the processed
portion of the file. Also when count=0
failure to discard the cache is diagnosed
and reflected in the exit status.
Here as some usage examples:
@example
# Advise to drop cache for whole file
dd if=ifile iflag=nocache count=0
# Ensure drop cache for the whole file
dd of=ofile oflag=nocache conv=notrunc,fdatasync count=0
# Drop cache for part of file
dd if=ifile iflag=nocache skip=10 count=10 of=/dev/null
# Stream data using just the read-ahead cache
dd if=ifile of=ofile iflag=nocache oflag=nocache
@end example
@item nonblock
@opindex nonblock
@cindex nonblocking I/O
@@ -11504,7 +11536,7 @@ Exit status:
* File type tests:: -[bcdfhLpSt]
* Access permission tests:: -[gkruwxOG]
* File characteristic tests:: -e -s -nt -ot -ef
* String tests:: -z -n = !=
* String tests:: -z -n = == !=
* Numeric tests:: -eq -ne -lt -le -gt -ge
* Connectives for test:: ! -a -o
@end menu
@@ -11695,6 +11727,11 @@ True if the length of @var{string} is nonzero.
@cindex equal string check
True if the strings are equal.
@item @var{string1} == @var{string2}
@opindex ==
@cindex equal string check
True if the strings are equal (synonym for =).
@item @var{string1} != @var{string2}
@opindex !=
@cindex not-equal string check

View File

@@ -1,237 +0,0 @@
/* Set operations for device-inode pairs stored in a space-efficient manner.
Copyright 2009-2011 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 <http://www.gnu.org/licenses/>. */
/* written by Paul Eggert and Jim Meyering */
#include <config.h>
#include "di-set.h"
#include "hash.h"
#include "ino-map.h"
#include <limits.h>
#include <stdlib.h>
/* The hash package hashes "void *", but this package wants to hash
integers. Use integers that are as large as possible, but no
larger than void *, so that they can be cast to void * and back
without losing information. */
typedef size_t hashint;
#define HASHINT_MAX ((hashint) -1)
/* Integers represent inode numbers. Integers in the range
1..(LARGE_INO_MIN-1) represent inode numbers directly. (The hash
package does not work with null pointers, so inode 0 cannot be used
as a key.) To find the representations of other inode numbers, map
them through INO_MAP. */
#define LARGE_INO_MIN (HASHINT_MAX / 2)
/* Set operations for device-inode pairs stored in a space-efficient
manner. Use a two-level hash table. The top level hashes by
device number, as there are typically a small number of devices.
The lower level hashes by mapped inode numbers. In the typical
case where the inode number is positive and small, the inode number
maps to itself, masquerading as a void * value; otherwise, its
value is the result of hashing the inode value through INO_MAP. */
/* A pair that maps a device number to a set of inode numbers. */
struct di_ent
{
dev_t dev;
struct hash_table *ino_set;
};
/* A two-level hash table that manages and indexes these pairs. */
struct di_set
{
/* Map device numbers to sets of inode number representatives. */
struct hash_table *dev_map;
/* If nonnull, map large inode numbers to their small
representatives. If null, there are no large inode numbers in
this set. */
struct ino_map *ino_map;
/* Cache of the most recently allocated and otherwise-unused storage
for probing this table. */
struct di_ent *probe;
};
/* Hash a device-inode-set entry. */
static size_t
di_ent_hash (void const *x, size_t table_size)
{
struct di_ent const *p = x;
dev_t dev = p->dev;
/* When DEV is wider than size_t, exclusive-OR the words of DEV into H.
This avoids loss of info, without applying % to the wider type,
which could be quite slow on some systems. */
size_t h = dev;
unsigned int i;
unsigned int n_words = sizeof dev / sizeof h + (sizeof dev % sizeof h != 0);
for (i = 1; i < n_words; i++)
h ^= dev >> CHAR_BIT * sizeof h * i;
return h % table_size;
}
/* Return true if two device-inode-set entries are the same. */
static bool
di_ent_compare (void const *x, void const *y)
{
struct di_ent const *a = x;
struct di_ent const *b = y;
return a->dev == b->dev;
}
/* Free a device-inode-set entry. */
static void
di_ent_free (void *v)
{
struct di_ent *a = v;
hash_free (a->ino_set);
free (a);
}
/* Create a set of device-inode pairs. Return NULL on allocation failure. */
struct di_set *
di_set_alloc (void)
{
struct di_set *dis = malloc (sizeof *dis);
if (dis)
{
enum { INITIAL_DEV_MAP_SIZE = 11 };
dis->dev_map = hash_initialize (INITIAL_DEV_MAP_SIZE, NULL,
di_ent_hash, di_ent_compare,
di_ent_free);
if (! dis->dev_map)
{
free (dis);
return NULL;
}
dis->ino_map = NULL;
dis->probe = NULL;
}
return dis;
}
/* Free a set of device-inode pairs. */
void
di_set_free (struct di_set *dis)
{
hash_free (dis->dev_map);
free (dis->ino_map);
free (dis->probe);
free (dis);
}
/* Hash an encoded inode number I. */
static size_t
di_ino_hash (void const *i, size_t table_size)
{
return (hashint) i % table_size;
}
/* Using the DIS table, map a device to a hash table that represents
a set of inode numbers. Return NULL on error. */
static struct hash_table *
map_device (struct di_set *dis, dev_t dev)
{
/* Find space for the probe, reusing the cache if available. */
struct di_ent *ent;
struct di_ent *probe = dis->probe;
if (probe)
{
/* If repeating a recent query, return the cached result. */
if (probe->dev == dev)
return probe->ino_set;
}
else
{
dis->probe = probe = malloc (sizeof *probe);
if (! probe)
return NULL;
}
/* Probe for the device. */
probe->dev = dev;
ent = hash_insert (dis->dev_map, probe);
if (! ent)
return NULL;
if (ent != probe)
{
/* Use the existing entry. */
probe->ino_set = ent->ino_set;
}
else
{
enum { INITIAL_INO_SET_SIZE = 1021 };
/* Prepare to allocate a new probe next time; this one is in use. */
dis->probe = NULL;
/* DEV is new; allocate an inode set for it. */
probe->ino_set = hash_initialize (INITIAL_INO_SET_SIZE, NULL,
di_ino_hash, NULL, NULL);
}
return probe->ino_set;
}
/* Using the DIS table, map an inode number to a mapped value.
Return INO_MAP_INSERT_FAILURE on error. */
static hashint
map_inode_number (struct di_set *dis, ino_t ino)
{
if (0 < ino && ino < LARGE_INO_MIN)
return ino;
if (! dis->ino_map)
{
dis->ino_map = ino_map_alloc (LARGE_INO_MIN);
if (! dis->ino_map)
return INO_MAP_INSERT_FAILURE;
}
return ino_map_insert (dis->ino_map, ino);
}
/* Attempt to insert the DEV,INO pair into the set DIS.
If it matches a pair already in DIS, keep that pair and return 0.
Otherwise, if insertion is successful, return 1.
Upon any failure return -1. */
int
di_set_insert (struct di_set *dis, dev_t dev, ino_t ino)
{
hashint i;
/* Map the device number to a set of inodes. */
struct hash_table *ino_set = map_device (dis, dev);
if (! ino_set)
return -1;
/* Map the inode number to a small representative I. */
i = map_inode_number (dis, ino);
if (i == INO_MAP_INSERT_FAILURE)
return -1;
/* Put I into the inode set. */
return hash_insert0 (ino_set, (void *) i, NULL);
}

View File

@@ -1,12 +0,0 @@
#include <sys/types.h>
#undef _ATTRIBUTE_NONNULL_
#if __GNUC__ == 3 && __GNUC_MINOR__ >= 3 || 3 < __GNUC__
# define _ATTRIBUTE_NONNULL_(m) __attribute__ ((__nonnull__ (m)))
#else
# define _ATTRIBUTE_NONNULL_(m)
#endif
struct di_set *di_set_alloc (void);
int di_set_insert (struct di_set *, dev_t, ino_t) _ATTRIBUTE_NONNULL_ (1);
void di_set_free (struct di_set *) _ATTRIBUTE_NONNULL_ (1);

View File

@@ -1,164 +0,0 @@
/* Map an ino_t inode number to a small integer.
Copyright 2009-2011 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 <http://www.gnu.org/licenses/>. */
/* written by Paul Eggert and Jim Meyering */
#include <config.h>
#include "ino-map.h"
#include "hash.h"
#include "verify.h"
#include <limits.h>
#include <stdlib.h>
/* A pair that maps an inode number to a mapped inode number; the
latter is a small unique ID for the former. */
struct ino_map_ent
{
ino_t ino;
size_t mapped_ino;
};
/* A table that manages and indexes these pairs. */
struct ino_map
{
/* A table of KEY,VAL pairs, where KEY is the raw ino_t value and
VAL is the small number that it maps to. */
struct hash_table *map;
/* The next mapped inode number to hand out. */
size_t next_mapped_ino;
/* Cache of the most recently allocated and otherwise-unused storage
for probing the table. */
struct ino_map_ent *probe;
};
/* Hash an inode map entry. */
static size_t
ino_hash (void const *x, size_t table_size)
{
struct ino_map_ent const *p = x;
ino_t ino = p->ino;
/* When INO is wider than size_t, exclusive-OR the words of INO into H.
This avoids loss of info, without applying % to the wider type,
which could be quite slow on some systems. */
size_t h = ino;
unsigned int i;
unsigned int n_words = sizeof ino / sizeof h + (sizeof ino % sizeof h != 0);
for (i = 1; i < n_words; i++)
h ^= ino >> CHAR_BIT * sizeof h * i;
return h % table_size;
}
/* Return true if two inode map entries are the same. */
static bool
ino_compare (void const *x, void const *y)
{
struct ino_map_ent const *a = x;
struct ino_map_ent const *b = y;
return a->ino == b->ino;
}
/* Allocate an inode map that will hand out integers starting with
NEXT_MAPPED_INO. Return NULL if memory is exhausted. */
struct ino_map *
ino_map_alloc (size_t next_mapped_ino)
{
struct ino_map *im = malloc (sizeof *im);
if (im)
{
enum { INITIAL_INO_MAP_TABLE_SIZE = 1021 };
im->map = hash_initialize (INITIAL_INO_MAP_TABLE_SIZE, NULL,
ino_hash, ino_compare, free);
if (! im->map)
{
free (im);
return NULL;
}
im->next_mapped_ino = next_mapped_ino;
im->probe = NULL;
}
return im;
}
/* Free an inode map. */
void
ino_map_free (struct ino_map *map)
{
hash_free (map->map);
free (map->probe);
free (map);
}
/* Insert into MAP the inode number INO if it's not there already,
and return its nonnegative mapped inode number.
If INO is already in MAP, return the existing mapped inode number.
Return INO_MAP_INSERT_FAILURE on memory or counter exhaustion. */
size_t
ino_map_insert (struct ino_map *im, ino_t ino)
{
struct ino_map_ent *ent;
/* Find space for the probe, reusing the cache if available. */
struct ino_map_ent *probe = im->probe;
if (probe)
{
/* If repeating a recent query, return the cached result. */
if (probe->ino == ino)
return probe->mapped_ino;
}
else
{
im->probe = probe = malloc (sizeof *probe);
if (! probe)
return INO_MAP_INSERT_FAILURE;
}
probe->ino = ino;
ent = hash_insert (im->map, probe);
if (! ent)
return INO_MAP_INSERT_FAILURE;
if (ent != probe)
{
/* Use the existing entry. */
probe->mapped_ino = ent->mapped_ino;
}
else
{
/* If adding 1 to map->next_mapped_ino would cause it to
overflow to zero, then it must equal INO_MAP_INSERT_FAILURE,
which is the value that should be returned in that case.
Verify that this works. */
verify (INO_MAP_INSERT_FAILURE + 1 == 0);
/* Prepare to allocate a new probe next time; this one is in use. */
im->probe = NULL;
/* INO is new; allocate a mapped inode number for it. */
probe->mapped_ino = im->next_mapped_ino++;
}
return probe->mapped_ino;
}

View File

@@ -1,14 +0,0 @@
#include <sys/types.h>
#undef _ATTRIBUTE_NONNULL_
#if __GNUC__ == 3 && __GNUC_MINOR__ >= 3 || 3 < __GNUC__
# define _ATTRIBUTE_NONNULL_(m) __attribute__ ((__nonnull__ (m)))
#else
# define _ATTRIBUTE_NONNULL_(m)
#endif
#define INO_MAP_INSERT_FAILURE ((size_t) -1)
struct ino_map *ino_map_alloc (size_t);
void ino_map_free (struct ino_map *) _ATTRIBUTE_NONNULL_ (1);
size_t ino_map_insert (struct ino_map *, ino_t) _ATTRIBUTE_NONNULL_ (1);

View File

@@ -79,27 +79,6 @@ wc_truncate (wchar_t *wc, size_t width)
return cells;
}
/* FIXME: move this function to gnulib as it's missing on:
OpenBSD 3.8, IRIX 5.3, Solaris 2.5.1, mingw, BeOS */
static int
rpl_wcswidth (const wchar_t *s, size_t n)
{
int ret = 0;
while (n-- > 0 && *s != L'\0')
{
int nwidth = wcwidth (*s++);
if (nwidth == -1) /* non printable */
return -1;
if (ret > (INT_MAX - nwidth)) /* overflow */
return -1;
ret += nwidth;
}
return ret;
}
/* Write N_SPACES space characters to DEST while ensuring
nothing is written beyond DEST_END. A terminating NUL
is always added to DEST.
@@ -171,7 +150,7 @@ mbsalign (const char *src, char *dest, size_t dest_size,
str_wc[src_chars - 1] = L'\0';
wc_enabled = true;
conversion = wc_ensure_printable (str_wc);
n_cols = rpl_wcswidth (str_wc, src_chars);
n_cols = wcswidth (str_wc, src_chars);
}
}

View File

@@ -19,7 +19,7 @@
typedef enum { MBS_ALIGN_LEFT, MBS_ALIGN_RIGHT, MBS_ALIGN_CENTER } mbs_align_t;
enum {
/* Use unibyte mode for invalid multibyte strings or
/* Use unibyte mode for invalid multibyte strings
or when heap memory is exhausted. */
MBA_UNIBYTE_FALLBACK = 0x0001

View File

@@ -1,24 +0,0 @@
Description:
manipulate sets of device-inode pairs efficiently
Files:
lib/di-set.c
lib/di-set.h
Depends-on:
ino-map
hash
configure.ac:
Makefile.am:
lib_SOURCES += di-set.c di-set.h
Include:
"di-set.h"
License
GPL
Maintainer:
Jim Meyering

View File

@@ -1,10 +0,0 @@
Files:
tests/test-di-set.c
Depends-on:
configure.ac:
Makefile.am:
TESTS += test-di-set
check_PROGRAMS += test-di-set

View File

@@ -1,24 +0,0 @@
Description:
maintain a mapping of ino_t numbers to small integers
Files:
lib/ino-map.c
lib/ino-map.h
Depends-on:
hash
verify
configure.ac:
Makefile.am:
lib_SOURCES += ino-map.c ino-map.h
Include:
"ino-map.h"
License
GPL
Maintainer:
Jim Meyering

View File

@@ -1,10 +0,0 @@
Files:
tests/test-ino-map.c
Depends-on:
configure.ac:
Makefile.am:
TESTS += test-ino-map
check_PROGRAMS += test-ino-map

View File

@@ -1,5 +1,6 @@
Files:
tests/test-rand-isaac.c
tests/macros.h
Depends-on:

View File

@@ -1,63 +0,0 @@
/* Test the di-set module.
Copyright (C) 2010-2011 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 <http://www.gnu.org/licenses/>. */
/* Written by Jim Meyering. */
#include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#define ASSERT(expr) \
do \
{ \
if (!(expr)) \
{ \
fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
fflush (stderr); \
abort (); \
} \
} \
while (0)
#include "di-set.h"
int
main (void)
{
struct di_set *dis = di_set_alloc ();
ASSERT (dis);
ASSERT (di_set_insert (dis, 2, 5) == 1); /* first insertion succeeds */
ASSERT (di_set_insert (dis, 2, 5) == 0); /* duplicate fails */
ASSERT (di_set_insert (dis, 3, 5) == 1); /* diff dev, duplicate inode is ok */
ASSERT (di_set_insert (dis, 2, 8) == 1); /* same dev, different inode is ok */
/* very large (or negative) inode number */
ASSERT (di_set_insert (dis, 5, (ino_t) -1) == 1);
ASSERT (di_set_insert (dis, 5, (ino_t) -1) == 0); /* dup */
unsigned int i;
for (i = 0; i < 3000; i++)
ASSERT (di_set_insert (dis, 9, i) == 1);
for (i = 0; i < 3000; i++)
ASSERT (di_set_insert (dis, 9, i) == 0); /* duplicate fails */
di_set_free (dis);
return 0;
}

View File

@@ -1,62 +0,0 @@
/* Test the ino-map module.
Copyright (C) 2010-2011 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 <http://www.gnu.org/licenses/>. */
/* Written by Jim Meyering. */
#include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* FIXME: once/if in gnulib, use #include "macros.h" in place of this */
#define ASSERT(expr) \
do \
{ \
if (!(expr)) \
{ \
fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
fflush (stderr); \
abort (); \
} \
} \
while (0)
#include "ino-map.h"
int
main ()
{
enum { INO_MAP_INIT = 123 };
struct ino_map *ino_map = ino_map_alloc (INO_MAP_INIT);
ASSERT (ino_map != NULL);
ASSERT (ino_map_insert (ino_map, 42) == INO_MAP_INIT);
ASSERT (ino_map_insert (ino_map, 42) == INO_MAP_INIT);
ASSERT (ino_map_insert (ino_map, 398) == INO_MAP_INIT + 1);
ASSERT (ino_map_insert (ino_map, 398) == INO_MAP_INIT + 1);
ASSERT (ino_map_insert (ino_map, 0) == INO_MAP_INIT + 2);
ASSERT (ino_map_insert (ino_map, 0) == INO_MAP_INIT + 2);
int i;
for (i = 0; i < 100; i++)
{
ASSERT (ino_map_insert (ino_map, 10000 + i) == INO_MAP_INIT + 3 + i);
}
ino_map_free (ino_map);
return 0;
}

View File

@@ -23,22 +23,9 @@
#include <fcntl.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* FIXME: once/if in gnulib, use #include "macros.h" in place of this */
#define ASSERT(expr) \
do \
{ \
if (!(expr)) \
{ \
fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
fflush (stderr); \
abort (); \
} \
} \
while (0)
#include "macros.h"
/* This expected output was generated by running the programs in
<http://burtleburtle.net/bob/rand/isaacafa.html>, as last modified

2
gnulib

Submodule gnulib updated: a036b7684f...a81348d2e1

View File

@@ -707,8 +707,8 @@ sc_check-AUTHORS: $(all_programs)
# Most functions in src/*.c should have static scope.
# Any that don't must be marked with `extern', but `main'
# and `usage' are exceptions. They're always extern, but
# don't need to be marked. Also functions starting with __
# and `usage' are exceptions: they're always extern, but
# do not need to be marked. Also functions starting with __
# are exempted due to possibly being added by the compiler
# (when compiled as a shared library for example).
#
@@ -717,9 +717,9 @@ sc_check-AUTHORS: $(all_programs)
sc_tight_scope: $(bin_PROGRAMS)
@t=exceptions-$$$$; \
trap 's=$$?; rm -f $$t; exit $$s' 0; \
am__exit='(exit $s); exit $s'; \
trap "s=129; $$am__exit" 1; trap "s=130; $$am__exit" 2; \
trap "s=141; $$am__exit" 13; trap "s=143; $$am__exit" 15; \
for sig in 1 2 3 13 15; do \
eval "trap 'v=`expr $$sig + 128`; (exit $$v); exit $$v' $$sig"; \
done; \
src=`for f in $(SOURCES); do \
test -f $$f && d= || d=$(srcdir)/; echo $$d$$f; done`; \
hdr=`for f in $(noinst_HEADERS); do \
@@ -727,7 +727,8 @@ sc_tight_scope: $(bin_PROGRAMS)
( printf 'main\nusage\n_.*\n'; \
grep -h -A1 '^extern .*[^;]$$' $$src \
| grep -vE '^(extern |--)' | sed 's/ .*//'; \
perl -ne '/^extern (?:enum )?\S+ (\S*) \(/ and print "$$1\n"' $$hdr; \
perl -lne '/^extern (?:enum )?\S+ \**(\S*) \(/ and print $$1' \
$$hdr; \
) | $(ASSORT) -u | sed 's/^/^/;s/$$/$$/' > $$t; \
nm -e *.$(OBJEXT) \
| sed -n 's/.* T //p' \
@@ -736,7 +737,7 @@ sc_tight_scope: $(bin_PROGRAMS)
{ echo 'the above functions should have static scope' 1>&2; \
exit 1; } || : ; \
( printf '^program_name$$\n'; \
perl -ne '/^extern .*?\**(\w+);/ and print "^$$1\$$\n"' \
perl -lne '/^extern .*?\**(\w+);/ and print "^$$1\$$"' \
$$hdr *.h ) | $(ASSORT) -u > $$t; \
nm -e *.$(OBJEXT) \
| sed -n 's/.* [BD] //p' \

View File

@@ -39,6 +39,7 @@
#include "extent-scan.h"
#include "error.h"
#include "fcntl--.h"
#include "fiemap.h"
#include "file-set.h"
#include "filemode.h"
#include "filenamecat.h"
@@ -233,21 +234,6 @@ sparse_copy (int src_fd, int dest_fd, char *buf, size_t buf_size,
return true;
}
/* If the file ends with a `hole' (i.e., if sparse_copy set wrote_hole_at_eof),
call this function to record the length of the output file. */
static bool
sparse_copy_finalize (int dest_fd, char const *dst_name)
{
off_t len = lseek (dest_fd, 0, SEEK_CUR);
if (0 <= len && ftruncate (dest_fd, len) < 0)
{
error (0, errno, _("truncating %s"), quote (dst_name));
return false;
}
return true;
}
/* Perform the O(1) btrfs clone operation, if possible.
Upon success, return 0. Otherwise, return -1 and set errno. */
static inline int
@@ -309,7 +295,7 @@ write_zeros (int fd, uint64_t n_bytes)
return false. */
static bool
extent_copy (int src_fd, int dest_fd, char *buf, size_t buf_size,
off_t src_total_size, bool make_holes,
off_t src_total_size, enum Sparse_type sparse_mode,
char const *src_name, char const *dst_name,
bool *require_normal_copy)
{
@@ -345,56 +331,105 @@ extent_copy (int src_fd, int dest_fd, char *buf, size_t buf_size,
}
unsigned int i;
for (i = 0; i < scan.ei_count; i++)
bool empty_extent = false;
for (i = 0; i < scan.ei_count || empty_extent; i++)
{
off_t ext_start = scan.ext_info[i].ext_logical;
uint64_t ext_len = scan.ext_info[i].ext_length;
off_t ext_start;
uint64_t ext_len;
uint64_t hole_size;
if (lseek (src_fd, ext_start, SEEK_SET) < 0)
if (i < scan.ei_count)
{
error (0, errno, _("cannot lseek %s"), quote (src_name));
fail:
extent_scan_free (&scan);
return false;
ext_start = scan.ext_info[i].ext_logical;
ext_len = scan.ext_info[i].ext_length;
}
else /* empty extent at EOF. */
{
i--;
ext_start = last_ext_start + scan.ext_info[i].ext_length;
ext_len = 0;
}
if (make_holes)
hole_size = ext_start - last_ext_start - last_ext_len;
wrote_hole_at_eof = false;
if (hole_size)
{
if (lseek (dest_fd, ext_start, SEEK_SET) < 0)
if (lseek (src_fd, ext_start, SEEK_SET) < 0)
{
error (0, errno, _("cannot lseek %s"), quote (dst_name));
goto fail;
error (0, errno, _("cannot lseek %s"), quote (src_name));
fail:
extent_scan_free (&scan);
return false;
}
}
else
{
/* When not inducing holes and when there is a hole between
the end of the previous extent and the beginning of the
current one, write zeros to the destination file. */
if (last_ext_start + last_ext_len < ext_start)
if ((empty_extent && sparse_mode == SPARSE_ALWAYS)
|| (!empty_extent && sparse_mode != SPARSE_NEVER))
{
uint64_t hole_size = (ext_start
- last_ext_start
- last_ext_len);
if (! write_zeros (dest_fd, hole_size))
if (lseek (dest_fd, ext_start, SEEK_SET) < 0)
{
error (0, errno, _("cannot lseek %s"), quote (dst_name));
goto fail;
}
wrote_hole_at_eof = true;
}
else
{
/* When not inducing holes and when there is a hole between
the end of the previous extent and the beginning of the
current one, write zeros to the destination file. */
off_t nzeros = hole_size;
if (empty_extent)
nzeros = MIN (src_total_size - dest_pos, hole_size);
if (! write_zeros (dest_fd, nzeros))
{
error (0, errno, _("%s: write failed"), quote (dst_name));
goto fail;
}
dest_pos = MIN (src_total_size, ext_start);
}
}
last_ext_start = ext_start;
last_ext_len = ext_len;
off_t n_read;
if ( ! sparse_copy (src_fd, dest_fd, buf, buf_size,
make_holes, src_name, dst_name,
ext_len, &n_read,
&wrote_hole_at_eof))
return false;
/* Treat an unwritten but allocated extent much like a hole.
I.E. don't read, but don't convert to a hole in the destination,
unless SPARSE_ALWAYS. */
if (scan.ext_info[i].ext_flags & FIEMAP_EXTENT_UNWRITTEN)
{
empty_extent = true;
last_ext_len = 0;
if (ext_len == 0) /* The last extent is empty and processed. */
empty_extent = false;
}
else
{
off_t n_read;
empty_extent = false;
last_ext_len = ext_len;
dest_pos = ext_start + n_read;
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))
goto fail;
dest_pos = ext_start + n_read;
}
/* If the file ends with unwritten extents not accounted for in the
size, then skip processing them, and the associated redundant
read() calls which will always return 0. We will need to
remove this when we add fallocate() so that we can maintain
extents beyond the apparent size. */
if (dest_pos == src_total_size)
{
scan.hit_final_extent = true;
break;
}
}
/* Release the space allocated to scan->ext_info. */
@@ -412,7 +447,7 @@ extent_copy (int src_fd, int dest_fd, char *buf, size_t buf_size,
just converted them to a hole in the destination, we must call ftruncate
here in order to record the proper length in the destination. */
if ((dest_pos < src_total_size || wrote_hole_at_eof)
&& (make_holes
&& (sparse_mode != SPARSE_NEVER
? ftruncate (dest_fd, src_total_size)
: ! write_zeros (dest_fd, src_total_size - dest_pos)))
{
@@ -531,8 +566,11 @@ copy_attr (char const *src_path ATTRIBUTE_UNUSED,
DST_NAME_IN is a directory that was created previously in the
recursion. SRC_SB and ANCESTORS describe SRC_NAME_IN.
Set *COPY_INTO_SELF if SRC_NAME_IN is a parent of
FIRST_DIR_CREATED_PER_COMMAND_LINE_ARG FIXME
(or the same as) DST_NAME_IN; otherwise, clear it.
Propagate *FIRST_DIR_CREATED_PER_COMMAND_LINE_ARG from
caller to each invocation of copy_internal. Be careful to
pass the address of a temporary, and to update
*FIRST_DIR_CREATED_PER_COMMAND_LINE_ARG only upon completion.
Return true if successful. */
static bool
@@ -561,16 +599,18 @@ copy_dir (char const *src_name_in, char const *dst_name_in, bool new_dst,
if (x->dereference == DEREF_COMMAND_LINE_ARGUMENTS)
non_command_line_options.dereference = DEREF_NEVER;
bool new_first_dir_created = false;
namep = name_space;
while (*namep != '\0')
{
bool local_copy_into_self;
char *src_name = file_name_concat (src_name_in, namep, NULL);
char *dst_name = file_name_concat (dst_name_in, namep, NULL);
bool first_dir_created = *first_dir_created_per_command_line_arg;
ok &= copy_internal (src_name, dst_name, new_dst, src_sb->st_dev,
ancestors, &non_command_line_options, false,
first_dir_created_per_command_line_arg,
&first_dir_created,
&local_copy_into_self, NULL);
*copy_into_self |= local_copy_into_self;
@@ -583,9 +623,12 @@ copy_dir (char const *src_name_in, char const *dst_name_in, bool new_dst,
if (local_copy_into_self)
break;
new_first_dir_created |= first_dir_created;
namep += strlen (namep) + 1;
}
free (name_space);
*first_dir_created_per_command_line_arg = new_first_dir_created;
return ok;
}
@@ -983,7 +1026,8 @@ copy_reg (char const *src_name, char const *dst_name,
'--sparse=never' option is specified, write all data but use
any extents to read more efficiently. */
if (extent_copy (source_desc, dest_desc, buf, buf_size,
src_open_sb.st_size, make_holes,
src_open_sb.st_size,
S_ISREG (sb.st_mode) ? x->sparse_mode : SPARSE_NEVER,
src_name, dst_name, &normal_copy_required))
goto preserve_metadata;
@@ -1000,8 +1044,9 @@ copy_reg (char const *src_name, char const *dst_name,
UINTMAX_MAX, &n_read,
&wrote_hole_at_eof)
|| (wrote_hole_at_eof &&
! sparse_copy_finalize (dest_desc, dst_name)))
ftruncate (dest_desc, n_read) < 0))
{
error (0, errno, _("failed to extend %s"), quote (dst_name));
return_val = false;
goto close_src_and_dst_desc;
}
@@ -2184,13 +2229,24 @@ copy_internal (char const *src_name, char const *dst_name,
}
}
/* cp, invoked with `--link --no-dereference', should not follow the
link; we guarantee this with gnulib's linkat module (on systems
where link(2) follows the link, gnulib creates a symlink with
identical contents, which is good enough for our purposes). */
/* POSIX 2008 states that it is implementation-defined whether
link() on a symlink creates a hard-link to the symlink, or only
to the referent (effectively dereferencing the symlink) (POSIX
2001 required the latter behavior, although many systems provided
the former). Yet cp, invoked with `--link --no-dereference',
should not follow the link. We can approximate the desired
behavior by skipping this hard-link creating block and instead
copying the symlink, via the `S_ISLNK'- copying code below.
LINK_FOLLOWS_SYMLINKS is tri-state; if it is -1, we don't know
how link() behaves, so we use the fallback case for safety.
Note gnulib's linkat module, guarantees that the symlink is not
dereferenced. However its emulation currently doesn't maintain
timestamps or ownership so we only call it when we know the
emulation will not be needed. */
else if (x->hard_link
&& (!S_ISLNK (src_mode)
|| x->dereference != DEREF_NEVER))
&& !(LINK_FOLLOWS_SYMLINKS && S_ISLNK (src_mode)
&& x->dereference == DEREF_NEVER))
{
if (linkat (AT_FDCWD, src_name, AT_FDCWD, dst_name, 0))
{
@@ -2313,7 +2369,9 @@ copy_internal (char const *src_name, char const *dst_name,
/* If we've just created a hard-link due to cp's --link option,
we're done. */
if (x->hard_link && ! S_ISDIR (src_mode))
if (x->hard_link && ! S_ISDIR (src_mode)
&& !(LINK_FOLLOWS_SYMLINKS && S_ISLNK (src_mode)
&& x->dereference == DEREF_NEVER))
return delayed_ok;
if (copied_as_regular)

View File

@@ -496,6 +496,8 @@ set_fields (const char *fieldstr)
if (rp[i].hi > max_range_endpoint)
max_range_endpoint = rp[i].hi;
}
if (max_range_endpoint < eol_range_start)
max_range_endpoint = eol_range_start;
/* Allocate an array large enough so that it may be indexed by
the field numbers corresponding to all finite ranges

227
src/dd.c
View File

@@ -199,6 +199,9 @@ static int input_seek_errno;
static uintmax_t input_offset;
static bool input_offset_overflow;
/* True if a partial read should be diagnosed. */
static bool warn_partial_read;
/* Records truncated by conv=block. */
static uintmax_t r_truncate = 0;
@@ -225,6 +228,9 @@ static sig_atomic_t volatile interrupt_signal;
/* A count of the number of pending info signals that have been received. */
static sig_atomic_t volatile info_signal_count;
/* Whether to discard cache for input or output. */
static bool i_nocache, o_nocache;
/* Function used for read (to handle iflag=fullblock parameter). */
static ssize_t (*iread_fnc) (int fd, char *buf, size_t size);
@@ -259,6 +265,7 @@ static struct symbol_value const conversions[] =
{"", 0}
};
#define FFS_MASK(x) ((x) ^ ((x) & ((x) - 1)))
enum
{
/* Compute a value that's bitwise disjoint from the union
@@ -278,17 +285,23 @@ enum
| O_SYNC
| O_TEXT
),
/* Use its lowest bit. */
O_FULLBLOCK = v ^ (v & (v - 1))
/* Use its lowest bits for private flags. */
O_FULLBLOCK = FFS_MASK (v),
v2 = v ^ O_FULLBLOCK,
O_NOCACHE = FFS_MASK (v2)
};
/* Ensure that we got something. */
verify (O_FULLBLOCK != 0);
verify (O_NOCACHE != 0);
#define MULTIPLE_BITS_SET(i) (((i) & ((i) - 1)) != 0)
/* Ensure that this is a single-bit value. */
verify ( ! MULTIPLE_BITS_SET (O_FULLBLOCK));
verify ( ! MULTIPLE_BITS_SET (O_NOCACHE));
/* Flags, for iflag="..." and oflag="...". */
static struct symbol_value const flags[] =
@@ -300,6 +313,7 @@ static struct symbol_value const flags[] =
{"directory", O_DIRECTORY},
{"dsync", O_DSYNC},
{"noatime", O_NOATIME},
{"nocache", O_NOCACHE}, /* Discard cache. */
{"noctty", O_NOCTTY},
{"nofollow", HAVE_WORKING_O_NOFOLLOW ? O_NOFOLLOW : 0},
{"nolinks", O_NOLINKS},
@@ -467,11 +481,11 @@ Usage: %s [OPERAND]...\n\
fputs (_("\
Copy a file, converting and formatting according to the operands.\n\
\n\
bs=BYTES read and write BYTES bytes at a time (also see ibs=,obs=)\n\
bs=BYTES read and write up to BYTES bytes at a time\n\
cbs=BYTES convert BYTES bytes at a time\n\
conv=CONVS convert the file as per the comma separated symbol list\n\
count=BLOCKS copy only BLOCKS input blocks\n\
ibs=BYTES read BYTES bytes at a time (default: 512)\n\
ibs=BYTES read up to BYTES bytes at a time (default: 512)\n\
"), stdout);
fputs (_("\
if=FILE read from FILE instead of stdin\n\
@@ -499,18 +513,16 @@ Each CONV symbol may be:\n\
block pad newline-terminated records with spaces to cbs-size\n\
unblock replace trailing spaces in cbs-size records with newline\n\
lcase change upper case to lower case\n\
"), stdout);
fputs (_("\
nocreat do not create the output file\n\
excl fail if the output file already exists\n\
notrunc do not truncate the output file\n\
ucase change lower case to upper case\n\
swab swap every pair of input bytes\n\
"), stdout);
fputs (_("\
noerror continue after read errors\n\
sync pad every input block with NULs to ibs-size; when used\n\
with block or unblock, pad with spaces rather than NULs\n\
"), stdout);
fputs (_("\
excl fail if the output file already exists\n\
nocreat do not create the output file\n\
notrunc do not truncate the output file\n\
noerror continue after read errors\n\
fdatasync physically write output file data before finishing\n\
fsync likewise, but also write metadata\n\
"), stdout);
@@ -536,6 +548,10 @@ Each FLAG symbol may be:\n\
fputs (_(" nonblock use non-blocking I/O\n"), stdout);
if (O_NOATIME)
fputs (_(" noatime do not update access time\n"), stdout);
#if HAVE_POSIX_FADVISE
if (O_NOCACHE)
fputs (_(" nocache discard cached data\n"), stdout);
#endif
if (O_NOCTTY)
fputs (_(" noctty do not assign controlling terminal from file\n"),
stdout);
@@ -789,6 +805,91 @@ process_signals (void)
}
}
/* Return LEN rounded down to a multiple of PAGE_SIZE
while storing the remainder internally per FD.
Pass LEN == 0 to get the current remainder. */
static off_t
cache_round (int fd, off_t len)
{
static off_t i_pending, o_pending;
off_t *pending = (fd == STDIN_FILENO ? &i_pending : &o_pending);
if (len)
{
off_t c_pending = *pending + len;
*pending = c_pending % page_size;
if (c_pending > *pending)
len = c_pending - *pending;
else
len = 0;
}
else
len = *pending;
return len;
}
/* Discard the cache from the current offset of either
STDIN_FILENO or STDOUT_FILENO.
Return true on success. */
static bool
invalidate_cache (int fd, off_t len)
{
int adv_ret = -1;
/* Minimize syscalls. */
off_t clen = cache_round (fd, len);
if (len && !clen)
return true; /* Don't advise this time. */
if (!len && !clen && max_records)
return true; /* Nothing pending. */
off_t pending = len ? cache_round (fd, 0) : 0;
if (fd == STDIN_FILENO)
{
if (input_seekable)
{
/* Note we're being careful here to only invalidate what
we've read, so as not to dump any read ahead cache. */
#if HAVE_POSIX_FADVISE
adv_ret = posix_fadvise (fd, input_offset - clen - pending, clen,
POSIX_FADV_DONTNEED);
#else
errno = ENOTSUP;
#endif
}
else
errno = ESPIPE;
}
else if (fd == STDOUT_FILENO)
{
static off_t output_offset = -2;
if (output_offset != -1)
{
if (0 > output_offset)
{
output_offset = lseek (fd, 0, SEEK_CUR);
output_offset -= clen + pending;
}
if (0 <= output_offset)
{
#if HAVE_POSIX_FADVISE
adv_ret = posix_fadvise (fd, output_offset, clen,
POSIX_FADV_DONTNEED);
#else
errno = ENOTSUP;
#endif
output_offset += clen + pending;
}
}
}
return adv_ret != -1 ? true : false;
}
/* Read from FD into the buffer BUF of size SIZE, processing any
signals that arrive before bytes are read. Return the number of
bytes read if successful, -1 (setting errno) on failure. */
@@ -796,14 +897,35 @@ process_signals (void)
static ssize_t
iread (int fd, char *buf, size_t size)
{
while (true)
ssize_t nread;
do
{
ssize_t nread;
process_signals ();
nread = read (fd, buf, size);
if (! (nread < 0 && errno == EINTR))
return nread;
}
while (nread < 0 && errno == EINTR);
if (0 < nread && warn_partial_read)
{
static ssize_t prev_nread;
if (0 < prev_nread && prev_nread < size)
{
uintmax_t prev = prev_nread;
error (0, 0, ngettext (("warning: partial read (%"PRIuMAX" byte); "
"suggest iflag=fullblock"),
("warning: partial read (%"PRIuMAX" bytes); "
"suggest iflag=fullblock"),
select_plural (prev)),
prev);
warn_partial_read = false;
}
prev_nread = nread;
}
return nread;
}
/* Wrapper around iread function to accumulate full blocks. */
@@ -849,9 +971,7 @@ iwrite (int fd, char const *buf, size_t size)
posix_fadvise to tell the system not to pollute the buffer
cache with this data. Don't bother to diagnose lseek or
posix_fadvise failure. */
off_t off = lseek (STDOUT_FILENO, 0, SEEK_CUR);
if (0 <= off)
fdadvise (STDOUT_FILENO, off, 0, FADVISE_DONTNEED);
invalidate_cache (STDOUT_FILENO, 0);
/* Attempt to ensure that that final block is committed
to disk as quickly as possible. */
@@ -880,6 +1000,9 @@ iwrite (int fd, char const *buf, size_t size)
total_written += nwritten;
}
if (o_nocache && total_written)
invalidate_cache (fd, total_written);
return total_written;
}
@@ -1070,7 +1193,7 @@ scanargs (int argc, char *const *argv)
input_blocksize = output_blocksize = blocksize;
else
{
/* POSIX says dd aggregates short reads into
/* POSIX says dd aggregates partial reads into
output_blocksize if bs= is not specified. */
conversions_mask |= C_TWOBUFS;
}
@@ -1090,6 +1213,17 @@ scanargs (int argc, char *const *argv)
error (0, 0, "%s: %s", _("invalid output flag"), "'fullblock'");
usage (EXIT_FAILURE);
}
/* Warn about partial reads if bs=SIZE is given and iflag=fullblock
is not, and if counting or skipping bytes or using direct I/O.
This helps to avoid confusion with miscounts, and to avoid issues
with direct I/O on GNU/Linux. */
warn_partial_read =
(! (conversions_mask & C_TWOBUFS) && ! (input_flags & O_FULLBLOCK)
&& (skip_records
|| (0 < max_records && max_records < (uintmax_t) -1)
|| (input_flags | output_flags) & O_DIRECT));
iread_fnc = ((input_flags & O_FULLBLOCK)
? iread_fullblock
: iread);
@@ -1103,6 +1237,20 @@ scanargs (int argc, char *const *argv)
error (EXIT_FAILURE, 0, _("cannot combine lcase and ucase"));
if (multiple_bits_set (conversions_mask & (C_EXCL | C_NOCREAT)))
error (EXIT_FAILURE, 0, _("cannot combine excl and nocreat"));
if (multiple_bits_set (input_flags & (O_DIRECT | O_NOCACHE))
|| multiple_bits_set (output_flags & (O_DIRECT | O_NOCACHE)))
error (EXIT_FAILURE, 0, _("cannot combine direct and nocache"));
if (input_flags & O_NOCACHE)
{
i_nocache = true;
input_flags &= ~O_NOCACHE;
}
if (output_flags & O_NOCACHE)
{
o_nocache = true;
output_flags &= ~O_NOCACHE;
}
}
/* Fix up translation table. */
@@ -1639,7 +1787,7 @@ dd_copy (void)
There are 3 reasons why there might be unskipped blocks/bytes:
1. file is too small
2. pipe has not enough data
3. short reads */
3. partial reads */
if (us_blocks || (!input_offset_overflow && us_bytes))
{
error (0, 0,
@@ -1685,6 +1833,9 @@ dd_copy (void)
nread = iread_fnc (STDIN_FILENO, ibuf, input_blocksize);
if (nread >= 0 && i_nocache)
invalidate_cache (STDIN_FILENO, nread);
if (nread == 0)
break; /* EOF. */
@@ -1694,8 +1845,14 @@ dd_copy (void)
if (conversions_mask & C_NOERROR)
{
print_stats ();
size_t bad_portion = input_blocksize - partread;
/* We already know this data is not cached,
but call this so that correct offsets are maintained. */
invalidate_cache (STDIN_FILENO, bad_portion);
/* Seek past the bad block if possible. */
if (!advance_input_after_read_error (input_blocksize - partread))
if (!advance_input_after_read_error (bad_portion))
{
exit_status = EXIT_FAILURE;
@@ -1950,5 +2107,31 @@ main (int argc, char **argv)
exit_status = dd_copy ();
if (max_records == 0)
{
/* Special case to invalidate cache to end of file. */
if (i_nocache && !invalidate_cache (STDIN_FILENO, 0))
{
error (0, errno, _("failed to discard cache for: %s"),
quote (input_file));
exit_status = EXIT_FAILURE;
}
if (o_nocache && !invalidate_cache (STDOUT_FILENO, 0))
{
error (0, errno, _("failed to discard cache for: %s"),
quote (output_file));
exit_status = EXIT_FAILURE;
}
}
else if (max_records != (uintmax_t) -1)
{
/* Invalidate any pending region less that page size,
in case the kernel might round up. */
if (i_nocache)
invalidate_cache (STDIN_FILENO, 0);
if (o_nocache)
invalidate_cache (STDOUT_FILENO, 0);
}
quit (exit_status);
}

470
src/df.c
View File

@@ -22,11 +22,14 @@
#include <stdio.h>
#include <sys/types.h>
#include <getopt.h>
#include <assert.h>
#include "system.h"
#include "error.h"
#include "fsusage.h"
#include "human.h"
#include "mbsalign.h"
#include "mbswidth.h"
#include "mountlist.h"
#include "quote.h"
#include "find-mount-point.h"
@@ -112,6 +115,52 @@ static bool print_grand_total;
/* Grand total data. */
static struct fs_usage grand_fsu;
/* Display modes. */
enum { DEFAULT_MODE, INODES_MODE, HUMAN_MODE, POSIX_MODE, NMODES };
static int header_mode = DEFAULT_MODE;
/* Displayable fields. */
enum
{
DEV_FIELD, /* file system */
TYPE_FIELD, /* FS type */
TOTAL_FIELD, /* blocks or inodes */
USED_FIELD, /* ditto */
FREE_FIELD, /* ditto */
PCENT_FIELD, /* percent used */
MNT_FIELD, /* mount point */
NFIELDS
};
/* Header strings for the above fields in each mode.
NULL means to use the header for the default mode. */
static const char *headers[NFIELDS][NMODES] = {
/* DEFAULT_MODE INODES_MODE HUMAN_MODE POSIX_MODE */
{ N_("Filesystem"), NULL, NULL, NULL },
{ N_("Type"), NULL, NULL, NULL },
{ N_("blocks"), N_("Inodes"), N_("Size"), NULL },
{ N_("Used"), N_("IUsed"), NULL, NULL },
{ N_("Available"), N_("IFree"), N_("Avail"), NULL },
{ N_("Use%"), N_("IUse%"), NULL, N_("Capacity") },
{ N_("Mounted on"), NULL, NULL, NULL }
};
/* Alignments for the 3 textual and 4 numeric fields. */
static mbs_align_t alignments[NFIELDS] = {
MBS_ALIGN_LEFT, MBS_ALIGN_LEFT,
MBS_ALIGN_RIGHT, MBS_ALIGN_RIGHT, MBS_ALIGN_RIGHT, MBS_ALIGN_RIGHT,
MBS_ALIGN_LEFT
};
/* Auto adjusted (up) widths used to align columns. */
static size_t widths[NFIELDS] = { 14, 4, 5, 5, 5, 4, 0 };
/* Storage for pointers for each string (cell of table). */
static char ***table;
/* The current number of processed rows (including header). */
static size_t nrows;
/* For long options that have no equivalent short option, use a
non-character as a pseudo short option, starting with CHAR_MAX + 1. */
enum
@@ -141,70 +190,133 @@ static struct option const long_options[] =
{NULL, 0, NULL, 0}
};
/* Dynamically allocate a row of pointers in TABLE, which
can then be accessed with standard 2D array notation. */
static void
print_header (void)
alloc_table_row (void)
{
char buf[MAX (LONGEST_HUMAN_READABLE + 1, INT_BUFSIZE_BOUND (uintmax_t))];
nrows++;
table = xnrealloc (table, nrows, sizeof (char *));
table[nrows-1] = xnmalloc (NFIELDS, sizeof (char *));
}
if (print_type)
/* TRANSLATORS:
For best results (df header/column alignment), ensure that
your translation has the same length as the original. */
fputs (_("Filesystem Type"), stdout);
else
fputs (_("Filesystem "), stdout);
/* Output each cell in the table, accounting for the
alignment and max width of each column. */
if (inode_format)
/* TRANSLATORS:
For best results (df header/column alignment), ensure that
your translation has the same length as the original.
Also, each column name translation should end at the same
column as the corresponding original. */
fputs (_(" Inodes IUsed IFree IUse%"), stdout);
else if (human_output_opts & human_autoscale)
static void
print_table (void)
{
size_t field, row;
for (row = 0; row < nrows; row ++)
{
if (human_output_opts & human_base_1024)
fputs (_(" Size Used Avail Use%"), stdout);
else
fputs (_(" Size Used Avail Use%"), stdout);
}
else if (posix_format)
printf (_(" %s-blocks Used Available Capacity"),
umaxtostr (output_block_size, buf));
else
{
int opts = (human_suppress_point_zero
| human_autoscale | human_SI
| (human_output_opts
& (human_group_digits | human_base_1024 | human_B)));
/* Prefer the base that makes the human-readable value more exact,
if there is a difference. */
uintmax_t q1000 = output_block_size;
uintmax_t q1024 = output_block_size;
bool divisible_by_1000;
bool divisible_by_1024;
do
for (field = 0; field < NFIELDS; field++)
{
divisible_by_1000 = q1000 % 1000 == 0; q1000 /= 1000;
divisible_by_1024 = q1024 % 1024 == 0; q1024 /= 1024;
size_t width = widths[field];
char *cell = table[row][field];
if (!cell)
continue;
/* Note the DEV_FIELD used to be displayed on it's own line
if (!posix_format && mbswidth (cell) > 20), but that
functionality is probably more problematic than helpful. */
if (field != 0)
putchar (' ');
if (field == MNT_FIELD) /* The last one. */
fputs (cell, stdout);
else
{
cell = ambsalign (table[row][field], &width,
alignments[field], MBA_UNIBYTE_FALLBACK);
fputs (cell, stdout);
free (cell);
}
IF_LINT (free (table[row][field]));
}
while (divisible_by_1000 & divisible_by_1024);
if (divisible_by_1000 < divisible_by_1024)
opts |= human_base_1024;
if (divisible_by_1024 < divisible_by_1000)
opts &= ~human_base_1024;
if (! (opts & human_base_1024))
opts |= human_B;
printf (_(" %4s-blocks Used Available Use%%"),
human_readable (output_block_size, buf, opts, 1, 1));
putchar ('\n');
IF_LINT (free (table[row]));
}
fputs (_(" Mounted on\n"), stdout);
IF_LINT (free (table));
}
/* Optain the appropriate header entries. */
static void
get_header (void)
{
size_t field;
alloc_table_row ();
for (field = 0; field < NFIELDS; field++)
{
if (field == TYPE_FIELD && !print_type)
{
table[nrows-1][field] = NULL;
continue;
}
char *cell = NULL;
char const *header = _(headers[field][header_mode]);
if (!header)
header = _(headers[field][DEFAULT_MODE]);
if (header_mode == DEFAULT_MODE && field == TOTAL_FIELD)
{
char buf[LONGEST_HUMAN_READABLE + 1];
int opts = (human_suppress_point_zero
| human_autoscale | human_SI
| (human_output_opts
& (human_group_digits | human_base_1024 | human_B)));
/* Prefer the base that makes the human-readable value more exact,
if there is a difference. */
uintmax_t q1000 = output_block_size;
uintmax_t q1024 = output_block_size;
bool divisible_by_1000;
bool divisible_by_1024;
do
{
divisible_by_1000 = q1000 % 1000 == 0; q1000 /= 1000;
divisible_by_1024 = q1024 % 1024 == 0; q1024 /= 1024;
}
while (divisible_by_1000 & divisible_by_1024);
if (divisible_by_1000 < divisible_by_1024)
opts |= human_base_1024;
if (divisible_by_1024 < divisible_by_1000)
opts &= ~human_base_1024;
if (! (opts & human_base_1024))
opts |= human_B;
char *num = human_readable (output_block_size, buf, opts, 1, 1);
if (asprintf (&cell, "%s-%s", num, header) == -1)
cell = NULL;
}
else if (header_mode == POSIX_MODE && field == TOTAL_FIELD)
{
char buf[INT_BUFSIZE_BOUND (uintmax_t)];
char *num = umaxtostr (output_block_size, buf);
if (asprintf (&cell, "%s-%s", num, header) == -1)
cell = NULL;
}
else
cell = strdup (header);
if (!cell)
xalloc_die ();
table[nrows-1][field] = cell;
widths[field] = MAX (widths[field], mbswidth (cell, 0));
}
}
/* Is FSTYPE a type of file system that should be listed? */
@@ -305,7 +417,7 @@ add_uint_with_neg_flag (uintmax_t *dest, bool *dest_neg,
*dest = -*dest;
}
/* Display a space listing for the disk device with absolute file name DISK.
/* Optain a space listing for the disk device with absolute file name DISK.
If MOUNT_POINT is non-NULL, it is the name of the root of the
file system on DISK.
If STAT_FILE is non-null, it is the name of a file within the file
@@ -319,16 +431,13 @@ add_uint_with_neg_flag (uintmax_t *dest, bool *dest_neg,
ME_DUMMY and ME_REMOTE are the mount entry flags. */
static void
show_dev (char const *disk, char const *mount_point,
char const *stat_file, char const *fstype,
bool me_dummy, bool me_remote,
const struct fs_usage *force_fsu)
get_dev (char const *disk, char const *mount_point,
char const *stat_file, char const *fstype,
bool me_dummy, bool me_remote,
const struct fs_usage *force_fsu)
{
struct fs_usage fsu;
char buf[3][LONGEST_HUMAN_READABLE + 2];
int width;
int col1_adjustment = 0;
int use_width;
char buf[LONGEST_HUMAN_READABLE + 2];
uintmax_t input_units;
uintmax_t output_units;
uintmax_t total;
@@ -338,6 +447,8 @@ show_dev (char const *disk, char const *mount_point,
uintmax_t used;
bool negate_used;
double pct = -1;
char* cell;
size_t field;
if (me_remote && show_local_fs)
return;
@@ -370,39 +481,18 @@ show_dev (char const *disk, char const *mount_point,
if (! file_systems_processed)
{
file_systems_processed = true;
print_header ();
get_header ();
}
alloc_table_row ();
if (! disk)
disk = "-"; /* unknown */
if (! fstype)
fstype = "-"; /* unknown */
/* df.c reserved 5 positions for fstype,
but that does not suffice for type iso9660 */
if (print_type)
{
size_t disk_name_len = strlen (disk);
size_t fstype_len = strlen (fstype);
if (disk_name_len + fstype_len < 18)
printf ("%s%*s ", disk, 18 - (int) disk_name_len, fstype);
else if (!posix_format)
printf ("%s\n%18s ", disk, fstype);
else
printf ("%s %s", disk, fstype);
}
else
{
if (strlen (disk) > 20 && !posix_format)
printf ("%s\n%20s", disk, "");
else
printf ("%-20s", disk);
}
if (inode_format)
{
width = 7;
use_width = 5;
input_units = output_units = 1;
total = fsu.fsu_files;
available = fsu.fsu_ffree;
@@ -416,22 +506,6 @@ show_dev (char const *disk, char const *mount_point,
}
else
{
if (human_output_opts & human_autoscale)
width = 5 + ! (human_output_opts & human_base_1024);
else
{
width = 9;
if (posix_format)
{
uintmax_t b;
col1_adjustment = -3;
for (b = output_block_size; 9 < b; b /= 10)
col1_adjustment++;
}
}
use_width = ((posix_format
&& ! (human_output_opts & human_autoscale))
? 8 : 4);
input_units = fsu.fsu_blocksize;
output_units = output_block_size;
total = fsu.fsu_blocks;
@@ -458,73 +532,110 @@ show_dev (char const *disk, char const *mount_point,
negate_used = (total < available_to_root);
}
printf (" %*s %*s %*s ",
width + col1_adjustment,
df_readable (false, total,
buf[0], input_units, output_units),
width, df_readable (negate_used, used,
buf[1], input_units, output_units),
width, df_readable (negate_available, available,
buf[2], input_units, output_units));
if (! known_value (used) || ! known_value (available))
;
else if (!negate_used
&& used <= TYPE_MAXIMUM (uintmax_t) / 100
&& used + available != 0
&& (used + available < used) == negate_available)
for (field = 0; field < NFIELDS; field++)
{
uintmax_t u100 = used * 100;
uintmax_t nonroot_total = used + available;
pct = u100 / nonroot_total + (u100 % nonroot_total != 0);
}
else
{
/* The calculation cannot be done easily with integer
arithmetic. Fall back on floating point. This can suffer
from minor rounding errors, but doing it exactly requires
multiple precision arithmetic, and it's not worth the
aggravation. */
double u = negate_used ? - (double) - used : used;
double a = negate_available ? - (double) - available : available;
double nonroot_total = u + a;
if (nonroot_total)
switch (field)
{
long int lipct = pct = u * 100 / nonroot_total;
double ipct = lipct;
case DEV_FIELD:
cell = xstrdup (disk);
break;
/* Like `pct = ceil (dpct);', but avoid ceil so that
the math library needn't be linked. */
if (ipct - 1 < pct && pct <= ipct + 1)
pct = ipct + (ipct < pct);
}
}
case TYPE_FIELD:
cell = print_type ? xstrdup (fstype) : NULL;
break;
if (0 <= pct)
printf ("%*.0f%%", use_width - 1, pct);
else
printf ("%*s", use_width, "- ");
case TOTAL_FIELD:
cell = xstrdup (df_readable (false, total, buf,
input_units, output_units));
break;
case USED_FIELD:
cell = xstrdup (df_readable (negate_used, used, buf,
input_units, output_units));
break;
case FREE_FIELD:
cell = xstrdup (df_readable (negate_available, available, buf,
input_units, output_units));
break;
if (mount_point)
{
case PCENT_FIELD:
if (! known_value (used) || ! known_value (available))
;
else if (!negate_used
&& used <= TYPE_MAXIMUM (uintmax_t) / 100
&& used + available != 0
&& (used + available < used) == negate_available)
{
uintmax_t u100 = used * 100;
uintmax_t nonroot_total = used + available;
pct = u100 / nonroot_total + (u100 % nonroot_total != 0);
}
else
{
/* The calculation cannot be done easily with integer
arithmetic. Fall back on floating point. This can suffer
from minor rounding errors, but doing it exactly requires
multiple precision arithmetic, and it's not worth the
aggravation. */
double u = negate_used ? - (double) - used : used;
double a = negate_available ? - (double) - available : available;
double nonroot_total = u + a;
if (nonroot_total)
{
long int lipct = pct = u * 100 / nonroot_total;
double ipct = lipct;
/* Like `pct = ceil (dpct);', but avoid ceil so that
the math library needn't be linked. */
if (ipct - 1 < pct && pct <= ipct + 1)
pct = ipct + (ipct < pct);
}
}
if (0 <= pct)
{
if (asprintf (&cell, "%.0f%%", pct) == -1)
cell = NULL;
}
else
cell = strdup ("-");
if (!cell)
xalloc_die ();
break;
case MNT_FIELD:
if (mount_point)
{
#ifdef HIDE_AUTOMOUNT_PREFIX
/* Don't print the first directory name in MOUNT_POINT if it's an
artifact of an automounter. This is a bit too aggressive to be
the default. */
if (strncmp ("/auto/", mount_point, 6) == 0)
mount_point += 5;
else if (strncmp ("/tmp_mnt/", mount_point, 9) == 0)
mount_point += 8;
/* Don't print the first directory name in MOUNT_POINT if it's an
artifact of an automounter. This is a bit too aggressive to be
the default. */
if (STRNCMP_LIT (mount_point, "/auto/") == 0)
mount_point += 5;
else if (STRNCMP_LIT (mount_point, "/tmp_mnt/") == 0)
mount_point += 8;
#endif
printf (" %s", mount_point);
cell = xstrdup (mount_point);
}
else
cell = NULL;
break;
default:
assert (!"unhandled field");
}
if (cell)
widths[field] = MAX (widths[field], mbswidth (cell, 0));
table[nrows-1][field] = cell;
}
putchar ('\n');
}
/* If DISK corresponds to a mount point, show its usage
and return true. Otherwise, return false. */
static bool
show_disk (char const *disk)
get_disk (char const *disk)
{
struct mount_entry const *me;
struct mount_entry const *best_match = NULL;
@@ -535,9 +646,9 @@ show_disk (char const *disk)
if (best_match)
{
show_dev (best_match->me_devname, best_match->me_mountdir, NULL,
best_match->me_type, best_match->me_dummy,
best_match->me_remote, NULL);
get_dev (best_match->me_devname, best_match->me_mountdir, NULL,
best_match->me_type, best_match->me_dummy,
best_match->me_remote, NULL);
return true;
}
@@ -548,7 +659,7 @@ show_disk (char const *disk)
and show its disk usage.
STATP must be the result of `stat (POINT, STATP)'. */
static void
show_point (const char *point, const struct stat *statp)
get_point (const char *point, const struct stat *statp)
{
struct stat disk_stats;
struct mount_entry *me;
@@ -571,7 +682,7 @@ show_point (const char *point, const struct stat *statp)
if (best_match_len <= len && len <= resolved_len
&& (len == 1 /* root file system */
|| ((len == resolved_len || resolved[len] == '/')
&& strncmp (me->me_mountdir, resolved, len) == 0)))
&& STREQ_LEN (me->me_mountdir, resolved, len))))
{
best_match = me;
best_match_len = len;
@@ -621,9 +732,9 @@ show_point (const char *point, const struct stat *statp)
}
if (best_match)
show_dev (best_match->me_devname, best_match->me_mountdir, point,
best_match->me_type, best_match->me_dummy, best_match->me_remote,
NULL);
get_dev (best_match->me_devname, best_match->me_mountdir, point,
best_match->me_type, best_match->me_dummy, best_match->me_remote,
NULL);
else
{
/* We couldn't find the mount entry corresponding to POINT. Go ahead and
@@ -634,7 +745,7 @@ show_point (const char *point, const struct stat *statp)
char *mp = find_mount_point (point, statp);
if (mp)
{
show_dev (NULL, mp, NULL, NULL, false, false, NULL);
get_dev (NULL, mp, NULL, NULL, false, false, NULL);
free (mp);
}
}
@@ -644,25 +755,25 @@ show_point (const char *point, const struct stat *statp)
for it. STATP is the results of `stat' on NAME. */
static void
show_entry (char const *name, struct stat const *statp)
get_entry (char const *name, struct stat const *statp)
{
if ((S_ISBLK (statp->st_mode) || S_ISCHR (statp->st_mode))
&& show_disk (name))
&& get_disk (name))
return;
show_point (name, statp);
get_point (name, statp);
}
/* Show all mounted file systems, except perhaps those that are of
an unselected type or are empty. */
static void
show_all_entries (void)
get_all_entries (void)
{
struct mount_entry *me;
for (me = mount_list; me; me = me->me_next)
show_dev (me->me_devname, me->me_mountdir, NULL, me->me_type,
get_dev (me->me_devname, me->me_mountdir, NULL, me->me_type,
me->me_dummy, me->me_remote, NULL);
}
@@ -862,6 +973,13 @@ main (int argc, char **argv)
&human_output_opts, &output_block_size);
}
if (inode_format)
header_mode = INODES_MODE;
else if (human_output_opts & human_autoscale)
header_mode = HUMAN_MODE;
else if (posix_format)
header_mode = POSIX_MODE;
/* Fail if the same file system type was both selected and excluded. */
{
bool match = false;
@@ -939,18 +1057,20 @@ main (int argc, char **argv)
for (i = optind; i < argc; ++i)
if (argv[i])
show_entry (argv[i], &stats[i - optind]);
get_entry (argv[i], &stats[i - optind]);
}
else
show_all_entries ();
get_all_entries ();
if (print_grand_total)
{
if (inode_format)
grand_fsu.fsu_blocks = 1;
show_dev ("total", NULL, NULL, NULL, false, false, &grand_fsu);
get_dev ("total", NULL, NULL, NULL, false, false, &grand_fsu);
}
print_table ();
if (! file_systems_processed)
error (EXIT_FAILURE, 0, _("no file systems processed"));

View File

@@ -926,19 +926,19 @@ main (int argc, char **argv)
bool skip_file = false;
enum argv_iter_err ai_err;
char *file_name = argv_iter (ai, &ai_err);
if (ai_err == AI_ERR_EOF)
break;
if (!file_name)
{
switch (ai_err)
{
case AI_ERR_EOF:
goto argv_iter_done;
case AI_ERR_READ:
error (0, errno, _("%s: read error"), quote (files_from));
continue;
error (0, errno, _("%s: read error"),
quotearg_colon (files_from));
ok = false;
goto argv_iter_done;
case AI_ERR_MEM:
xalloc_die ();
default:
assert (!"unexpected error code from argv_iter");
}
@@ -985,11 +985,12 @@ main (int argc, char **argv)
ok &= du_files (temp_argv, bit_flags);
}
}
argv_iter_done:
argv_iter_free (ai);
di_set_free (di_set);
if (files_from && (ferror (stdin) || fclose (stdin) != 0))
if (files_from && (ferror (stdin) || fclose (stdin) != 0) && ok)
error (EXIT_FAILURE, 0, _("error reading %s"), quote (files_from));
if (print_grand_total)

View File

@@ -17,18 +17,48 @@
Written by Jie Liu (jeff.liu@oracle.com). */
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/utsname.h>
#include <assert.h>
#include "system.h"
#include "extent-scan.h"
#include "xstrtol.h"
#ifndef HAVE_FIEMAP
# include "fiemap.h"
#endif
/* Work around Linux kernel issues on BTRFS and EXT4 before 2.6.39.
FIXME: remove in 2013, or whenever we're pretty confident
that the offending, unpatched kernels are no longer in use. */
static bool
extent_need_sync (void)
{
static int need_sync = -1;
if (need_sync == -1)
{
struct utsname name;
need_sync = 0; /* No workaround by default. */
#ifdef __linux__
if (uname (&name) != -1 && STRNCMP_LIT (name.release, "2.6.") == 0)
{
unsigned long val;
if (xstrtoul (name.release + 4, NULL, 10, &val, NULL) == LONGINT_OK)
{
if (val < 39)
need_sync = 1;
}
}
#endif
}
return need_sync;
}
/* Allocate space for struct extent_scan, initialize the entries if
necessary and return it as the input argument of extent_scan_read(). */
extern void
@@ -36,9 +66,11 @@ extent_scan_init (int src_fd, struct extent_scan *scan)
{
scan->fd = src_fd;
scan->ei_count = 0;
scan->ext_info = NULL;
scan->scan_start = 0;
scan->initial_scan_failed = false;
scan->hit_final_extent = false;
scan->fm_flags = extent_need_sync () ? FIEMAP_FLAG_SYNC : 0;
}
#ifdef __linux__
@@ -50,60 +82,126 @@ extent_scan_init (int src_fd, struct extent_scan *scan)
extern bool
extent_scan_read (struct extent_scan *scan)
{
union { struct fiemap f; char c[4096]; } fiemap_buf;
struct fiemap *fiemap = &fiemap_buf.f;
struct fiemap_extent *fm_extents = &fiemap->fm_extents[0];
enum { count = (sizeof fiemap_buf - sizeof *fiemap) / sizeof *fm_extents };
verify (count != 0);
unsigned int si = 0;
struct extent_info *last_ei IF_LINT ( = scan->ext_info);
/* This is required at least to initialize fiemap->fm_start,
but also serves (in mid 2010) to appease valgrind, which
appears not to know the semantics of the FIEMAP ioctl. */
memset (&fiemap_buf, 0, sizeof fiemap_buf);
fiemap->fm_start = scan->scan_start;
fiemap->fm_flags = FIEMAP_FLAG_SYNC;
fiemap->fm_extent_count = count;
fiemap->fm_length = FIEMAP_MAX_OFFSET - scan->scan_start;
/* Fall back to the standard copy if call ioctl(2) failed for the
the first time. */
if (ioctl (scan->fd, FS_IOC_FIEMAP, fiemap) < 0)
while (true)
{
if (scan->scan_start == 0)
scan->initial_scan_failed = true;
return false;
union { struct fiemap f; char c[4096]; } fiemap_buf;
struct fiemap *fiemap = &fiemap_buf.f;
struct fiemap_extent *fm_extents = &fiemap->fm_extents[0];
enum { count = (sizeof fiemap_buf - sizeof *fiemap)/sizeof *fm_extents };
verify (count > 1);
/* This is required at least to initialize fiemap->fm_start,
but also serves (in mid 2010) to appease valgrind, which
appears not to know the semantics of the FIEMAP ioctl. */
memset (&fiemap_buf, 0, sizeof fiemap_buf);
fiemap->fm_start = scan->scan_start;
fiemap->fm_flags = scan->fm_flags;
fiemap->fm_extent_count = count;
fiemap->fm_length = FIEMAP_MAX_OFFSET - scan->scan_start;
/* Fall back to the standard copy if call ioctl(2) failed for
the first time. */
if (ioctl (scan->fd, FS_IOC_FIEMAP, fiemap) < 0)
{
if (scan->scan_start == 0)
scan->initial_scan_failed = true;
return false;
}
/* If 0 extents are returned, then no more scans are needed. */
if (fiemap->fm_mapped_extents == 0)
{
scan->hit_final_extent = true;
return scan->scan_start != 0;
}
assert (scan->ei_count <= SIZE_MAX - fiemap->fm_mapped_extents);
scan->ei_count += fiemap->fm_mapped_extents;
scan->ext_info = xnrealloc (scan->ext_info, scan->ei_count,
sizeof (struct extent_info));
unsigned int i = 0;
for (i = 0; i < fiemap->fm_mapped_extents; i++)
{
assert (fm_extents[i].fe_logical <=
OFF_T_MAX - fm_extents[i].fe_length);
if (si && last_ei->ext_flags ==
(fm_extents[i].fe_flags & ~FIEMAP_EXTENT_LAST)
&& (last_ei->ext_logical + last_ei->ext_length
== fm_extents[i].fe_logical))
{
/* Merge previous with last. */
last_ei->ext_length += fm_extents[i].fe_length;
/* Copy flags in case different. */
last_ei->ext_flags = fm_extents[i].fe_flags;
}
else if ((si == 0 && scan->scan_start > fm_extents[i].fe_logical)
|| (si && last_ei->ext_logical + last_ei->ext_length >
fm_extents[i].fe_logical))
{
/* BTRFS before 2.6.38 could return overlapping extents
for sparse files. We adjust the returned extents
rather than failing, as otherwise it would be inefficient
to detect this on the initial scan. */
uint64_t new_logical;
uint64_t length_adjust;
if (si == 0)
new_logical = scan->scan_start;
else
{
/* We could return here if scan->scan_start == 0
but don't so as to minimize special cases. */
new_logical = last_ei->ext_logical + last_ei->ext_length;
}
length_adjust = new_logical - fm_extents[i].fe_logical;
/* If an extent is contained within the previous one, fail. */
if (length_adjust < fm_extents[i].fe_length)
{
if (scan->scan_start == 0)
scan->initial_scan_failed = true;
return false;
}
fm_extents[i].fe_logical = new_logical;
fm_extents[i].fe_length -= length_adjust;
/* Process the adjusted extent again. */
i--;
continue;
}
else
{
last_ei = scan->ext_info + si;
last_ei->ext_logical = fm_extents[i].fe_logical;
last_ei->ext_length = fm_extents[i].fe_length;
last_ei->ext_flags = fm_extents[i].fe_flags;
si++;
}
}
if (last_ei->ext_flags & FIEMAP_EXTENT_LAST)
scan->hit_final_extent = true;
/* If we have enough extents, discard the last as it might
be merged with one from the next scan. */
if (si > count && !scan->hit_final_extent)
last_ei = scan->ext_info + --si - 1;
/* We don't bother reallocating any trailing slots. */
scan->ei_count = si;
if (scan->hit_final_extent)
break;
else
scan->scan_start = last_ei->ext_logical + last_ei->ext_length;
if (si >= count)
break;
}
/* If 0 extents are returned, then more get_extent_table() are not needed. */
if (fiemap->fm_mapped_extents == 0)
{
scan->hit_final_extent = true;
return false;
}
scan->ei_count = fiemap->fm_mapped_extents;
scan->ext_info = xnmalloc (scan->ei_count, sizeof (struct extent_info));
unsigned int i;
for (i = 0; i < scan->ei_count; i++)
{
assert (fm_extents[i].fe_logical <= OFF_T_MAX);
scan->ext_info[i].ext_logical = fm_extents[i].fe_logical;
scan->ext_info[i].ext_length = fm_extents[i].fe_length;
scan->ext_info[i].ext_flags = fm_extents[i].fe_flags;
}
i--;
if (scan->ext_info[i].ext_flags & FIEMAP_EXTENT_LAST)
{
scan->hit_final_extent = true;
return true;
}
scan->scan_start = fm_extents[i].fe_logical + fm_extents[i].fe_length;
return true;
}
#else

View File

@@ -41,6 +41,9 @@ struct extent_scan
/* Next scan start offset. */
off_t scan_start;
/* Flags to use for scan. */
uint32_t fm_flags;
/* How many extent info returned for a scan. */
uint32_t ei_count;
@@ -63,6 +66,8 @@ static inline void
extent_scan_free (struct extent_scan *scan)
{
free (scan->ext_info);
scan->ext_info = NULL;
scan->ei_count = 0;
}
#endif /* EXTENT_SCAN_H */

View File

@@ -75,7 +75,7 @@ struct fiemap
/* Location still pending, Sets EXTENT_UNKNOWN. */
# define FIEMAP_EXTENT_DELALLOC 0x00000004
/* Data can not be read while fs is unmounted. */
/* Data cannot be read while fs is unmounted. */
# define FIEMAP_EXTENT_ENCODED 0x00000008
/* Data is encrypted by fs. Sets EXTENT_NO_BYPASS. */

View File

@@ -29,11 +29,11 @@
Give a diagnostic and return NULL if unable to determine the mount point.
Exit if unable to restore current working directory. */
extern char *
find_mount_point (const char *file, const struct stat *file_stat)
find_mount_point (char const *file, struct stat const *file_stat)
{
struct saved_cwd cwd;
struct stat last_stat;
char *mp = NULL; /* The malloced mount point. */
char *mp = NULL; /* The malloc'd mount point. */
if (save_cwd (&cwd) != 0)
{

View File

@@ -14,4 +14,4 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
extern char* find_mount_point (const char *, const struct stat *);
extern char *find_mount_point (char const *, struct stat const *);

View File

@@ -68,23 +68,6 @@ static bool use_default_selinux_context = true;
# define matchpathcon_init_prefix(a, p) /* empty */
#endif
static bool change_timestamps (struct stat const *from_sb, char const *to);
static bool change_attributes (char const *name);
static bool copy_file (const char *from, const char *to,
const struct cp_options *x);
static bool install_file_in_file_parents (char const *from, char *to,
struct cp_options *x);
static bool install_file_in_dir (const char *from, const char *to_dir,
const struct cp_options *x);
static bool install_file_in_file (const char *from, const char *to,
const struct cp_options *x);
static void get_ids (void);
static void strip (char const *name);
static void announce_mkdir (char const *dir, void *options);
static int make_ancestor (char const *dir, char const *component,
void *options);
void usage (int status);
/* The user name that will own the files, or NULL to make the owner
the current user ID. */
static char *owner_name;
@@ -131,7 +114,6 @@ static char const *strip_program = "strip";
enum
{
PRESERVE_CONTEXT_OPTION = CHAR_MAX + 1,
PRESERVE_CONTEXT_OPTION_DEPRECATED,
STRIP_PROGRAM_OPTION
};
@@ -147,9 +129,6 @@ static struct option const long_options[] =
{"owner", required_argument, NULL, 'o'},
{"preserve-timestamps", no_argument, NULL, 'p'},
{"preserve-context", no_argument, NULL, PRESERVE_CONTEXT_OPTION},
/* --preserve_context was silently supported until Apr 2009.
FIXME: disable altogether in a year or so. */
{"preserve_context", no_argument, NULL, PRESERVE_CONTEXT_OPTION_DEPRECATED},
{"strip", no_argument, NULL, 's'},
{"strip-program", required_argument, NULL, STRIP_PROGRAM_OPTION},
{"suffix", required_argument, NULL, 'S'},
@@ -407,6 +386,27 @@ target_directory_operand (char const *file)
return is_a_dir;
}
/* Report that directory DIR was made, if OPTIONS requests this. */
static void
announce_mkdir (char const *dir, void *options)
{
struct cp_options const *x = options;
if (x->verbose)
prog_fprintf (stdout, _("creating directory %s"), quote (dir));
}
/* Make ancestor directory DIR, whose last file name component is
COMPONENT, with options OPTIONS. Assume the working directory is
COMPONENT's parent. */
static int
make_ancestor (char const *dir, char const *component, void *options)
{
int r = mkdir (component, DEFAULT_MODE);
if (r == 0)
announce_mkdir (dir, options);
return r;
}
/* Process a command-line file name, for the -d option. */
static int
process_dir (char *dir, struct savewd *wd, void *options)
@@ -419,6 +419,312 @@ process_dir (char *dir, struct savewd *wd, void *options)
: EXIT_FAILURE);
}
/* Copy file FROM onto file TO, creating TO if necessary.
Return true if successful. */
static bool
copy_file (const char *from, const char *to, const struct cp_options *x)
{
bool copy_into_self;
if (copy_only_if_needed && !need_copy (from, to, x))
return true;
/* Allow installing from non-regular files like /dev/null.
Charles Karney reported that some Sun version of install allows that
and that sendmail's installation process relies on the behavior.
However, since !x->recursive, the call to "copy" will fail if FROM
is a directory. */
return copy (from, to, false, x, &copy_into_self, NULL);
}
/* Set the attributes of file or directory NAME.
Return true if successful. */
static bool
change_attributes (char const *name)
{
bool ok = false;
/* chown must precede chmod because on some systems,
chown clears the set[ug]id bits for non-superusers,
resulting in incorrect permissions.
On System V, users can give away files with chown and then not
be able to chmod them. So don't give files away.
We don't normally ignore errors from chown because the idea of
the install command is that the file is supposed to end up with
precisely the attributes that the user specified (or defaulted).
If the file doesn't end up with the group they asked for, they'll
want to know. */
if (! (owner_id == (uid_t) -1 && group_id == (gid_t) -1)
&& lchown (name, owner_id, group_id) != 0)
error (0, errno, _("cannot change ownership of %s"), quote (name));
else if (chmod (name, mode) != 0)
error (0, errno, _("cannot change permissions of %s"), quote (name));
else
ok = true;
if (use_default_selinux_context)
setdefaultfilecon (name);
return ok;
}
/* Set the timestamps of file DEST to match those of SRC_SB.
Return true if successful. */
static bool
change_timestamps (struct stat const *src_sb, char const *dest)
{
struct timespec timespec[2];
timespec[0] = get_stat_atime (src_sb);
timespec[1] = get_stat_mtime (src_sb);
if (utimens (dest, timespec))
{
error (0, errno, _("cannot set time stamps for %s"), quote (dest));
return false;
}
return true;
}
/* Strip the symbol table from the file NAME.
We could dig the magic number out of the file first to
determine whether to strip it, but the header files and
magic numbers vary so much from system to system that making
it portable would be very difficult. Not worth the effort. */
static void
strip (char const *name)
{
int status;
pid_t pid = fork ();
switch (pid)
{
case -1:
error (EXIT_FAILURE, errno, _("fork system call failed"));
break;
case 0: /* Child. */
execlp (strip_program, strip_program, name, NULL);
error (EXIT_FAILURE, errno, _("cannot run %s"), strip_program);
break;
default: /* Parent. */
if (waitpid (pid, &status, 0) < 0)
error (EXIT_FAILURE, errno, _("waiting for strip"));
else if (! WIFEXITED (status) || WEXITSTATUS (status))
error (EXIT_FAILURE, 0, _("strip process terminated abnormally"));
break;
}
}
/* Initialize the user and group ownership of the files to install. */
static void
get_ids (void)
{
struct passwd *pw;
struct group *gr;
if (owner_name)
{
pw = getpwnam (owner_name);
if (pw == NULL)
{
unsigned long int tmp;
if (xstrtoul (owner_name, NULL, 0, &tmp, NULL) != LONGINT_OK
|| UID_T_MAX < tmp)
error (EXIT_FAILURE, 0, _("invalid user %s"), quote (owner_name));
owner_id = tmp;
}
else
owner_id = pw->pw_uid;
endpwent ();
}
else
owner_id = (uid_t) -1;
if (group_name)
{
gr = getgrnam (group_name);
if (gr == NULL)
{
unsigned long int tmp;
if (xstrtoul (group_name, NULL, 0, &tmp, NULL) != LONGINT_OK
|| GID_T_MAX < tmp)
error (EXIT_FAILURE, 0, _("invalid group %s"), quote (group_name));
group_id = tmp;
}
else
group_id = gr->gr_gid;
endgrent ();
}
else
group_id = (gid_t) -1;
}
void
usage (int status)
{
if (status != EXIT_SUCCESS)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... [-T] SOURCE DEST\n\
or: %s [OPTION]... SOURCE... DIRECTORY\n\
or: %s [OPTION]... -t DIRECTORY SOURCE...\n\
or: %s [OPTION]... -d DIRECTORY...\n\
"),
program_name, program_name, program_name, program_name);
fputs (_("\
\n\
This install program copies files (often just compiled) into destination\n\
locations you choose. If you want to download and install a ready-to-use\n\
package on a GNU/Linux system, you should instead be using a package manager\n\
like yum(1) or apt-get(1).\n\
\n\
In the first three forms, copy SOURCE to DEST or multiple SOURCE(s) to\n\
the existing DIRECTORY, while setting permission modes and owner/group.\n\
In the 4th form, create all components of the given DIRECTORY(ies).\n\
\n\
"), stdout);
fputs (_("\
Mandatory arguments to long options are mandatory for short options too.\n\
"), stdout);
fputs (_("\
--backup[=CONTROL] make a backup of each existing destination file\n\
-b like --backup but does not accept an argument\n\
-c (ignored)\n\
-C, --compare compare each pair of source and destination files, and\n\
in some cases, do not modify the destination at all\n\
-d, --directory treat all arguments as directory names; create all\n\
components of the specified directories\n\
"), stdout);
fputs (_("\
-D create all leading components of DEST except the last,\n\
then copy SOURCE to DEST\n\
-g, --group=GROUP set group ownership, instead of process' current group\n\
-m, --mode=MODE set permission mode (as in chmod), instead of rwxr-xr-x\n\
-o, --owner=OWNER set ownership (super-user only)\n\
"), stdout);
fputs (_("\
-p, --preserve-timestamps apply access/modification times of SOURCE files\n\
to corresponding destination files\n\
-s, --strip strip symbol tables\n\
--strip-program=PROGRAM program used to strip binaries\n\
-S, --suffix=SUFFIX override the usual backup suffix\n\
-t, --target-directory=DIRECTORY copy all SOURCE arguments into DIRECTORY\n\
-T, --no-target-directory treat DEST as a normal file\n\
-v, --verbose print the name of each directory as it is created\n\
"), stdout);
fputs (_("\
--preserve-context preserve SELinux security context\n\
-Z, --context=CONTEXT set SELinux security context of files and directories\
\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\
The version control method may be selected via the --backup option or through\n\
the VERSION_CONTROL environment variable. Here are the values:\n\
\n\
"), stdout);
fputs (_("\
none, off never make backups (even if --backup is given)\n\
numbered, t make numbered backups\n\
existing, nil numbered if numbered backups exist, simple otherwise\n\
simple, never always make simple backups\n\
"), stdout);
emit_ancillary_info ();
}
exit (status);
}
/* Copy file FROM onto file TO and give TO the appropriate
attributes.
Return true if successful. */
static bool
install_file_in_file (const char *from, const char *to,
const struct cp_options *x)
{
struct stat from_sb;
if (x->preserve_timestamps && stat (from, &from_sb) != 0)
{
error (0, errno, _("cannot stat %s"), quote (from));
return false;
}
if (! copy_file (from, to, x))
return false;
if (strip_files)
strip (to);
if (x->preserve_timestamps && (strip_files || ! S_ISREG (from_sb.st_mode))
&& ! change_timestamps (&from_sb, to))
return false;
return change_attributes (to);
}
/* Copy file FROM onto file TO, creating any missing parent directories of TO.
Return true if successful. */
static bool
install_file_in_file_parents (char const *from, char *to,
struct cp_options *x)
{
bool save_working_directory =
! (IS_ABSOLUTE_FILE_NAME (from) && IS_ABSOLUTE_FILE_NAME (to));
int status = EXIT_SUCCESS;
struct savewd wd;
savewd_init (&wd);
if (! save_working_directory)
savewd_finish (&wd);
if (mkancesdirs (to, &wd, make_ancestor, x) == -1)
{
error (0, errno, _("cannot create directory %s"), to);
status = EXIT_FAILURE;
}
if (save_working_directory)
{
int restore_result = savewd_restore (&wd, status);
int restore_errno = errno;
savewd_finish (&wd);
if (EXIT_SUCCESS < restore_result)
return false;
if (restore_result < 0 && status == EXIT_SUCCESS)
{
error (0, restore_errno, _("cannot create directory %s"), to);
return false;
}
}
return (status == EXIT_SUCCESS && install_file_in_file (from, to, x));
}
/* Copy file FROM into directory TO_DIR, keeping its same name,
and give the copy the appropriate attributes.
Return true if successful. */
static bool
install_file_in_dir (const char *from, const char *to_dir,
const struct cp_options *x)
{
const char *from_base = last_component (from);
char *to = file_name_concat (to_dir, from_base, NULL);
bool ret = install_file_in_file (from, to, x);
free (to);
return ret;
}
int
main (int argc, char **argv)
{
@@ -529,10 +835,6 @@ main (int argc, char **argv)
no_target_directory = true;
break;
case PRESERVE_CONTEXT_OPTION_DEPRECATED:
error (0, 0, _("WARNING: --preserve_context is deprecated; "
"use --preserve-context instead"));
/* fall through */
case PRESERVE_CONTEXT_OPTION:
if ( ! selinux_enabled)
{
@@ -681,330 +983,3 @@ main (int argc, char **argv)
exit (exit_status);
}
/* Copy file FROM onto file TO, creating any missing parent directories of TO.
Return true if successful. */
static bool
install_file_in_file_parents (char const *from, char *to,
struct cp_options *x)
{
bool save_working_directory =
! (IS_ABSOLUTE_FILE_NAME (from) && IS_ABSOLUTE_FILE_NAME (to));
int status = EXIT_SUCCESS;
struct savewd wd;
savewd_init (&wd);
if (! save_working_directory)
savewd_finish (&wd);
if (mkancesdirs (to, &wd, make_ancestor, x) == -1)
{
error (0, errno, _("cannot create directory %s"), to);
status = EXIT_FAILURE;
}
if (save_working_directory)
{
int restore_result = savewd_restore (&wd, status);
int restore_errno = errno;
savewd_finish (&wd);
if (EXIT_SUCCESS < restore_result)
return false;
if (restore_result < 0 && status == EXIT_SUCCESS)
{
error (0, restore_errno, _("cannot create directory %s"), to);
return false;
}
}
return (status == EXIT_SUCCESS && install_file_in_file (from, to, x));
}
/* Copy file FROM onto file TO and give TO the appropriate
attributes.
Return true if successful. */
static bool
install_file_in_file (const char *from, const char *to,
const struct cp_options *x)
{
struct stat from_sb;
if (x->preserve_timestamps && stat (from, &from_sb) != 0)
{
error (0, errno, _("cannot stat %s"), quote (from));
return false;
}
if (! copy_file (from, to, x))
return false;
if (strip_files)
strip (to);
if (x->preserve_timestamps && (strip_files || ! S_ISREG (from_sb.st_mode))
&& ! change_timestamps (&from_sb, to))
return false;
return change_attributes (to);
}
/* Copy file FROM into directory TO_DIR, keeping its same name,
and give the copy the appropriate attributes.
Return true if successful. */
static bool
install_file_in_dir (const char *from, const char *to_dir,
const struct cp_options *x)
{
const char *from_base = last_component (from);
char *to = file_name_concat (to_dir, from_base, NULL);
bool ret = install_file_in_file (from, to, x);
free (to);
return ret;
}
/* Copy file FROM onto file TO, creating TO if necessary.
Return true if successful. */
static bool
copy_file (const char *from, const char *to, const struct cp_options *x)
{
bool copy_into_self;
if (copy_only_if_needed && !need_copy (from, to, x))
return true;
/* Allow installing from non-regular files like /dev/null.
Charles Karney reported that some Sun version of install allows that
and that sendmail's installation process relies on the behavior.
However, since !x->recursive, the call to "copy" will fail if FROM
is a directory. */
return copy (from, to, false, x, &copy_into_self, NULL);
}
/* Set the attributes of file or directory NAME.
Return true if successful. */
static bool
change_attributes (char const *name)
{
bool ok = false;
/* chown must precede chmod because on some systems,
chown clears the set[ug]id bits for non-superusers,
resulting in incorrect permissions.
On System V, users can give away files with chown and then not
be able to chmod them. So don't give files away.
We don't normally ignore errors from chown because the idea of
the install command is that the file is supposed to end up with
precisely the attributes that the user specified (or defaulted).
If the file doesn't end up with the group they asked for, they'll
want to know. */
if (! (owner_id == (uid_t) -1 && group_id == (gid_t) -1)
&& lchown (name, owner_id, group_id) != 0)
error (0, errno, _("cannot change ownership of %s"), quote (name));
else if (chmod (name, mode) != 0)
error (0, errno, _("cannot change permissions of %s"), quote (name));
else
ok = true;
if (use_default_selinux_context)
setdefaultfilecon (name);
return ok;
}
/* Set the timestamps of file TO to match those of file FROM.
Return true if successful. */
static bool
change_timestamps (struct stat const *from_sb, char const *to)
{
struct timespec timespec[2];
timespec[0] = get_stat_atime (from_sb);
timespec[1] = get_stat_mtime (from_sb);
if (utimens (to, timespec))
{
error (0, errno, _("cannot set time stamps for %s"), quote (to));
return false;
}
return true;
}
/* Strip the symbol table from the file NAME.
We could dig the magic number out of the file first to
determine whether to strip it, but the header files and
magic numbers vary so much from system to system that making
it portable would be very difficult. Not worth the effort. */
static void
strip (char const *name)
{
int status;
pid_t pid = fork ();
switch (pid)
{
case -1:
error (EXIT_FAILURE, errno, _("fork system call failed"));
break;
case 0: /* Child. */
execlp (strip_program, strip_program, name, NULL);
error (EXIT_FAILURE, errno, _("cannot run %s"), strip_program);
break;
default: /* Parent. */
if (waitpid (pid, &status, 0) < 0)
error (EXIT_FAILURE, errno, _("waiting for strip"));
else if (! WIFEXITED (status) || WEXITSTATUS (status))
error (EXIT_FAILURE, 0, _("strip process terminated abnormally"));
break;
}
}
/* Initialize the user and group ownership of the files to install. */
static void
get_ids (void)
{
struct passwd *pw;
struct group *gr;
if (owner_name)
{
pw = getpwnam (owner_name);
if (pw == NULL)
{
unsigned long int tmp;
if (xstrtoul (owner_name, NULL, 0, &tmp, NULL) != LONGINT_OK
|| UID_T_MAX < tmp)
error (EXIT_FAILURE, 0, _("invalid user %s"), quote (owner_name));
owner_id = tmp;
}
else
owner_id = pw->pw_uid;
endpwent ();
}
else
owner_id = (uid_t) -1;
if (group_name)
{
gr = getgrnam (group_name);
if (gr == NULL)
{
unsigned long int tmp;
if (xstrtoul (group_name, NULL, 0, &tmp, NULL) != LONGINT_OK
|| GID_T_MAX < tmp)
error (EXIT_FAILURE, 0, _("invalid group %s"), quote (group_name));
group_id = tmp;
}
else
group_id = gr->gr_gid;
endgrent ();
}
else
group_id = (gid_t) -1;
}
/* Report that directory DIR was made, if OPTIONS requests this. */
static void
announce_mkdir (char const *dir, void *options)
{
struct cp_options const *x = options;
if (x->verbose)
prog_fprintf (stdout, _("creating directory %s"), quote (dir));
}
/* Make ancestor directory DIR, whose last file name component is
COMPONENT, with options OPTIONS. Assume the working directory is
COMPONENT's parent. */
static int
make_ancestor (char const *dir, char const *component, void *options)
{
int r = mkdir (component, DEFAULT_MODE);
if (r == 0)
announce_mkdir (dir, options);
return r;
}
void
usage (int status)
{
if (status != EXIT_SUCCESS)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... [-T] SOURCE DEST\n\
or: %s [OPTION]... SOURCE... DIRECTORY\n\
or: %s [OPTION]... -t DIRECTORY SOURCE...\n\
or: %s [OPTION]... -d DIRECTORY...\n\
"),
program_name, program_name, program_name, program_name);
fputs (_("\
\n\
This install program copies files (often just compiled) into destination\n\
locations you choose. If you want to download and install a ready-to-use\n\
package on a GNU/Linux system, you should instead be using a package manager\n\
like yum(1) or apt-get(1).\n\
\n\
In the first three forms, copy SOURCE to DEST or multiple SOURCE(s) to\n\
the existing DIRECTORY, while setting permission modes and owner/group.\n\
In the 4th form, create all components of the given DIRECTORY(ies).\n\
\n\
"), stdout);
fputs (_("\
Mandatory arguments to long options are mandatory for short options too.\n\
"), stdout);
fputs (_("\
--backup[=CONTROL] make a backup of each existing destination file\n\
-b like --backup but does not accept an argument\n\
-c (ignored)\n\
-C, --compare compare each pair of source and destination files, and\n\
in some cases, do not modify the destination at all\n\
-d, --directory treat all arguments as directory names; create all\n\
components of the specified directories\n\
"), stdout);
fputs (_("\
-D create all leading components of DEST except the last,\n\
then copy SOURCE to DEST\n\
-g, --group=GROUP set group ownership, instead of process' current group\n\
-m, --mode=MODE set permission mode (as in chmod), instead of rwxr-xr-x\n\
-o, --owner=OWNER set ownership (super-user only)\n\
"), stdout);
fputs (_("\
-p, --preserve-timestamps apply access/modification times of SOURCE files\n\
to corresponding destination files\n\
-s, --strip strip symbol tables\n\
--strip-program=PROGRAM program used to strip binaries\n\
-S, --suffix=SUFFIX override the usual backup suffix\n\
-t, --target-directory=DIRECTORY copy all SOURCE arguments into DIRECTORY\n\
-T, --no-target-directory treat DEST as a normal file\n\
-v, --verbose print the name of each directory as it is created\n\
"), stdout);
fputs (_("\
--preserve-context preserve SELinux security context\n\
-Z, --context=CONTEXT set SELinux security context of files and directories\
\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\
The version control method may be selected via the --backup option or through\n\
the VERSION_CONTROL environment variable. Here are the values:\n\
\n\
"), stdout);
fputs (_("\
none, off never make backups (even if --backup is given)\n\
numbered, t make numbered backups\n\
existing, nil numbered if numbered backups exist, simple otherwise\n\
simple, never always make simple backups\n\
"), stdout);
emit_ancillary_info ();
}
exit (status);
}

View File

@@ -22,7 +22,7 @@
#include "system.h"
#include "verify.h"
/* Note currently for glibc (2.3.5) the following call does not change the
/* Note currently for glibc (2.3.5) the following call does not change
the buffer size, and more problematically does not give any indication
that the new size request was ignored:

View File

@@ -1131,8 +1131,8 @@ is_colored (enum indicator_no type)
size_t len = color_indicator[type].len;
char const *s = color_indicator[type].string;
return ! (len == 0
|| (len == 1 && strncmp (s, "0", 1) == 0)
|| (len == 2 && strncmp (s, "00", 2) == 0));
|| (len == 1 && STRNCMP_LIT (s, "0") == 0)
|| (len == 2 && STRNCMP_LIT (s, "00") == 0));
}
static void
@@ -1996,7 +1996,7 @@ decode_switches (int argc, char **argv)
if (! (style = getenv ("TIME_STYLE")))
style = bad_cast ("locale");
while (strncmp (style, posix_prefix, sizeof posix_prefix - 1) == 0)
while (STREQ_LEN (style, posix_prefix, sizeof posix_prefix - 1))
{
if (! hard_locale (LC_TIME))
return optind;
@@ -2388,7 +2388,7 @@ parse_ls_color (void)
}
if (color_indicator[C_LINK].len == 6
&& !strncmp (color_indicator[C_LINK].string, "target", 6))
&& !STRNCMP_LIT (color_indicator[C_LINK].string, "target"))
color_symlink_as_referent = true;
}
@@ -4178,7 +4178,7 @@ print_color_indicator (const struct fileinfo *f, bool symlink_target)
}
else if (S_ISLNK (mode))
type = ((!linkok
&& (!strncmp (color_indicator[C_LINK].string, "target", 6)
&& (!STRNCMP_LIT (color_indicator[C_LINK].string, "target")
|| color_indicator[C_ORPHAN].string))
? C_ORPHAN : C_LINK);
else if (S_ISFIFO (mode))
@@ -4209,8 +4209,8 @@ print_color_indicator (const struct fileinfo *f, bool symlink_target)
for (ext = color_ext_list; ext != NULL; ext = ext->next)
{
if (ext->ext.len <= len
&& strncmp (name - ext->ext.len, ext->ext.string,
ext->ext.len) == 0)
&& STREQ_LEN (name - ext->ext.len, ext->ext.string,
ext->ext.len))
break;
}
}

View File

@@ -262,7 +262,7 @@ split_3 (char *s, size_t s_len,
/* Check for BSD-style checksum line. */
algo_name_len = strlen (DIGEST_TYPE_STRING);
if (strncmp (s + i, DIGEST_TYPE_STRING, algo_name_len) == 0)
if (STREQ_LEN (s + i, DIGEST_TYPE_STRING, algo_name_len))
{
if (s[i + algo_name_len] == ' ')
++i;

View File

@@ -109,12 +109,16 @@ struct rlimit { size_t rlim_cur; };
and is responsible for merging TOTAL lines. */
#define MAX_MERGE(total, level) (((total) >> (2 * ((level) + 1))) + 1)
/* Heuristic value for the number of lines for which it is worth
creating a subthread, during an internal merge sort, on a machine
that has processors galore. Currently this number is just a guess.
This value must be at least 4. We don't know of any machine where
this number has any practical effect. */
enum { SUBTHREAD_LINES_HEURISTIC = 4 };
/* Heuristic value for the number of lines for which it is worth creating
a subthread, during an internal merge sort. I.e., it is a small number
of "average" lines for which sorting via two threads is faster than
sorting via one on an "average" system. On an dual-core 2.0 GHz i686
system with 3GB of RAM and 2MB of L2 cache, a file containing 128K
lines of gensort -a output is sorted slightly faster with --parallel=2
than with --parallel=1. By contrast, using --parallel=1 is about 10%
faster than using --parallel=2 with a 64K-line input. */
enum { SUBTHREAD_LINES_HEURISTIC = 128 * 1024 };
verify (4 <= SUBTHREAD_LINES_HEURISTIC);
/* The number of threads after which there are
diminishing performance gains. */
@@ -315,8 +319,12 @@ static size_t merge_buffer_size = MAX (MIN_MERGE_BUFFER_SIZE, 256 * 1024);
specified by the user. Zero if the user has not specified a size. */
static size_t sort_size;
/* The guessed size for non-regular files. */
#define INPUT_FILE_SIZE_GUESS (1024 * 1024)
/* The initial allocation factor for non-regular files.
This is used, e.g., when reading from a pipe.
Don't make it too big, since it is multiplied by ~130 to
obtain the size of the actual buffer sort will allocate.
Also, there may be 8 threads all doing this at the same time. */
#define INPUT_FILE_SIZE_GUESS (128 * 1024)
/* Array of directory names in which any temporary files are to be created. */
static char const **temp_dirs;

View File

@@ -895,12 +895,12 @@ main (int argc, char **argv)
/* skip any whitespace */
while (isspace (to_uchar (*optarg)))
optarg++;
if (strncmp (optarg, "r/", 2) == 0)
if (STRNCMP_LIT (optarg, "r/") == 0)
{
split_type = type_rr;
optarg += 2;
}
else if (strncmp (optarg, "l/", 2) == 0)
else if (STRNCMP_LIT (optarg, "l/") == 0)
{
split_type = type_chunk_lines;
optarg += 2;

View File

@@ -209,7 +209,7 @@ set_LD_PRELOAD (void)
char const *const *path = search_path;
char *libstdbuf;
do
while (true)
{
struct stat sb;
@@ -224,8 +224,11 @@ set_LD_PRELOAD (void)
if (stat (libstdbuf, &sb) == 0) /* file_exists */
break;
free (libstdbuf);
++path;
if ( ! *path)
error (EXIT_CANCELED, 0, _("failed to find %s"), quote (LIB_NAME));
}
while (*++path);
/* FIXME: Do we need to support libstdbuf.dll, c:, '\' separators etc? */

View File

@@ -257,6 +257,13 @@ select_plural (uintmax_t n)
}
#define STREQ(a, b) (strcmp (a, b) == 0)
#define STREQ_LEN(a, b, n) (strncmp (a, b, n) == 0)
#define STRPREFIX(a, b) (strncmp(a, b, strlen (b)) == 0)
/* Just like strncmp, but the first argument must be a literal string
and you don't specify the length. */
#define STRNCMP_LIT(s, literal) \
strncmp (s, "" literal "", sizeof (literal) - 1)
#if !HAVE_DECL_GETLOGIN
char *getlogin ();
@@ -607,7 +614,7 @@ emit_ancillary_info (void)
/* Don't output this redundant message for English locales.
Note we still output for 'C' so that it gets included in the man page. */
const char *lc_messages = setlocale (LC_MESSAGES, NULL);
if (lc_messages && strncmp (lc_messages, "en_", 3))
if (lc_messages && STRNCMP_LIT (lc_messages, "en_"))
{
/* TRANSLATORS: Replace LANG_CODE in this URL with your language code
<http://translationproject.org/team/LANG_CODE.html> to form one of

View File

@@ -173,7 +173,8 @@ get_mtime (char const *filename, struct timespec *mtime)
static bool
binop (char const *s)
{
return ((STREQ (s, "=")) || (STREQ (s, "!=")) || (STREQ (s, "-nt")) ||
return ((STREQ (s, "=")) || (STREQ (s, "!=")) || (STREQ (s, "==")) ||
(STREQ (s, "-nt")) ||
(STREQ (s, "-ot")) || (STREQ (s, "-ef")) || (STREQ (s, "-eq")) ||
(STREQ (s, "-ne")) || (STREQ (s, "-lt")) || (STREQ (s, "-le")) ||
(STREQ (s, "-gt")) || (STREQ (s, "-ge")));
@@ -360,7 +361,8 @@ binary_operator (bool l_is_l)
test_syntax_error (_("unknown binary operator"), argv[op]);
}
if (argv[op][0] == '=' && !argv[op][1])
if (argv[op][0] == '=' && (!argv[op][1] ||
((argv[op][1] == '=') && !argv[op][2])))
{
bool value = STREQ (argv[pos], argv[pos + 2]);
pos += 3;

View File

@@ -548,7 +548,7 @@ look_up_char_class (char const *class_str, size_t len)
enum Char_class i;
for (i = 0; i < ARRAY_CARDINALITY (char_class_name); i++)
if (strncmp (class_str, char_class_name[i], len) == 0
if (STREQ_LEN (class_str, char_class_name[i], len)
&& strlen (char_class_name[i]) == len)
return i;
return CC_NO_CLASS;

View File

@@ -333,7 +333,7 @@ main (int argc, char **argv)
/* Hack "safely" around the ppc vs. powerpc return value. */
if (cputype == CPU_TYPE_POWERPC
&& strncmp (element, "ppc", 3) == 0)
&& STRNCMP_LIT (element, "ppc") == 0)
element = "powerpc";
}
# endif

View File

@@ -151,11 +151,7 @@ print_uptime (size_t n, const STRUCT_UTMP *this)
printf (ngettext ("%lu user", "%lu users", entries),
(unsigned long int) entries);
#if defined HAVE_GETLOADAVG || defined C_GETLOADAVG
loads = getloadavg (avg, 3);
#else
loads = -1;
#endif
if (loads == -1)
putchar ('\n');

View File

@@ -709,6 +709,9 @@ main (int argc, char **argv)
ai = argv_iter_init_argv (files);
}
if (!ai)
xalloc_die ();
fstatus = get_input_fstatus (nfiles, files);
number_width = compute_number_width (nfiles, fstatus);
@@ -719,16 +722,17 @@ main (int argc, char **argv)
bool skip_file = false;
enum argv_iter_err ai_err;
char *file_name = argv_iter (ai, &ai_err);
if (ai_err == AI_ERR_EOF)
break;
if (!file_name)
{
switch (ai_err)
{
case AI_ERR_EOF:
goto argv_iter_done;
case AI_ERR_READ:
error (EXIT_FAILURE, errno, _("%s: read error"),
quote (files_from));
continue;
error (0, errno, _("%s: read error"),
quotearg_colon (files_from));
ok = false;
goto argv_iter_done;
case AI_ERR_MEM:
xalloc_die ();
default:
@@ -770,6 +774,7 @@ main (int argc, char **argv)
else
ok &= wc_file (file_name, &fstatus[nfiles ? i : 0]);
}
argv_iter_done:
/* No arguments on the command line is fine. That means read from stdin.
However, no arguments on the --files0-from input stream is an error

View File

@@ -584,7 +584,7 @@ scan_entries (size_t n, const STRUCT_UTMP *utmp_buf)
ttyname_b = ttyname (STDIN_FILENO);
if (!ttyname_b)
return;
if (strncmp (ttyname_b, DEV_DIR_WITH_TRAILING_SLASH, DEV_DIR_LEN) == 0)
if (STRNCMP_LIT (ttyname_b, DEV_DIR_WITH_TRAILING_SLASH) == 0)
ttyname_b += DEV_DIR_LEN; /* Discard /dev/ prefix. */
}

View File

@@ -11,6 +11,7 @@ EXTRA_DIST = \
check.mk \
envvar-check \
filefrag-extent-compare \
fiemap-capable \
init.cfg \
init.sh \
lang-default \
@@ -26,7 +27,7 @@ root_tests = \
cp/special-bits \
cp/cp-mv-enotsup-xattr \
cp/capability \
cp/sparse-fiemap \
cp/sparse-fiemap \
dd/skip-seek-past-dev \
install/install-C-root \
ls/capability \
@@ -320,6 +321,7 @@ TESTS = \
cp/dir-vs-file \
cp/existing-perm-race \
cp/fail-perm \
cp/fiemap-empty \
cp/fiemap-perf \
cp/fiemap-2 \
cp/file-perm-race \
@@ -327,6 +329,7 @@ TESTS = \
cp/link \
cp/link-no-deref \
cp/link-preserve \
cp/link-symlink \
cp/no-deref-link1 \
cp/no-deref-link2 \
cp/no-deref-link3 \
@@ -351,6 +354,7 @@ TESTS = \
df/unreadable \
dd/direct \
dd/misc \
dd/nocache \
dd/not-rewound \
dd/reblock \
dd/skip-seek \
@@ -369,6 +373,7 @@ TESTS = \
du/exclude \
du/fd-leak \
du/files0-from \
du/files0-from-dir \
du/hard-link \
du/inacc-dest \
du/inacc-dir \

View File

@@ -40,8 +40,13 @@ vc_exe_in_TESTS: Makefile
check: vc_exe_in_TESTS
.PHONY: vc_exe_in_TESTS
built_programs = \
(cd $(top_builddir)/src && MAKEFLAGS= $(MAKE) -s built_programs.list)
CLEANFILES =
CLEANFILES += .built-programs
check-am: .built-programs
.built-programs:
$(AM_V_GEN)(cd $(top_builddir)/src \
&& MAKEFLAGS= $(MAKE) -s built_programs.list) \
> $@-t && mv $@-t $@
# Note that the first lines are statements. They ensure that environment
# variables that can perturb tests are unset or set to expected values.
@@ -76,7 +81,7 @@ TESTS_ENVIRONMENT = \
abs_top_builddir='$(abs_top_builddir)' \
abs_top_srcdir='$(abs_top_srcdir)' \
abs_srcdir='$(abs_srcdir)' \
built_programs="`$(built_programs)`" \
built_programs="`cat .built-programs`" \
host_os=$(host_os) \
host_triplet='$(host_triplet)' \
srcdir='$(srcdir)' \

View File

@@ -20,7 +20,8 @@
print_ver_ cp
# Require a fiemap-enabled FS.
fiemap_capable_ . \
touch fiemap_chk # check a file rather than current dir for best coverage
fiemap_capable_ fiemap_chk \
|| skip_ "this file system lacks FIEMAP support"
# Exercise the code that handles a file ending in a hole.

96
tests/cp/fiemap-empty Executable file
View File

@@ -0,0 +1,96 @@
#!/bin/sh
# Test cp reads unwritten extents efficiently
# Copyright (C) 2011 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 <http://www.gnu.org/licenses/>.
. "${srcdir=.}/init.sh"; path_prepend_ ../src
print_ver_ cp
touch fiemap_chk
fiemap_capable_ fiemap_chk ||
skip_test_ '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_test_ 'The fallocate utility is required'
fallocate -l 1 -n falloc.test ||
skip_test_ '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_test_ '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_test_ 'the `filefrag` utility is missing'
filefrag -v space.test | grep -F 'unwritten' > /dev/null ||
skip_test_ '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

View File

@@ -20,12 +20,24 @@
print_ver_ cp
# Require a fiemap-enabled FS.
fiemap_capable_ . \
|| skip_ "this file system lacks FIEMAP support"
touch fiemap_chk
fiemap_capable_ fiemap_chk ||
skip_ "this file system lacks FIEMAP support"
# Exclude ext3 (or unknown fs types)
# as the emulated extent scanning is slow
df -t ext3 . >/dev/null &&
skip_ "ext3 has known slow FIEMAP scanning"
# Create a large-but-sparse file.
timeout 10 truncate -s1T f || framework_failure_
# Disable this test on old BTRFS (e.g. Fedora 14)
# which reports (unwritten) extents for holes.
filefrag f || skip_test_ 'the `filefrag` utility is missing'
filefrag f | grep -F ': 0 extents found' > /dev/null ||
skip_test_ 'this file system reports extents for holes'
# Nothing can read (much less write) that many bytes in so little time.
timeout 10 cp f f2 || fail=1

41
tests/cp/link-symlink Executable file
View File

@@ -0,0 +1,41 @@
#!/bin/sh
# Ensure that cp -a --link maintains timestamps if possible
# Copyright (C) 2011 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 <http://www.gnu.org/licenses/>.
. "${srcdir=.}/init.sh"; path_prepend_ ../src
print_ver_ cp
# Check that the timestamps of the symlink are copied
# if we're using hardlink to symlink emulation.
touch file
ln -s file link || framework_failure
touch -m -h -d 2011-01-01 link ||
skip_test_ "Your system doesn't support updating symlink timestamps"
case `stat --format=%y link` in
2011-01-01*) ;;
*) skip_test_ "Your system doesn't support updating symlink timestamps" ;;
esac
# link.cp is probably a hardlink, but may also be a symlink
# In either case the timestamp should match the original.
cp -al link link.cp
case `stat --format=%y link.cp` in
2011-01-01*) ;;
*) fail=1 ;;
esac
Exit $fail

View File

@@ -52,14 +52,6 @@ t0() {
fi
}
t1() {
f=$1; shift
u=$1; shift
g=$1; shift
t0 "$f" "$u" "$g" setuidgid -g "$nameless_gid1,$nameless_gid2" \
"$nameless_uid" "$@"
}
nameless_uid=`$PERL -le '
foreach my $i (1000..16*1024-1)
{
@@ -105,6 +97,30 @@ t0 b1 "$nameless_uid" "$nameless_gid2" cp -p
t0 c0 0 "$nameless_gid1" cp -p
t0 c1 0 "$nameless_gid2" cp -p
# For the remaining tests, we need a cp binary that is accessible to a user
# with UID of $nameless_uid. The build directory may not be accessible,
# so create a temporary directory and copy cp into it, ensure that
# $nameless_uid can access it and then make that directory the search path.
tmp_path=
cleanup_() { rm -rf "$tmp_path"; }
# Cause mktemp to create a directory directly under /tmp.
# Setting TMPDIR explicitly is required here, in case $TMPDIR
# is not readable by our nameless IDs.
test -d /tmp && TMPDIR=/tmp
tmp_path=$(mktemp -d) || fail_ "failed to create temporary directory"
cp "$abs_path_dir_/cp" "$tmp_path"
chmod -R a+rx "$tmp_path"
t1() {
f=$1; shift
u=$1; shift
g=$1; shift
t0 "$f" "$u" "$g" \
setuidgid -g "$nameless_gid1,$nameless_gid2" \
"$nameless_uid" env PATH="$tmp_path" "$@"
}
t1 a0 "$nameless_uid" "$nameless_gid1" cp
t1 b0 "$nameless_uid" "$nameless_gid1" cp
t1 b1 "$nameless_uid" "$nameless_gid1" cp

View File

@@ -18,9 +18,13 @@
. "${srcdir=.}/init.sh"; path_prepend_ ../src
print_ver_ cp
$PERL -e 1 || skip_test_ 'you lack perl'
if fiemap_capable_ . ; then
: # Current dir is on a partition with working extents. Good!
# The test was seen to fail on ext3 so exclude that type
# (or any file system where the type can't be determined)
touch fiemap_chk
if fiemap_capable_ fiemap_chk && ! df -t ext3 . >/dev/null; then
: # Current partition has working extents. Good!
else
# It's not; we need to create one, hence we need root access.
require_root_
@@ -49,8 +53,6 @@ fi
# in which it calls ioctl (fd, FS_IOC_FIEMAP,...
# This also verifies that non-trivial extents are preserved.
$PERL -e 1 || skip_test_ 'skipping part of this test; you lack perl'
# Extract logical block number and length pairs from filefrag -v output.
# The initial sed is to remove the "eof" from the normally-empty "flags" field.
# Similarly, remove flags values like "unknown,delalloc,eof".
@@ -66,39 +68,41 @@ for i in $(seq 1 2 21); do
$PERL -e 'BEGIN { $n = '$i' * 1024; *F = *STDOUT }' \
-e 'for (1..'$j') { sysseek (*F, $n, 1)' \
-e '&& syswrite (*F, chr($_)x$n) or die "$!"}' > j1 || fail=1
# sync
# Note there is an implicit sync performed by cp on Linux kernels
# before 2.6.39 to work around bugs in EXT4 and BTRFS.
# Note also the -s parameter to the filefrag commands below
# for the same reasons.
cp --sparse=always j1 j2 || fail=1
# sync
# Technically we may need the 'sync' uses above, but
# uncommenting them makes this test take much longer.
cmp j1 j2 || fail=1
filefrag -v j1 | grep extent \
|| skip_test_ 'skipping part of this test; you lack filefrag'
if ! filefrag -vs j1 | grep -F extent >/dev/null; then
test $skip != 1 && warn_ 'skipping part; you lack filefrag'
skip=1
else
# Here is sample filefrag output:
# $ perl -e 'BEGIN{$n=16*1024; *F=*STDOUT}' \
# -e 'for (1..5) { sysseek(*F,$n,1)' \
# -e '&& syswrite *F,"."x$n or die "$!"}' > j
# $ filefrag -v j
# File system type is: ef53
# File size of j is 163840 (40 blocks, blocksize 4096)
# ext logical physical expected length flags
# 0 4 6258884 4
# 1 12 6258892 6258887 4
# 2 20 6258900 6258895 4
# 3 28 6258908 6258903 4
# 4 36 6258916 6258911 4 eof
# j: 6 extents found
# Here is sample filefrag output:
# $ perl -e 'BEGIN{$n=16*1024; *F=*STDOUT}' \
# -e 'for (1..5) { sysseek(*F,$n,1)' \
# -e '&& syswrite *F,"."x$n or die "$!"}' > j
# $ filefrag -v j
# File system type is: ef53
# File size of j is 163840 (40 blocks, blocksize 4096)
# ext logical physical expected length flags
# 0 4 6258884 4
# 1 12 6258892 6258887 4
# 2 20 6258900 6258895 4
# 3 28 6258908 6258903 4
# 4 36 6258916 6258911 4 eof
# j: 6 extents found
# exclude the physical block numbers; they always differ
filefrag -v j1 > ff1 || fail=1
filefrag -v j2 > ff2 || fail=1
{ f ff1; f ff2; } \
| $PERL $abs_top_srcdir/tests/filefrag-extent-compare \
|| { fail=1; break; }
# exclude the physical block numbers; they always differ
filefrag -v j1 > ff1 || framework_failure
filefrag -vs j2 > ff2 || framework_failure
{ f ff1; f ff2; } | $PERL $abs_top_srcdir/tests/filefrag-extent-compare ||
fail=1
fi
test $fail = 1 && break 2
done
test $fail = 1 && break
done
Exit $fail

View File

@@ -26,6 +26,10 @@ timeout 10 cat pipe > copy &
truncate -s1M sparse || framework_failure_
cp sparse pipe || fail=1
# Ensure that the cat has completed before comparing.
wait
cmp sparse copy || fail=1
Exit $fail

58
tests/dd/nocache Executable file
View File

@@ -0,0 +1,58 @@
#!/bin/sh
# Ensure dd handles the 'nocache' flag
# Copyright (C) 2011 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 <http://www.gnu.org/licenses/>.
. "${srcdir=.}/init.sh"; path_prepend_ ../src
print_ver_ dd
# This should not call posix_fadvise
dd iflag=nocache oflag=nocache if=/dev/null of=/dev/null || fail=1
# We should get an error for trying to process a pipe
dd count=0 | dd iflag=nocache count=0 && fail=1
# O_DIRECT is orthogonal to drop cache so mutually exclusive
dd iflag=nocache,direct if=/dev/null && fail=1
# The rest ensure that the documented uses cases
# proceed without error
for f in ifile ofile; do
dd if=/dev/zero of=$f conv=fdatasync count=100 || framework_failure
done
# Advise to drop cache for whole file
if ! dd if=ifile iflag=nocache count=0 2>err; then
if grep -F 'Operation not supported' err >/dev/null; then
warn_ 'skipping part; this file system lacks support for posix_fadvise()'
skip=1
else
fail=1
fi
fi
if test "$skip" != 1; then
# Ensure drop cache for whole file
dd of=ofile oflag=nocache conv=notrunc,fdatasync count=0 || fail=1
# Drop cache for part of file
dd if=ifile iflag=nocache skip=10 count=10 of=/dev/null || fail=1
# Stream data just using readahead cache
dd if=ifile of=ofile iflag=nocache oflag=nocache || fail=1
fi
Exit $fail

39
tests/du/files0-from-dir Executable file
View File

@@ -0,0 +1,39 @@
#!/bin/sh
# ensure that du and wc handle --files0-from=DIR
# Copyright (C) 2011 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 <http://www.gnu.org/licenses/>.
. "${srcdir=.}/init.sh"; path_prepend_ ../src
print_ver_ du wc
mkdir dir
# Skip this test if reading from a directory succeeds.
# In that case, using --files0-from=dir would yield garbage,
# interpreting the directory entry as a sequence of
# NUL-separated file names.
cat dir > /dev/null && skip_ "cat dir/ succeeds"
for prog in du wc; do
$prog --files0-from=dir > /dev/null 2>err && fail=1
printf "$prog: dir:\n" > exp || fail=1
# The diagnostic string is usually "Is a directory" (ENOTDIR),
# but accept a different string or errno value.
sed 's/dir:.*/dir:/' err > k; mv k err
compare err exp || fail=1
done
Exit $fail

16
tests/fiemap-capable Normal file
View File

@@ -0,0 +1,16 @@
import struct, fcntl, sys, os
def sizeof(t): return struct.calcsize(t)
IOCPARM_MASK = 0x7f
IOC_OUT = 0x40000000
IOC_IN = 0x80000000
IOC_INOUT = (IOC_IN|IOC_OUT)
def _IOWR(x,y,t): return (IOC_INOUT|((sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|y)
try:
fd = os.open (len (sys.argv) == 2 and sys.argv[1] or '.', os.O_RDONLY)
struct_fiemap = '=qqllll'
FS_IOC_FIEMAP = _IOWR (ord ('f'), 11, struct_fiemap)
fcntl.ioctl (fd, FS_IOC_FIEMAP, struct.pack(struct_fiemap, 0,~0,0,0,0,0))
except:
sys.exit (1)

View File

@@ -28,30 +28,47 @@ my @b;
foreach my $i (0..@A/2-1) { $a[$i] = { L_BLK => $A[2*$i], LEN => $A[2*$i+1] } };
foreach my $i (0..@B/2-1) { $b[$i] = { L_BLK => $B[2*$i], LEN => $B[2*$i+1] } };
# Merge adjacent extents in array E.
sub merge_extents($)
{
my ($e) = @_;
my $i = 0;
while (1)
{
!defined $e->[$i+1]
and last;
$e->[$i]->{L_BLK} + $e->[$i]->{LEN} != $e->[$i+1]->{L_BLK}
and ++$i, next;
$e->[$i]->{LEN} += $e->[$i+1]->{LEN};
# Remove $e->[$i+1]
splice @$e, $i+1, 1;
}
}
merge_extents \@a;
merge_extents \@b;
@a == @b
or die "$ME: extent counts differ, even after adjustment\n";
my $i = 0;
my $j = 0;
while (1)
while (defined $a[$i])
{
!defined $a[$i] && !defined $b[$j]
and exit 0;
defined $a[$i] && defined $b[$j]
or die "\@a and \@b have different lengths, even after adjustment\n";
($a[$i]->{L_BLK} == $b[$j]->{L_BLK}
&& $a[$i]->{LEN} == $b[$j]->{LEN})
and next;
($a[$i]->{LEN} < $b[$j]->{LEN}
&& exists $a[$i+1] && $a[$i]->{LEN} + $a[$i+1]->{LEN} == $b[$j]->{LEN})
and ++$i, next;
exists $b[$j+1] && $a[$i]->{LEN} == $b[$i]->{LEN} + $b[$i+1]->{LEN}
and ++$j, next;
die "differing extent:\n"
. " [$i]=$a[$i]->{L_BLK} $a[$i]->{LEN}\n"
. " [$j]=$b[$j]->{L_BLK} $b[$j]->{LEN}\n"
}
continue
{
++$i;
++$j;
my $start_match = $a[$i]->{L_BLK} == $b[$i]->{L_BLK};
my $len_match = $a[$i]->{LEN} == $b[$i]->{LEN};
if ( ! ($start_match && ($len_match || $i == (@a - 1))))
{
# On XFS on Linux kernel 2.6.38, it was seen that the size of the
# last extent can vary, and can extend beyond the length of the file.
# So we ignore the length of the last extent, because if the
# file is the wrong length we'll get failures elsewhere.
die "$ME: differing extent:\n"
. " [$i]=$a[$i]->{L_BLK} $a[$i]->{LEN}\n"
. " [$i]=$b[$i]->{L_BLK} $b[$i]->{LEN}\n";
}
$i++;
}
### Setup "GNU" style for perl-mode and cperl-mode.

View File

@@ -151,6 +151,14 @@ require_built_()
test $skip_ = yes && skip_test_ "required program(s) not built"
}
require_file_system_bytes_free_()
{
local req=$1
local expr=$(stat -f --printf "$req / %S <= %a" .)
awk "BEGIN{ exit !($expr) }" \
|| skip_test_ "this test needs at least $req bytes of free space"
}
uid_is_privileged_()
{
# Make sure id -u succeeds.
@@ -216,6 +224,13 @@ skip_if_()
require_selinux_()
{
# When in a chroot of an SELinux-enabled system, but with a mock-simulated
# SELinux-*disabled* system, recognize that SELinux is disabled system wide:
grep 'selinuxfs$' /proc/filesystems > /dev/null \
|| skip_test_ "this system lacks SELinux support"
# Independent of whether SELinux is enabled system-wide,
# the current file system may lack SELinux support.
case `ls -Zd .` in
'? .'|'unlabeled .')
skip_test_ "this system (or maybe just" \
@@ -295,13 +310,16 @@ require_proc_pid_status_()
kill $pid
}
# Return nonzero if the specified directory is on a file system for
# which FIEMAP support exists, and the file system type is new enough
# (unlike ext2 and ext3) that it is hard to find an instance *without*
# FIEMAP support.
# Return nonzero if the specified path is on a file system for
# which FIEMAP support exists. Note some file systems (like ext3 and btrfs)
# only support FIEMAP for files, not directories.
fiemap_capable_()
{
df -T -t btrfs -t xfs -t ext4 -t ocfs2 -t gfs2 "$@"
if ! python < /dev/null; then
warn_ 'fiemap_capable_: python missing: assuming not fiemap capable'
return 1
fi
python $abs_srcdir/fiemap-capable "$@"
}
# Does the current (working-dir) file system support sparse files?

View File

@@ -74,10 +74,10 @@ Exit () { set +e; (exit $1); exit $1; }
# the reason for skip/failure to console, rather than to the .log files.
: ${stderr_fileno_=2}
warn_() { echo "$@" 1>&$stderr_fileno_; }
fail_() { warn_ "$ME_: failed test: $@"; Exit 1; }
skip_() { warn_ "$ME_: skipped test: $@"; Exit 77; }
framework_failure_() { warn_ "$ME_: set-up failure: $@"; Exit 99; }
warn_ () { echo "$@" 1>&$stderr_fileno_; }
fail_ () { warn_ "$ME_: failed test: $@"; Exit 1; }
skip_ () { warn_ "$ME_: skipped test: $@"; Exit 77; }
framework_failure_ () { warn_ "$ME_: set-up failure: $@"; Exit 99; }
# Sanitize this shell to POSIX mode, if possible.
DUALCASE=1; export DUALCASE
@@ -193,7 +193,7 @@ fi
test -n "$EXEEXT" && shopt -s expand_aliases
# Enable glibc's malloc-perturbing option.
# This is cheap and useful for exposing code that depends on the fact that
# This is useful for exposing code that depends on the fact that
# malloc-related functions often return memory that is mostly zeroed.
# If you have the time and cycles, use valgrind to do an even better job.
: ${MALLOC_PERTURB_=87}
@@ -202,22 +202,22 @@ export MALLOC_PERTURB_
# This is a stub function that is run upon trap (upon regular exit and
# interrupt). Override it with a per-test function, e.g., to unmount
# a partition, or to undo any other global state changes.
cleanup_() { :; }
cleanup_ () { :; }
if ( diff --version < /dev/null 2>&1 | grep GNU ) > /dev/null 2>&1; then
compare() { diff -u "$@"; }
compare () { diff -u "$@"; }
elif ( cmp --version < /dev/null 2>&1 | grep GNU ) > /dev/null 2>&1; then
compare() { cmp -s "$@"; }
compare () { cmp -s "$@"; }
else
compare() { cmp "$@"; }
compare () { cmp "$@"; }
fi
# An arbitrary prefix to help distinguish test directories.
testdir_prefix_() { printf gt; }
testdir_prefix_ () { printf gt; }
# Run the user-overridable cleanup_ function, remove the temporary
# directory and exit with the incoming value of $?.
remove_tmp_()
remove_tmp_ ()
{
__st=$?
cleanup_
@@ -233,7 +233,7 @@ remove_tmp_()
# contains only the specified bytes (see the case stmt below), then print
# a space-separated list of those names and return 0. Otherwise, don't
# print anything and return 1. Naming constraints apply also to DIR.
find_exe_basenames_()
find_exe_basenames_ ()
{
feb_dir_=$1
feb_fail_=0
@@ -266,7 +266,7 @@ find_exe_basenames_()
# PROG that simply invokes PROG.exe, then return 0. If any selected
# file name or the directory name, $1, contains an unexpected character,
# define no alias and return 1.
create_exe_shims_()
create_exe_shims_ ()
{
case $EXEEXT in
'') return 0 ;;
@@ -288,7 +288,7 @@ create_exe_shims_()
# Use this function to prepend to PATH an absolute name for each
# specified, possibly-$initial_cwd_-relative, directory.
path_prepend_()
path_prepend_ ()
{
while test $# != 0; do
path_dir_=$1
@@ -311,7 +311,7 @@ path_prepend_()
export PATH
}
setup_()
setup_ ()
{
if test "$VERBOSE" = yes; then
# Test whether set -x may cause the selected shell to corrupt an
@@ -364,7 +364,7 @@ setup_()
# - make only $MAX_TRIES_ attempts
# Helper function. Print $N pseudo-random bytes from a-zA-Z0-9.
rand_bytes_()
rand_bytes_ ()
{
n_=$1
@@ -396,7 +396,7 @@ rand_bytes_()
| LC_ALL=C tr -c $chars_ 01234567$chars_$chars_$chars_
}
mktempd_()
mktempd_ ()
{
case $# in
2);;

View File

@@ -27,7 +27,7 @@ umask 22
# Output time as something constant
export TIME_STYLE="+norm"
# helper to to strip ls columns up to "norm" time
# helper to strip ls columns up to "norm" time
qls() { sed 's/-r.*norm/norm/'; }
touch exe || framework_failure

View File

@@ -150,6 +150,10 @@ my @Tests =
{ERR=>$no_endpoint}],
['inval5', '-f', '1-,-', {IN=>''}, {OUT=>''}, {EXIT=>1}, {ERR=>$no_endpoint}],
['inval6', '-f', '-1,-', {IN=>''}, {OUT=>''}, {EXIT=>1}, {ERR=>$no_endpoint}],
# This would evoke a segfault from 5.3.0..6.10
['big-unbounded-b', '--output-d=:', '-b1234567890-', {IN=>''}, {OUT=>''}],
['big-unbounded-c', '--output-d=:', '-c1234567890-', {IN=>''}, {OUT=>''}],
['big-unbounded-f', '--output-d=:', '-f1234567890-', {IN=>''}, {OUT=>''}],
);
@Tests = triple_test \@Tests;

View File

@@ -226,7 +226,7 @@ id_setup () { args=-u; }
# Use env to avoid invoking built-in sleep of Solaris 11's /bin/sh.
kill_setup () {
env sleep 10m &
env sleep 31.5 &
args=$!
}

View File

@@ -104,7 +104,7 @@ retry_delay_ stdbuf_unbuffer .1 6 || fail=1
# Ensure block buffering stdout takes effect
# We don't currently test block buffering failures as
# this doesn't work on on GLIBC-2.7 or GLIBC-2.9 at least.
# this doesn't work on GLIBC-2.7 or GLIBC-2.9 at least.
# stdbuf_blockbuffer()
# {
# local delay="$1"

View File

@@ -132,6 +132,8 @@ my @Tests =
['streq-1', qw(t = t)],
['streq-2', qw(t = f), {EXIT=>1}],
['streqeq-1', qw(t == t)],
['streqeq-2', qw(t == f), {EXIT=>1}],
['streq-3', qw(! = !)],
['streq-4', qw(= = =)],
['streq-5', "'(' = '('"],

View File

@@ -47,8 +47,7 @@ version=`
`
case $version in
$PACKAGE_VERSION) ;;
*) echo "$0: cannot access just-built mv as user $NON_ROOT_USERNAME" 1>&2
fail=1 ;;
*) skip_ "cannot access just-built mv as user $NON_ROOT_USERNAME";;
esac
setuidgid $NON_ROOT_USERNAME env PATH="$PATH" \

View File

@@ -24,12 +24,12 @@ fi
. "${srcdir=.}/init.sh"; path_prepend_ ../src
expensive_
# Wait up to 10 seconds for grep REGEXP FILE to succeed.
# Wait several seconds for grep REGEXP FILE to succeed.
# Usage: grep_timeout REGEXP FILE
grep_timeout()
{
local j
for j in $(seq 100); do
for j in $(seq 150); do
grep $1 $2 > /dev/null && return 0
sleep 0.1
done