Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tail overhaul (--follow=name, etc.) #2695

Merged
merged 68 commits into from
Jun 7, 2022
Merged
Show file tree
Hide file tree
Changes from 66 commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
1f24b1f
tail: implement sub-second sleep interval e.g. `-s.1`
jhscheer Sep 16, 2021
a727b2e
tail: handle file NotFound error correctly
jhscheer Sep 16, 2021
fe3d020
tail: use crate `notify` for polling (implement `--disable-inotify`)
jhscheer Sep 18, 2021
a9066e2
tail: switch from Notify 4.0.17 to 5.0.0-pre.13
jhscheer Sep 23, 2021
c70b7a0
tail: implement `--follow=name`
jhscheer Sep 27, 2021
5615ba9
test_tail: add tests for `--follow=name`
jhscheer Sep 27, 2021
d9cd28f
test_tail: add tests for `--follow=name --disable-inotify` (polling)
jhscheer Sep 27, 2021
e935d40
tail: implement handling of truncate event for `--follow=name`
jhscheer Sep 28, 2021
22f78b1
tail: update README
jhscheer Sep 28, 2021
94cc966
tail: change notify backend on macOS from `FSEvents` to `kqueue`
jhscheer Oct 1, 2021
22b5928
Merge branch 'master' into tail_notify
jhscheer Oct 2, 2021
23d3e58
tail: improve file handling for `--follow=name`
jhscheer Oct 3, 2021
a120615
tail: fix the behavior for `-f` and rename events
jhscheer Oct 8, 2021
e3b3586
test_tail: clean up tests for `--follow=name`
jhscheer Oct 9, 2021
9338b3f
test_tail: add test_retry1-2
jhscheer Oct 24, 2021
8c5c528
test_tail: add test_retry3
jhscheer Oct 24, 2021
5770921
test_tail: add test_retry4
jhscheer Oct 24, 2021
4bfb462
test_tail: add test_retry5
jhscheer Oct 24, 2021
c7c5deb
test_tail: add test_retry6
jhscheer Oct 24, 2021
016291b
test_tail: add test_retr7
jhscheer Oct 24, 2021
07eb502
test_tail: add test_retry8-9
jhscheer Oct 24, 2021
3f4b014
test_tail: add test_follow_descriptor_vs_rename1-2
jhscheer Oct 24, 2021
1d2940b
test_tail: add test_follow_name_truncate1-3
jhscheer Oct 24, 2021
a9c34ef
test_tail: add more tests for `--follow=name`
jhscheer Oct 24, 2021
2238a87
tail: implement `--retry` and `-F`
jhscheer Oct 26, 2021
63e9cd9
Merge branch 'master' into tail_notify
jhscheer Oct 26, 2021
18a06c3
tail: add some tweaks to pass more of GNU's testsuite checks related …
jhscheer Nov 3, 2021
a9fa948
tail: switch from Notify 5.0.0-pre.13 to 5.0.0-pre.14
jhscheer Apr 5, 2022
eb21330
Merge branch 'main' into tail_notify
jhscheer Apr 19, 2022
7228902
Merge branch 'main' into tail_notify
jhscheer Apr 19, 2022
4a56d29
tail: fix handling of `-f` with non regular files
jhscheer Apr 21, 2022
6c09626
Merge branch 'main' into tail_notify
jhscheer Apr 21, 2022
132cab1
tail: update notify crate
jhscheer Apr 22, 2022
ceb2e99
tail: update readmes
jhscheer Apr 22, 2022
6e1e3ac
Merge branch 'main' into tail_notify
jhscheer Apr 22, 2022
5331a10
tail: update README
jhscheer Apr 24, 2022
90a0226
tail: improve support for polling
jhscheer Apr 30, 2022
5004d4b
build-gnu: replace `timeout` for `tests/tail/follow-stdin.sh`
jhscheer May 16, 2022
59827bc
test_tail: add various tests for stdin-follow and stdin-redirect
jhscheer May 16, 2022
5aee95b
tail: add check to detect a closed file descriptor
jhscheer May 16, 2022
ede7374
test_tail: add various tests for follow-stdin and redirect-stdin
jhscheer May 16, 2022
90cef98
tail: implement `follow` for stdin (pipe, fifo, and redirects)
jhscheer May 16, 2022
409878e
Merge branch 'main' into tail_notify
jhscheer May 16, 2022
75a6641
Merge branch 'main' into tail_notify
jhscheer May 17, 2022
07231e6
tail: fix handling of stdin redirects for macOS
jhscheer May 18, 2022
6a1cf72
Merge branch 'main' into tail_notify
jhscheer May 18, 2022
84480f8
tail: add equivalent of stdin_is_pipe_or_fifo() for Windows
jhscheer May 19, 2022
a62f71f
Merge branch 'main' into tail_notify
jhscheer May 19, 2022
7dae3f7
Merge branch 'main' into tail_notify
sylvestre May 21, 2022
6a7b6cc
tail: add test_follow_name_move_retry
jhscheer May 22, 2022
dc4b6f2
Merge branch 'main' into tail_notify
jhscheer May 22, 2022
3077455
Merge branch 'tail_notify' of github.com:jhscheer/coreutils into tail…
jhscheer May 22, 2022
519ab2d
test_tail: add two new tests for `--follow`
jhscheer May 25, 2022
5f86e23
tail: refactor FileHandling and fixes for new tests
jhscheer May 25, 2022
6bd9a1d
Merge branch 'main' into tail_notify
jhscheer May 25, 2022
4bbf708
tail: fix handling of PermissionDenied Error
jhscheer May 26, 2022
bb5dc8b
tail: verify that -[nc]0 without -f, exit without reading
jhscheer May 27, 2022
4cb6b09
Merge branch 'main' into tail_notify
jhscheer May 27, 2022
767eeed
tail: update README
jhscheer May 27, 2022
8ee806a
Merge branch 'main' into tail_notify
jhscheer Jun 2, 2022
f3aacac
test_tail: add test_follow_name_truncate4
jhscheer Jun 2, 2022
42fa386
test_tail: add test_follow_truncate_fast
jhscheer Jun 2, 2022
2e91881
test_tail: add test_follow_name_move_create2
jhscheer Jun 2, 2022
94fe426
test_tail: a lot of minor improvements
jhscheer Jun 2, 2022
70fed83
tail: refactor and fixes to pass more GNU test-suite checks
jhscheer Jun 2, 2022
e0efd6c
tail: update readme
jhscheer Jun 2, 2022
beb2b7c
tail: use functionality from `uucore::error` where applicable
jhscheer Jun 6, 2022
e883459
Merge branch 'main' into tail_notify
jhscheer Jun 6, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -422,10 +422,10 @@ See https://github.com/uutils/coreutils/issues/3336 for the main meta bugs
| comm | sort | |
| csplit | split | |
| cut | tac | |
| dircolors | tail | |
| dirname | test | |
| du | dir | |
| echo | vdir | |
| dircolors | test | |
| dirname | dir | |
| du | vdir | |
| echo | | |
| env | | |
| expand | | |
| factor | | |
Expand Down Expand Up @@ -478,6 +478,7 @@ See https://github.com/uutils/coreutils/issues/3336 for the main meta bugs
| stdbuf | | |
| sum | | |
| sync | | |
| tail | | |
| tee | | |
| timeout | | |
| touch | | |
Expand Down
4 changes: 4 additions & 0 deletions src/uu/tail/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# spell-checker:ignore (libs) kqueue
[package]
name = "uu_tail"
version = "0.0.14"
Expand All @@ -17,10 +18,13 @@ path = "src/tail.rs"
[dependencies]
clap = { version = "3.1", features = ["wrap_help", "cargo"] }
libc = "0.2.126"
notify = { version = "5.0.0-pre.15", features=["macos_kqueue"]}
# notify = { git = "https://github.com/notify-rs/notify", features=["macos_kqueue"]}
jhscheer marked this conversation as resolved.
Show resolved Hide resolved
uucore = { version=">=0.0.11", package="uucore", path="../../uucore", features=["ringbuffer", "lines"] }

