Skip to content

Commit 7a609ee

Browse files
committed
kernel: Fix dash-equality to be on key, not parameter
We had use cases which were doing `iter().find(|v| v.key ==` which would NOT do the `-_` insensitive comparison. Add a newtype `ParameterKey` and move the comparison there. This makes the API slightly more akward to use when inspecting as one needs `.key.0` but eh. Signed-off-by: Colin Walters <[email protected]>
1 parent a22b019 commit 7a609ee

File tree

2 files changed

+67
-44
lines changed

2 files changed

+67
-44
lines changed

crates/lib/src/install.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1666,12 +1666,10 @@ fn find_root_args_to_inherit(cmdline: &Cmdline, root_info: &Filesystem) -> Resul
16661666
let root = cmdline.find("root");
16671667
// If we have a root= karg, then use that
16681668
let (mount_spec, kargs) = if let Some(root) = root {
1669-
let rootflags = cmdline
1670-
.iter()
1671-
.find(|arg| arg.key == crate::kernel::ROOTFLAGS);
1669+
let rootflags = cmdline.find(crate::kernel::ROOTFLAGS);
16721670
let inherit_kargs = cmdline
16731671
.iter()
1674-
.filter(|arg| arg.key.starts_with(crate::kernel::INITRD_ARG_PREFIX));
1672+
.filter(|arg| arg.key.0.starts_with(crate::kernel::INITRD_ARG_PREFIX));
16751673
(
16761674
root.value_lossy(),
16771675
rootflags

crates/lib/src/kernel.rs

Lines changed: 65 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -59,29 +59,56 @@ impl<'a> Cmdline<'a> {
5959
/// Returns the first parameter matching the given key, or `None` if not found.
6060
/// Key comparison treats dashes and underscores as equivalent.
6161
pub fn find(&'a self, key: impl AsRef<[u8]>) -> Option<Parameter<'a>> {
62-
let key = key.as_ref();
62+
let key = ParameterKey(key.as_ref());
6363
self.iter().find(|p| p.key == key)
6464
}
6565
}
6666

67-
/// A single kernel command line parameter.
67+
/// A single kernel command line parameter key
6868
///
69-
/// Can represent either a simple switch (key only) or a key-value pair.
7069
/// Handles quoted values and treats dashes and underscores in keys as equivalent.
7170
#[derive(Debug, Eq)]
71+
pub(crate) struct ParameterKey<'a>(pub &'a [u8]);
72+
73+
impl<'a> From<&'a [u8]> for ParameterKey<'a> {
74+
fn from(value: &'a [u8]) -> Self {
75+
Self(value)
76+
}
77+
}
78+
79+
/// A single kernel command line parameter.
80+
#[derive(Debug, PartialEq, Eq)]
7281
pub(crate) struct Parameter<'a> {
7382
/// The parameter key as raw bytes
74-
pub key: &'a [u8],
83+
pub key: ParameterKey<'a>,
7584
/// The parameter value as raw bytes, if present
7685
pub value: Option<&'a [u8]>,
7786
}
7887

7988
impl<'a> Parameter<'a> {
89+
/// Create a new parameter with the provided key and value.
90+
#[cfg(test)]
91+
pub fn new_kv<'k: 'a, 'v: 'a>(key: &'k [u8], value: &'v [u8]) -> Self {
92+
Self {
93+
key: ParameterKey(key),
94+
value: Some(value),
95+
}
96+
}
97+
98+
/// Create a new parameter with the provided key.
99+
#[cfg(test)]
100+
pub fn new_key(key: &'a [u8]) -> Self {
101+
Self {
102+
key: ParameterKey(key),
103+
value: None,
104+
}
105+
}
106+
80107
/// Returns the key as a lossy UTF-8 string.
81108
///
82109
/// Invalid UTF-8 sequences are replaced with the Unicode replacement character.
83110
pub fn key_lossy(&self) -> String {
84-
String::from_utf8_lossy(self.key).to_string()
111+
String::from_utf8_lossy(self.key.0).to_string()
85112
}
86113

87114
/// Returns the value as a lossy UTF-8 string.
@@ -105,11 +132,12 @@ impl<'a, T: AsRef<[u8]> + ?Sized> From<&'a T> for Parameter<'a> {
105132

106133
match equals {
107134
None => Self {
108-
key: input,
135+
key: ParameterKey(input),
109136
value: None,
110137
},
111138
Some(i) => {
112139
let (key, mut value) = input.split_at(i);
140+
let key = ParameterKey(key);
113141

114142
// skip `=`, we know it's the first byte because we
115143
// found it above
@@ -131,7 +159,7 @@ impl<'a, T: AsRef<[u8]> + ?Sized> From<&'a T> for Parameter<'a> {
131159
}
132160
}
133161

134-
impl PartialEq for Parameter<'_> {
162+
impl PartialEq for ParameterKey<'_> {
135163
/// Compares two parameters for equality.
136164
///
137165
/// Keys are compared with dashes and underscores treated as equivalent.
@@ -150,17 +178,9 @@ impl PartialEq for Parameter<'_> {
150178
//
151179
// For example, "foo" == "foobar" since the zipped iterator
152180
// only compares the first three chars.
153-
let our_iter = self.key.iter().map(dedashed);
154-
let other_iter = other.key.iter().map(dedashed);
155-
if !our_iter.eq(other_iter) {
156-
return false;
157-
}
158-
159-
match (self.value, other.value) {
160-
(Some(ours), Some(other)) => ours == other,
161-
(None, None) => true,
162-
_ => false,
163-
}
181+
let our_iter = self.0.iter().map(dedashed);
182+
let other_iter = other.0.iter().map(dedashed);
183+
our_iter.eq(other_iter)
164184
}
165185
}
166186

