mirror of
https://github.com/storytold/craft-libs.git
synced 2026-11-14 06:22:24 +00:00
print: run lpoptions with a timeout and capped output (#871)
This commit is contained in:
1 parent
ce4f4816a1
commit
4559fe4171
1 file changed
+22
-5
+22
-5
@@ -377,11 +377,7 @@ pub fn printer_options(printer: &str) -> Vec<PrinterOption> {
|
||||
f.take(PPD_CAP).read_to_end(&mut bytes).ok().map(|_| bytes)
|
||||
});
|
||||
let mut options = ppd.map(|b| parse_ppd(&ppd_text(&b))).unwrap_or_default();
|
||||
let current = std::process::Command::new("lpoptions")
|
||||
.args(["-p", printer, "-l"])
|
||||
.output()
|
||||
.map(|o| parse_lpoptions(&String::from_utf8_lossy(&o.stdout)))
|
||||
.unwrap_or_default();
|
||||
let current = queue_defaults(std::process::Command::new("lpoptions").args(["-p", printer, "-l"]), QUEUES_LIMIT);
|
||||
apply_queue_defaults(&mut options, ¤t);
|
||||
options
|
||||
}
|
||||
@@ -516,6 +512,13 @@ fn printers_via(
|
||||
printers_parsed(&queues, available.as_deref())
|
||||
}
|
||||
|
||||
/// The queue's current choices from `lpoptions -p NAME -l`, run like the `lpstat` commands: its
|
||||
/// output capped, and given `limit` to answer (none when it doesn't).
|
||||
#[cfg(all(unix, not(target_arch = "wasm32")))]
|
||||
fn queue_defaults(command: &mut std::process::Command, limit: std::time::Duration) -> Vec<(String, String)> {
|
||||
output_within(command, limit).map(|out| parse_lpoptions(&String::from_utf8_lossy(&out))).unwrap_or_default()
|
||||
}
|
||||
|
||||
/// The most of a command's output that is read: far more than any `lpstat` listing.
|
||||
#[cfg(all(unix, not(target_arch = "wasm32")))]
|
||||
const OUTPUT_CAP: u64 = 4 << 20;
|
||||
@@ -612,6 +615,20 @@ mod lpstat_limits {
|
||||
assert!(started.elapsed() < Duration::from_secs(5), "{:?}", started.elapsed());
|
||||
}
|
||||
|
||||
/// `lpoptions` that never answers or prints without end gives no defaults, in time and in bounded memory.
|
||||
#[test]
|
||||
fn lpoptions_is_bounded_in_time_and_output() {
|
||||
let started = Instant::now();
|
||||
assert!(queue_defaults(&mut sh("sleep 30"), Duration::from_millis(300)).is_empty());
|
||||
assert!(started.elapsed() < Duration::from_secs(5), "{:?}", started.elapsed());
|
||||
let answer = queue_defaults(&mut sh("printf 'Duplex/2-Sided: None *DuplexNoTumble\\n'"), Duration::from_secs(5));
|
||||
assert_eq!(answer, [("Duplex".to_string(), "DuplexNoTumble".to_string())]);
|
||||
// Endless output stops at the cap (the command is killed at the deadline), and does not hang.
|
||||
let started = Instant::now();
|
||||
let _ = queue_defaults(&mut sh("yes 'Key/Label: a *b c'"), Duration::from_millis(500));
|
||||
assert!(started.elapsed() < Duration::from_secs(5), "{:?}", started.elapsed());
|
||||
}
|
||||
|
||||
/// A command that isn't there is no printers, at once.
|
||||
#[test]
|
||||
fn no_lpstat_is_no_printers() {
|
||||
|
||||
Reference in new issue
Block a user