fn run() -> Result<()> {
    let matches = App::new("Clean XAR Mounts")
        .arg(
            Arg::with_name("timeout")
                .long("timeout")
                .default_value("15")
                .help("time, in minutes, after a xar was mounted to attempt to unmount it"),
        )
        .arg(
            Arg::with_name("verbose")
                .long("verbose")
                .short("v")
                .help("display detailed output"),
        )
        .arg(
            Arg::with_name("dryrun")
                .long("dry-run")
                .help("display detailed output"),
        )
        .get_matches();
    let timeout = value_t!(matches, "timeout", u32)?;
    let dryrun = matches.is_present("dryrun");
    let level = if matches.is_present("verbose") {
        slog::Level::Debug
    } else {
        slog::Level::Info
    };

    let root_log = setup_logger(level);

    let orig_ns_fd = nix::fcntl::open(
        "/proc/self/ns/mnt",
        nix::fcntl::OFlag::O_RDONLY,
        nix::sys::stat::Mode::from_bits(0700).unwrap(),
    )?;
    let mount_namespaces = get_mount_namespaces()?;
    info!(
        root_log,
        "Considering {} namespaces",
        mount_namespaces.len()
    );
    for nsinfo in mount_namespaces {
        info!(
            root_log,
            "Entering namespace {:?}...", nsinfo.namespace_path
        );
        // Enter the new namespace and then check /proc/mounts for the
        // now-visible mounts.
        let mounts = get_mounts(&nsinfo, &root_log);
        if mounts.is_err() {
            info!(
                root_log,
                "Unable to read mounts in {:?}", nsinfo.namespace_path
            );
            continue;
        }
        let _ns_saver = NamespaceSaver::new(orig_ns_fd, &nsinfo.namespace_path);
        if _ns_saver.is_err() && nix::unistd::geteuid().is_root() {
            info!(
                root_log,
                "Unable to enter namespace {:?}, skipping", nsinfo.namespace_path
            );
            continue;
        }
        for mount in mounts.unwrap() {
            let result = should_unmount(&root_log, &mount, timeout)?;
            if result.should_unmount {
                // TODO: consider forking and chrooting into the
                // process' chroot rather than constructing a path
                // from outside.  It may not always be true that we
                // can append paths to find the actual mount point to
                // unmount.
                let mut target = mount.chroot.clone();
                target.push(&mount.mountpoint[1..]); // strip leading slash
                info!(
                    root_log,
                    "unmounting {:?}:{:?}", nsinfo.namespace_path, target
                );
                if !dryrun {
                    if nix::unistd::geteuid().is_root() {
                        if let Err(e) = nix::mount::umount(&target) {
                            info!(root_log, "Failed to unmount {:?}: {}", target, e);
                        }
                    } else {
                        let output = Command::new("fusermount").arg("-u").arg(&target).output()?;
                        if !output.status.success() {
                            info!(
                                root_log,
                                "fusermount -u failed to unmount {:?}: {}",
                                target,
                                String::from_utf8_lossy(&output.stderr).trim()
                            );
                        }
                    }
                }
            }
        }
    }
    Ok(())
}
// This is our main function.
This is our main function.
This is our main function .
fn run() -> Result<()> {
    let matches = App::new("Clean XAR Mounts")
        .arg(
            Arg::with_name("timeout")
                .long("timeout")
                .default_value("15")
                .help("time, in minutes, after a xar was mounted to attempt to unmount it"),
        )
        .arg(
            Arg::with_name("verbose")
                .long("verbose")
                .short("v")
                .help("display detailed output"),
        )
        .arg(
            Arg::with_name("dryrun")
                .long("dry-run")
                .help("display detailed output"),
        )
        .get_matches();
    let timeout = value_t!(matches, "timeout", u32)?;
    let dryrun = matches.is_present("dryrun");
    let level = if matches.is_present("verbose") {
        slog::Level::Debug
    } else {
        slog::Level::Info
    };
    let root_log = setup_logger(level);
    let orig_ns_fd = nix::fcntl::open(
        "/proc/self/ns/mnt",
        nix::fcntl::OFlag::O_RDONLY,
        nix::sys::stat::Mode::from_bits(0700).unwrap(),
    )?;
    let mount_namespaces = get_mount_namespaces()?;
    info!(
        root_log,
        "Considering {} namespaces",
        mount_namespaces.len()
    );
    for nsinfo in mount_namespaces {
        info!(
            root_log,
            "Entering namespace {:?}...", nsinfo.namespace_path
        );
        // Enter the new namespace and then check /proc/mounts for the
        // now-visible mounts.
        let mounts = get_mounts(&nsinfo, &root_log);
        if mounts.is_err() {
            info!(
                root_log,
                "Unable to read mounts in {:?}", nsinfo.namespace_path
            );
            continue;
        }
        let _ns_saver = NamespaceSaver::new(orig_ns_fd, &nsinfo.namespace_path);
        if _ns_saver.is_err() && nix::unistd::geteuid().is_root() {
            info!(
                root_log,
                "Unable to enter namespace {:?}, skipping", nsinfo.namespace_path
            );
            continue;
        }
        for mount in mounts.unwrap() {
            let result = should_unmount(&root_log, &mount, timeout)?;
            if result.should_unmount {
                // TODO: consider forking and chrooting into the
                // process' chroot rather than constructing a path
                // from outside.  It may not always be true that we
                // can append paths to find the actual mount point to
                // unmount.
                let mut target = mount.chroot.clone();
                target.push(&mount.mountpoint[1..]); // strip leading slash
                info!(
                    root_log,
                    "unmounting {:?}:{:?}", nsinfo.namespace_path, target
                );
                if !dryrun {
                    if nix::unistd::geteuid().is_root() {
                        if let Err(e) = nix::mount::umount(&target) {
                            info!(root_log, "Failed to unmount {:?}: {}", target, e);
                        }
                    } else {
                        let output = Command::new("fusermount").arg("-u").arg(&target).output()?;
                        if !output.status.success() {
                            info!(
                                root_log,
                                "fusermount -u failed to unmount {:?}: {}",
                                target,
                                String::from_utf8_lossy(&output.stderr).trim()
                            );
                        }
                    }
                }
            }
        }
    }
    Ok(())
}
fn run ( ) -> Result < ( ) > { let matches = App :: new ( " " ) . arg ( Arg :: with_name ( " " ) . long ( " " ) . default_value ( " " ) . help ( " " ) , ) . arg ( Arg :: with_name ( " " ) . long ( " " ) . short ( " " ) . help ( " " ) , ) . arg ( Arg :: with_name ( " " ) . long ( " " ) . help ( " " ) , ) . get_matches ( ) ; let timeout = value_t ! ( matches " " u32 ) ? ; let dryrun = matches . is_present ( " " ) ; let level = if matches . is_present ( " " ) { slog :: Level :: Debug } else { slog :: Level :: Info } ; let root_log = setup_logger ( level ) ; let orig_ns_fd = nix :: fcntl :: open ( " " , nix :: fcntl :: OFlag :: O_RDONLY , nix :: sys :: stat :: Mode :: from_bits ( 0700 ) . unwrap ( ) , ) ? ; let mount_namespaces = get_mount_namespaces ( ) ? ; info ! ( root_log " " mount_namespaces len ( ) ) ; for nsinfo in mount_namespaces { info ! ( root_log " " nsinfo namespace_path ) ; // Enter the new namespace and then check /proc/mounts for the // now-visible mounts. let mounts = get_mounts ( & nsinfo , & root_log ) ; if mounts . is_err ( ) { info ! ( root_log " " nsinfo namespace_path ) ; continue ; } let _ns_saver = NamespaceSaver :: new ( orig_ns_fd , & nsinfo . namespace_path ) ; if _ns_saver . is_err ( ) && nix :: unistd :: geteuid ( ) . is_root ( ) { info ! ( root_log " " nsinfo namespace_path ) ; continue ; } for mount in mounts . unwrap ( ) { let result = should_unmount ( & root_log , & mount , timeout ) ? ; if result . should_unmount { // TODO: consider forking and chrooting into the // process' chroot rather than constructing a path // from outside.  It may not always be true that we // can append paths to find the actual mount point to // unmount. let mut target = mount . chroot . clone ( ) ; target . push ( & mount . mountpoint [ 1 .. ] ) ; // strip leading slash info ! ( root_log " " nsinfo namespace_path target ) ; if ! dryrun { if nix :: unistd :: geteuid ( ) . is_root ( ) { if let Err ( e ) = nix :: mount :: umount ( & target ) { info ! ( root_log " " target e ) ; } } else { let output = Command :: new ( " " ) . arg ( " " ) . arg ( & target ) . output ( ) ? ; if ! output . status . success ( ) { info ! ( root_log " " target String from_utf8_lossy ( output stderr ) trim ( ) ) ; } } } } } } Ok ( ( ) ) }
This is our main function.
This is our main function .