[target.'cfg(windows)'.dependencies]
winapi = { version="0.3", features=["fileapi", "handleapi", "processthreadsapi", "synchapi", "winbase"] }
winapi-util = { version= "0.1.5" }
jhscheer marked this conversation as resolved.
Show resolved Hide resolved

[target.'cfg(unix)'.dependencies]
nix = { version = "0.24.1", features = ["fs"] }
Expand Down
81 changes: 73 additions & 8 deletions src/uu/tail/README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,83 @@
# Notes / ToDO
<!-- spell-checker:ignore markdownlint ; (misc) backends kqueue Testsuite ksyms stdlib -->

- Rudimentary tail implementation.
# Notes / ToDO

## Missing features

### Flags with features
* `--max-unchanged-stats`
* check whether process p is alive at least every number of seconds (relevant for `--pid`)

- [ ] `--max-unchanged-stats` : with `--follow=name`, reopen a FILE which has not changed size after N (default 5) iterations to see if it has been unlinked or renamed (this is the usual case of rotated log files). With `inotify`, this option is rarely useful.
- [ ] `--retry` : keep trying to open a file even when it is or becomes inaccessible; useful when follow‐ing by name, i.e., with `--follow=name`
Note:
There's a stub for `--max-unchanged-stats` so GNU test-suite checks using it can run, however this flag has no functionality yet.

