fix: handle = syntax and some tokens

This commit is contained in:
2026-02-01 15:36:09 +01:00
parent ba8537063f
commit 6108b3f481
4 changed files with 422 additions and 246 deletions

View File

@@ -11,7 +11,7 @@
//! [ssh(1)]: <https://manpages.debian.org/testing/manpages-de/ssh.1.de.html>
//! [ssh_config(5)]: <https://manpages.debian.org/bullseye/openssh-client/ssh_config.5.en.html>
mod words;
mod ssh;
use std::{
collections::HashSet,
@@ -25,9 +25,7 @@ use std::{
use clap::Parser;
use glob::glob;
use crate::words::{Keyword, Words, expand};
const SYSTEM_CONFIG: &str = "/etc/ssh/ssh_config";
use crate::ssh::{SSH_SYSTEM_CONFIG, SSH_USER_CONFIG, Words, expand_inlude_args, is_host_pattern};
/// List host names in ssh_config(5) files
#[derive(Debug, Parser)]
@@ -44,8 +42,8 @@ fn main() {
Some(path) if path == "none" => vec![],
Some(path) => vec![path.clone()],
None => match env::home_dir() {
Some(home) => vec![SYSTEM_CONFIG.into(), home.join(".ssh/config")],
None => vec![SYSTEM_CONFIG.into()],
Some(home) => vec![SSH_SYSTEM_CONFIG.into(), home.join(SSH_USER_CONFIG)],
None => vec![SSH_SYSTEM_CONFIG.into()],
},
};
@@ -61,7 +59,7 @@ fn main() {
};
}
let mut hosts = Vec::from_iter(hosts.into_iter());
let mut hosts = Vec::from_iter(hosts);
hosts.sort();
hosts
};
@@ -94,30 +92,31 @@ fn find_hosts(filename: &Path) -> io::Result<HashSet<String>> {
let line = buf[..n].trim();
let mut words: Words<'_> = line.into();
let Some(Ok(directive)) = words.next() else {
continue;
};
let Ok(keyword) = Keyword::try_from(directive.as_str()) else {
let Some(Ok(keyword)) = words.next() else {
continue;
};
match keyword {
Keyword::Include => find_hosts_in_include_directive(&mut hosts, words),
Keyword::Host => find_hosts_in_host_directive(&mut hosts, words),
k if k.eq_ignore_ascii_case("include") => {
find_hosts_in_include_directive(&mut hosts, words);
}
k if k.eq_ignore_ascii_case("host") => {
find_hosts_in_host_directive(&mut hosts, words);
}
_ => continue,
}
}
}
fn find_hosts_in_include_directive(hosts: &mut HashSet<String>, words: Words<'_>) {
for pattern in words {
let Ok(pattern) = pattern else {
for arg in words {
let Ok(arg) = arg else {
// TODO: print warning
continue;
};
// Expanding env vars before globbing is what ssh does as well.
let Ok(pattern) = expand(&pattern) else {
let Ok(pattern) = expand_inlude_args(arg) else {
// TODO: print warning
continue;
};
@@ -145,18 +144,17 @@ fn find_hosts_in_include_directive(hosts: &mut HashSet<String>, words: Words<'_>
}
fn find_hosts_in_host_directive(hosts: &mut HashSet<String>, words: Words<'_>) {
for host in words {
let Ok(host) = host else {
for word in words {
let Ok(word) = word else {
// TODO: print warning
continue;
};
if host.contains(['*', '?', '!', ',']) {
// Ignore patterns (see ssh_config(5) "PATTERNS").
if is_host_pattern(word) {
continue;
}
hosts.insert(host.into());
hosts.insert(word.to_string());
}
}
@@ -172,7 +170,7 @@ mod tests {
}
#[test]
fn test() {
fn find_hosts() {
let mut hosts = HashSet::new();
find_hosts_in_host_directive(&mut hosts, "foo.test".into());
assert!(hosts.contains("foo.test"));