tail: add WASI support by disabling notify and pid features (#11569)

WASI has no file watching (inotify/kqueue) or process management APIs.
Disable notify and libc on WASI, provide Observer stubs so tail
compiles, and add fallback values for BACKEND and polling_help.
The follow mode (-f) returns an error on WASI since it cannot work
without a file watching backend.
This commit is contained in:
Sylvestre Ledru
2026-04-03 12:14:59 +02:00
committed by GitHub
parent 76b2f7877f
commit ab37e41a96
7 changed files with 98 additions and 2 deletions
+1
View File
@@ -216,6 +216,7 @@ feat_wasm = [
"shuf",
"sleep",
"sum",
"tail",
"tee",
"tr",
"true",
+4 -2
View File
@@ -21,13 +21,15 @@ path = "src/tail.rs"
[dependencies]
clap = { workspace = true }
libc = { workspace = true }
memchr = { workspace = true }
notify = { workspace = true }
uucore = { workspace = true, features = ["fs", "parser-size", "signals"] }
same-file = { workspace = true }
fluent = { workspace = true }
[target.'cfg(not(target_os = "wasi"))'.dependencies]
libc = { workspace = true }
notify = { workspace = true }
[target.'cfg(unix)'.dependencies]
rustix = { workspace = true, features = ["fs"] }
+2
View File
@@ -447,6 +447,8 @@ pub fn uu_app() -> Command {
let polling_help = translate!("tail-help-polling-unix");
#[cfg(target_os = "windows")]
let polling_help = translate!("tail-help-polling-windows");
#[cfg(not(any(unix, target_os = "windows")))]
let polling_help = translate!("tail-help-polling-unix");
Command::new(uucore::util_name())
.version(uucore::crate_version!())
+63
View File
@@ -4,6 +4,69 @@
// file that was distributed with this source code.
mod files;
#[cfg(not(target_os = "wasi"))]
mod watch;
#[cfg(not(target_os = "wasi"))]
pub use watch::{Observer, follow};
// WASI: notify/inotify are unavailable, so `tail -f` cannot work.
// Provide minimal stubs matching the real Observer API so tail compiles.
#[cfg(target_os = "wasi")]
mod wasi_stubs {
use crate::args::Settings;
use std::io::BufRead;
use std::path::Path;
use uucore::error::{UResult, USimpleError};
pub struct Observer {
pub use_polling: bool,
pub pid: super::super::platform::Pid,
}
impl Observer {
pub fn from(settings: &Settings) -> Self {
Self {
use_polling: false,
pid: settings.pid,
}
}
pub fn start(&mut self, _settings: &Settings) -> UResult<()> {
Ok(())
}
pub fn add_path(
&mut self,
_path: &Path,
_display_name: &str,
_reader: Option<Box<dyn BufRead>>,
_update_last: bool,
) -> UResult<()> {
Ok(())
}
pub fn add_bad_path(
&mut self,
_path: &Path,
_display_name: &str,
_update_last: bool,
) -> UResult<()> {
Ok(())
}
pub fn follow_name_retry(&self) -> bool {
false
}
}
pub fn follow(_observer: Observer, _settings: &Settings) -> UResult<()> {
Err(USimpleError::new(
1,
"follow mode is not supported on this platform",
))
}
}
#[cfg(target_os = "wasi")]
pub use wasi_stubs::{Observer, follow};
+4
View File
@@ -197,6 +197,10 @@ impl MetadataExtTail for Metadata {
// }
false
}
#[cfg(not(any(unix, windows)))]
{
false
}
}
}
+22
View File
@@ -14,6 +14,28 @@ pub use self::unix::{
#[cfg(windows)]
pub use self::windows::{Pid, ProcessChecker, supports_pid_checks};
// WASI has no process management; provide stubs so tail compiles.
#[cfg(target_os = "wasi")]
pub type Pid = u64;
#[cfg(target_os = "wasi")]
pub struct ProcessChecker;
#[cfg(target_os = "wasi")]
impl ProcessChecker {
pub fn new(_pid: Pid) -> Self {
Self
}
pub fn is_dead(&mut self) -> bool {
true
}
}
#[cfg(target_os = "wasi")]
pub fn supports_pid_checks(_pid: Pid) -> bool {
false
}
#[cfg(unix)]
mod unix;
+2
View File
@@ -18,3 +18,5 @@ pub const BACKEND: &str = "inotify";
pub const BACKEND: &str = "kqueue";
#[cfg(target_os = "windows")]
pub const BACKEND: &str = "ReadDirectoryChanges";
#[cfg(not(any(unix, target_os = "windows")))]
pub const BACKEND: &str = "polling";