### Others
### Platform support for `--follow` and `--retry`
The `--follow=descriptor`, `--follow=name` and `--retry` flags have very good support on Linux (inotify backend).
They work good enough on macOS/BSD (kqueue backend) with some tests failing due to differences of how kqueue works compared to inotify.
Windows support is there in theory due to ReadDirectoryChanges support by the notify-crate, however these flags are completely untested on Windows.

- [ ] The current implementation doesn't follow stdin in non-unix platforms
Note:
The undocumented `---disable-inotify` flag is used to disable the inotify backend to test polling.
However inotify is a Linux only backend and polling is now supported also for the other backends.
Because of this, `disable-inotify` is now an alias to the new and more versatile flag name: `--use-polling`.

## Possible optimizations

- [ ] Don't read the whole file if not using `-f` and input is regular file. Read in chunks from the end going backwards, reading each individual chunk forward.
* Don't read the whole file if not using `-f` and input is regular file. Read in chunks from the end going backwards, reading each individual chunk forward.
* Reduce number of system calls to e.g. `fstat`
* Improve resource management by adding more system calls to `inotify_rm_watch` when appropriate.

# GNU test-suite results

The functionality for the test "gnu/tests/tail-2/follow-stdin.sh" is implemented.
It fails because it is provoking closing a file descriptor with `tail -f <&-` and as part of a workaround, Rust's stdlib reopens closed FDs as `/dev/null` which means uu_tail cannot detect this.
See also, e.g. the discussion at: https://github.com/uutils/coreutils/issues/2873

The functionality for the test "gnu/tests/tail-2/inotify-rotate-resources.sh" is implemented.
It fails with an error because it is using `strace` to look for calls to `inotify_add_watch` and `inotify_rm_watch`,
however in uu_tail these system calls are invoked from a separate thread.
If the GNU test would follow threads, i.e. use `strace -f`, this issue could be resolved.

## Testsuite summary for GNU coreutils 9.1.8-e08752:
jhscheer marked this conversation as resolved.
Show resolved Hide resolved

