Skip to content

Commit 735a0b0

Browse files
authored
Merge pull request #1483 from cgwalters/kernel-cleanups
kernel: Add value helpers
2 parents 7a4abcc + 58a37d7 commit 735a0b0

File tree

2 files changed

+145
-2
lines changed

2 files changed

+145
-2
lines changed

crates/lib/src/install.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1663,15 +1663,17 @@ struct RootMountInfo {
16631663
/// Discover how to mount the root filesystem, using existing kernel arguments and information
16641664
/// about the root mount.
16651665
fn find_root_args_to_inherit(cmdline: &Cmdline, root_info: &Filesystem) -> Result<RootMountInfo> {
1666-
let root = cmdline.find("root");
1666+
let root = cmdline
1667+
.value_of_utf8("root")
1668+
.context("Parsing root= karg")?;
16671669
// If we have a root= karg, then use that
16681670
let (mount_spec, kargs) = if let Some(root) = root {
16691671
let rootflags = cmdline.find(crate::kernel::ROOTFLAGS);
16701672
let inherit_kargs = cmdline
16711673
.iter()
16721674
.filter(|arg| arg.key.starts_with(crate::kernel::INITRD_ARG_PREFIX));
16731675
(
1674-
root.value_lossy(),
1676+
root.to_owned(),
16751677
rootflags
16761678
.into_iter()
16771679
.chain(inherit_kargs)

crates/lib/src/kernel.rs

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,43 @@ impl<'a> Cmdline<'a> {
6262
let key = ParameterKey(key.as_ref());
6363
self.iter().find(|p| p.key == key)
6464
}
65+
66+
/// Locate the value of the kernel argument with the given key name.
67+
///
68+
/// Returns the first value matching the given key, or `None` if not found.
69+
/// Key comparison treats dashes and underscores as equivalent.
70+
pub fn value_of(&'a self, key: impl AsRef<[u8]>) -> Option<&'a [u8]> {
71+
self.find(key).and_then(|p| p.value)
72+
}
73+
74+
/// Locate the UTF-8 value of the kernel argument with the given key name.
75+
///
76+
/// Returns the first value matching the given key, or `None` if not found.
77+
/// Key comparison treats dashes and underscores as equivalent.
78+
pub fn value_of_utf8(&'a self, key: &str) -> Result<Option<&'a str>, std::str::Utf8Error> {
79+
self.value_of(key).map(std::str::from_utf8).transpose()
80+
}
81+
82+
/// Find the value of the kernel argument with the provided name, which must be present.
83+
///
84+
/// Otherwise the same as [`Self::value_of`].
85+
#[cfg(test)]
86+
pub fn require_value_of(&'a self, key: impl AsRef<[u8]>) -> Result<&'a [u8]> {
87+
let key = key.as_ref();
88+
self.value_of(key).ok_or_else(|| {
89+
let key = String::from_utf8_lossy(key);
90+
anyhow::anyhow!("Failed to find kernel argument '{key}'")
91+
})
92+
}
93+
94+
/// Find the value of the kernel argument with the provided name, which must be present.
95+
///
96+
/// Otherwise the same as [`Self::value_of`].
97+
#[cfg(test)]
98+
pub fn require_value_of_utf8(&'a self, key: &str) -> Result<&'a str> {
99+
self.value_of_utf8(key)?
100+
.ok_or_else(|| anyhow::anyhow!("Failed to find kernel argument '{key}'"))
101+
}
65102
}
66103

67104
/// A single kernel command line parameter key
@@ -342,4 +379,108 @@ mod tests {
342379
assert_eq!(p.key.0, b"a_b");
343380
assert_eq!(p.value.unwrap(), b"2");
344381
}
382+
383+
#[test]
384+
fn test_value_of() {
385+
let kargs = Cmdline::from(b"foo=bar baz=qux switch".as_slice());
386+
387+
// Test existing key with value
388+
assert_eq!(kargs.value_of("foo"), Some(b"bar".as_slice()));
389+
assert_eq!(kargs.value_of("baz"), Some(b"qux".as_slice()));
390+
391+
// Test key without value
392+
assert_eq!(kargs.value_of("switch"), None);
393+
394+
// Test non-existent key
395+
assert_eq!(kargs.value_of("missing"), None);
396+
397+
// Test dash/underscore equivalence
398+
let kargs = Cmdline::from(b"dash-key=value1 under_key=value2".as_slice());
399+
assert_eq!(kargs.value_of("dash_key"), Some(b"value1".as_slice()));
400+
assert_eq!(kargs.value_of("under-key"), Some(b"value2".as_slice()));
401+
}
402+
403+
#[test]
404+
fn test_value_of_utf8() {
405+
let kargs = Cmdline::from(b"foo=bar baz=qux switch".as_slice());
406+
407+
// Test existing key with UTF-8 value
408+
assert_eq!(kargs.value_of_utf8("foo").unwrap(), Some("bar"));
409+
assert_eq!(kargs.value_of_utf8("baz").unwrap(), Some("qux"));
410+
411+
// Test key without value
412+
assert_eq!(kargs.value_of_utf8("switch").unwrap(), None);
413+
414+
// Test non-existent key
415+
assert_eq!(kargs.value_of_utf8("missing").unwrap(), None);
416+
417+
// Test dash/underscore equivalence
418+
let kargs = Cmdline::from(b"dash-key=value1 under_key=value2".as_slice());
419+
assert_eq!(kargs.value_of_utf8("dash_key").unwrap(), Some("value1"));
420+
assert_eq!(kargs.value_of_utf8("under-key").unwrap(), Some("value2"));
421+
422+
// Test invalid UTF-8
423+
let mut invalid_utf8 = b"invalid=".to_vec();
424+
invalid_utf8.push(0xff);
425+
let kargs = Cmdline::from(&invalid_utf8);
426+
assert!(kargs.value_of_utf8("invalid").is_err());
427+
}
428+
429+
#[test]
430+
fn test_require_value_of() {
431+
let kargs = Cmdline::from(b"foo=bar baz=qux switch".as_slice());
432+
433+
// Test existing key with value
434+
assert_eq!(kargs.require_value_of("foo").unwrap(), b"bar");
435+
assert_eq!(kargs.require_value_of("baz").unwrap(), b"qux");
436+
437+
// Test key without value should fail
438+
let err = kargs.require_value_of("switch").unwrap_err();
439+
assert!(err
440+
.to_string()
441+
.contains("Failed to find kernel argument 'switch'"));
442+
443+
// Test non-existent key should fail
444+
let err = kargs.require_value_of("missing").unwrap_err();
445+
assert!(err
446+
.to_string()
447+
.contains("Failed to find kernel argument 'missing'"));
448+
449+
// Test dash/underscore equivalence
450+
let kargs = Cmdline::from(b"dash-key=value1 under_key=value2".as_slice());
451+
assert_eq!(kargs.require_value_of("dash_key").unwrap(), b"value1");
452+
assert_eq!(kargs.require_value_of("under-key").unwrap(), b"value2");
453+
}
454+
455+
#[test]
456+
fn test_require_value_of_utf8() {
457+
let kargs = Cmdline::from(b"foo=bar baz=qux switch".as_slice());
458+
459+
// Test existing key with UTF-8 value
460+
assert_eq!(kargs.require_value_of_utf8("foo").unwrap(), "bar");
461+
assert_eq!(kargs.require_value_of_utf8("baz").unwrap(), "qux");
462+
463+
// Test key without value should fail
464+
let err = kargs.require_value_of_utf8("switch").unwrap_err();
465+
assert!(err
466+
.to_string()
467+
.contains("Failed to find kernel argument 'switch'"));
468+
469+
// Test non-existent key should fail
470+
let err = kargs.require_value_of_utf8("missing").unwrap_err();
471+
assert!(err
472+
.to_string()
473+
.contains("Failed to find kernel argument 'missing'"));
474+
475+
// Test dash/underscore equivalence
476+
let kargs = Cmdline::from(b"dash-key=value1 under_key=value2".as_slice());
477+
assert_eq!(kargs.require_value_of_utf8("dash_key").unwrap(), "value1");
478+
assert_eq!(kargs.require_value_of_utf8("under-key").unwrap(), "value2");
479+
480+
// Test invalid UTF-8 should fail
481+
let mut invalid_utf8 = b"invalid=".to_vec();
482+
invalid_utf8.push(0xff);
483+
let kargs = Cmdline::from(&invalid_utf8);
484+
assert!(kargs.require_value_of_utf8("invalid").is_err());
485+
}
345486
}

0 commit comments

Comments
 (0)