sys-mount-3.0.1/.cargo_vcs_info.json0000644000000001360000000000100130130ustar { "git": { "sha1": "a6aa8818af8f504002b2f6fbe221243843b6c5e5" }, "path_in_vcs": "" }sys-mount-3.0.1/.gitignore000064400000000000000000000000361046102023000135720ustar 00000000000000/target **/*.rs.bk Cargo.lock sys-mount-3.0.1/.vscode/settings.json000064400000000000000000000002021046102023000156710ustar 00000000000000{ "rust-analyzer.checkOnSave.command": "clippy", "rust-analyzer.checkOnSave.extraArgs": ["--", "-W", "clippy::pedantic"] }sys-mount-3.0.1/CHANGELOG.md000064400000000000000000000012541046102023000134160ustar 00000000000000# 2.0.0 (2022-11-04) - Improvements to loopback device mounting support - `Mount::builder` is now the preferred way to configure mount options - `Mount::new` has been simplified to accept only a source and dest target - Which will attempt to automatically guess the filesystem type - Applied all suggestions from clippy's pedantic lints - Updated to Rust 2021 edition, with Rust 1.65.0 features - Updated all dependencies # 1.2.0 Add ability to mount any file that contains a filesystem # 1.1.0 Add `swapoff` and `Mounts` to API # 1.0.3 Fix ISO and squashfs mounting # 1.0.2 Fix the crate examples # 1.0.1 Fix source type parameter in `Mount` # 1.0.0 Intiail release sys-mount-3.0.1/Cargo.lock0000644000000344500000000000100107740ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "aho-corasick" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] [[package]] name = "anstream" version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", "utf8parse", ] [[package]] name = "anstyle" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" [[package]] name = "anstyle-parse" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" dependencies = [ "anstyle", "windows-sys 0.52.0", ] [[package]] name = "bindgen" version = "0.68.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "726e4313eb6ec35d2730258ad4e15b547ee75d6afaa1361a922e78e59b7d8078" dependencies = [ "bitflags", "cexpr", "clang-sys", "lazy_static", "lazycell", "peeking_take_while", "proc-macro2", "quote", "regex", "rustc-hash", "shlex", "syn", ] [[package]] name = "bitflags" version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" [[package]] name = "cexpr" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ "nom", ] [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clang-sys" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" dependencies = [ "glob", "libc", "libloading", ] [[package]] name = "clap" version = "4.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" version = "4.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" dependencies = [ "anstream", "anstyle", "clap_lex", "strsim", ] [[package]] name = "clap_lex" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "colorchoice" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "errno" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ "libc", "windows-sys 0.52.0", ] [[package]] name = "glob" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "lazycell" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libloading" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" dependencies = [ "cfg-if", "windows-sys 0.48.0", ] [[package]] name = "loopdev-3" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "378e7ca4e85e592564e6a96c362303972b5c7860367014383aadc10a8704fc38" dependencies = [ "bindgen", "errno", "libc", ] [[package]] name = "memchr" version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "minimal-lexical" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "nom" version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", ] [[package]] name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "peeking_take_while" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "pin-project-lite" version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "proc-macro2" version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] [[package]] name = "regex" version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "rustc-hash" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "smart-default" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eb01866308440fc64d6c44d9e86c5cc17adfe33c4d6eed55da9145044d0ffc1" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "strsim" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "sys-mount" version = "3.0.1" dependencies = [ "bitflags", "clap", "libc", "loopdev-3", "smart-default", "thiserror", "tracing", ] [[package]] name = "thiserror" version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "tracing" version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "pin-project-lite", "tracing-attributes", "tracing-core", ] [[package]] name = "tracing-attributes" version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "tracing-core" version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", ] [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "utf8parse" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ "windows-targets 0.48.5", ] [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets 0.52.0", ] [[package]] name = "windows-targets" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm 0.48.5", "windows_aarch64_msvc 0.48.5", "windows_i686_gnu 0.48.5", "windows_i686_msvc 0.48.5", "windows_x86_64_gnu 0.48.5", "windows_x86_64_gnullvm 0.48.5", "windows_x86_64_msvc 0.48.5", ] [[package]] name = "windows-targets" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" dependencies = [ "windows_aarch64_gnullvm 0.52.0", "windows_aarch64_msvc 0.52.0", "windows_i686_gnu 0.52.0", "windows_i686_msvc 0.52.0", "windows_x86_64_gnu 0.52.0", "windows_x86_64_gnullvm 0.52.0", "windows_x86_64_msvc 0.52.0", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" sys-mount-3.0.1/Cargo.toml0000644000000025240000000000100110140ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "sys-mount" version = "3.0.1" authors = ["Michael Aaron Murphy "] description = "High level FFI binding around the sys mount & umount2 calls" readme = "README.md" keywords = [ "linux", "sys", "mount", "umount", ] categories = [ "external-ffi-bindings", "filesystem", "os::unix-apis", ] license = "MIT OR Apache-2.0" repository = "https://github.com/pop-os/sys-mount" [dependencies.bitflags] version = "2.4.1" [dependencies.libc] version = "0.2.139" [dependencies.loopdev] version = "0.5.0" optional = true package = "loopdev-3" [dependencies.smart-default] version = "0.7.1" [dependencies.thiserror] version = "1.0.38" [dependencies.tracing] version = "0.1.37" [dev-dependencies.clap] version = "4.1.4" [features] default = ["loop"] loop = ["loopdev"] [badges.maintenance] status = "passively-maintained" sys-mount-3.0.1/Cargo.toml.orig000064400000000000000000000013301046102023000144670ustar 00000000000000[package] name = "sys-mount" version = "3.0.1" description = "High level FFI binding around the sys mount & umount2 calls" repository = "https://github.com/pop-os/sys-mount" authors = ["Michael Aaron Murphy "] license = "MIT OR Apache-2.0" keywords = ["linux", "sys", "mount", "umount"] categories = ["external-ffi-bindings", "filesystem", "os::unix-apis"] edition = "2021" [badges] maintenance = { status = "passively-maintained" } [dependencies] bitflags = "2.4.1" libc = "0.2.139" loopdev = { package = "loopdev-3", version = "0.5.0", optional = true } smart-default = "0.7.1" thiserror = "1.0.38" tracing = "0.1.37" [dev-dependencies] clap = "4.1.4" [features] default = ["loop"] loop = ["loopdev"] sys-mount-3.0.1/LICENSE000064400000000000000000000020561046102023000126130ustar 00000000000000MIT License Copyright (c) 2018-2022 System76 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. sys-mount-3.0.1/README.md000064400000000000000000000046771046102023000131000ustar 00000000000000# sys-mount ![Rust Compatibility](https://img.shields.io/badge/rust-1.24.1%20tested-green.svg) [![License](https://img.shields.io/badge/license-MIT-green.svg)](https://gitlab.com/evertiro/maco/blob/master/LICENSE) High level FFI bindings to the `mount` and `umount2` system calls, for Rust. ## Examples ### Mount This is how the `mount` command could be written with this API. ```rust extern crate clap; extern crate sys_mount; use clap::{App, Arg}; use sys_mount::{Mount, MountFlags, SupportedFilesystems}; use std::process::exit; fn main() { let matches = App::new("mount") .arg(Arg::with_name("source").required(true)) .arg(Arg::with_name("directory").required(true)) .get_matches(); let src = matches.value_of("source").unwrap(); let dir = matches.value_of("directory").unwrap(); // Fetch a listed of supported file systems on this system. This will be used // as the fstype to `Mount::new`, as the `Auto` mount parameter. let supported = match SupportedFilesystems::new() { Ok(supported) => supported, Err(why) => { eprintln!("failed to get supported file systems: {}", why); exit(1); } }; // The source block will be mounted to the target directory, and the fstype is likely // one of the supported file systems. let result = Mount::builder() .fstype(FilesystemType::from(&supported)) .mount(src, dir); match result { Ok(mount) => { println!("mounted {} ({}) to {}", src, mount.get_fstype(), dir); } Err(why) => { eprintln!("failed to mount {} to {}: {}", src, dir, why); exit(1); } } } ``` ### Umount This is how the `umount` command could be implemented. ```rust extern crate clap; extern crate sys_mount; use clap::{App, Arg}; use sys_mount::{unmount, UnmountFlags}; use std::process::exit; fn main() { let matches = App::new("umount") .arg(Arg::with_name("lazy") .short("l") .long("lazy")) .arg(Arg::with_name("source").required(true)) .get_matches(); let src = matches.value_of("source").unwrap(); let flags = if matches.is_present("lazy") { UnmountFlags::DETACH } else { UnmountFlags::empty() }; match unmount(src, flags) { Ok(()) => (), Err(why) => { eprintln!("failed to unmount {}: {}", src, why); exit(1); } } } ```sys-mount-3.0.1/examples/mount.rs000064400000000000000000000025451046102023000151370ustar 00000000000000// Copyright 2018-2022 System76 // SPDX-License-Identifier: MIT OR Apache-2.0 use clap::{Arg, Command}; use std::process::ExitCode; use sys_mount::{Mount, SupportedFilesystems}; fn main() -> ExitCode { let matches = Command::new("mount") .arg(Arg::new("source").required(true)) .arg(Arg::new("directory").required(true)) .get_matches(); let src = matches.get_one::("source").unwrap(); let dir = matches.get_one::("directory").unwrap(); // Fetch a listed of supported file systems on this system. This will be used // as the fstype to `Mount::new`, as the `Auto` mount parameter. let supported = match SupportedFilesystems::new() { Ok(supported) => supported, Err(why) => { eprintln!("failed to get supported file systems: {}", why); return ExitCode::FAILURE; } }; // The source block will be mounted to the target directory, and the fstype is likely // one of the supported file systems. match Mount::builder().fstype(&supported).mount(src, dir) { Ok(mount) => { println!("mounted {} ({}) to {}", src, mount.get_fstype(), dir); ExitCode::SUCCESS } Err(why) => { eprintln!("failed to mount {} to {}: {}", src, dir, why); ExitCode::FAILURE } } } sys-mount-3.0.1/examples/umount.rs000064400000000000000000000014171046102023000153210ustar 00000000000000// Copyright 2018-2022 System76 // SPDX-License-Identifier: MIT OR Apache-2.0 extern crate clap; extern crate sys_mount; use clap::{Arg, Command}; use std::process::ExitCode; use sys_mount::{unmount, UnmountFlags}; fn main() -> ExitCode { let matches = Command::new("umount") .arg(Arg::new("lazy").short('l').long("lazy")) .arg(Arg::new("source").required(true)) .get_matches(); let src = matches.get_one::("source").unwrap(); let flags = if matches.get_flag("lazy") { UnmountFlags::DETACH } else { UnmountFlags::empty() }; let Err(why) = unmount(src, flags) else { return ExitCode::SUCCESS; }; eprintln!("failed to unmount {}: {}", src, why); ExitCode::FAILURE } sys-mount-3.0.1/src/builder.rs000064400000000000000000000227631046102023000144000ustar 00000000000000// Copyright 2018-2022 System76 // SPDX-License-Identifier: MIT OR Apache-2.0 use super::to_cstring; use crate::{ io, libc, CString, FilesystemType, Mount, MountFlags, OsStrExt, Path, SupportedFilesystems, Unmount, UnmountDrop, UnmountFlags, }; use libc::mount; use std::ptr; /// Builder API for mounting devices /// /// ```no_run /// use sys_mount::*; /// /// fn main() -> std::io::Result<()> { /// let _mount = Mount::builder() /// .fstype("btrfs") /// .data("subvol=@home") /// .mount("/dev/sda1", "/home")?; /// Ok(()) /// } /// ``` #[derive(Clone, Copy, smart_default::SmartDefault)] #[allow(clippy::module_name_repetitions)] pub struct MountBuilder<'a> { #[default(MountFlags::empty())] flags: MountFlags, fstype: Option>, #[cfg(feature = "loop")] loopback_offset: u64, #[cfg(feature = "loop")] explicit_loopback: bool, data: Option<&'a str>, } impl<'a> MountBuilder<'a> { /// Options to apply for the file system on mount. #[must_use] pub fn data(mut self, data: &'a str) -> Self { self.data = Some(data); self } /// The file system that is to be mounted. #[must_use] pub fn fstype(mut self, fs: impl Into>) -> Self { self.fstype = Some(fs.into()); self } /// Mount flags for the mount syscall. #[must_use] pub fn flags(mut self, flags: MountFlags) -> Self { self.flags = flags; self } /// Offset for the loopback device #[cfg(feature = "loop")] #[must_use] pub fn loopback_offset(mut self, offset: u64) -> Self { self.loopback_offset = offset; self } /// Use loopback even if not an iso or squashfs is being mounted #[cfg(feature = "loop")] #[must_use] pub fn explicit_loopback(mut self) -> Self { self.explicit_loopback = true; self } /// Mounts a file system at `source` to a `target` path in the system. /// /// ```rust,no_run /// use sys_mount::{ /// Mount, /// MountFlags, /// SupportedFilesystems /// }; /// /// // Fetch a list of supported file systems. /// // When mounting, a file system will be selected from this. /// let supported = SupportedFilesystems::new().unwrap(); /// /// // Attempt to mount the src device to the dest directory. /// let mount_result = Mount::builder() /// .fstype(&supported) /// .mount("/imaginary/block/device", "/tmp/location"); /// ``` /// # Notes /// /// The provided `source` device and `target` destinations must exist within the file system. /// /// If the `source` is a file with an extension, a loopback device will be created, and the /// file will be associated with the loopback device. If the extension is `iso` or `squashfs`, /// the filesystem type will be set accordingly, and the `MountFlags` will also be modified to /// ensure that the `MountFlags::RDONLY` flag is set before mounting. /// /// The `fstype` parameter accepts either a `&str` or `&SupportedFilesystem` as input. If the /// input is a `&str`, then a particular file system will be used to mount the `source` with. /// If the input is a `&SupportedFilesystems`, then the file system will be selected /// automatically from the list. /// /// The automatic variant of `fstype` works by attempting to mount the `source` with all /// supported device-based file systems until it succeeds, or fails after trying all /// possible options. /// /// # Errors /// /// - If a fstype is not defined and supported filesystems cannot be detected /// - If a loopback device cannot be created /// - If the source or target are not valid C strings /// - If mounting fails pub fn mount(self, source: impl AsRef, target: impl AsRef) -> io::Result { let MountBuilder { data, fstype, flags, #[cfg(feature = "loop")] loopback_offset, #[cfg(feature = "loop")] explicit_loopback, } = self; let supported; let fstype = if let Some(fstype) = fstype { fstype } else { supported = SupportedFilesystems::new()?; FilesystemType::Auto(&supported) }; let source = source.as_ref(); let mut c_source = None; #[cfg(feature = "loop")] let (mut flags, mut fstype, mut loopback, mut loop_path) = (flags, fstype, None, None); if !source.as_os_str().is_empty() { #[cfg(feature = "loop")] let mut create_loopback = |flags: &MountFlags| -> io::Result { let new_loopback = loopdev::LoopControl::open()?.next_free()?; new_loopback .with() .read_only(flags.contains(MountFlags::RDONLY)) .offset(loopback_offset) .attach(source)?; let path = new_loopback.path().expect("loopback does not have path"); c_source = Some(to_cstring(path.as_os_str().as_bytes())?); loop_path = Some(path); Ok(new_loopback) }; // Create a loopback device if an iso or squashfs is being mounted. #[cfg(feature = "loop")] if let Some(ext) = source.extension() { let extf = i32::from(ext == "iso") | if ext == "squashfs" { 2 } else { 0 }; if extf != 0 { fstype = if extf == 1 { flags |= MountFlags::RDONLY; FilesystemType::Manual("iso9660") } else { flags |= MountFlags::RDONLY; FilesystemType::Manual("squashfs") }; } loopback = Some(create_loopback(&flags)?); } #[cfg(feature = "loop")] if loopback.is_none() && explicit_loopback { loopback = Some(create_loopback(&flags)?); } if c_source.is_none() { c_source = Some(to_cstring(source.as_os_str().as_bytes())?); } }; let c_target = to_cstring(target.as_ref().as_os_str().as_bytes())?; let data = match data.map(|o| to_cstring(o.as_bytes())) { Some(Ok(string)) => Some(string), Some(Err(why)) => return Err(why), None => None, }; let mut mount_data = MountData { c_source, c_target, flags, data, }; let mut res = match fstype { FilesystemType::Auto(supported) => mount_data.automount(supported.dev_file_systems()), FilesystemType::Set(set) => mount_data.automount(set.iter().copied()), FilesystemType::Manual(fstype) => mount_data.mount(fstype), }; match res { Ok(ref mut _mount) => { #[cfg(feature = "loop")] { _mount.loopback = loopback; _mount.loop_path = loop_path; } } Err(_) => { #[cfg(feature = "loop")] if let Some(loopback) = loopback { let _res = loopback.detach(); } } } res } /// Perform a mount which auto-unmounts on drop. /// /// # Errors /// /// On failure to mount pub fn mount_autodrop( self, source: impl AsRef, target: impl AsRef, unmount_flags: UnmountFlags, ) -> io::Result> { self.mount(source, target) .map(|m| m.into_unmount_drop(unmount_flags)) } } struct MountData { c_source: Option, c_target: CString, flags: MountFlags, data: Option, } impl MountData { fn mount(&mut self, fstype: &str) -> io::Result { let c_fstype = to_cstring(fstype.as_bytes())?; match mount_( self.c_source.as_ref(), &self.c_target, &c_fstype, self.flags, self.data.as_ref(), ) { Ok(()) => Ok(Mount::from_target_and_fstype( self.c_target.clone(), fstype.to_owned(), )), Err(why) => Err(why), } } fn automount<'a, I: Iterator + 'a>(mut self, iter: I) -> io::Result { let mut res = Ok(()); for fstype in iter { match self.mount(fstype) { mount @ Ok(_) => return mount, Err(why) => res = Err(why), } } match res { Ok(()) => Err(io::Error::new( io::ErrorKind::NotFound, "no supported file systems found", )), Err(why) => Err(why), } } } fn mount_( c_source: Option<&CString>, c_target: &CString, c_fstype: &CString, flags: MountFlags, c_data: Option<&CString>, ) -> io::Result<()> { let result = unsafe { mount( c_source.map_or_else(ptr::null, |s| s.as_ptr()), c_target.as_ptr(), c_fstype.as_ptr(), flags.bits(), c_data .map_or_else(ptr::null, |s| s.as_ptr()) .cast::(), ) }; match result { 0 => Ok(()), _err => Err(io::Error::last_os_error()), } } sys-mount-3.0.1/src/flags.rs000064400000000000000000000143461046102023000140440ustar 00000000000000// Copyright 2018-2022 System76 // SPDX-License-Identifier: MIT OR Apache-2.0 use libc::{ c_int, c_ulong, MNT_DETACH, MNT_EXPIRE, MNT_FORCE, MS_BIND, MS_DIRSYNC, MS_MANDLOCK, MS_MOVE, MS_NOATIME, MS_NODEV, MS_NODIRATIME, MS_NOEXEC, MS_NOSUID, MS_RDONLY, MS_REC, MS_RELATIME, MS_REMOUNT, MS_SILENT, MS_STRICTATIME, MS_SYNCHRONOUS, O_NOFOLLOW, }; bitflags! { /// Flags which may be specified when mounting a file system. #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct MountFlags: c_ulong { /// Perform a bind mount, making a file or a directory subtree visible at another /// point within a file system. Bind mounts may cross file system boundaries and /// span chroot(2) jails. The filesystemtype and data arguments are ignored. Up /// until Linux 2.6.26, mountflags was also ignored (the bind mount has the same /// mount options as the underlying mount point). const BIND = MS_BIND; /// Make directory changes on this file system synchronous.(This property can be /// obtained for individual directories or subtrees using chattr(1).) const DIRSYNC = MS_DIRSYNC; /// Permit mandatory locking on files in this file system. (Mandatory locking must /// still be enabled on a per-file basis, as described in fcntl(2).) const MANDLOCK = MS_MANDLOCK; /// Move a subtree. source specifies an existing mount point and target specifies /// the new location. The move is atomic: at no point is the subtree unmounted. /// The filesystemtype, mountflags, and data arguments are ignored. const MOVE = MS_MOVE; /// Do not update access times for (all types of) files on this file system. const NOATIME = MS_NOATIME; /// Do not allow access to devices (special files) on this file system. const NODEV = MS_NODEV; /// Do not update access times for directories on this file system. This flag provides /// a subset of the functionality provided by MS_NOATIME; that is, MS_NOATIME implies /// MS_NODIRATIME. const NODIRATIME = MS_NODIRATIME; /// Do not allow programs to be executed from this file system. const NOEXEC = MS_NOEXEC; /// Do not honor set-user-ID and set-group-ID bits when executing programs from this /// file system. const NOSUID = MS_NOSUID; /// Mount file system read-only. const RDONLY = MS_RDONLY; /// Used in conjunction with MS_BIND to create a recursive bind mount, and in /// conjunction with the propagation type flags to recursively change the propagation /// type of all of the mounts in a subtree. const REC = MS_REC; /// When a file on this file system is accessed, only update the file's last access /// time (atime) if the current value of atime is less than or equal to the file's /// last modification time (mtime) or last status change time (ctime). This option is /// useful for programs, such as mutt(1), that need to know when a file has been read /// since it was last modified. Since Linux 2.6.30, the kernel defaults to the behavior /// provided by this flag (unless MS_NOATIME was specified), and the MS_STRICTATIME /// flag is required to obtain traditional semantics. In addition, since Linux 2.6.30, /// the file's last access time is always updated if it is more than 1 day old. const RELATIME = MS_RELATIME; /// Remount an existing mount. This allows you to change the mountflags and data of an /// existing mount without having to unmount and remount the file system. target should /// be the same value specified in the initial mount() call; source and filesystemtype /// are ignored. /// /// The following mountflags can be changed: MS_RDONLY, MS_SYNCHRONOUS, MS_MANDLOCK; /// before kernel 2.6.16, the following could also be changed: MS_NOATIME and /// MS_NODIRATIME; and, additionally, before kernel 2.4.10, the following could also /// be changed: MS_NOSUID, MS_NODEV, MS_NOEXEC. const REMOUNT = MS_REMOUNT; /// Suppress the display of certain (printk()) warning messages in the kernel log. /// This flag supersedes the misnamed and obsolete MS_VERBOSE flag (available /// since Linux 2.4.12), which has the same meaning. const SILENT = MS_SILENT; /// Always update the last access time (atime) when files on this file system are /// accessed. (This was the default behavior before Linux 2.6.30.) Specifying this /// flag overrides the effect of setting the MS_NOATIME and MS_RELATIME flags. const STRICTATIME = MS_STRICTATIME; /// Make writes on this file system synchronous (as though the O_SYNC flag to /// open(2) was specified for all file opens to this file system). const SYNCHRONOUS = MS_SYNCHRONOUS; } } bitflags! { /// Flags which may be specified when unmounting a file system. #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct UnmountFlags: c_int { /// Force unmount even if busy. This can cause data loss. (Only for NFS mounts.) const FORCE = MNT_FORCE; /// Perform a lazy unmount: make the mount point unavailable for new accesses, /// and actually perform the unmount when the mount point ceases to be busy. const DETACH = MNT_DETACH; /// Mark the mount point as expired. If a mount point is not currently in use, /// then an initial call to umount2() with this flag fails with the error EAGAIN, /// but marks the mount point as expired. The mount point remains expired as /// long as it isn't accessed by any process. A second umount2() call specifying /// MNT_EXPIRE unmounts an expired mount point. This flag cannot be specified with /// either MNT_FORCE or MNT_DETACH. const EXPIRE = MNT_EXPIRE; /// Don't dereference target if it is a symbolic link. This flag allows security /// problems to be avoided in set-user-ID-root programs that allow unprivileged /// users to unmount file systems. const NOFOLLOW = O_NOFOLLOW; } } sys-mount-3.0.1/src/fstype.rs000064400000000000000000000021011046102023000142440ustar 00000000000000// Copyright 2018-2022 System76 // SPDX-License-Identifier: MIT OR Apache-2.0 use crate::supported::SupportedFilesystems; /// Defines how the file system type should be derived for a mount -- auto or manual #[derive(Clone, Copy, Debug)] pub enum FilesystemType<'a> { /// The automatic variant will iterate through a list of pre-generated supported /// file systems, and attempt to mount each one before giving up. Auto(&'a SupportedFilesystems), /// The caller can avoid costly trial-and-error iteration with this variant. Manual(&'a str), /// A specific set of file systems to attempt to mount with. Set(&'a [&'a str]), } impl<'a> From<&'a SupportedFilesystems> for FilesystemType<'a> { fn from(s: &'a SupportedFilesystems) -> Self { FilesystemType::Auto(s) } } impl<'a> From<&'a str> for FilesystemType<'a> { fn from(s: &'a str) -> Self { FilesystemType::Manual(s) } } impl<'a> From<&'a [&'a str]> for FilesystemType<'a> { fn from(s: &'a [&'a str]) -> Self { FilesystemType::Set(s) } } sys-mount-3.0.1/src/lib.rs000064400000000000000000000074031046102023000135120ustar 00000000000000// Copyright 2018-2022 System76 // SPDX-License-Identifier: MIT OR Apache-2.0 //! High level abstraction over the `mount` and `umount2` system calls. //! //! If the `loop` feature is enabled (default), additionally supports creating loopback devices //! automatically when mounting an iso or squashfs file. //! //! # Example //! //! ```rust,no_run //! extern crate sys_mount; //! //! use std::process::exit; //! use sys_mount::{ //! Mount, //! MountFlags, //! SupportedFilesystems, //! Unmount, //! UnmountFlags //! }; //! //! fn main() { //! // Fetch a list of supported file systems. //! // When mounting, a file system will be selected from this. //! let supported = SupportedFilesystems::new().unwrap(); //! //! // Attempt to mount the src device to the dest directory. //! let mount_result = Mount::builder() //! .fstype("btrfs") //! .data("subvol=@home") //! .mount("/dev/sda1", "/home"); //! //! match mount_result { //! Ok(mount) => { //! // Make the mount temporary, so that it will be unmounted on drop. //! let mount = mount.into_unmount_drop(UnmountFlags::DETACH); //! // Do thing with the mounted device. //! } //! Err(why) => { //! eprintln!("failed to mount device: {}", why); //! exit(1); //! } //! } //! } extern crate libc; #[macro_use] extern crate bitflags; #[macro_use] extern crate thiserror; mod builder; mod flags; mod fstype; mod mount; mod supported; mod umount; pub use self::{builder::*, flags::*, fstype::*, mount::*, supported::*, umount::*}; use libc::swapoff as c_swapoff; use std::{ ffi::CString, io::{self, Error, ErrorKind}, os::unix::ffi::OsStrExt, path::Path, }; #[derive(Debug, Error)] pub enum ScopedMountError { #[error("cannot get list of supported file systems")] Supported(#[source] io::Error), #[error("could not mount partition")] Mount(#[source] io::Error), } /// Mount a partition temporarily for the duration of the scoped block within. /// /// # Errors /// /// - Fails if the supported file systems cannot be found. /// - Or if it fails to unmount pub fn scoped_mount T>( source: &Path, mount_at: &Path, scope: S, ) -> Result { let supported = SupportedFilesystems::new().map_err(ScopedMountError::Supported)?; Mount::builder() .fstype(&supported) .mount(source, mount_at) .map_err(ScopedMountError::Mount)?; let result = scope(); if let Err(why) = unmount(mount_at, UnmountFlags::empty()) { tracing::warn!("{}: failed to unmount: {}", mount_at.display(), why); } Ok(result) } /// Unmounts a swap partition using `libc::swapoff` /// /// # Errors /// /// - If the destination path is not a valid C String /// - Or the swapoff function fails pub fn swapoff>(dest: P) -> io::Result<()> { let Ok(swap) = CString::new(dest.as_ref().as_os_str().as_bytes().to_owned()) else { return Err(Error::new( ErrorKind::Other, format!( "swap path is not a valid c string: '{}'", dest.as_ref().display() ) )) }; match unsafe { c_swapoff(swap.as_ptr()) } { 0 => Ok(()), _err => Err(Error::new( ErrorKind::Other, format!( "failed to swapoff {}: {}", dest.as_ref().display(), Error::last_os_error() ), )), } } #[inline] fn to_cstring(data: &[u8]) -> io::Result { CString::new(data).map_err(|why| { io::Error::new( io::ErrorKind::InvalidData, format!("failed to create `CString`: {}", why), ) }) } sys-mount-3.0.1/src/mount.rs000064400000000000000000000071401046102023000141040ustar 00000000000000// Copyright 2018-2022 System76 // SPDX-License-Identifier: MIT OR Apache-2.0 use crate::umount::{unmount_, Unmount, UnmountDrop}; use crate::{MountBuilder, UnmountFlags}; use std::{ ffi::{CString, OsStr}, io, os::unix::ffi::OsStrExt, path::Path, }; /// Handle for managing a mounted file system. #[derive(Debug)] pub struct Mount { pub(crate) target: CString, pub(crate) fstype: String, #[cfg(feature = "loop")] pub(crate) loopback: Option, pub(crate) loop_path: Option, } impl Unmount for Mount { fn unmount(&self, flags: UnmountFlags) -> io::Result<()> { unsafe { unmount_(self.target.as_ptr(), flags)?; } #[cfg(feature = "loop")] if let Some(ref loopback) = self.loopback { loopback.detach()?; } Ok(()) } } impl Mount { /// Creates a [`MountBuilder`] for configuring a new mount. /// /// ```no_run /// use sys_mount::*; /// /// fn main() -> std::io::Result<()> { /// let _mount = Mount::builder() /// .fstype("btrfs") /// .data("subvol=@home") /// .mount("/dev/sda1", "/home")?; /// Ok(()) /// } /// ``` #[inline] #[must_use] pub fn builder<'a>() -> MountBuilder<'a> { MountBuilder::default() } /// Mounts the source device to the target path. /// /// Attempts to automatically detect the filesystem of the source device. /// /// For more flexibility, use [`Mount::builder`] instead. /// /// # Errors /// /// Errors if supported filesystems cannot be detected, or the mount fails. #[inline] pub fn new(source: impl AsRef, target: impl AsRef) -> io::Result { let supported = crate::SupportedFilesystems::new()?; MountBuilder::default() .fstype(&supported) .mount(source, target) } /// If the device was associated with a loopback device, that device's path /// can be retrieved here. #[inline] #[must_use] pub fn backing_loop_device(&self) -> Option<&Path> { self.loop_path.as_deref() } /// Describes the file system which this mount was mounted with. /// /// This is useful in the event that the mounted device was mounted automatically. #[inline] #[must_use] pub fn get_fstype(&self) -> &str { &self.fstype } /// Return the path this mount was mounted on. #[inline] #[must_use] pub fn target_path(&self) -> &Path { Path::new(OsStr::from_bytes(self.target.as_bytes())) } #[inline] pub(crate) fn from_target_and_fstype(target: CString, fstype: String) -> Self { Mount { target, fstype, #[cfg(feature = "loop")] loopback: None, loop_path: None, } } } /// An abstraction that will ensure that temporary mounts are dropped in reverse. pub struct Mounts(pub Vec>); impl Mounts { /// Unmounts all mounts, with the option to do so lazily. /// /// # Errors /// /// Returns on the first error when unmounting. pub fn unmount(&mut self, lazy: bool) -> io::Result<()> { let flags = if lazy { UnmountFlags::DETACH } else { UnmountFlags::empty() }; self.0 .iter_mut() .rev() .try_for_each(|mount| mount.unmount(flags)) } } impl Drop for Mounts { fn drop(&mut self) { for mount in self.0.drain(..).rev() { drop(mount); } } } sys-mount-3.0.1/src/supported.rs000064400000000000000000000054261046102023000147740ustar 00000000000000// Copyright 2018-2022 System76 // SPDX-License-Identifier: MIT OR Apache-2.0 use std::{ fs::File, io::{self, BufRead, BufReader}, }; /// Data structure for validating if a filesystem argument is valid, and used within /// automatic file system mounting. #[derive(Clone, Debug)] #[allow(clippy::module_name_repetitions)] pub struct SupportedFilesystems { nodev: Vec, fs: Vec, } impl SupportedFilesystems { /// Detects available supported file systems on the system /// /// # Errors /// /// - On failure to open `/proc/filesystems` pub fn new() -> io::Result { let mut fss = Vec::with_capacity(64); let mut nodevs = Vec::with_capacity(64); for line in BufReader::new(File::open("/proc/filesystems")?).lines() { let line = line?; let mut line = line.split_whitespace(); let (nodev, fs) = match (line.next(), line.next()) { (Some(fs), None) => (false, fs), (Some("nodev"), Some(fs)) => (true, fs), _ => continue, }; nodevs.push(nodev); fss.push(fs.to_owned()); } Ok(SupportedFilesystems { nodev: nodevs, fs: fss, }) } /// Check if a provided file system is valid on this system. /// /// ```rust /// extern crate sys_mount; /// /// use sys_mount::SupportedFilesystems; /// /// fn main() { /// let supports = SupportedFilesystems::new().unwrap(); /// println!("btrfs is {}", if supports.is_supported("btrfs") { /// "supported" /// } else { /// "not supported" /// }); /// } /// ``` #[must_use] pub fn is_supported(&self, fs: &str) -> bool { self.fs.iter().any(|s| s.as_str() == fs) } /// Iterate through file systems which are not associated with physical devices. #[must_use] pub fn nodev_file_systems<'a>(&'a self) -> Box + 'a> { // TODO: When we can, switch to `impl Iterator`. let iter = self.nodev.iter().enumerate().filter_map(move |(id, &x)| { if x { Some(self.fs[id].as_str()) } else { None } }); Box::new(iter) } /// Iterate through file systems which are associated with physical devices. #[must_use] pub fn dev_file_systems<'a>(&'a self) -> Box + 'a> { // TODO: When we can, switch to `impl Iterator`. let iter = self.nodev.iter().enumerate().filter_map(move |(id, &x)| { if x { None } else { Some(self.fs[id].as_str()) } }); Box::new(iter) } } sys-mount-3.0.1/src/umount.rs000064400000000000000000000052561046102023000142770ustar 00000000000000// Copyright 2018-2022 System76 // SPDX-License-Identifier: MIT OR Apache-2.0 use crate::UnmountFlags; use libc::{c_char, umount2}; use std::{ffi::CString, io, ops::Deref, os::unix::ffi::OsStrExt, path::Path, ptr}; /// Unmount trait which enables any type that implements it to be upgraded into an `UnmountDrop`. pub trait Unmount { /// Unmount this mount with the given `flags`. /// /// This will also detach the loopback device that the mount is assigned to, if /// it was associated with a loopback device. /// /// # Errors /// /// On failure to unmount fn unmount(&self, flags: UnmountFlags) -> io::Result<()>; /// Upgrades `Self` into an `UnmountDrop`, which will unmount the mount when it is dropped. fn into_unmount_drop(self, flags: UnmountFlags) -> UnmountDrop where Self: Sized, { UnmountDrop { mount: self, flags } } } /// Unmounts the underlying mounted device upon drop. pub struct UnmountDrop { pub(crate) mount: T, pub(crate) flags: UnmountFlags, } impl UnmountDrop { /// Modify the previously-set unmount flags. pub fn set_unmount_flags(&mut self, flags: UnmountFlags) { self.flags = flags; } } impl Deref for UnmountDrop { type Target = T; fn deref(&self) -> &T { &self.mount } } impl Drop for UnmountDrop { fn drop(&mut self) { let _res = self.mount.unmount(self.flags); } } /// Unmounts the device at `path` using the provided `UnmountFlags`. /// /// This will not detach a loopback device if the mount was attached to one. This behavior may /// change in the future, once the [loopdev](https://crates.io/crates/loopdev) crate supports /// querying loopback device info. /// /// # Errors /// /// - If the path is not a valid C String /// - Or the unmount function fails /// /// # Example /// /// ```rust,no_run /// extern crate sys_mount; /// /// use sys_mount::{unmount, UnmountFlags}; /// /// fn main() { /// // Unmount device at `/target/path` lazily. /// let result = unmount("/target/path", UnmountFlags::DETACH); /// } /// ``` pub fn unmount>(path: P, flags: UnmountFlags) -> io::Result<()> { let mount = CString::new(path.as_ref().as_os_str().as_bytes().to_owned()); let mount_ptr = mount .as_ref() .ok() .map_or(ptr::null(), |cstr| cstr.as_ptr()); unsafe { unmount_(mount_ptr, flags) } } #[inline] pub(crate) unsafe fn unmount_(mount_ptr: *const c_char, flags: UnmountFlags) -> io::Result<()> { match umount2(mount_ptr, flags.bits()) { 0 => Ok(()), _err => Err(io::Error::last_os_error()), } }