|
0 |
commit 500771c78d4b6b62bc7203d1624174cd28bd994b
|
|
1 |
Author: Ivan <diskonnect@tut.by>
|
|
2 |
Date: Sat Mar 27 22:02:49 2021 +0300
|
|
3 |
|
|
4 |
tee: should match GNU's output if used with /dev/full (#1944)
|
|
5 |
|
|
6 |
+ aligned 'tee' output with GNU tee when one of the files is '/dev/full'
|
|
7 |
+ don't stop tee when one of the outputs fails; just continue and return
|
|
8 |
error status from tee in the end
|
|
9 |
|
|
10 |
Co-authored-by: Ivan Rymarchyk <irymarchyk@arlo.com>
|
|
11 |
|
|
12 |
diff --git b/src/uu/tee/Cargo.toml a/src/uu/tee/Cargo.toml
|
|
13 |
index 51bba2e4..99a6ec23 100644
|
|
14 |
--- b/src/uu/tee/Cargo.toml
|
|
15 |
+++ a/src/uu/tee/Cargo.toml
|
|
16 |
@@ -17,7 +17,6 @@ path = "src/tee.rs"
|
|
17 |
[dependencies]
|
|
18 |
clap = "2.33.3"
|
|
19 |
libc = "0.2.42"
|
|
20 |
-retain_mut = "0.1.2"
|
|
21 |
uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features=["libc"] }
|
|
22 |
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
|
|
23 |
|
|
24 |
diff --git b/src/uu/tee/src/tee.rs a/src/uu/tee/src/tee.rs
|
|
25 |
index 7c6a86b4..c54fa0d1 100644
|
|
26 |
--- b/src/uu/tee/src/tee.rs
|
|
27 |
+++ a/src/uu/tee/src/tee.rs
|
|
28 |
@@ -9,7 +9,6 @@
|
|
29 |
extern crate uucore;
|
|
30 |
|
|
31 |
use clap::{App, Arg};
|
|
32 |
-use retain_mut::RetainMut;
|
|
33 |
use std::fs::OpenOptions;
|
|
34 |
use std::io::{copy, sink, stdin, stdout, Error, ErrorKind, Read, Result, Write};
|
|
35 |
use std::path::{Path, PathBuf};
|
|
36 |
@@ -94,32 +93,18 @@ fn tee(options: Options) -> Result<()> {
|
|
37 |
if options.ignore_interrupts {
|
|
38 |
ignore_interrupts()?
|
|
39 |
}
|
|
40 |
- let mut writers: Vec<NamedWriter> = options
|
|
41 |
+ let mut writers: Vec<Box<dyn Write>> = options
|
|
42 |
.files
|
|
43 |
.clone()
|
|
44 |
.into_iter()
|
|
45 |
- .map(|file| NamedWriter {
|
|
46 |
- name: file.clone(),
|
|
47 |
- inner: open(file, options.append),
|
|
48 |
- })
|
|
49 |
+ .map(|file| open(file, options.append))
|
|
50 |
.collect();
|
|
51 |
-
|
|
52 |
- writers.insert(
|
|
53 |
- 0,
|
|
54 |
- NamedWriter {
|
|
55 |
- name: "'standard output'".to_owned(),
|
|
56 |
- inner: Box::new(stdout()),
|
|
57 |
- },
|
|
58 |
- );
|
|
59 |
-
|
|
60 |
- let mut output = MultiWriter::new(writers);
|
|
61 |
+ writers.push(Box::new(stdout()));
|
|
62 |
+ let output = &mut MultiWriter { writers };
|
|
63 |
let input = &mut NamedReader {
|
|
64 |
inner: Box::new(stdin()) as Box<dyn Read>,
|
|
65 |
};
|
|
66 |
-
|
|
67 |
- // TODO: replaced generic 'copy' call to be able to stop copying
|
|
68 |
- // if all outputs are closed (due to errors)
|
|
69 |
- if copy(input, &mut output).is_err() || output.flush().is_err() || output.error_occured() {
|
|
70 |
+ if copy(input, output).is_err() || output.flush().is_err() {
|
|
71 |
Err(Error::new(ErrorKind::Other, ""))
|
|
72 |
} else {
|
|
73 |
Ok(())
|
|
74 |
@@ -127,7 +112,7 @@ fn tee(options: Options) -> Result<()> {
|
|
75 |
}
|
|
76 |
|
|
77 |
fn open(name: String, append: bool) -> Box<dyn Write> {
|
|
78 |
- let path = PathBuf::from(name.clone());
|
|
79 |
+ let path = PathBuf::from(name);
|
|
80 |
let inner: Box<dyn Write> = {
|
|
81 |
let mut options = OpenOptions::new();
|
|
82 |
let mode = if append {
|
|
83 |
@@ -140,68 +125,55 @@ fn open(name: String, append: bool) -> Box<dyn Write> {
|
|
84 |
Err(_) => Box::new(sink()),
|
|
85 |
}
|
|
86 |
};
|
|
87 |
- Box::new(NamedWriter { inner, name }) as Box<dyn Write>
|
|
88 |
+ Box::new(NamedWriter { inner, path }) as Box<dyn Write>
|
|
89 |
}
|
|
90 |
|
|
91 |
struct MultiWriter {
|
|
92 |
- writers: Vec<NamedWriter>,
|
|
93 |
- initial_len: usize,
|
|
94 |
-}
|
|
95 |
-
|
|
96 |
-impl MultiWriter {
|
|
97 |
- fn new(writers: Vec<NamedWriter>) -> Self {
|
|
98 |
- Self {
|
|
99 |
- initial_len: writers.len(),
|
|
100 |
- writers,
|
|
101 |
- }
|
|
102 |
- }
|
|
103 |
- fn error_occured(&self) -> bool {
|
|
104 |
- self.writers.len() != self.initial_len
|
|
105 |
- }
|
|
106 |
+ writers: Vec<Box<dyn Write>>,
|
|
107 |
}
|
|
108 |
|
|
109 |
impl Write for MultiWriter {
|
|
110 |
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
|
111 |
- self.writers.retain_mut(|writer| {
|
|
112 |
- let result = writer.write_all(buf);
|
|
113 |
- match result {
|
|
114 |
- Err(f) => {
|
|
115 |
- show_info!("{}: {}", writer.name, f.to_string());
|
|
116 |
- false
|
|
117 |
- }
|
|
118 |
- _ => true,
|
|
119 |
- }
|
|
120 |
- });
|
|
121 |
+ for writer in &mut self.writers {
|
|
122 |
+ writer.write_all(buf)?;
|
|
123 |
+ }
|
|
124 |
Ok(buf.len())
|
|
125 |
}
|
|
126 |
|
|
127 |
fn flush(&mut self) -> Result<()> {
|
|
128 |
- self.writers.retain_mut(|writer| {
|
|
129 |
- let result = writer.flush();
|
|
130 |
- match result {
|
|
131 |
- Err(f) => {
|
|
132 |
- show_info!("{}: {}", writer.name, f.to_string());
|
|
133 |
- false
|
|
134 |
- }
|
|
135 |
- _ => true,
|
|
136 |
- }
|
|
137 |
- });
|
|
138 |
+ for writer in &mut self.writers {
|
|
139 |
+ writer.flush()?;
|
|
140 |
+ }
|
|
141 |
Ok(())
|
|
142 |
}
|
|
143 |
}
|
|
144 |
|
|
145 |
struct NamedWriter {
|
|
146 |
inner: Box<dyn Write>,
|
|
147 |
- pub name: String,
|
|
148 |
+ path: PathBuf,
|
|
149 |
}
|
|
150 |
|
|
151 |
impl Write for NamedWriter {
|
|
152 |
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
|
153 |
- self.inner.write(buf)
|
|
154 |
+ match self.inner.write(buf) {
|
|
155 |
+ Err(f) => {
|
|
156 |
+ self.inner = Box::new(sink()) as Box<dyn Write>;
|
|
157 |
+ show_warning!("{}: {}", self.path.display(), f.to_string());
|
|
158 |
+ Err(f)
|
|
159 |
+ }
|
|
160 |
+ okay => okay,
|
|
161 |
+ }
|
|
162 |
}
|
|
163 |
|
|
164 |
fn flush(&mut self) -> Result<()> {
|
|
165 |
- self.inner.flush()
|
|
166 |
+ match self.inner.flush() {
|
|
167 |
+ Err(f) => {
|
|
168 |
+ self.inner = Box::new(sink()) as Box<dyn Write>;
|
|
169 |
+ show_warning!("{}: {}", self.path.display(), f.to_string());
|
|
170 |
+ Err(f)
|
|
171 |
+ }
|
|
172 |
+ okay => okay,
|
|
173 |
+ }
|
|
174 |
}
|
|
175 |
}
|
|
176 |
|
|
177 |
@@ -213,7 +185,7 @@ impl Read for NamedReader {
|
|
178 |
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
|
179 |
match self.inner.read(buf) {
|
|
180 |
Err(f) => {
|
|
181 |
- show_info!("{}: {}", Path::new("stdin").display(), f.to_string());
|
|
182 |
+ show_warning!("{}: {}", Path::new("stdin").display(), f.to_string());
|
|
183 |
Err(f)
|
|
184 |
}
|
|
185 |
okay => okay,
|