summaryrefslogtreecommitdiff
path: root/init/src/mounts/fstab.rs
blob: 0765cfde7f212f1c5dc46d9862e7654ad46ee1a1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
use libc::{self};
use std::ffi::CString;

#[derive(Debug)]
pub struct FstabEntry {
    pub source: String,
    pub mountpoint: String,
    pub fstype: String,
    pub options: String,
    pub dump: u32,
    pub pass: u32,
}

fn parse_mount_options(
    options: &str,
) -> Result<(libc::c_ulong, Option<String>), Box<dyn std::error::Error>> {
    let mut flags = 0;
    let mut data_parts = Vec::new();

    for opt in options.split(',') {
        match opt {
            "defaults" => { /* handled by not setting any restrictive flags */ }
            "ro" => flags |= libc::MS_RDONLY,
            "rw" => flags &= !libc::MS_RDONLY,
            "noexec" => flags |= libc::MS_NOEXEC,
            "nosuid" => flags |= libc::MS_NOSUID,
            "nodev" => flags |= libc::MS_NODEV,
            "sync" => flags |= libc::MS_SYNCHRONOUS,
            "dirsync" => flags |= libc::MS_DIRSYNC,
            "bind" => flags |= libc::MS_BIND,
            "rbind" => flags |= libc::MS_BIND | libc::MS_REC,
            "remount" => flags |= libc::MS_REMOUNT,
            _ => {
                if !opt.is_empty() {
                    data_parts.push(opt);
                }
            }
        }
    }

    let data = if data_parts.is_empty() {
        None
    } else {
        Some(data_parts.join(","))
    };

    Ok((flags, data))
}

pub fn mount_from_fstab(entries: &[FstabEntry]) -> Result<(), Box<dyn std::error::Error>> {
    for entry in entries {
        if entry.fstype == "swap" {
            println!("Skipping swap: {}", entry.source);
            continue;
        }

        if entry.mountpoint == "none" {
            continue;
        }

        if entry.options.contains("noauto") {
            continue;
        }

        let (flags, data) = parse_mount_options(&entry.options)?;

        let source_c = CString::new(&*entry.source)?;
        let target_c = CString::new(&*entry.mountpoint)?;
        let fstype_c = CString::new(&*entry.fstype)?;
        let data_c = data.map(|s| CString::new(s).expect("\x1b[31m * \x1b[0m Something went wrong while mounting partitions. You are going to rescue mode..."));

        let data_ptr = data_c
            .as_ref()
            .map_or(std::ptr::null(), |s| s.as_ptr() as *const libc::c_void);

        let ret = unsafe {
            libc::syscall(
                libc::SYS_mount,
                source_c.as_ptr(),
                target_c.as_ptr(),
                fstype_c.as_ptr(),
                flags,
                data_ptr,
            )
        };

        if ret != 0 {
            eprintln!(
                "\x1b[31m * \x1b[0m Failed to mount {}: {}",
                entry.mountpoint,
                std::io::Error::last_os_error()
            );
        } else {
            println!("\x1b[32m * \x1b[0m Mounted {}", entry.mountpoint);
        }
    }
    Ok(())
}