Bug 1689358 - Generate minidumps for child process crashes using the minidump-writer...
[gecko.git] / third_party / rust / procfs-core / src / mounts.rs
blob773057f99312d8563ff93871f56707d4fa159394
1 use std::{collections::HashMap, io::BufRead};
3 use super::ProcResult;
4 use std::str::FromStr;
6 #[cfg(feature = "serde1")]
7 use serde::{Deserialize, Serialize};
9 /// A mountpoint entry under `/proc/mounts`
10 #[derive(Debug, Clone)]
11 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
12 #[allow(non_snake_case)]
13 pub struct MountEntry {
14     /// Device
15     pub fs_spec: String,
16     /// Mountpoint
17     pub fs_file: String,
18     /// FS type
19     pub fs_vfstype: String,
20     /// Mount options
21     pub fs_mntops: HashMap<String, Option<String>>,
22     /// Dump
23     pub fs_freq: u8,
24     /// Check
25     pub fs_passno: u8,
28 impl super::FromBufRead for Vec<MountEntry> {
29     fn from_buf_read<R: BufRead>(r: R) -> ProcResult<Self> {
30         let mut vec = Vec::new();
32         for line in r.lines() {
33             let line = expect!(line);
34             let mut s = line.split_whitespace();
36             let fs_spec = unmangle_octal(expect!(s.next()));
37             let fs_file = unmangle_octal(expect!(s.next()));
38             let fs_vfstype = unmangle_octal(expect!(s.next()));
39             let fs_mntops = unmangle_octal(expect!(s.next()));
40             let fs_mntops: HashMap<String, Option<String>> = fs_mntops
41                 .split(',')
42                 .map(|s| {
43                     let mut split = s.splitn(2, '=');
44                     let k = split.next().unwrap().to_string(); // can not fail, splitn will always return at least 1 element
45                     let v = split.next().map(|s| s.to_string());
47                     (k, v)
48                 })
49                 .collect();
50             let fs_freq = expect!(u8::from_str(expect!(s.next())));
51             let fs_passno = expect!(u8::from_str(expect!(s.next())));
53             let mount_entry = MountEntry {
54                 fs_spec,
55                 fs_file,
56                 fs_vfstype,
57                 fs_mntops,
58                 fs_freq,
59                 fs_passno,
60             };
62             vec.push(mount_entry);
63         }
65         Ok(vec)
66     }
69 /// Unmangle spaces ' ', tabs '\t', line breaks '\n', backslashes '\\', and hashes '#'
70 ///
71 /// See https://elixir.bootlin.com/linux/v6.2.8/source/fs/proc_namespace.c#L89
72 pub(crate) fn unmangle_octal(input: &str) -> String {
73     let mut input = input.to_string();
75     for (octal, c) in [(r"\011", "\t"), (r"\012", "\n"), (r"\134", "\\"), (r"\043", "#")] {
76         input = input.replace(octal, c);
77     }
79     input
82 #[test]
83 fn test_unmangle_octal() {
84     let tests = [
85         (r"a\134b\011c\012d\043e", "a\\b\tc\nd#e"), // all escaped chars with abcde in between
86         (r"abcd", r"abcd"),                         // do nothing
87     ];
89     for (input, expected) in tests {
90         assert_eq!(unmangle_octal(input), expected);
91     }
94 #[test]
95 fn test_mounts() {
96     use crate::FromBufRead;
97     use std::io::Cursor;
99     let s = "proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
100 sysfs /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0
101 /dev/mapper/ol-root / xfs rw,relatime,attr2,inode64,logbufs=8,logbsize=32k,noquota 0 0
102 Downloads /media/sf_downloads vboxsf rw,nodev,relatime,iocharset=utf8,uid=0,gid=977,dmode=0770,fmode=0770,tag=VBoxAutomounter 0 0";
104     let cursor = Cursor::new(s);
105     let mounts = Vec::<MountEntry>::from_buf_read(cursor).unwrap();
106     assert_eq!(mounts.len(), 4);