1mod serialized;
26mod typ;
27
28pub use serialized::*;
29pub use typ::*;
30
31use crate::util::count_bytes_until_null;
32use core::cmp::Ordering;
33use core::ffi::CStr;
34use core::fmt::{Debug, Display, Formatter};
35#[cfg(feature = "alloc")]
36use {alloc::borrow::ToOwned, alloc::ffi::CString, alloc::string::String, alloc::string::ToString};
37bitflags::bitflags! {
38 #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
40 pub struct AuxVarFlags: usize {
41 const NOT_PRESERVE_ARGV0 = 0;
43 const PRESERVE_ARGV0 = 1;
45 }
46}
47
48#[derive(Debug, Eq, PartialEq, Clone)]
59pub enum AuxVarString<'a> {
60 #[cfg(feature = "alloc")]
61 String(String),
62 #[cfg(feature = "alloc")]
63 CString(CString),
64 Str(&'a str),
65 CStr(&'a CStr),
66}
67
68impl<'a> AuxVarString<'a> {
69 pub fn as_bytes(&self) -> &[u8] {
75 match self {
76 #[cfg(feature = "alloc")]
77 AuxVarString::String(str) => str.as_bytes(),
78 #[cfg(feature = "alloc")]
79 AuxVarString::CString(cstr) => cstr.to_bytes_with_nul(),
80 AuxVarString::Str(str) => str.as_bytes(),
81 AuxVarString::CStr(cstr) => cstr.to_bytes_with_nul(),
82 }
83 }
84
85 pub fn count_bytes(&self) -> usize {
87 count_bytes_until_null(self.as_bytes()).unwrap_or(self.as_bytes().len())
88 }
89
90 #[cfg(feature = "alloc")]
94 pub fn upgrade_to_owned(self) -> Self {
95 match self {
96 AuxVarString::Str(str) => Self::String(str.to_owned()),
97 AuxVarString::CStr(cstr) => Self::CString(cstr.to_owned()),
98 o => o,
99 }
100 }
101
102 #[cfg(feature = "alloc")]
104 pub fn into_string(self) -> String {
105 match self {
106 AuxVarString::String(str) => str,
107 AuxVarString::CString(str) => str.to_str().unwrap().to_string(),
108 AuxVarString::Str(str) => str.to_string(),
109 AuxVarString::CStr(str) => str.to_str().unwrap().to_string(),
110 }
111 }
112}
113
114impl Display for AuxVarString<'_> {
115 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
116 match self {
117 #[cfg(feature = "alloc")]
118 AuxVarString::String(v) => Display::fmt(v, f),
119 #[cfg(feature = "alloc")]
120 AuxVarString::CString(v) => Debug::fmt(&v.to_str(), f),
121 AuxVarString::Str(v) => Display::fmt(v, f),
122 AuxVarString::CStr(v) => Debug::fmt(&v.to_str(), f),
123 }
124 }
125}
126
127impl<'a> From<&'a str> for AuxVarString<'a> {
128 fn from(str: &'a str) -> Self {
129 Self::Str(str)
130 }
131}
132
133impl<'a> From<&'a CStr> for AuxVarString<'a> {
134 fn from(str: &'a CStr) -> Self {
135 Self::CStr(str)
136 }
137}
138
139#[cfg(feature = "alloc")]
140impl<'a> From<String> for AuxVarString<'a> {
141 fn from(str: String) -> Self {
142 Self::String(str)
143 }
144}
145
146#[cfg(feature = "alloc")]
147impl<'a> From<CString> for AuxVarString<'a> {
148 fn from(str: CString) -> Self {
149 Self::CString(str)
150 }
151}
152
153#[derive(Debug, Eq, PartialEq, Clone)]
166pub enum AuxVar<'a> {
167 Null,
169 Ignore,
171 ExecFd(usize),
173 Phdr(*const u8),
175 Phent(usize),
177 Phnum(usize),
179 Pagesz(usize),
181 Base(*const u8),
183 Flags(AuxVarFlags),
185 Entry(*const u8),
187 NotElf(bool),
189 Uid(usize),
191 EUid(usize),
193 Gid(usize),
195 EGid(usize),
197 Platform(AuxVarString<'a>),
199 HwCap(usize),
201 Clktck(usize),
203 Secure(bool),
205 BasePlatform(AuxVarString<'a>),
207 Random([u8; 16]),
209 HwCap2(usize),
211 ExecFn(AuxVarString<'a>),
213 Sysinfo(*const u8),
215 SysinfoEhdr(*const u8),
217 L1iCacheSize(usize),
219 L1iCacheGeometry(usize),
221 L1dCacheSize(usize),
223 L1dCacheGeometry(usize),
225 L2CacheSize(usize),
227 L2CacheGeometry(usize),
229 L3CacheSize(usize),
231 L3CacheGeometry(usize),
233 MinSigStkSz(usize),
235}
236
237impl<'a> AuxVar<'a> {
238 fn _from_raw_to_cstr(ptr: usize, buffer: &[u8]) -> &CStr {
247 let begin_index = ptr - buffer.as_ptr() as usize;
248
249 let bytes = &buffer[begin_index..];
250 CStr::from_bytes_until_nul(bytes).unwrap()
251 }
252
253 pub(crate) unsafe fn from_raw(serialized: &AuxVarRaw, buffer: &'a [u8]) -> Self {
264 let key = serialized.key().unwrap();
265
266 match key {
267 AuxVarType::Platform => {
268 Self::Platform(Self::_from_raw_to_cstr(serialized.value(), buffer).into())
269 }
270 AuxVarType::BasePlatform => {
271 Self::BasePlatform(Self::_from_raw_to_cstr(serialized.value(), buffer).into())
272 }
273 AuxVarType::ExecFn => {
274 Self::ExecFn(Self::_from_raw_to_cstr(serialized.value(), buffer).into())
275 }
276 AuxVarType::Random => {
277 let begin_index = serialized.value() - buffer.as_ptr() as usize;
278 let end_index = begin_index + 16 ;
279 assert!(end_index < buffer.len());
280
281 let mut bytes = [0; 16];
282 bytes.copy_from_slice(&buffer[begin_index..end_index]);
283
284 Self::Random(bytes)
285 }
286 AuxVarType::Null => Self::Null,
287 AuxVarType::Ignore => Self::Ignore,
288 AuxVarType::ExecFd => Self::ExecFd(serialized.value()),
289 AuxVarType::Phdr => Self::Phdr(serialized.value() as *const u8),
290 AuxVarType::Phent => Self::Phent(serialized.value()),
291 AuxVarType::Phnum => Self::Phnum(serialized.value()),
292 AuxVarType::Pagesz => Self::Pagesz(serialized.value()),
293 AuxVarType::Base => Self::Base(serialized.value() as *const u8),
294 AuxVarType::Flags => Self::Flags(AuxVarFlags::from_bits_truncate(serialized.value())),
295 AuxVarType::Entry => Self::Entry(serialized.value() as *const u8),
296 AuxVarType::NotElf => Self::NotElf(serialized.value() == 1),
297 AuxVarType::Uid => Self::Uid(serialized.value()),
298 AuxVarType::EUid => Self::EUid(serialized.value()),
299 AuxVarType::Gid => Self::Gid(serialized.value()),
300 AuxVarType::EGid => Self::EGid(serialized.value()),
301 AuxVarType::HwCap => Self::HwCap(serialized.value()),
303 AuxVarType::Clktck => Self::Clktck(serialized.value()),
304 AuxVarType::Secure => Self::Secure(serialized.value() == 1),
305 AuxVarType::HwCap2 => Self::HwCap2(serialized.value()),
308 AuxVarType::Sysinfo => Self::Sysinfo(serialized.value() as *const u8),
310 AuxVarType::SysinfoEhdr => Self::SysinfoEhdr(serialized.value() as *const u8),
311 AuxVarType::L1iCacheSize => Self::L1iCacheSize(serialized.value()),
312 AuxVarType::L1iCacheGeometry => Self::L1iCacheGeometry(serialized.value()),
313 AuxVarType::L1dCacheSize => Self::L1dCacheSize(serialized.value()),
314 AuxVarType::L1dCacheGeometry => Self::L1dCacheGeometry(serialized.value()),
315 AuxVarType::L2CacheSize => Self::L2CacheSize(serialized.value()),
316 AuxVarType::L2CacheGeometry => Self::L2CacheGeometry(serialized.value()),
317 AuxVarType::L3CacheSize => Self::L3CacheSize(serialized.value()),
318 AuxVarType::L3CacheGeometry => Self::L3CacheGeometry(serialized.value()),
319 AuxVarType::MinSigStkSz => Self::MinSigStkSz(serialized.value()),
320 }
321 }
322
323 #[must_use]
325 pub const fn key(&self) -> AuxVarType {
326 match self {
327 AuxVar::Null => AuxVarType::Null,
328 AuxVar::Ignore => AuxVarType::Ignore,
329 AuxVar::ExecFd(_) => AuxVarType::ExecFd,
330 AuxVar::Phdr(_) => AuxVarType::Phdr,
331 AuxVar::Phent(_) => AuxVarType::Phent,
332 AuxVar::Phnum(_) => AuxVarType::Phnum,
333 AuxVar::Pagesz(_) => AuxVarType::Pagesz,
334 AuxVar::Base(_) => AuxVarType::Base,
335 AuxVar::Flags(_) => AuxVarType::Flags,
336 AuxVar::Entry(_) => AuxVarType::Entry,
337 AuxVar::NotElf(_) => AuxVarType::NotElf,
338 AuxVar::Uid(_) => AuxVarType::Uid,
339 AuxVar::EUid(_) => AuxVarType::EUid,
340 AuxVar::Gid(_) => AuxVarType::Gid,
341 AuxVar::EGid(_) => AuxVarType::EGid,
342 AuxVar::Platform(_) => AuxVarType::Platform,
343 AuxVar::HwCap(_) => AuxVarType::HwCap,
344 AuxVar::Clktck(_) => AuxVarType::Clktck,
345 AuxVar::Secure(_) => AuxVarType::Secure,
346 AuxVar::BasePlatform(_) => AuxVarType::BasePlatform,
347 AuxVar::Random(_) => AuxVarType::Random,
348 AuxVar::HwCap2(_) => AuxVarType::HwCap2,
349 AuxVar::ExecFn(_) => AuxVarType::ExecFn,
350 AuxVar::Sysinfo(_) => AuxVarType::Sysinfo,
351 AuxVar::SysinfoEhdr(_) => AuxVarType::SysinfoEhdr,
352 AuxVar::L1iCacheSize(_) => AuxVarType::L1iCacheSize,
353 AuxVar::L1iCacheGeometry(_) => AuxVarType::L1iCacheGeometry,
354 AuxVar::L1dCacheSize(_) => AuxVarType::L1dCacheSize,
355 AuxVar::L1dCacheGeometry(_) => AuxVarType::L1dCacheGeometry,
356 AuxVar::L2CacheSize(_) => AuxVarType::L2CacheSize,
357 AuxVar::L2CacheGeometry(_) => AuxVarType::L2CacheGeometry,
358 AuxVar::L3CacheSize(_) => AuxVarType::L3CacheSize,
359 AuxVar::L3CacheGeometry(_) => AuxVarType::L3CacheGeometry,
360 AuxVar::MinSigStkSz(_) => AuxVarType::MinSigStkSz,
361 }
362 }
363
364 #[must_use]
370 pub fn value_raw(&self) -> usize {
371 match self {
372 AuxVar::Platform(_)
373 | AuxVar::BasePlatform(_)
374 | AuxVar::Random(_)
375 | AuxVar::ExecFn(_) => todo!("return Result instead"),
376 AuxVar::Null => 0,
377 AuxVar::Ignore => 0,
378 AuxVar::ExecFd(val) => *val,
379 AuxVar::Phdr(val) => *val as _,
380 AuxVar::Phent(val) => *val,
381 AuxVar::Phnum(val) => *val,
382 AuxVar::Pagesz(val) => *val,
383 AuxVar::Base(val) => *val as _,
384 AuxVar::Flags(val) => val.bits(),
385 AuxVar::Entry(val) => *val as _,
386 AuxVar::NotElf(val) => {
387 if *val {
388 1
389 } else {
390 0
391 }
392 }
393 AuxVar::Uid(val) => *val,
394 AuxVar::EUid(val) => *val,
395 AuxVar::Gid(val) => *val,
396 AuxVar::EGid(val) => *val,
397 AuxVar::HwCap(val) => *val,
399 AuxVar::Clktck(val) => *val,
400 AuxVar::Secure(val) => {
401 if *val {
402 1
403 } else {
404 0
405 }
406 }
407 AuxVar::HwCap2(val) => *val,
410 AuxVar::Sysinfo(val) => *val as _,
412 AuxVar::SysinfoEhdr(val) => *val as _,
413 AuxVar::L1iCacheSize(val) => *val,
414 AuxVar::L1iCacheGeometry(val) => *val,
415 AuxVar::L1dCacheSize(val) => *val,
416 AuxVar::L1dCacheGeometry(val) => *val,
417 AuxVar::L2CacheSize(val) => *val,
418 AuxVar::L2CacheGeometry(val) => *val,
419 AuxVar::L3CacheSize(val) => *val,
420 AuxVar::L3CacheGeometry(val) => *val,
421 AuxVar::MinSigStkSz(val) => *val,
422 }
423 }
424
425 #[must_use]
428 pub const fn value_integer(&self) -> Option<usize> {
429 match self {
430 AuxVar::ExecFd(val) => Some(*val),
431 AuxVar::Phent(val) => Some(*val),
432 AuxVar::Phnum(val) => Some(*val),
433 AuxVar::Pagesz(val) => Some(*val),
434 AuxVar::Uid(val) => Some(*val),
435 AuxVar::EUid(val) => Some(*val),
436 AuxVar::Gid(val) => Some(*val),
437 AuxVar::EGid(val) => Some(*val),
438 AuxVar::HwCap(val) => Some(*val),
439 AuxVar::Clktck(val) => Some(*val),
440 AuxVar::HwCap2(val) => Some(*val),
441 AuxVar::L1iCacheSize(val) => Some(*val),
442 AuxVar::L1iCacheGeometry(val) => Some(*val),
443 AuxVar::L1dCacheSize(val) => Some(*val),
444 AuxVar::L1dCacheGeometry(val) => Some(*val),
445 AuxVar::L2CacheSize(val) => Some(*val),
446 AuxVar::L2CacheGeometry(val) => Some(*val),
447 AuxVar::L3CacheSize(val) => Some(*val),
448 AuxVar::L3CacheGeometry(val) => Some(*val),
449 AuxVar::MinSigStkSz(val) => Some(*val),
450 _ => None,
451 }
452 }
453
454 #[must_use]
457 pub const fn value_flags(&self) -> Option<AuxVarFlags> {
458 match self {
459 AuxVar::Flags(flags) => Some(*flags),
460 _ => None,
461 }
462 }
463
464 #[must_use]
467 pub const fn value_boolean(&self) -> Option<bool> {
468 match self {
469 AuxVar::NotElf(val) => Some(*val),
470 AuxVar::Secure(val) => Some(*val),
471 _ => None,
472 }
473 }
474
475 #[must_use]
481 pub const fn value_ptr(&self) -> Option<*const u8> {
482 match self {
483 AuxVar::Phdr(val) => Some(*val),
484 AuxVar::Base(val) => Some(*val),
485 AuxVar::Entry(val) => Some(*val),
486 AuxVar::Sysinfo(val) => Some(*val),
487 AuxVar::SysinfoEhdr(val) => Some(*val),
488 _ => None,
489 }
490 }
491
492 #[must_use]
499 pub fn value_payload_bytes(&'a self) -> Option<&'a [u8]> {
500 match self {
501 AuxVar::Random(bytes) => Some(&bytes[..]),
502 _ => None,
503 }
504 }
505
506 #[must_use]
513 pub const fn value_payload_str(&'a self) -> Option<&'a AuxVarString<'a>> {
514 match self {
515 AuxVar::Platform(val) => Some(val),
516 AuxVar::BasePlatform(val) => Some(val),
517 AuxVar::ExecFn(val) => Some(val),
518 _ => None,
519 }
520 }
521}
522
523impl<'a> PartialOrd for AuxVar<'a> {
524 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
525 Some(self.cmp(other))
526 }
527}
528
529impl<'a> Ord for AuxVar<'a> {
530 fn cmp(&self, other: &Self) -> Ordering {
531 self.key().cmp(&other.key())
532 }
533}
534
535#[cfg(test)]
536mod tests {
537 use super::*;
538 use std::collections::BTreeSet;
539
540 #[test]
543 fn test_aux_var_order() {
544 let mut set = BTreeSet::new();
545 set.insert(AuxVar::ExecFn(c"./executable".into()));
546 set.insert(AuxVar::Platform(c"x86_64".into()));
547 set.insert(AuxVar::Null);
548 set.insert(AuxVar::Clktck(0x1337));
549 set.insert(AuxVar::ExecFn(c"./executable".into()));
550 assert_eq!(set.iter().last().unwrap().key(), AuxVarType::Null);
551 }
552}