Skip to content
Snippets Groups Projects
mount.rs 10.3 KiB
Newer Older
#![cfg_attr(not(target_os = "redox"), feature(libc))]
#[cfg(not(target_os = "redox"))]
Jeremy Soller's avatar
Jeremy Soller committed
#[cfg(target_os = "redox")]
extern crate syscall;

Jeremy Soller's avatar
Jeremy Soller committed
extern crate uuid;
Jeremy Soller's avatar
Jeremy Soller committed
use std::io::{Read, Write};
use std::os::unix::io::{FromRawFd, RawFd};
use redoxfs::{mount, DiskCache, DiskFile, FileSystem};
#[cfg(target_os = "redox")]
extern "C" fn unmount_handler(_s: usize) {
    use std::sync::atomic::Ordering;
    redoxfs::IS_UMT.store(1, Ordering::SeqCst);
#[cfg(target_os = "redox")]
//set up a signal handler on redox, this implements unmounting. I have no idea what sa_flags is
//for, so I put 2. I don't think 0,0 is a valid sa_mask. I don't know what i'm doing here. When u
//send it a sigkill, it shuts off the filesystem
fn setsig() {
    use syscall::{sigaction, SigAction, SigActionFlags, SIGTERM};
    let sig_action = SigAction {
        sa_handler: Some(unmount_handler),
Xavier L'Heureux's avatar
Xavier L'Heureux committed
        sa_mask: [0, 0],
        sa_flags: SigActionFlags::empty(),
    };

    sigaction(SIGTERM, Some(&sig_action), None).unwrap();
#[cfg(not(target_os = "redox"))]
// on linux, this is implemented properly, so no need for this unscrupulous nonsense!
fn setsig() {
    ()
}
#[cfg(not(target_os = "redox"))]
fn fork() -> isize {
    unsafe { libc::fork() as isize }
}

#[cfg(not(target_os = "redox"))]
fn pipe(pipes: &mut [i32; 2]) -> isize {
Jeremy Soller's avatar
Jeremy Soller committed
    unsafe { libc::pipe(pipes.as_mut_ptr()) as isize }
Jeremy Soller's avatar
Jeremy Soller committed
#[cfg(not(target_os = "redox"))]
fn capability_mode() {
    ()
}

#[cfg(target_os = "redox")]
fn fork() -> isize {
    unsafe { syscall::Error::mux(syscall::clone(syscall::CloneFlags::empty())) as isize }
}

#[cfg(target_os = "redox")]
fn pipe(pipes: &mut [usize; 2]) -> isize {
    syscall::Error::mux(syscall::pipe2(pipes, 0)) as isize
}

Jeremy Soller's avatar
Jeremy Soller committed
#[cfg(target_os = "redox")]
fn capability_mode() {
    syscall::setrens(0, 0).expect("redoxfs: failed to enter null namespace");
}

Jeremy Soller's avatar
Jeremy Soller committed
fn usage() {
    println!("redoxfs [--uuid] [disk or uuid] [mountpoint] [block in hex]");
Jeremy Soller's avatar
Jeremy Soller committed
}

enum DiskId {
    Path(String),
    Uuid(Uuid),
}

fn filesystem_by_path(path: &str, block_opt: Option<u64>) -> Option<(String, FileSystem<DiskCache<DiskFile>>)> {
    println!("redoxfs: opening {}", path);
    match DiskFile::open(&path).map(|image| DiskCache::new(image)) {
        Ok(disk) => match redoxfs::FileSystem::open(disk, block_opt) {
            Ok(filesystem) => {
                println!(
                    "redoxfs: opened filesystem on {} with uuid {}",
                    path,
                    Uuid::from_bytes(&filesystem.header.1.uuid)
                        .unwrap()
                        .hyphenated()
                );

                return Some((path.to_string(), filesystem));
            }
            Err(err) => println!("redoxfs: failed to open filesystem {}: {}", path, err),
        },
        Err(err) => println!("redoxfs: failed to open image {}: {}", path, err),
    }
    None
}

Jeremy Soller's avatar
Jeremy Soller committed
#[cfg(not(target_os = "redox"))]
fn filesystem_by_uuid(_uuid: &Uuid, _block_opt: Option<u64>) -> Option<(String, FileSystem<DiskCache<DiskFile>>)> {
    None
}
Jeremy Soller's avatar
Jeremy Soller committed

#[cfg(target_os = "redox")]
fn filesystem_by_uuid(uuid: &Uuid, block_opt: Option<u64>) -> Option<(String, FileSystem<DiskCache<DiskFile>>)> {
Jeremy Soller's avatar
Jeremy Soller committed
    use std::fs;

    match fs::read_dir(":") {
Xavier L'Heureux's avatar
Xavier L'Heureux committed
        Ok(entries) => {
            for entry_res in entries {
                if let Ok(entry) = entry_res {
                    if let Ok(path) = entry.path().into_os_string().into_string() {
                        let scheme = path.trim_start_matches(':').trim_matches('/');
                        if scheme.starts_with("disk") {
                            println!("redoxfs: found scheme {}", scheme);
                            match fs::read_dir(&format!("{}:", scheme)) {
                                Ok(entries) => {
                                    for entry_res in entries {
                                        if let Ok(entry) = entry_res {
                                            if let Ok(path) = entry.path().into_os_string().into_string() {
                                                println!("redoxfs: found path {}", path);
                                                if let Some((path, filesystem)) = filesystem_by_path(&path, block_opt) {
                                                    if &filesystem.header.1.uuid == uuid.as_bytes() {
                                                        println!(
                                                            "redoxfs: filesystem on {} matches uuid {}",
                                                            path,
                                                            uuid.hyphenated()
                                                        );
                                                        return Some((path, filesystem))
                                                    } else {
                                                        println!(
                                                            "redoxfs: filesystem on {} does not match uuid {}",
                                                            path,
                                                            uuid.hyphenated()
                                                        );
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                                Err(err) => {
                                    println!("redoxfs: failed to list '{}': {}", scheme, err);
                                }
                            }
Jeremy Soller's avatar
Jeremy Soller committed
        Err(err) => {
            println!("redoxfs: failed to list schemes: {}", err);
        }
    }

fn daemon(disk_id: &DiskId, mountpoint: &str, block_opt: Option<u64>, mut write: File) -> ! {
    let filesystem_opt = match *disk_id {
Jeremy Soller's avatar
Jeremy Soller committed
        DiskId::Path(ref path) => {
            filesystem_by_path(path, block_opt)
Jeremy Soller's avatar
Jeremy Soller committed
        DiskId::Uuid(ref uuid) => {
            filesystem_by_uuid(uuid, block_opt)
Jeremy Soller's avatar
Jeremy Soller committed

    if let Some((path, filesystem)) = filesystem_opt {
        match mount(filesystem, &mountpoint, |mounted_path| {
            capability_mode();

            println!(
                "redoxfs: mounted filesystem on {} to {}",
                path,
                mounted_path.display()
            );
            let _ = write.write(&[0]);
        }) {
            Ok(()) => {
                process::exit(0);
            }
            Err(err) => {
                println!(
                    "redoxfs: failed to mount {} to {}: {}",
                    path, mountpoint, err
                );
            }
Jeremy Soller's avatar
Jeremy Soller committed
        }
    }

    match *disk_id {
        DiskId::Path(ref path) => {
            println!("redoxfs: not able to mount path {}", path);
Jeremy Soller's avatar
Jeremy Soller committed
        DiskId::Uuid(ref uuid) => {
            println!("redoxfs: not able to mount uuid {}", uuid.hyphenated());
Jeremy Soller's avatar
Jeremy Soller committed
    }

    let _ = write.write(&[1]);
    process::exit(1);
fn print_uuid(path: &str) {
    match DiskFile::open(&path).map(|image| DiskCache::new(image)) {
        Ok(disk) => match redoxfs::FileSystem::open(disk, None) {
            Ok(filesystem) => {
Xavier L'Heureux's avatar
Xavier L'Heureux committed
                println!(
                    "{}",
                    Uuid::from_bytes(&filesystem.header.1.uuid)
                        .unwrap()
                        .hyphenated()
                );
            }
            Err(err) => println!("redoxfs: failed to open filesystem {}: {}", path, err),
Xavier L'Heureux's avatar
Xavier L'Heureux committed
        Err(err) => println!("redoxfs: failed to open image {}: {}", path, err),
Jeremy Soller's avatar
Jeremy Soller committed
    let mut args = env::args().skip(1);

    let disk_id = match args.next() {
Xavier L'Heureux's avatar
Xavier L'Heureux committed
        Some(arg) => {
            if arg == "--uuid" {
                let uuid = match args.next() {
                    Some(arg) => match Uuid::parse_str(&arg) {
                        Ok(uuid) => uuid,
                        Err(err) => {
                            println!("redoxfs: invalid uuid '{}': {}", arg, err);
                            usage();
                            process::exit(1);
                        }
                    },
                    None => {
                        println!("redoxfs: no uuid provided");
Jeremy Soller's avatar
Jeremy Soller committed
                        usage();
                        process::exit(1);
                    }
Xavier L'Heureux's avatar
Xavier L'Heureux committed
                };

                DiskId::Uuid(uuid)
            } else if arg == "--get-uuid" {
                match args.next() {
                    Some(arg) => {
                        print_uuid(&arg);
                        process::exit(1);
                    }
                    None => {
                        println!("redoxfs: no disk provided");
                        usage();
                        process::exit(1);
                    }
                };
            } else {
                DiskId::Path(arg)
            }
        }
Jeremy Soller's avatar
Jeremy Soller committed
        None => {
            println!("redoxfs: no disk provided");
            usage();
            process::exit(1);
        }
    };

    let mountpoint = match args.next() {
        Some(arg) => arg,
        None => {
            println!("redoxfs: no mountpoint provided");
            usage();
            process::exit(1);
        }
    };
    let block_opt = match args.next() {
        Some(arg) => match u64::from_str_radix(&arg, 16) {
            Ok(block) => Some(block),
            Err(err) => {
                println!("redoxfs: invalid block '{}': {}", arg, err);
                usage();
                process::exit(1);
            }
        },
        None => None,
    };

    let mut pipes = [0; 2];
    if pipe(&mut pipes) == 0 {
        let mut read = unsafe { File::from_raw_fd(pipes[0] as RawFd) };
        let write = unsafe { File::from_raw_fd(pipes[1] as RawFd) };

        let pid = fork();
        if pid == 0 {
            drop(read);
            daemon(&disk_id, &mountpoint, block_opt, write);
        } else if pid > 0 {
            drop(write);

            let mut res = [0];
            read.read(&mut res).unwrap();

            process::exit(res[0] as i32);
        } else {
            panic!("redoxfs: failed to fork");
        }
    } else {
        panic!("redoxfs: failed to create pipe");
    }
}