@@ -194,11 +214,11 @@ mod tests {
194214
#[test]
195215
fn test_parameter_simple() {
196216
let switch = Parameter::from("foo");
197-
assert_eq!(switch.key, b"foo");
217+
assert_eq!(switch.key.0, b"foo");
198218
assert_eq!(switch.value, None);
199219

200220
let kv = Parameter::from("bar=baz");
201-
assert_eq!(kv.key, b"bar");
221+
assert_eq!(kv.key.0, b"bar");
202222
assert_eq!(kv.value, Some(b"baz".as_slice()));
203223
}
204224

@@ -214,7 +234,7 @@ mod tests {
214234

215235
// quotes don't get removed from keys
216236
let p = Parameter::from("\"\"\"");
217-
assert_eq!(p.key, b"\"\"\"");
237+
assert_eq!(p.key.0, b"\"\"\"");
218238

219239
// quotes only get stripped from the absolute ends of values
220240
let p = Parameter::from("foo=\"internal \" quotes \" are ok\"");
@@ -270,30 +290,14 @@ mod tests {
270290
let kargs = Cmdline::from(b"foo=bar,bar2 baz=fuz wiz".as_slice());
271291
let mut iter = kargs.iter();
272292

273-
assert_eq!(
274-
iter.next(),
275-
Some(Parameter {
276-
key: b"foo",
277-
value: Some(b"bar,bar2".as_slice())
278-
})
279-
);
280-
281-
assert_eq!(
282-
iter.next(),
283-
Some(Parameter {
284-
key: b"baz",
285-
value: Some(b"fuz".as_slice())
286-
})
287-
);
293+
assert_eq!(iter.next(), Some(Parameter::new_kv(b"foo", b"bar,bar2")));
288294

289295
assert_eq!(
290296
iter.next(),
291-
Some(Parameter {
292-
key: b"wiz",
293-
value: None,
294-
})
297+
Some(Parameter::new_kv(b"baz", b"fuz".as_slice()))
295298
);
296299

300+
assert_eq!(iter.next(), Some(Parameter::new_key(b"wiz")));
297301
assert_eq!(iter.next(), None);
298302

299303
// Test the find API
@@ -310,4 +314,25 @@ mod tests {
310314
// tests are running
311315
assert!(kargs.iter().count() > 0);
312316
}
317+
318+
#[test]
319+
fn test_kargs_find_dash_hyphen() {
320+
let kargs = Cmdline::from(b"a-b=1 a_b=2".as_slice());
321+
// find should find the first one, which is a-b=1
322+
let p = kargs.find("a_b").unwrap();
323+
assert_eq!(p.key.0, b"a-b");
324+
assert_eq!(p.value.unwrap(), b"1");
325+
let p = kargs.find("a-b").unwrap();
326+
assert_eq!(p.key.0, b"a-b");
327+
assert_eq!(p.value.unwrap(), b"1");
328+
329+
let kargs = Cmdline::from(b"a_b=2 a-b=1".as_slice());
330+
// find should find the first one, which is a_b=2
331+
let p = kargs.find("a_b").unwrap();
332+
assert_eq!(p.key.0, b"a_b");
333+
assert_eq!(p.value.unwrap(), b"2");
334+
let p = kargs.find("a-b").unwrap();
335+
assert_eq!(p.key.0, b"a_b");
336+
assert_eq!(p.value.unwrap(), b"2");
337+
}
313338
}

0 commit comments

Comments
 (0)