### PASS:
- [x] `tail-2/F-headers.sh`
- [x] `tail-2/F-vs-missing.sh`
- [x] `tail-2/F-vs-rename.sh`
- [x] `tail-2/append-only.sh # skipped test: must be run as root`
- [x] `tail-2/assert-2.sh`
- [x] `tail-2/assert.sh`
- [x] `tail-2/big-4gb.sh`
- [x] `tail-2/descriptor-vs-rename.sh`
- [x] `tail-2/end-of-device.sh # skipped test: must be run as root`
- [x] `tail-2/flush-initial.sh`
- [x] `tail-2/follow-name.sh`
- [x] `tail-2/inotify-dir-recreate.sh`
- [x] `tail-2/inotify-hash-abuse.sh`
- [x] `tail-2/inotify-hash-abuse2.sh`
- [x] `tail-2/inotify-only-regular.sh`
- [x] `tail-2/inotify-rotate.sh`
- [x] `tail-2/overlay-headers.sh`
- [x] `tail-2/pid.sh`
- [x] `tail-2/pipe-f2.sh`
- [x] `tail-2/proc-ksyms.sh`
- [x] `tail-2/retry.sh`
- [x] `tail-2/start-middle.sh`
- [x] `tail-2/tail-c.sh`
- [x] `tail-2/tail-n0f.sh`
- [x] `tail-2/truncate.sh`


### SKIP:
- [ ] `tail-2/inotify-race.sh # skipped test: breakpoint not hit`
- [ ] `tail-2/inotify-race2.sh # skipped test: breakpoint not hit`
- [ ] `tail-2/pipe-f.sh # skipped test: trapping SIGPIPE is not supported`

### FAIL:
- [ ] `misc/tail.pl`
- [ ] `tail-2/follow-stdin.sh`
- [ ] `tail-2/symlink.sh`
- [ ] `tail-2/wait.sh`


### ERROR:
- [ ] `tail-2/inotify-rotate-resources.sh`
2 changes: 1 addition & 1 deletion src/uu/tail/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

use std::ffi::OsString;

#[derive(PartialEq, Debug)]
#[derive(PartialEq, Eq, Debug)]
pub enum ParseError {
Syntax,
Overflow,
Expand Down
4 changes: 3 additions & 1 deletion src/uu/tail/src/platform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
*/

#[cfg(unix)]
pub use self::unix::{stdin_is_pipe_or_fifo, supports_pid_checks, Pid, ProcessChecker};
pub use self::unix::{
stdin_is_bad_fd, stdin_is_pipe_or_fifo, supports_pid_checks, Pid, ProcessChecker,
};

#[cfg(windows)]
pub use self::windows::{supports_pid_checks, Pid, ProcessChecker};
Expand Down
31 changes: 21 additions & 10 deletions src/uu/tail/src/platform/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
* file that was distributed with this source code.
*/

// spell-checker:ignore (ToDO) errno EPERM ENOSYS
// spell-checker:ignore (ToDO) stdlib
// spell-checker:ignore (options) GETFD EPERM ENOSYS

use std::io::{stdin, Error};

Expand Down Expand Up @@ -51,13 +52,23 @@ fn get_errno() -> i32 {

pub fn stdin_is_pipe_or_fifo() -> bool {
let fd = stdin().lock().as_raw_fd();
fd >= 0 // GNU tail checks fd >= 0
&& match fstat(fd) {
Ok(stat) => {
let mode = stat.st_mode as libc::mode_t;
// NOTE: This is probably not the most correct way to check this
(mode & S_IFIFO != 0) || (mode & S_IFSOCK != 0)
}
Err(err) => panic!("{}", err),
}
// GNU tail checks fd >= 0
fd >= 0
&& match fstat(fd) {
Ok(stat) => {
let mode = stat.st_mode as libc::mode_t;
// NOTE: This is probably not the most correct way to check this
(mode & S_IFIFO != 0) || (mode & S_IFSOCK != 0)
}
Err(err) => panic!("{}", err),
}
}

// FIXME: Detect a closed file descriptor, e.g.: `tail <&-`
pub fn stdin_is_bad_fd() -> bool {
let fd = stdin().as_raw_fd();
// this is never `true`, even with `<&-` because Rust's stdlib is reopening fds as /dev/null
// see also: https://github.com/uutils/coreutils/issues/2873
// (gnu/tests/tail-2/follow-stdin.sh fails because of this)
unsafe { libc::fcntl(fd, libc::F_GETFD) == -1 && get_errno() == libc::EBADF }
}
Loading