diff --git a/Cargo.lock b/Cargo.lock index a0b06edd..5e214521 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,10 +1,12 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "addr2line" -version = "0.14.1" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" dependencies = [ "gimli", ] @@ -23,27 +25,27 @@ checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" [[package]] name = "aho-corasick" -version = "0.7.15" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" dependencies = [ "memchr", ] [[package]] name = "ansi_term" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" dependencies = [ "winapi", ] [[package]] name = "anyhow" -version = "1.0.38" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1" +checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" [[package]] name = "apt-cli-wrappers" @@ -55,18 +57,6 @@ dependencies = [ "procfs", ] -[[package]] -name = "arrayref" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" - -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - [[package]] name = "atty" version = "0.2.14" @@ -80,39 +70,33 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.56" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d117600f438b1707d4e4ae15d3595657288f8235a0eb593e80ecc98ab34e1bc" +checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61" dependencies = [ "addr2line", - "cfg-if 1.0.0", + "cc", + "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", ] -[[package]] -name = "base64" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" - [[package]] name = "bindgen" -version = "0.53.3" +version = "0.58.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c72a978d268b1d70b0e963217e60fdabd9523a941457a6c42a7315d15c7e89e5" +checksum = "0f8523b410d7187a43085e7e064416ea32ded16bd0a4e6fc025e21616d01258f" dependencies = [ "bitflags", - "cexpr", - "cfg-if 0.1.10", + "cexpr 0.4.0", "clang-sys", "clap", "env_logger", @@ -129,21 +113,29 @@ dependencies = [ ] [[package]] -name = "bitflags" -version = "1.2.1" +name = "bindgen" +version = "0.59.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8" +dependencies = [ + "bitflags", + "cexpr 0.6.0", + "clang-sys", + "lazy_static", + "lazycell", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", +] [[package]] -name = "blake2b_simd" -version = "0.5.11" +name = "bitflags" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" -dependencies = [ - "arrayref", - "arrayvec", - "constant_time_eq", -] +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "byteorder" @@ -183,9 +175,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.67" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" [[package]] name = "cexpr" @@ -193,14 +185,17 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27" dependencies = [ - "nom", + "nom 5.1.2", ] [[package]] -name = "cfg-if" -version = "0.1.10" +name = "cexpr" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom 7.1.1", +] [[package]] name = "cfg-if" @@ -223,9 +218,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "0.29.3" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe6837df1d5cba2397b835c8530f51723267e16abbf83892e9e5af4f0e5dd10a" +checksum = "4cc00842eed744b858222c4c9faf7243aafc6d33f92f96935263ef4d8a41ce21" dependencies = [ "glob", "libc", @@ -234,9 +229,9 @@ dependencies = [ [[package]] name = "clap" -version = "2.33.3" +version = "2.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ "ansi_term", "atty", @@ -248,48 +243,75 @@ dependencies = [ ] [[package]] -name = "constant_time_eq" -version = "0.1.5" +name = "concat-in-place" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5b80dba65d26e0c4b692ad0312b837f1177e8175031af57fd1de4f3bc36b430" + +[[package]] +name = "const_format" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0936ffe6d0c8d6a51b3b0a73b2acbe925d786f346cf45bfddc8341d79fb7dc8a" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef196d5d972878a48da7decb7686eded338b4858fbabeed513d63a7c98b2b82d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "convert_case" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] name = "crc32fast" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] name = "crossbeam-channel" -version = "0.5.0" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775" +checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.3" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2584f639eb95fea8c798496315b297cf81b9b58b6d30ab066a75455333cf4b12" +checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" dependencies = [ - "cfg-if 1.0.0", + "autocfg", + "cfg-if", "crossbeam-utils", "lazy_static", "memoffset", @@ -298,12 +320,11 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.3" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" dependencies = [ - "autocfg", - "cfg-if 1.0.0", + "cfg-if", "lazy_static", ] @@ -329,12 +350,13 @@ dependencies = [ [[package]] name = "dbus" -version = "0.9.2" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f597e08dfa79b593f23bbfc7840b23b2c5aa2e3a98d8e68b67b5b9ff800dc0db" +checksum = "de0a745c25b32caa56b82a3950f5fec7893a960f4c10ca3b02060b0c38d8c2ce" dependencies = [ "libc", "libdbus-sys", + "winapi", ] [[package]] @@ -350,29 +372,31 @@ dependencies = [ [[package]] name = "derive_more" -version = "0.99.11" +version = "0.99.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cb0e6161ad61ed084a36ba71fbba9e3ac5aee3606fb607fe08da6acbcf3d8c" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ + "convert_case", "proc-macro2", "quote", + "rustc_version", "syn", ] [[package]] name = "dirs" -version = "3.0.1" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "142995ed02755914747cc6ca76fc7e4583cd18578746716d0508ea6ed558b9ff" +checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309" dependencies = [ "dirs-sys", ] [[package]] name = "dirs-sys" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" dependencies = [ "libc", "redox_users", @@ -383,7 +407,7 @@ dependencies = [ name = "disk-types" version = "0.1.5" dependencies = [ - "err-derive 0.3.0", + "err-derive 0.3.1", "libparted", "log", "os-detect", @@ -400,6 +424,8 @@ dependencies = [ "apt-cli-wrappers", "bitflags", "cascade 1.0.0", + "concat-in-place", + "const_format", "derive_more", "dirs", "disk-types", @@ -413,14 +439,14 @@ dependencies = [ "distinst-timezones", "distinst-utils", "envfile", - "err-derive 0.3.0", + "err-derive 0.3.1", "failure", "failure_derive", "fern", "fomat-macros", "fstab-generate", "hostname-validator", - "itertools 0.10.0", + "itertools", "libc", "libparted", "log", @@ -482,7 +508,7 @@ dependencies = [ "failure", "failure_derive", "fstab-generate", - "itertools 0.10.0", + "itertools", "libc", "libparted", "log", @@ -514,7 +540,7 @@ dependencies = [ name = "distinst-hardware-support" version = "0.1.0" dependencies = [ - "dbus 0.9.2", + "dbus 0.9.5", "distinst-utils", "log", "os-release", @@ -592,9 +618,9 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "env_logger" -version = "0.7.1" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" dependencies = [ "atty", "humantime", @@ -628,9 +654,9 @@ dependencies = [ [[package]] name = "err-derive" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcc7f65832b62ed38939f98966824eb6294911c3629b0e9a262bfb80836d9686" +checksum = "c34a887c8df3ed90498c1c437ce21f211c8e27672921a8ffa293cb8d6d4caa9e" dependencies = [ "proc-macro-error", "proc-macro2", @@ -642,9 +668,9 @@ dependencies = [ [[package]] name = "errno" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa68f2fb9cae9d37c9b2b3584aba698a2e97f72d7aef7b9f7aa71d8b54ce46fe" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" dependencies = [ "errno-dragonfly", "libc", @@ -653,11 +679,11 @@ dependencies = [ [[package]] name = "errno-dragonfly" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" dependencies = [ - "gcc", + "cc", "libc", ] @@ -688,11 +714,20 @@ dependencies = [ "synstructure", ] +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + [[package]] name = "fern" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9a4820f0ccc8a7afd67c39a0f1a0f4b07ca1725164271a64939d7aeb9af065" +checksum = "3bdd7b0849075e79ee9a1836df22c717d1eba30451796fdc631b04565dd11e2a" dependencies = [ "log", ] @@ -707,6 +742,7 @@ checksum = "fe56556a8c9f9f556150eb6b390bc1a8b3715fd2ddbb4585f36b6a5672c6a833" name = "fstab-generate" version = "0.1.2" dependencies = [ + "concat-in-place", "disk-types", "partition-identity", ] @@ -717,30 +753,24 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -[[package]] -name = "gcc" -version = "0.3.55" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" - [[package]] name = "getrandom" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "wasi 0.9.0+wasi-snapshot-preview1", ] [[package]] name = "getrandom" -version = "0.2.2" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "wasi 0.10.2+wasi-snapshot-preview1", ] @@ -766,9 +796,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.23.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" [[package]] name = "glob" @@ -778,18 +808,18 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "heck" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" dependencies = [ "unicode-segmentation", ] [[package]] name = "hermit-abi" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] @@ -802,42 +832,39 @@ checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" [[package]] name = "hostname-validator" -version = "1.0.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70b8bcb948d9f63a35f0527cde7ca4f4794e817451eaebd47a3c92ef6905c129" +checksum = "f558a64ac9af88b5ba400d99b579451af0d39c6d360980045b91aac966d705e2" [[package]] name = "humantime" -version = "1.3.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -dependencies = [ - "quick-error", -] +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] -name = "itertools" -version = "0.9.0" +name = "instant" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "either", + "cfg-if", ] [[package]] name = "itertools" -version = "0.10.0" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" dependencies = [ "either", ] [[package]] name = "itoa" -version = "0.4.7" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" [[package]] name = "lazy_static" @@ -853,15 +880,15 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.88" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b07a082330a35e43f63177cc01689da34fbffa0105e1246cf0311472cac73a" +checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" [[package]] name = "libdbus-sys" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc12a3bc971424edbbf7edaf6e5740483444db63aa8e23d3751ff12a30f306f0" +checksum = "c185b5b7ad900923ef3a8ff594083d4d9b5aea80bb4f32b8342363138c0d456b" dependencies = [ "pkg-config", ] @@ -880,19 +907,19 @@ dependencies = [ [[package]] name = "libloading" -version = "0.5.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" +checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" dependencies = [ - "cc", + "cfg-if", "winapi", ] [[package]] name = "libparted" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec38269ef0cf73e85149a81a2083bda75281c888e5da6fea8f31be490a220f3a" +checksum = "d3e3f767bdcb00e4fec15206d7c588b62cd1dbc4e36e1e90af1171baf87610ef" dependencies = [ "libc", "libparted-sys", @@ -900,11 +927,11 @@ dependencies = [ [[package]] name = "libparted-sys" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6e9358d23e00345992308519b2dd084a37456544cfdd05ee4c691a6a4e03bd" +checksum = "1d70e9f63341a566248e4549ffecebf66e2e7cdffc213e5cabb278f5046649e5" dependencies = [ - "bindgen", + "bindgen 0.58.1", ] [[package]] @@ -920,11 +947,11 @@ dependencies = [ [[package]] name = "log" -version = "0.4.14" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -939,37 +966,43 @@ dependencies = [ [[package]] name = "loopdev" -version = "0.2.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac9e35cfb6646d67059f2ca8913a90e6c60633053c103df423975297f33d6fcc" +checksum = "5bfa0855b04611e38acaff718542e9e809cddfc16535d39f9d9c694ab19f7388" dependencies = [ + "bindgen 0.59.2", "errno", "libc", ] [[package]] name = "memchr" -version = "2.3.4" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memoffset" -version = "0.6.1" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" dependencies = [ "autocfg", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" -version = "0.4.4" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082" dependencies = [ "adler", - "autocfg", ] [[package]] @@ -982,11 +1015,21 @@ dependencies = [ "version_check", ] +[[package]] +name = "nom" +version = "7.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "num-integer" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ "autocfg", "num-traits", @@ -994,18 +1037,18 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", ] [[package]] name = "num_cpus" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" dependencies = [ "hermit-abi", "libc", @@ -1013,25 +1056,28 @@ dependencies = [ [[package]] name = "numtoa" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e521b6adefa0b2c1fa5d2abdf9a5216288686fe6146249215d884c0e5ab320b0" +checksum = "6aa2c4e539b869820a2b82e1aef6ff40aa85e65decdd5185e83fb4b1249cd00f" [[package]] name = "object" -version = "0.23.0" +version = "0.28.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4" +checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" +dependencies = [ + "memchr", +] [[package]] name = "once_cell" -version = "1.7.2" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" +checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" [[package]] name = "os-detect" -version = "0.2.2" +version = "0.3.0" dependencies = [ "log", "os-release", @@ -1076,17 +1122,23 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + [[package]] name = "pkg-config" -version = "0.3.19" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" [[package]] name = "ppv-lite86" -version = "0.2.10" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "proc-macro-error" @@ -1114,9 +1166,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.24" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +checksum = "9027b48e9d4c9175fa2218adf3557f91c1137021739951d4932f5f8268ac48aa" dependencies = [ "unicode-xid", ] @@ -1152,17 +1204,11 @@ dependencies = [ "libflate", ] -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - [[package]] name = "quote" -version = "1.0.9" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" dependencies = [ "proc-macro2", ] @@ -1188,21 +1234,9 @@ checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ "getrandom 0.1.16", "libc", - "rand_chacha 0.2.2", + "rand_chacha", "rand_core 0.5.1", - "rand_hc 0.2.0", -] - -[[package]] -name = "rand" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" -dependencies = [ - "libc", - "rand_chacha 0.3.0", - "rand_core 0.6.2", - "rand_hc 0.3.0", + "rand_hc", ] [[package]] @@ -1215,16 +1249,6 @@ dependencies = [ "rand_core 0.5.1", ] -[[package]] -name = "rand_chacha" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.2", -] - [[package]] name = "rand_core" version = "0.3.1" @@ -1249,15 +1273,6 @@ dependencies = [ "getrandom 0.1.16", ] -[[package]] -name = "rand_core" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" -dependencies = [ - "getrandom 0.2.2", -] - [[package]] name = "rand_hc" version = "0.2.0" @@ -1267,15 +1282,6 @@ dependencies = [ "rand_core 0.5.1", ] -[[package]] -name = "rand_hc" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" -dependencies = [ - "rand_core 0.6.2", -] - [[package]] name = "raw-cpuid" version = "9.1.1" @@ -1287,9 +1293,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.5.0" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674" +checksum = "fd249e82c21598a9a426a4e00dd7adc1d640b22445ec8545feef801d1a74c221" dependencies = [ "autocfg", "crossbeam-deque", @@ -1299,14 +1305,13 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.9.0" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a" +checksum = "9f51245e1e62e1f1629cbfec37b5793bbabcaeb90f30e94d2ba03564687353e4" dependencies = [ "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "lazy_static", "num_cpus", ] @@ -1321,47 +1326,40 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" - -[[package]] -name = "redox_syscall" -version = "0.2.5" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" dependencies = [ "bitflags", ] [[package]] name = "redox_users" -version = "0.3.5" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom 0.1.16", - "redox_syscall 0.1.57", - "rust-argon2", + "getrandom 0.2.6", + "redox_syscall", + "thiserror", ] [[package]] name = "regex" -version = "1.4.3" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a" +checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" dependencies = [ "aho-corasick", "memchr", "regex-syntax", - "thread_local", ] [[package]] name = "regex-syntax" -version = "0.6.22" +version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "remove_dir_all" @@ -1374,27 +1372,15 @@ dependencies = [ [[package]] name = "rle-decode-fast" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac" - -[[package]] -name = "rust-argon2" -version = "0.8.3" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" -dependencies = [ - "base64", - "blake2b_simd", - "constant_time_eq", - "crossbeam-utils", -] +checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422" [[package]] name = "rustc-demangle" -version = "0.1.18" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" [[package]] name = "rustc-hash" @@ -1402,17 +1388,26 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + [[package]] name = "rustversion" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb5d2a036dc6d2d8fd16fde3498b04306e29bd193bf306a57427019b823d5acd" +checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" [[package]] name = "ryu" -version = "1.0.5" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" [[package]] name = "scopeguard" @@ -1422,18 +1417,24 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "sedregex" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e938a8943651a6f1ab7606996b758cdc4628cb7a8c27fb1e9923e5871716972f" +checksum = "19411e23596093f03bbd11dc45603b6329bb4bfec77b9fd13e2b9fc9b02efe3e" dependencies = [ "regex", ] +[[package]] +name = "semver" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd" + [[package]] name = "serde" -version = "1.0.124" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd761ff957cb2a45fbb9ab3da6512de9de55872866160b23c25f1a841e99d29f" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" dependencies = [ "serde_derive", ] @@ -1452,9 +1453,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.124" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1800f7693e94e186f5e25a28291ae1570da908aff7d97a095dec1e56ff99069b" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" dependencies = [ "proc-macro2", "quote", @@ -1463,9 +1464,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.64" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" +checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" dependencies = [ "itoa", "ryu", @@ -1474,9 +1475,9 @@ dependencies = [ [[package]] name = "shlex" -version = "0.1.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" [[package]] name = "smart-default" @@ -1506,9 +1507,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "syn" -version = "1.0.63" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd9bc7ccc2688b3344c2f48b9b546648b25ce0b20fc717ee7fa7981a8ca9717" +checksum = "7ff7c592601f11445996a06f8ad0c27f094a58857c2f89e97974ab9235b92c52" dependencies = [ "proc-macro2", "quote", @@ -1517,9 +1518,9 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.12.4" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ "proc-macro2", "quote", @@ -1529,13 +1530,16 @@ dependencies = [ [[package]] name = "sys-mount" -version = "1.2.1" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f5703caf67c45ad3450104001b4620a605e9def0cef13dde3c9add23f73cee" +checksum = "5c1af10c09a6d1f65753e52772a4621e00da8b1d772d0f24595b60ccd36d6b51" dependencies = [ "bitflags", "libc", "loopdev", + "smart-default", + "thiserror", + "tracing", ] [[package]] @@ -1549,11 +1553,11 @@ dependencies = [ [[package]] name = "systemd-boot-conf" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "967f8204e6b71a75e985e22414d744cbba779977972d51666299a831192ddc90" +checksum = "4545a0119a68d37acdd4588adb70f25e21a32171921e3503ef3ad59a0e1184b0" dependencies = [ - "itertools 0.9.0", + "itertools", "once_cell", "thiserror", ] @@ -1576,23 +1580,23 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.2.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", + "fastrand", "libc", - "rand 0.8.3", - "redox_syscall 0.2.5", + "redox_syscall", "remove_dir_all", "winapi", ] [[package]] name = "termcolor" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" dependencies = [ "winapi-util", ] @@ -1608,33 +1612,24 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.24" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.24" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" dependencies = [ "proc-macro2", "quote", "syn", ] -[[package]] -name = "thread_local" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd" -dependencies = [ - "once_cell", -] - [[package]] name = "time" version = "0.1.43" @@ -1647,13 +1642,45 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" dependencies = [ "serde", ] +[[package]] +name = "tracing" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc6b8ad3567499f98a1db7a752b07a7c8c7c7c34c332ec00effb2b0027974b7c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f" +dependencies = [ + "lazy_static", +] + [[package]] name = "unicode-segmentation" version = "1.9.0" @@ -1662,15 +1689,15 @@ checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" [[package]] name = "unicode-width" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "unicode-xid" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" [[package]] name = "unicode_categories" @@ -1686,9 +1713,9 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "version_check" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasi" @@ -1744,6 +1771,6 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "xml-rs" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a" +checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" diff --git a/Cargo.toml b/Cargo.toml index 1932acd6..f2c20e2d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,8 @@ pbr = "1.0.2" [dependencies] cascade = "1.0" +concat-in-place = "1.1.0" +const_format = "0.2.22" dirs = "3.0" disk-types = { path = "crates/disk-types"} distinst-bootloader = { path = "crates/bootloader" } @@ -55,7 +57,7 @@ os-release = "0.1.0" partition-identity = "0.2.8" proc-mounts = "0.2.4" rayon = "1.3.0" -sys-mount = "1.2.1" +sys-mount = "1.5.1" tempdir = "0.3.7" bitflags = "1.2.1" err-derive = "0.3" diff --git a/cli/src/configure/decrypt.rs b/cli/src/configure/decrypt.rs index 969e9040..193fc01a 100644 --- a/cli/src/configure/decrypt.rs +++ b/cli/src/configure/decrypt.rs @@ -16,7 +16,7 @@ pub(crate) fn decrypt(disks: &mut Disks, decrypt: Option) -> Result<(), parse_key(&values[2], &mut pass, &mut keydata)?; disks - .decrypt_partition(device, &LvmEncryption::new(pv, pass, keydata)) + .decrypt_partition(device, &mut LuksEncryption::new(pv, pass, keydata, FileSystem::Btrfs)) .map_err(|why| DistinstError::DecryptFailed { why })?; } } diff --git a/cli/src/configure/lvm.rs b/cli/src/configure/lvm.rs index 8b9cc93b..03a5885a 100644 --- a/cli/src/configure/lvm.rs +++ b/cli/src/configure/lvm.rs @@ -64,8 +64,15 @@ pub(crate) fn lvm( if let Some(fs) = fs { let fs = match fs { PartType::Fs(fs) => fs, + PartType::Luks(encryption) => { + partition.set_encryption(encryption); + Some(FileSystem::Luks) + } PartType::Lvm(volume_group, encryption) => { - partition.set_volume_group(volume_group, encryption); + partition.set_volume_group(volume_group); + if let Some(params) = encryption { + partition.set_encryption(params); + } Some(FileSystem::Lvm) } }; @@ -162,7 +169,7 @@ fn parse_logical Result<(), DistinstError>>( size: parse_sector(values[2])?, fs: match parse_fs(values[3])? { PartType::Fs(fs) => fs, - PartType::Lvm(..) => { + _ => { unimplemented!("LUKS on LVM is unsupported"); } }, diff --git a/cli/src/configure/new.rs b/cli/src/configure/new.rs index c8104bfa..a02f5137 100644 --- a/cli/src/configure/new.rs +++ b/cli/src/configure/new.rs @@ -38,10 +38,21 @@ pub(crate) fn new(disks: &mut Disks, parts: Option) -> Result<(), Distin let start = disk.get_sector(start); let end = disk.get_sector(end); let mut builder = match fs { + PartType::Luks(encryption) => { + PartitionBuilder::new(start, end, FileSystem::Luks) + .partition_type(kind) + .encryption(encryption) + } PartType::Lvm(volume_group, encryption) => { - PartitionBuilder::new(start, end, FileSystem::Lvm) + let mut builder = PartitionBuilder::new(start, end, FileSystem::Lvm) .partition_type(kind) - .logical_volume(volume_group, encryption) + .logical_volume(volume_group); + + if let Some(params) = encryption { + builder = builder.encryption(params); + } + + builder } PartType::Fs(fs) => PartitionBuilder::new(start, end, fs).partition_type(kind), }; diff --git a/cli/src/configure/reuse.rs b/cli/src/configure/reuse.rs index 31bfbe01..15ef0fed 100644 --- a/cli/src/configure/reuse.rs +++ b/cli/src/configure/reuse.rs @@ -56,8 +56,15 @@ pub(crate) fn reused(disks: &mut Disks, parts: Option) -> Result<(), Dis if let Some(fs) = fs { let fs = match fs { PartType::Fs(fs) => fs, + PartType::Luks(encryption) => { + partition.set_encryption(encryption); + Some(FileSystem::Luks) + } PartType::Lvm(volume_group, encryption) => { - partition.set_volume_group(volume_group, encryption); + partition.set_volume_group(volume_group); + if let Some(encryption) = encryption { + partition.set_encryption(encryption); + } Some(FileSystem::Lvm) } }; diff --git a/cli/src/main.rs b/cli/src/main.rs index 3b1d0ebb..beceb550 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -450,7 +450,8 @@ enum PartType { /// A normal partition with a standard file system Fs(Option), /// A partition that is formatted with LVM, optionally with encryption. - Lvm(String, Option), + Lvm(String, Option), + Luks(LuksEncryption) } fn parse_key( @@ -480,10 +481,22 @@ fn parse_key( } fn parse_fs(fs: &str) -> Result { - if fs.starts_with("enc=") { + if let Some(fs) = fs.strip_prefix("luks=") { let (mut pass, mut keydata) = (None, None); - let mut fields = fs[4..].split(','); + let mut fields = fs.split(','); + let physical_volume = + fields.next().map(|pv| pv.into()).ok_or(DistinstError::NoPhysicalVolume)?; + + for field in fields { + parse_key(field, &mut pass, &mut keydata)?; + } + + Ok(PartType::Luks(LuksEncryption::new(physical_volume, pass, keydata, FileSystem::Btrfs))) + } else if let Some(fs) = fs.strip_prefix("enc=") { + let (mut pass, mut keydata) = (None, None); + + let mut fields = fs.split(','); let physical_volume = fields.next().map(|pv| pv.into()).ok_or(DistinstError::NoPhysicalVolume)?; @@ -498,7 +511,7 @@ fn parse_fs(fs: &str) -> Result { if pass.is_none() && keydata.is_none() { None } else { - Some(LvmEncryption::new(physical_volume, pass, keydata)) + Some(LuksEncryption::new(physical_volume, pass, keydata, FileSystem::Btrfs)) }, )) } else if fs.starts_with("lvm=") { diff --git a/crates/chroot/Cargo.toml b/crates/chroot/Cargo.toml index 9f09bd1d..0b42ef1d 100644 --- a/crates/chroot/Cargo.toml +++ b/crates/chroot/Cargo.toml @@ -11,7 +11,7 @@ categories = ["os", "os::unix-apis"] edition = "2018" [dependencies] -sys-mount = "1.2.1" +sys-mount = "1.5.1" cascade = "1.0" log = "0.4.8" libc = "0.2.68" diff --git a/crates/disk-ops/Cargo.toml b/crates/disk-ops/Cargo.toml index a0f08ed8..321adadd 100644 --- a/crates/disk-ops/Cargo.toml +++ b/crates/disk-ops/Cargo.toml @@ -17,7 +17,7 @@ disk-types = { path = "../disk-types" } distinst-external-commands = { path = "../external" } log = "0.4.8" tempdir = "0.3.7" -sys-mount = "1.2.1" +sys-mount = "1.5.1" libparted = "0.1.4" rayon = "1.3.0" smart-default = "0.6.0" diff --git a/crates/disk-ops/src/mkpart.rs b/crates/disk-ops/src/mkpart.rs index 9fb078fb..a79257a4 100644 --- a/crates/disk-ops/src/mkpart.rs +++ b/crates/disk-ops/src/mkpart.rs @@ -34,7 +34,7 @@ pub struct PartitionCreate { impl BlockDeviceExt for PartitionCreate { fn get_device_path(&self) -> &Path { &self.path } - fn get_mount_point(&self) -> Option<&Path> { None } + fn get_mount_point(&self) -> &[PathBuf] { &[] } } impl PartitionExt for PartitionCreate { diff --git a/crates/disk-ops/src/ops.rs b/crates/disk-ops/src/ops.rs index 9381e4b5..d6fb67c0 100644 --- a/crates/disk-ops/src/ops.rs +++ b/crates/disk-ops/src/ops.rs @@ -292,7 +292,7 @@ impl FormatPartitions { info!("executing format operations"); self.0 .par_iter() - .map(|&(ref part, fs)| { + .try_for_each(|&(ref part, fs)| { info!("formatting {} with {:?}", part.display(), fs); mkfs(part, fs).map_err(|why| { io::Error::new( @@ -301,6 +301,5 @@ impl FormatPartitions { ) }) }) - .collect::>() } } diff --git a/crates/disk-ops/src/resize.rs b/crates/disk-ops/src/resize.rs index 1a101049..2cf60a7d 100644 --- a/crates/disk-ops/src/resize.rs +++ b/crates/disk-ops/src/resize.rs @@ -401,19 +401,3 @@ fn ntfs_dry_run(path: &Path, size: &str) -> io::Result<()> { Err(io::Error::new(io::ErrorKind::Other, format!("ntfsresize exited with {:?}", status))) } } - -fn ntfs_consistency_check(path: &Path) -> io::Result<()> { - let mut consistency_check = Command::new("ntfsresize"); - consistency_check.args(&["-i", "-f"]).arg(path); - - info!("executing {:?}", consistency_check); - let mut child = consistency_check.stdin(Stdio::piped()).spawn()?; - child.stdin.as_mut().expect("failed to get stdin").write_all(b"y\n")?; - - let status = child.wait()?; - if status.success() { - Ok(()) - } else { - Err(io::Error::new(io::ErrorKind::Other, format!("ntfsresize exited with {:?}", status))) - } -} diff --git a/crates/disk-types/Cargo.toml b/crates/disk-types/Cargo.toml index e4acd674..f350a930 100644 --- a/crates/disk-types/Cargo.toml +++ b/crates/disk-types/Cargo.toml @@ -8,7 +8,7 @@ categories = ["filesystem", "os"] edition = "2018" [dependencies] -sys-mount = "1.2.1" +sys-mount = "1.5.1" tempdir = "0.3.7" os-detect = { path = "../os-detect" } sysfs-class = "0.1.2" diff --git a/crates/disk-types/src/device.rs b/crates/disk-types/src/device.rs index 40ce93fd..7b52933a 100644 --- a/crates/disk-types/src/device.rs +++ b/crates/disk-types/src/device.rs @@ -1,6 +1,4 @@ -use std::{io, fs, fmt::Debug}; use std::path::{Path, PathBuf}; -use std::str::FromStr; use sysfs_class::{Block, SysClass}; /// Methods that all block devices share, whether they are partitions or disks. @@ -48,7 +46,7 @@ pub trait BlockDeviceExt { fn get_device_path(&self) -> &Path; /// The mount point of this block device, if it is mounted. - fn get_mount_point(&self) -> Option<&Path> { None } + fn get_mount_point(&self) -> &[PathBuf] { &[] } /// The name of the device, such as `sda1`. fn get_device_name(&self) -> String { diff --git a/crates/disk-types/src/partition.rs b/crates/disk-types/src/partition.rs index cda66e98..1b47154c 100644 --- a/crates/disk-types/src/partition.rs +++ b/crates/disk-types/src/partition.rs @@ -32,6 +32,10 @@ pub trait PartitionExt: BlockDeviceExt + SectorExt { /// The sector where this partition begins on the parent block device.. fn get_sector_start(&self) -> u64; + fn encrypted_info(&self) -> Option<(std::path::PathBuf, FileSystem)> { + None + } + /// True if the partition is an ESP partition. fn is_esp_partition(&self) -> bool { self.get_file_system().map_or(false, |fs| { @@ -80,8 +84,16 @@ pub trait PartitionExt: BlockDeviceExt + SectorExt { /// Detects if an OS is installed to this partition, and if so, what the OS /// is named. - fn probe_os(&self) -> Option { - self.get_file_system().and_then(|fs| detect_os_from_device(self.get_device_path(), fs)) + fn probe_os(&self, subvol: Option<&str>) -> Option { + let (device_path, fs) = match self.encrypted_info() { + Some((p, f)) => (p, f), + None => ( + self.get_device_path().to_path_buf(), + self.get_file_system()? + ) + }; + + detect_os_from_device(&device_path, subvol, fs) } /// True if the sectors in the compared partition differs from the source. diff --git a/crates/disks/Cargo.toml b/crates/disks/Cargo.toml index 03746b8a..31e6bbbc 100644 --- a/crates/disks/Cargo.toml +++ b/crates/disks/Cargo.toml @@ -8,7 +8,7 @@ readme = "README.md" license = "MIT" keywords = ["distinst", "disk", "management", "partition"] categories = ["filesystem", "os"] -edition = "2018" +edition = "2021" [dependencies] bitflags = "1.2.1" @@ -31,6 +31,6 @@ partition-identity = "0.2.8" proc-mounts = "0.2.4" rand = "0.7" rayon = "1.3.0" -sys-mount = "1.2.1" +sys-mount = "1.5.1" sysfs-class = "0.1.2" tempdir = "0.3.7" diff --git a/crates/disks/src/config/disk.rs b/crates/disks/src/config/disk.rs index 066c1937..47948a5d 100644 --- a/crates/disks/src/config/disk.rs +++ b/crates/disks/src/config/disk.rs @@ -64,8 +64,11 @@ pub fn detect_fs_on_device(path: &Path) -> Option { }; } - part.mount_point = - mounts.get_mount_by_source(device_path).map(|m| m.dest.clone()); + part.mount_point = mounts.0 + .iter() + .filter(|mount| &mount.source == device_path) + .map(|m| m.dest.clone()) + .collect(); part.bitflags |= if swaps.get_swapped(device_path) { SWAPPED } else { 0 }; part.original_vg = original_vg; @@ -99,7 +102,7 @@ pub struct Disk { /// Account for the possibility that the entire disk is a file system. pub file_system: Option, /// Where the device is mounted, if mounted at all. - pub mount_point: Option, + pub mount_point: Vec, /// The size of the disk in sectors. pub size: u64, /// The type of the device, such as SCSI. @@ -118,7 +121,7 @@ pub struct Disk { impl BlockDeviceExt for Disk { fn get_device_path(&self) -> &Path { &self.device_path } - fn get_mount_point(&self) -> Option<&Path> { self.mount_point.as_deref() } + fn get_mount_point(&self) -> &[PathBuf] { self.mount_point.as_ref() } fn is_read_only(&self) -> bool { self.read_only } } @@ -190,7 +193,11 @@ impl Disk { Ok(Disk { model_name, - mount_point: mounts.get_mount_by_source(&device_path).map(|m| m.dest.clone()), + mount_point: mounts.0 + .iter() + .filter(|mount| &mount.source == &device_path) + .map(|m| m.dest.clone()) + .collect(), device_path, file_system: None, serial, @@ -269,7 +276,8 @@ impl Disk { x.bitflags & REMOVE != 0 || x.bitflags & FORMAT != 0 || x.target.is_some() - || x.volume_group.is_some() + || x.lvm_vg.is_some() + || !x.subvolumes.is_empty() }) } @@ -279,7 +287,7 @@ impl Disk { let swaps = SWAPS.read().expect("failed to get swaps in unmount_all_partitions"); for partition in &mut self.partitions { - if let Some(ref mount) = partition.mount_point { + for mount in partition.mount_point.iter().rev() { if mount == Path::new("/cdrom") || mount == Path::new("/") { continue; } @@ -314,7 +322,8 @@ impl Disk { } let mut mounts = BTreeSet::new(); - for mount in mountstab.source_starts_with(self.path()) { + for mount in dbg!(&mountstab).source_starts_with(self.path()) { + debug!("checking {:?}", mount); if mount.dest == Path::new("/cdrom") || mount.dest == Path::new("/") || mount.dest == Path::new("/boot/efi") @@ -809,14 +818,26 @@ impl Disk { // Back up any fields that need to be carried over after reloading disk data. let collected = self .partitions - .iter() + .iter_mut() .filter_map(|partition| { let start = partition.start_sector; + let name = partition.name.clone(); let mount = partition.target.as_ref().map(|ref path| path.to_path_buf()); - let vg = partition.volume_group.as_ref().cloned(); + let vg = partition.lvm_vg.clone(); + let enc = partition.encryption.clone(); let keyid = partition.key_id.as_ref().cloned(); - if mount.is_some() || vg.is_some() || keyid.is_some() { - Some((start, mount, vg, keyid)) + let mut subvolumes = std::collections::HashMap::new(); + + let format = if partition.flag_is_enabled(FORMAT) && enc.is_some() { + Some(FORMAT) + } else { + None + }; + + std::mem::swap(&mut subvolumes, &mut partition.subvolumes); + + if mount.is_some() || name.is_some() || enc.is_some() || vg.is_some() || keyid.is_some() || !subvolumes.is_empty() || format.is_some() { + Some((start, name, mount, vg, enc, keyid, subvolumes, format)) } else { None } @@ -827,16 +848,27 @@ impl Disk { *self = Disk::from_name_with_serial(&self.device_path, &self.serial)?; // Then re-add the critical information which was lost. - for (sector, mount, vg, keyid) in collected { + for (sector, name, mount, vg, enc, keyid, subvolumes, format) in collected { info!("checking for mount target at {}", sector); let part = self .get_partition_at(sector) .and_then(|num| self.get_partition_mut(num)) .expect("partition sectors are off"); + part.name = name; part.target = mount; - part.volume_group = vg; + part.lvm_vg = vg; + part.encryption = enc; part.key_id = keyid; + part.subvolumes = subvolumes; + + if !part.subvolumes.is_empty() { + part.filesystem = Some(FileSystem::Btrfs); + } + + if let Some(format) = format { + part.bitflags |= format; + } } Ok(()) diff --git a/crates/disks/src/config/disk_trait.rs b/crates/disks/src/config/disk_trait.rs index d4325e18..38f21ceb 100644 --- a/crates/disks/src/config/disk_trait.rs +++ b/crates/disks/src/config/disk_trait.rs @@ -68,17 +68,35 @@ pub trait DiskExt: BlockDeviceExt + SectorExt + PartitionTableExt { let check_partitions = || { self.get_partitions().iter().any(|partition| { - if partition.mount_point == Some(mount.into()) { + let m = Path::new(mount); + + if partition.mount_point.iter().any(|mount| mount == m) { return true; } - partition.volume_group.as_ref().map_or(false, |&(ref vg, _)| { - parent.get_logical_device(vg).map_or(false, |d| d.contains_mount(mount, parent)) - }) + if let Some(device) = partition.lvm_vg.as_ref().and_then(|vg| parent.get_logical_device(vg)) { + if device.contains_mount(mount, parent) { + return true; + } + } + + false }) || check_sysfs() }; - self.get_mount_point().map_or_else(check_partitions, |m| m == Path::new(mount)) + let mounts = self.get_mount_point(); + + if mounts.is_empty() { + check_partitions() + } else { + for mount in mounts { + if mount == Path::new(mount) { + return true + } + } + + false + } } fn is_logical(&self) -> bool { Self::LOGICAL } @@ -184,6 +202,10 @@ pub fn find_partition<'a, T: DiskExt>( return Some((disk.get_device_path(), partition)); } } + + if partition.subvolumes.get(target).is_some() { + return Some((disk.get_device_path(), partition)); + } } } None @@ -201,32 +223,29 @@ pub fn find_partition_mut<'a, T: DiskExt>( let disk = disk as *mut T; if let Some(partition) = unsafe { &mut *disk }.get_file_system_mut() { - // TODO: NLL - let mut found = false; if let Some(ref ptarget) = partition.target { if ptarget == target { - found = true; + return Some((path, partition)); } } - if found { + if partition.subvolumes.get(target).is_some() { return Some((path, partition)); } } for partition in unsafe { &mut *disk }.get_partitions_mut() { - // TODO: NLL - let mut found = false; if let Some(ref ptarget) = partition.target { if ptarget == target { - found = true; + return Some((path, partition)); } } - if found { + if partition.subvolumes.get(target).is_some() { return Some((path, partition)); } } } + None } diff --git a/crates/disks/src/config/disks.rs b/crates/disks/src/config/disks.rs index 24a7036f..791712ce 100644 --- a/crates/disks/src/config/disks.rs +++ b/crates/disks/src/config/disks.rs @@ -5,7 +5,7 @@ use super::{ }, detect_fs_on_device, find_partition, find_partition_mut, partitions::{FORMAT, REMOVE, SOURCE}, - Disk, LvmEncryption, PartitionTable, PVS, + Disk, LuksEncryption, PartitionTable, PVS, }; use disk_types::{BlockDeviceExt, PartitionExt, PartitionTableExt, SectorExt}; use crate::external::{ @@ -14,7 +14,6 @@ use crate::external::{ }; use itertools::Itertools; use libparted::{Device, DeviceType}; -use misc; use partition_identity::PartitionID; use proc_mounts::{MountIter, MOUNTS, SWAPS}; use rayon::{iter::IntoParallelRefIterator, prelude::*}; @@ -169,61 +168,92 @@ impl Disks { pub fn mount_all_targets>(&self, base_dir: P) -> io::Result { let base_dir = base_dir.as_ref(); let targets = - self.get_partitions().filter(|part| part.target.is_some() && part.filesystem.is_some()); + self.get_partitions().filter(|part| { + (part.target.is_some() && part.filesystem.is_some()) + || !part.subvolumes.is_empty() + }); + #[derive(Debug)] enum MountKind { - Direct { device: PathBuf, fs: &'static str }, + Direct { data: String, device: PathBuf, fs: &'static str }, Bind { source: PathBuf }, } // The mount path will actually consist of the target concatenated with the // root. NOTE: It is assumed that the target is an absolute path. let paths: BTreeMap = targets - .map(|target| { - // Path mangling commences here, since we need to concatenate an absolute - // path onto another absolute path, and the standard library opts for - // overwriting the original path when doing that. - let target_mount: PathBuf = { - // Ensure that the base_dir path has the ending '/'. - let base_dir = base_dir.as_os_str().as_bytes(); - let mut target_mount: Vec = if base_dir[base_dir.len() - 1] == b'/' { - base_dir.to_owned() - } else { - let mut temp = base_dir.to_owned(); - temp.push(b'/'); - temp + .flat_map(|partition| { + let generate_target = |part: &PartitionInfo, data: String, target: &Path| { + // Path mangling commences here, since we need to concatenate an absolute + // path onto another absolute path, and the standard library opts for + // overwriting the original path when doing that. + let target_mount: PathBuf = { + // Ensure that the base_dir path has the ending '/'. + let base_dir = base_dir.as_os_str().as_bytes(); + let mut target_mount: Vec = if base_dir[base_dir.len() - 1] == b'/' { + base_dir.to_owned() + } else { + let mut temp = base_dir.to_owned(); + temp.push(b'/'); + temp + }; + + // Cut the starting '/' from the target path if it exists. + let target_path = target.as_os_str().as_bytes(); + let target_path = if !target_path.is_empty() && target_path[0] == b'/' { + if target_path.len() > 1 { + &target_path[1..] + } else { + b"" + } + } else { + target_path + }; + + // Append the target path to the base_dir, and return it as a path type. + target_mount.extend_from_slice(target_path); + PathBuf::from(OsString::from_vec(target_mount)) }; - // Cut the starting '/' from the target path if it exists. - let target_path = target.target.as_ref().unwrap().as_os_str().as_bytes(); - let target_path = if !target_path.is_empty() && target_path[0] == b'/' { - if target_path.len() > 1 { - &target_path[1..] + // If a partition is already mounted, we should perform a bind mount. + // If it is not mounted, we can mount it directly. + let kind = if let Some(source) = part.mount_point.get(0).cloned() { + MountKind::Bind { source } + } else { + let device; + let fs; + + if let Some(encryption) = part.encryption.as_ref() { + fs = encryption.filesystem.into(); + device = PathBuf::from(["/dev/mapper/", &*encryption.physical_volume].concat()); } else { - b"" + match part.filesystem.unwrap() { + FileSystem::Fat16 | FileSystem::Fat32 => { + fs = "vfat"; + device = part.device_path.clone(); + } + other => { + fs = other.into(); + device = part.device_path.clone(); + }, + } } - } else { - target_path + + MountKind::Direct { data, device, fs } }; - // Append the target path to the base_dir, and return it as a path type. - target_mount.extend_from_slice(target_path); - PathBuf::from(OsString::from_vec(target_mount)) + (target_mount, kind) }; - // If a partition is already mounted, we should perform a bind mount. - // If it is not mounted, we can mount it directly. - let kind = if let Some(source) = target.mount_point.clone() { - MountKind::Bind { source } + if !partition.subvolumes.is_empty() { + partition.subvolumes.iter() + .map(|(target, subvol)| { + generate_target(partition, format!("subvol={}", subvol), target) + }) + .collect::>() } else { - let fs = match target.filesystem.unwrap() { - FileSystem::Fat16 | FileSystem::Fat32 => "vfat", - fs => fs.into(), - }; - - MountKind::Direct { device: target.device_path.clone(), fs } - }; - (target_mount, kind) + vec![generate_target(partition, String::new(), partition.target.as_deref().unwrap())] + } }) .collect(); @@ -239,9 +269,56 @@ impl Disks { } let mount = match kind { - MountKind::Direct { device, fs } => { - info!("mounting {:?} ({}) to {:?}", device, fs, target_mount); - Mount::new(device, &target_mount, fs, MountFlags::empty(), None)? + MountKind::Direct { data, device, fs } => { + info!("mounting {:?} ({}) to {:?} with {}", device, fs, target_mount, data); + + let mount = || Mount::builder() + .fstype(fs) + .data(&data) + .mount(&device, &target_mount); + + let mut result = mount(); + + while let Err(Some(16)) = result.as_ref().map_err(io::Error::raw_os_error) { + eprintln!("device was busy"); + std::thread::sleep(std::time::Duration::from_secs(1)); + result = mount(); + } + + // Create missing subvolumes with zstd compression. + if let Err(io::ErrorKind::NotFound) = result.as_ref().map_err(io::Error::kind) { + if let Some(subvol) = data.strip_prefix("subvol=") { + const BTRFS_MOUNT: &str = "/tmp/distinst.btrfs/"; + + let _ = fs::create_dir_all(BTRFS_MOUNT); + + let subvol = &*[BTRFS_MOUNT, subvol].concat(); + + info!("mounting {:?} to {}", device, BTRFS_MOUNT); + let mount = Mount::builder() + .fstype(fs) + .mount(&device, BTRFS_MOUNT)?; + + info!("creating subvolume at {}", subvol); + std::process::Command::new("btrfs") + .args(&["subvolume", "create", subvol]) + .status()?; + + info!("setting zstd compression on {}", subvol); + std::process::Command::new("btrfs") + .args(&["property", "set", subvol, "compression", "zstd"]) + .status()?; + + let _ = mount.unmount(UnmountFlags::DETACH); + + result = Mount::builder() + .fstype(fs) + .data(&data) + .mount(&device, &target_mount) + } + } + + result? } MountKind::Bind { source } => { info!("bind mounting {:?} to {:?}", source, target_mount); @@ -304,7 +381,10 @@ impl Disks { /// Obtains the partition which contains the given target. pub fn get_partition_with_target(&self, target: &Path) -> Option<&PartitionInfo> { self.get_partitions() - .find(|part| part.target.as_ref().map_or(false, |p| p.as_path() == target)) + .find(|part| { + part.target.as_ref().map_or(false, |p| p.as_path() == target) + || part.subvolumes.get(target).is_some() + }) } /// Obtains the partition which contains the given device path @@ -329,7 +409,19 @@ impl Disks { /// Obtains the partition which contains the given identity pub fn get_partition_by_id_mut(&mut self, id: &PartitionID) -> Option<&mut PartitionInfo> { - self.get_partitions_mut().find(|part| part.identifiers.matches(id)) + self.get_partitions_mut().find(|part| { + part.identifiers.matches(id) || { + if let Some((path, _)) = part.encrypted_info() { + if let Some(encrypted_id) = PartitionID::get_uuid(&path) { + if &encrypted_id == id { + return true + } + } + } + + false + } + }) } #[deprecated(note = "use the 'get_partition_by_id()' method instead")] @@ -423,7 +515,7 @@ impl Disks { .iter() .filter_map(|dev| volume_map.get(dev)) .unique() - .map(|entry| { + .try_for_each(|entry| { if let Some(ref vg) = *entry { umount(vg).and_then(|_| { vgdeactivate(vg).map_err(|why| DiskError::ExternalCommand { why }) @@ -432,7 +524,6 @@ impl Disks { Ok(()) } }) - .collect::>() } /// Attempts to decrypt the specified partition. @@ -443,7 +534,7 @@ impl Disks { pub fn decrypt_partition( &mut self, path: &Path, - enc: &LvmEncryption, + enc: &mut LuksEncryption, ) -> Result<(), DecryptionError> { info!("decrypting partition at {:?}", path); // An intermediary value that can avoid the borrowck issue. @@ -452,13 +543,13 @@ impl Disks { fn decrypt( partition: &mut PartitionInfo, path: &Path, - enc: &LvmEncryption, + enc: &mut LuksEncryption, ) -> Result { // Attempt to decrypt the device. - cryptsetup_open(path, &enc) + cryptsetup_open(path, enc) .map_err(|why| DecryptionError::Open { device: path.to_path_buf(), why })?; - // Determine which VG the newly-decrypted device belongs to. + // Determine which PV the newly-decrypted device belongs to. let pv = &PathBuf::from(["/dev/mapper/", &enc.physical_volume].concat()); info!("which belongs to PV {:?}", pv); let mut attempt = 0; @@ -471,7 +562,9 @@ impl Disks { match pvs().expect("pvs() failed in decrypt_partition").remove(pv) { Some(Some(vg)) => { // Set values in the device's partition. - partition.volume_group = Some((vg.clone(), Some(enc.clone()))); + partition.lvm_vg = Some(vg.clone()); + partition.encryption = Some(enc.clone()); + let mut luks = LogicalDevice::new( vg, Some(enc.clone()), @@ -496,6 +589,12 @@ impl Disks { true, ); + if let Some(fs) = fs.filesystem { + enc.filesystem = fs; + } + + partition.encryption = Some(enc.clone()); + luks.set_file_system(fs); info!("settings luks_parent to {:?}", path); luks.set_luks_parent(path.to_path_buf()); @@ -517,7 +616,7 @@ impl Disks { // TODO: NLL if let Some(partition) = device.get_file_system_mut() { if partition.get_device_path() == path { - decrypt(partition, path, &enc)?; + decrypt(partition, path, enc)?; } } @@ -525,7 +624,7 @@ impl Disks { device.file_system.as_mut().into_iter().chain(device.partitions.iter_mut()) { if partition.get_device_path() == path { - new_device = Some(decrypt(partition, path, &enc)?); + new_device = Some(decrypt(partition, path, enc)?); break; } } @@ -550,8 +649,8 @@ impl Disks { info!("unmounting devices"); self.physical .iter() - .map(|device| { - if let Some(mount) = device.get_mount_point() { + .try_for_each(|device| { + if let Some(mount) = device.get_mount_point().get(0) { if mount != Path::new("/cdrom") { info!("unmounting device mounted at {}", mount.display()); unmount(&mount, UnmountFlags::empty()).map_err(|why| { @@ -565,11 +664,11 @@ impl Disks { Ok(()) }) - .collect::>() } /// Probes for and returns disk information for every disk in the system. pub fn probe_devices() -> Result { + info!("probing devices"); let mut disks = Disks::default(); for mut device in Device::devices(true) { if let Some(name) = device.path().file_name().and_then(|x| x.to_str()) { @@ -645,16 +744,26 @@ impl Disks { // Check partitions which have already been mounted first. for partition in disks.get_physical_partitions() { - match partition.mount_point { - Some(ref path) if path == expected_at => return Ok(func(partition, path)), - Some(_) => continue, - None => (), + if ! partition.mount_point.is_empty() { + for path in &partition.mount_point { + if path == expected_at { + return Ok(func(partition, path)) + } + } + + continue } + + // match partition.mount_point { + // Some(ref path) if path == expected_at => return Ok(func(partition, path)), + // Some(_) => continue, + // None => (), + // } } // Then check partitions which have not been mounted yet. for partition in disks.get_physical_partitions() { - if partition.mount_point.is_some() { + if !partition.mount_point.is_empty() { continue; } @@ -722,9 +831,8 @@ impl Disks { // The volume group may be stored in either the `original_vg` // or `volume_group` fields. This combines the optionals. let vg: Option<&String> = partition - .volume_group + .lvm_vg .as_ref() - .map(|x| &x.0) .or_else(|| partition.original_vg.as_ref()); if let Some(ref pvg) = vg { @@ -803,6 +911,12 @@ impl Disks { } } + pub fn set_subvolume(&mut self, volume: &PartitionID, name: &str, target: impl AsRef) { + if let Some(partition) = self.get_partition_by_id_mut(volume) { + partition.subvolumes.insert(PathBuf::from(target.as_ref()), name.into()); + } + } + /// Ensure that keyfiles have key paths. pub fn verify_keyfile_paths(&self) -> Result<(), DiskError> { info!("verifying if keyfiles have paths"); @@ -880,7 +994,7 @@ impl Disks { .chain(self.logical.iter_mut().flat_map(|x| x.get_partitions_mut().iter_mut())); for partition in partitions { - if let Some(&mut (_, Some(ref mut enc))) = partition.volume_group.as_mut() { + if let Some(ref mut enc) = partition.encryption.as_mut() { if let Some((ref id, ref mut ppath)) = enc.keydata { if *id == *key { *ppath = paths.clone(); @@ -1024,9 +1138,9 @@ impl Disks { for disk in &self.physical { let sector_size = disk.get_logical_block_size(); for partition in disk.get_partitions().iter() { - if let Some(ref lvm) = partition.volume_group { + if let Some(ref lvm) = partition.lvm_vg { // TODO: NLL - let push = match existing_devices.iter_mut().find(|d| d.volume_group == lvm.0) { + let push = match existing_devices.iter_mut().find(|d| &d.volume_group == lvm) { Some(device) => { device.add_sectors(partition.get_sectors()); false @@ -1036,8 +1150,8 @@ impl Disks { if push { existing_devices.push(LogicalDevice::new( - lvm.0.clone(), - lvm.1.clone(), + lvm.clone(), + partition.encryption.clone(), partition.get_sectors(), sector_size, false, @@ -1172,6 +1286,27 @@ impl Disks { logical.luks_parent = Some(luks_parent); } + // FS on LUKS + for device in self.get_partitions_mut() { + let format = device.flag_is_enabled(FORMAT); + device.flag_disable(FORMAT); + if let Some(encryption) = device.encryption.as_mut() { + if encryption.filesystem == FileSystem::Lvm { + continue + } + + if format { + encryption.encrypt(&device.device_path)?; + encryption.open(&device.device_path)?; + + distinst_external_commands::mkfs( + &["/dev/mapper/", device.name.as_deref().unwrap()].concat(), + encryption.filesystem + ).unwrap(); + } + } + } + Ok(()) } } diff --git a/crates/disks/src/config/lvm/encryption.rs b/crates/disks/src/config/lvm/encryption.rs index 102ae1dd..e992dba6 100644 --- a/crates/disks/src/config/lvm/encryption.rs +++ b/crates/disks/src/config/lvm/encryption.rs @@ -1,38 +1,41 @@ use crate::external::{cryptsetup_encrypt, cryptsetup_open, pvcreate}; +use crate::DiskError; use std::{ fmt, path::{Path, PathBuf}, }; -use crate::DiskError; /// A structure which contains the encryption settings for a physical volume. #[derive(Clone, PartialEq)] -pub struct LvmEncryption { +pub struct LuksEncryption { pub physical_volume: String, pub password: Option, pub keydata: Option<(String, Option<(PathBuf, PathBuf)>)>, + pub filesystem: disk_types::FileSystem, } -impl fmt::Debug for LvmEncryption { +impl fmt::Debug for LuksEncryption { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, - "LvmEncryption {{ physical_volume: {}, password: hidden, keydata: {:?} }}", + "LuksEncryption {{ physical_volume: {}, password: hidden, keydata: {:?} }}", self.physical_volume, self.keydata ) } } -impl LvmEncryption { +impl LuksEncryption { pub fn new>>( physical_volume: String, password: S, keydata: S, - ) -> LvmEncryption { - LvmEncryption { + filesystem: disk_types::FileSystem, + ) -> LuksEncryption { + LuksEncryption { physical_volume, password: password.into(), keydata: keydata.into().map(|key| (key, None)), + filesystem, } } diff --git a/crates/disks/src/config/lvm/mod.rs b/crates/disks/src/config/lvm/mod.rs index 48d77be8..0be003eb 100644 --- a/crates/disks/src/config/lvm/mod.rs +++ b/crates/disks/src/config/lvm/mod.rs @@ -1,6 +1,5 @@ mod encryption; - -pub use self::encryption::LvmEncryption; +pub use self::encryption::LuksEncryption; use super::{ super::{ DiskError, DiskExt, PartitionError, PartitionInfo, PartitionTable, PartitionType, FORMAT, @@ -40,12 +39,13 @@ pub struct LogicalDevice { pub volume_group: String, pub device_path: PathBuf, pub luks_parent: Option, - pub mount_point: Option, + pub mount_point: Vec, pub file_system: Option, pub sectors: u64, pub sector_size: u64, pub partitions: Vec, - pub encryption: Option, + pub encryption: Option, + pub has_lvm: bool, pub is_source: bool, pub remove: bool, pub vg_data: VgData, @@ -54,7 +54,7 @@ pub struct LogicalDevice { impl BlockDeviceExt for LogicalDevice { fn get_device_path(&self) -> &Path { &self.device_path } - fn get_mount_point(&self) -> Option<&Path> { self.mount_point.as_deref() } + fn get_mount_point(&self) -> &[PathBuf] { self.mount_point.as_ref() } } impl PartitionTableExt for LogicalDevice { @@ -78,7 +78,8 @@ impl DiskExt for LogicalDevice { fn set_file_system(&mut self, mut fs: PartitionInfo) { // Set the volume group + encryption to be the same as the parent. - fs.volume_group = Some((self.volume_group.clone(), self.encryption.clone())); + fs.lvm_vg = Some(self.volume_group.clone()); + fs.encryption = self.encryption.clone(); self.file_system = Some(fs); self.partitions.clear(); @@ -97,7 +98,7 @@ impl LogicalDevice { /// Creates a new volume group, with an optional encryption configuration. pub fn new( volume_group: String, - encryption: Option, + encryption: Option, sectors: u64, sector_size: u64, is_source: bool, @@ -109,7 +110,11 @@ impl LogicalDevice { LogicalDevice { model_name: ["LVM ", &volume_group].concat(), - mount_point: mounts.get_mount_by_source(&device_path).map(|m| m.dest.clone()), + mount_point: mounts.0 + .iter() + .filter(|mount| &mount.source == &device_path) + .map(|m| m.dest.clone()) + .collect(), volume_group, device_path, sectors, @@ -209,7 +214,7 @@ impl LogicalDevice { let device_path = match path.canonicalize() { Ok(resolved) => resolved, Err(why) => { - eprintln!("LVM device path is not a symbolic link"); + eprintln!("LVM device path is not a symbolic link: {}", why); continue } }; @@ -235,12 +240,14 @@ impl LogicalDevice { Some(dev.split_at(value).1.into()) }, device_path, - mount_point: None, + mount_point: Vec::new(), target: None, original_vg: None, - volume_group: None, + lvm_vg: None, + encryption: None, key_id: None, identifiers, + subvolumes: std::collections::HashMap::new(), }; start_sector += length + 1; diff --git a/crates/disks/src/config/mod.rs b/crates/disks/src/config/mod.rs index 87f89bf8..14d10487 100644 --- a/crates/disks/src/config/mod.rs +++ b/crates/disks/src/config/mod.rs @@ -45,6 +45,7 @@ mod tests { use super::*; use operations::*; use partition_identity::PartitionIdentifiers; + use std::collections::HashMap; fn get_default() -> Disks { Disks { @@ -54,7 +55,7 @@ mod tests { serial: "Test Disk 123".into(), device_path: "/dev/sdz".into(), file_system: None, - mount_point: None, + mount_point: vec![], size: 1953525168, device_type: "TEST".into(), table_type: Some(PartitionTable::Gpt), @@ -64,7 +65,7 @@ mod tests { bitflags: ACTIVE | BUSY | SOURCE, device_path: Path::new("/dev/sdz1").to_path_buf(), flags: vec![], - mount_point: Some(Path::new("/boot/efi").to_path_buf()), + mount_point: vec!(Path::new("/boot/efi").to_path_buf()), target: Some(Path::new("/boot/efi").to_path_buf()), start_sector: 2048, end_sector: 1026047, @@ -75,14 +76,16 @@ mod tests { part_type: PartitionType::Primary, key_id: None, original_vg: None, - volume_group: None, + lvm_vg: None, + encryption: None, identifiers: PartitionIdentifiers::default(), + subvolumes: HashMap::new(), }, PartitionInfo { bitflags: ACTIVE | BUSY | SOURCE, device_path: Path::new("/dev/sdz2").to_path_buf(), flags: vec![], - mount_point: Some(Path::new("/").to_path_buf()), + mount_point: vec!(Path::new("/").to_path_buf()), target: Some(Path::new("/").to_path_buf()), start_sector: 1026048, end_sector: 420456447, @@ -93,14 +96,16 @@ mod tests { part_type: PartitionType::Primary, key_id: None, original_vg: None, - volume_group: None, + lvm_vg: None, + encryption: None, identifiers: PartitionIdentifiers::default(), + subvolumes: HashMap::new(), }, PartitionInfo { bitflags: SOURCE, device_path: Path::new("/dev/sdz3").to_path_buf(), flags: vec![], - mount_point: None, + mount_point: vec![], target: None, start_sector: 420456448, end_sector: 1936738303, @@ -111,14 +116,16 @@ mod tests { part_type: PartitionType::Primary, key_id: None, original_vg: None, - volume_group: None, + lvm_vg: None, + encryption: None, identifiers: PartitionIdentifiers::default(), + subvolumes: HashMap::new(), }, PartitionInfo { bitflags: ACTIVE | SOURCE, device_path: Path::new("/dev/sdz4").to_path_buf(), flags: vec![], - mount_point: None, + mount_point: Vec::new(), target: None, start_sector: 1936738304, end_sector: 1953523711, @@ -129,8 +136,10 @@ mod tests { part_type: PartitionType::Primary, key_id: None, original_vg: None, - volume_group: None, + lvm_vg: None, + encryption: None, identifiers: PartitionIdentifiers::default(), + subvolumes: HashMap::new(), }, ], }], @@ -146,7 +155,7 @@ mod tests { model_name: "Test Disk".into(), serial: "Test Disk 123".into(), device_path: "/dev/sdz".into(), - mount_point: None, + mount_point: Vec::new(), size: 1953525168, device_type: "TEST".into(), table_type: Some(PartitionTable::Gpt), @@ -161,7 +170,7 @@ mod tests { // 500 MiB Fat16 partition. fn boot_part(start: u64) -> PartitionBuilder { - PartitionBuilder::new(start, 1024_000 + start, FileSystem::Fat16) + PartitionBuilder::new(start, 1_024_000 + start, FileSystem::Fat16) } // 20 GiB Ext4 partition. @@ -180,7 +189,7 @@ mod tests { new.resize_partition(3, start + GIB20).unwrap(); new.remove_partition(4).unwrap(); new.add_partition(boot_part(2048)).unwrap(); - new.add_partition(root_part(1026_048)).unwrap(); + new.add_partition(root_part(1_026_048)).unwrap(); assert_eq!( source.diff(&new).unwrap(), DiskOps { @@ -201,7 +210,7 @@ mod tests { }, PartitionCreate { start_sector: 2048, - end_sector: 1024_000 + 2047, + end_sector: 1_024_000 + 2047, file_system: Some(FileSystem::Fat16), kind: PartitionType::Primary, flags: vec![], @@ -210,8 +219,8 @@ mod tests { path: PathBuf::from("/dev/sdz"), }, PartitionCreate { - start_sector: 1026_048, - end_sector: GIB20 + 1026_047, + start_sector: 1_026_048, + end_sector: GIB20 + 1_026_047, file_system: Some(FileSystem::Ext4), kind: PartitionType::Primary, flags: vec![], @@ -245,10 +254,10 @@ mod tests { // This should fail with an off by one error, due to the start // sector being located within the previous partition. - assert!(source.add_partition(root_part(1026_047)).is_err()); + assert!(source.add_partition(root_part(1_026_047)).is_err()); // Create 20GiB Ext4 partition after that. - source.add_partition(root_part(1026_048)).unwrap(); + source.add_partition(root_part(1_026_048)).unwrap(); } #[test] @@ -268,7 +277,7 @@ mod tests { let mut duplicate = source.clone(); assert!(source.validate_layout(&duplicate).is_ok()); duplicate - .add_partition(PartitionBuilder::new(2048, 1024_000 + 2048, FileSystem::Fat16)) + .add_partition(PartitionBuilder::new(2048, 1_024_000 + 2048, FileSystem::Fat16)) .unwrap(); assert!(source.validate_layout(&duplicate).is_ok()); } diff --git a/crates/disks/src/config/partitions/builder.rs b/crates/disks/src/config/partitions/builder.rs index fa2b7bb5..ad6398be 100644 --- a/crates/disks/src/config/partitions/builder.rs +++ b/crates/disks/src/config/partitions/builder.rs @@ -1,7 +1,9 @@ use super::{ - FileSystem, LvmEncryption, PartitionFlag, PartitionIdentifiers, PartitionInfo, PartitionType, + FileSystem, PartitionFlag, PartitionIdentifiers, PartitionInfo, PartitionType, FORMAT, }; +use crate::LuksEncryption; +use std::collections::HashMap; use std::path::PathBuf; /// Partition builders are supplied as inputs to `Disk::add_partition`. @@ -13,8 +15,10 @@ pub struct PartitionBuilder { pub name: Option, pub flags: Vec, pub mount: Option, - pub volume_group: Option<(String, Option)>, + pub lvm_vg: Option, + pub encryption: Option, pub key_id: Option, + pub subvolumes: HashMap } impl PartitionBuilder { @@ -28,8 +32,10 @@ impl PartitionBuilder { name: None, flags: Vec::new(), mount: None, - volume_group: None, + lvm_vg: None, + encryption: None, key_id: None, + subvolumes: HashMap::new() } } @@ -68,9 +74,16 @@ impl PartitionBuilder { pub fn logical_volume( mut self, group: String, - encryption: Option, ) -> PartitionBuilder { - self.volume_group = Some((group, encryption)); + self.lvm_vg = Some(group); + self + } + + pub fn encryption( + mut self, + encryption: LuksEncryption, + ) -> PartitionBuilder { + self.encryption = Some(encryption); self } @@ -81,6 +94,11 @@ impl PartitionBuilder { self } + pub fn subvolume(mut self, target: impl Into, volume: impl Into) -> Self { + self.subvolumes.insert(PathBuf::from(target.into()), volume.into()); + self + } + /// Builds a brand new Partition from the current state of the builder. pub fn build(self) -> PartitionInfo { PartitionInfo { @@ -89,25 +107,25 @@ impl PartitionBuilder { start_sector: self.start_sector, end_sector: self.end_sector, part_type: self.part_type, - filesystem: if self.volume_group.is_some() { - if self.volume_group.as_ref().unwrap().1.is_some() { - Some(FileSystem::Luks) - } else { - Some(FileSystem::Lvm) - } + filesystem: if self.encryption.is_some() { + Some(FileSystem::Luks) + } else if self.lvm_vg.is_some() { + Some(FileSystem::Lvm) } else { self.filesystem }, flags: self.flags, name: self.name, device_path: PathBuf::new(), - mount_point: None, + mount_point: Vec::new(), ordering: -1, target: self.mount, original_vg: None, - volume_group: self.volume_group.clone(), + lvm_vg: self.lvm_vg, + encryption: self.encryption, key_id: self.key_id, identifiers: PartitionIdentifiers::default(), + subvolumes: self.subvolumes } } } diff --git a/crates/disks/src/config/partitions/mod.rs b/crates/disks/src/config/partitions/mod.rs index 1224f4bd..f5b95856 100644 --- a/crates/disks/src/config/partitions/mod.rs +++ b/crates/disks/src/config/partitions/mod.rs @@ -2,17 +2,18 @@ mod builder; pub use self::builder::PartitionBuilder; use super::{ - super::{LvmEncryption, PartitionError}, + super::{LuksEncryption, PartitionError}, PVS, }; pub use disk_types::{BlockDeviceExt, FileSystem, PartitionExt, PartitionType, SectorExt}; -use crate::external::{get_label, is_encrypted}; +use crate::{external::{get_label, is_encrypted}}; use fstab_generate::BlockInfo; use libparted::{Partition, PartitionFlag}; pub use os_detect::OS; use partition_identity::PartitionIdentifiers; use proc_mounts::{MountList, SwapList}; use std::{ + collections::HashMap, io, path::{Path, PathBuf}, str::FromStr, @@ -71,24 +72,26 @@ pub struct PartitionInfo { /// the partition number. pub device_path: PathBuf, /// Where this partition is mounted in the file system, if at all. - pub mount_point: Option, + pub mount_point: Vec, /// Where this partition will be mounted in the future pub target: Option, /// The pre-existing volume group assigned to this partition. pub original_vg: Option, - /// The volume group & LUKS configuration to associate with this device. - // TODO: Separate the tuple? - pub volume_group: Option<(String, Option)>, + /// The LVM volume group + pub lvm_vg: Option, + pub encryption: Option, /// If the partition is associated with a keyfile, this will name the key. pub key_id: Option, /// Possible identifiers for this partition. pub identifiers: PartitionIdentifiers, + /// Subvolumes found on this device + pub subvolumes: HashMap } impl BlockDeviceExt for PartitionInfo { fn get_device_path(&self) -> &Path { &self.device_path } - fn get_mount_point(&self) -> Option<&Path> { self.mount_point.as_deref() } + fn get_mount_point(&self) -> &[PathBuf] { self.mount_point.as_ref() } } impl PartitionExt for PartitionInfo { @@ -103,6 +106,14 @@ impl PartitionExt for PartitionInfo { fn get_sector_end(&self) -> u64 { self.end_sector } fn get_sector_start(&self) -> u64 { self.start_sector } + + fn encrypted_info(&self) -> Option<(PathBuf, FileSystem)> { + self.encryption.as_ref() + .map(|enc| { + let path = PathBuf::from(["/dev/mapper/", &*enc.physical_volume].concat()); + (path, enc.filesystem) + }) + } } impl SectorExt for PartitionInfo { @@ -130,7 +141,7 @@ impl PartitionInfo { "logical" => PartitionType::Logical, _ => return Ok(None), }, - mount_point: None, + mount_point: Vec::new(), target: None, filesystem, flags: get_flags(partition), @@ -141,9 +152,11 @@ impl PartitionInfo { start_sector: partition.geom_start() as u64, end_sector: partition.geom_end() as u64, original_vg: None, - volume_group: None, + lvm_vg: None, + encryption: None, key_id: None, identifiers, + subvolumes: HashMap::new(), })) } @@ -166,7 +179,12 @@ impl PartitionInfo { }; } - self.mount_point = mounts.get_mount_by_source(device_path).map(|m| m.dest.clone()); + self.mount_point = mounts.0 + .iter() + .filter(|mount| &mount.source == device_path) + .map(|m| m.dest.clone()) + .collect(); + self.bitflags |= if swaps.get_swapped(device_path) { SWAPPED } else { 0 }; self.original_vg = original_vg; } @@ -178,7 +196,7 @@ impl PartitionInfo { swapoff(path).map_err(|why| (path.to_path_buf(), why))?; } } - self.mount_point = None; + self.mount_point = Vec::new(); self.flag_disable(SWAPPED); Ok(()) } @@ -217,12 +235,12 @@ impl PartitionInfo { pub fn set_mount(&mut self, target: PathBuf) { self.target = Some(target); } /// Defines that the partition belongs to a given volume group. - /// - /// Optionally, this partition may be encrypted, in which you will also need to - /// specify a new physical volume name as well. In the event of encryption, an LVM - /// device will be assigned to the encrypted partition. - pub fn set_volume_group(&mut self, group: String, encryption: Option) { - self.volume_group = Some((group, encryption)); + pub fn set_volume_group(&mut self, group: String) { + self.lvm_vg = Some(group); + } + + pub fn set_encryption(&mut self, encryption: LuksEncryption) { + self.encryption = Some(encryption); } /// Shrinks the partition, if possible. @@ -265,7 +283,7 @@ impl PartitionInfo { /// generating entries in "/etc/fstab". pub fn get_block_info(&self) -> Option { let fs = self.get_file_system()?; - if fs != FileSystem::Swap && self.target.is_none() { + if fs != FileSystem::Swap && self.target.is_none() && self.subvolumes.is_empty() { return None; } @@ -317,7 +335,7 @@ mod tests { bitflags: ACTIVE | BUSY | SOURCE, device_path: Path::new("/dev/sdz1").to_path_buf(), flags: vec![PartitionFlag::PED_PARTITION_ESP], - mount_point: Some(Path::new("/boot/efi").to_path_buf()), + mount_point: vec!(Path::new("/boot/efi").to_path_buf()), target: Some(Path::new("/boot/efi").to_path_buf()), start_sector: 2048, end_sector: 1026047, @@ -328,8 +346,10 @@ mod tests { part_type: PartitionType::Primary, key_id: None, original_vg: None, - volume_group: None, + lvm_vg: None, + encryption: None, identifiers: PartitionIdentifiers::default(), + subvolumes: HashMap::new() } } @@ -338,7 +358,7 @@ mod tests { bitflags: ACTIVE | BUSY | SOURCE, device_path: Path::new("/dev/sdz2").to_path_buf(), flags: vec![], - mount_point: Some(Path::new("/").to_path_buf()), + mount_point: vec!(Path::new("/").to_path_buf()), target: Some(Path::new("/").to_path_buf()), start_sector: 1026048, end_sector: 420456447, @@ -349,8 +369,10 @@ mod tests { part_type: PartitionType::Primary, key_id: None, original_vg: None, - volume_group: None, + lvm_vg: None, + encryption: None, identifiers: PartitionIdentifiers::default(), + subvolumes: HashMap::new(), } } @@ -359,7 +381,7 @@ mod tests { bitflags: ACTIVE | SOURCE, device_path: Path::new("/dev/sdz3").to_path_buf(), flags: vec![], - mount_point: None, + mount_point: vec![], target: None, start_sector: 420456448, end_sector: 1936738303, @@ -371,14 +393,14 @@ mod tests { key_id: None, original_vg: None, identifiers: PartitionIdentifiers::default(), - volume_group: Some(( - "LVM_GROUP".into(), - Some(LvmEncryption { - physical_volume: "LUKS_PV".into(), - password: Some("password".into()), - keydata: None, - }), - )), + lvm_vg: Some("LVM_GROUP".into()), + encryption: Some(LuksEncryption { + physical_volume: "LUKS_PV".into(), + password: Some("password".into()), + keydata: None, + filesystem: FileSystem::Lvm, + }), + subvolumes: HashMap::new(), } } @@ -387,7 +409,7 @@ mod tests { bitflags: ACTIVE | SOURCE, device_path: Path::new("/dev/sdz3").to_path_buf(), flags: vec![], - mount_point: None, + mount_point: vec![], target: None, start_sector: 420456448, end_sector: 1936738303, @@ -398,8 +420,10 @@ mod tests { part_type: PartitionType::Primary, key_id: None, original_vg: None, - volume_group: Some(("LVM_GROUP".into(), None)), + lvm_vg: Some("LVM_GROUP".into()), + encryption: None, identifiers: PartitionIdentifiers::default(), + subvolumes: HashMap::new(), } } @@ -408,7 +432,7 @@ mod tests { bitflags: ACTIVE | SOURCE, device_path: Path::new("/dev/sdz4").to_path_buf(), flags: vec![], - mount_point: None, + mount_point: vec![], target: None, start_sector: 1936738304, end_sector: 1953523711, @@ -419,8 +443,10 @@ mod tests { part_type: PartitionType::Primary, key_id: None, original_vg: None, - volume_group: None, + lvm_vg: None, + encryption: None, identifiers: PartitionIdentifiers::default(), + subvolumes: HashMap::new(), } } diff --git a/crates/disks/src/external.rs b/crates/disks/src/external.rs index d5e3306b..7eab9616 100644 --- a/crates/disks/src/external.rs +++ b/crates/disks/src/external.rs @@ -12,7 +12,7 @@ use std::{ }; use sys_mount::*; use tempdir::TempDir; -use crate::LvmEncryption; +use crate::LuksEncryption; fn remove_encrypted_device(device: &Path) -> io::Result<()> { let mounts = MountList::new().expect("failed to get mounts in deactivate_device_maps"); @@ -60,7 +60,7 @@ fn remove_encrypted_device(device: &Path) -> io::Result<()> { /// Creates a LUKS partition from a physical partition. This could be either a LUKS on LVM /// configuration, or a LVM on LUKS configurations. -pub fn cryptsetup_encrypt(device: &Path, enc: &LvmEncryption) -> io::Result<()> { +pub fn cryptsetup_encrypt(device: &Path, enc: &LuksEncryption) -> io::Result<()> { remove_encrypted_device(device)?; info!("cryptsetup is encrypting {} with {:?}", device.display(), enc); @@ -83,9 +83,10 @@ pub fn cryptsetup_encrypt(device: &Path, enc: &LvmEncryption) -> io::Result<()> (None, Some(&(_, ref keydata))) => { let keydata = keydata.as_ref().expect("field should have been populated"); let tmpfs = TempDir::new("distinst")?; - let supported = SupportedFilesystems::new()?; - let _mount = Mount::new(&keydata.0, tmpfs.path(), &supported, MountFlags::BIND, None)? - .into_unmount_drop(UnmountFlags::DETACH); + let _mount = Mount::builder() + .flags(MountFlags::BIND) + .mount_autodrop(&keydata.0, tmpfs.path(), UnmountFlags::DETACH)?; + let keypath = tmpfs.path().join(&enc.physical_volume); generate_keyfile(&keypath)?; @@ -111,7 +112,7 @@ pub fn cryptsetup_encrypt(device: &Path, enc: &LvmEncryption) -> io::Result<()> } /// Opens an encrypted partition and maps it to the pv name. -pub fn cryptsetup_open(device: &Path, enc: &LvmEncryption) -> io::Result<()> { +pub fn cryptsetup_open(device: &Path, enc: &LuksEncryption) -> io::Result<()> { deactivate_devices(&[device])?; let pv = &enc.physical_volume; info!("cryptsetup is opening {} with pv {} and {:?}", device.display(), pv, enc); @@ -126,9 +127,9 @@ pub fn cryptsetup_open(device: &Path, enc: &LvmEncryption) -> io::Result<()> { (None, Some(&(_, ref keydata))) => { let keydata = keydata.as_ref().expect("field should have been populated"); let tmpfs = TempDir::new("distinst")?; - let supported = SupportedFilesystems::new()?; - let _mount = Mount::new(&keydata.0, tmpfs.path(), &supported, MountFlags::BIND, None)? - .into_unmount_drop(UnmountFlags::DETACH); + let _mount = Mount::builder() + .flags(MountFlags::BIND) + .mount_autodrop(&keydata.0, tmpfs.path(),UnmountFlags::DETACH)?; let keypath = tmpfs.path().join(&enc.physical_volume); info!("keypath exists: {}", keypath.is_file()); diff --git a/crates/external/Cargo.toml b/crates/external/Cargo.toml index 32d2e035..e01d6696 100644 --- a/crates/external/Cargo.toml +++ b/crates/external/Cargo.toml @@ -16,5 +16,5 @@ log = "0.4.8" proc-mounts = "0.2.4" rand = "0.7" smart-default = "0.6.0" -sys-mount = "1.2.1" +sys-mount = "1.5.1" tempdir = "0.3.7" diff --git a/crates/fstab-generate/Cargo.toml b/crates/fstab-generate/Cargo.toml index 15e10c2d..c2341b7b 100644 --- a/crates/fstab-generate/Cargo.toml +++ b/crates/fstab-generate/Cargo.toml @@ -8,7 +8,9 @@ readme = "README.md" license = "MIT" categories = ["os::unix-apis"] keywords = ["linux", "fstab", "generate"] +edition = "2018" [dependencies] +concat-in-place = "1.1.0" disk-types = { path = "../disk-types" } partition-identity = "0.2.0" diff --git a/crates/fstab-generate/src/block.rs b/crates/fstab-generate/src/block.rs index 0767ebd1..f2ce9f97 100644 --- a/crates/fstab-generate/src/block.rs +++ b/crates/fstab-generate/src/block.rs @@ -1,17 +1,17 @@ - +use concat_in_place::strcat; use partition_identity::{PartitionID, PartitionSource}; -use std::ffi::{OsStr, OsString}; use std::path::{Path, PathBuf}; use disk_types::FileSystem; +use std::borrow::Cow; /// Information that will be used to generate a fstab entry for the given /// partition. #[derive(Debug, PartialEq)] pub struct BlockInfo<'a> { pub uid: PartitionID, - mount: Option, + pub mount: Option, pub fs: &'static str, - pub options: &'a str, + pub options: Cow<'a, str>, pub dump: bool, pub pass: bool, } @@ -28,21 +28,22 @@ impl<'a> BlockInfo<'a> { mount: if fs == FileSystem::Swap { None } else { - Some(target.expect("unable to get block info due to lack of target").to_path_buf()) + target.map(Path::to_path_buf) }, fs: match fs { FileSystem::Fat16 | FileSystem::Fat32 => "vfat", FileSystem::Swap => "swap", _ => fs.into(), }, - options, + options: Cow::Borrowed(options), dump: false, pass: false, } } + #[allow(unused_braces)] /// Writes a single line to the fstab buffer for this file system. - pub fn write_entry(&self, fstab: &mut OsString) { + pub fn write(&self, fstab: &mut String) { let mount_variant = match self.uid.variant { PartitionSource::ID => "ID=", PartitionSource::Label => "LABEL=", @@ -52,26 +53,26 @@ impl<'a> BlockInfo<'a> { PartitionSource::UUID => "UUID=", }; - fstab.push(mount_variant); - fstab.push(&self.uid.id); - fstab.push(" "); - fstab.push(self.mount()); - fstab.push(" "); - fstab.push(&self.fs); - fstab.push(" "); - fstab.push(&self.options); - fstab.push(" "); - fstab.push(if self.dump { "1" } else { "0" }); - fstab.push(" "); - fstab.push(if self.pass { "1" } else { "0" }); - fstab.push("\n"); + let id = &self.uid.id; + let mount = self.mount(); + + strcat!( + fstab, + mount_variant id + " " mount + " " self.fs + " " {&self.options} + " " if self.dump { "1" } else { "0" } + " " if self.pass { "1" } else { "0" } + "\n" + ); } /// Retrieve the mount point, which is `none` if non-existent. - pub fn mount(&self) -> &OsStr { + pub fn mount(&self) -> &str { self.mount .as_ref() - .map_or(OsStr::new("none"), |path| path.as_os_str()) + .map_or("none", |path| path.as_os_str().to_str().unwrap()) } /// Helper for fetching the Partition ID of a partition. @@ -92,6 +93,7 @@ mod tests { use super::*; use std::ffi::OsStr; + #[test] fn fstab_entries() { let swap_id = PartitionID { id: "SWAP".into(), variant: PartitionSource::UUID }; @@ -99,18 +101,18 @@ mod tests { let efi_id = PartitionID { id: "EFI".into(), variant: PartitionSource::PartUUID }; let efi = BlockInfo::new(efi_id, FileSystem::Fat32, Some(Path::new("/boot/efi")), "defaults"); let root_id = PartitionID { id: "ROOT".into(), variant: PartitionSource::UUID }; - let root = BlockInfo::new(root_id, FileSystem::Ext4, Some(Path::new("/")), "defaults"); + let root = BlockInfo::new(root_id, FileSystem::Btrfs, Some(Path::new("/")), "defaults"); - let fstab = &mut OsString::new(); - swap.write_entry(fstab); - efi.write_entry(fstab); - root.write_entry(fstab); + let fstab = &mut String::new(); + swap.write(fstab); + efi.write(fstab); + root.write(fstab); assert_eq!( *fstab, - OsString::from(r#"UUID=SWAP none swap sw 0 0 + String::from(r#"UUID=SWAP none swap sw 0 0 PARTUUID=EFI /boot/efi vfat defaults 0 0 -UUID=ROOT / ext4 defaults 0 0 +UUID=ROOT / btrfs defaults 0 0 "#) ); } @@ -131,7 +133,7 @@ UUID=ROOT / ext4 defaults 0 0 }, mount: None, fs: "swap", - options: "sw", + options: Cow::Borrowed("sw"), dump: false, pass: false, } @@ -155,7 +157,7 @@ UUID=ROOT / ext4 defaults 0 0 }, mount: Some(PathBuf::from("/boot/efi")), fs: "vfat", - options: "defaults", + options: Cow::Borrowed("defaults"), dump: false, pass: false, } @@ -179,7 +181,7 @@ UUID=ROOT / ext4 defaults 0 0 }, mount: Some(PathBuf::from("/")), fs: FileSystem::Ext4.into(), - options: "defaults", + options: Cow::Borrowed("defaults"), dump: false, pass: false, } diff --git a/crates/os-detect/Cargo.toml b/crates/os-detect/Cargo.toml index 12bfa05e..d15d85e9 100644 --- a/crates/os-detect/Cargo.toml +++ b/crates/os-detect/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "os-detect" -version = "0.2.2" +version = "0.3.0" authors = ["Jeremy Soller ", "Michael Aaron Murphy "] description = "Detect an OS installed on a partition" repository = "https://github.com/pop-os/distinst" @@ -12,6 +12,6 @@ keywords = ["detect", "probe", "os"] [dependencies] os-release = "0.1.0" partition-identity = "0.2.0" -sys-mount = "1.1.0" +sys-mount = "1.5.1" tempdir = "0.3.7" log = "0.4.6" diff --git a/crates/os-detect/src/lib.rs b/crates/os-detect/src/lib.rs index b15d5dda..c6dbaa9c 100644 --- a/crates/os-detect/src/lib.rs +++ b/crates/os-detect/src/lib.rs @@ -31,14 +31,21 @@ use std::path::PathBuf; use partition_identity::PartitionID; use sys_mount::*; +#[derive(Debug, Clone)] +pub struct LinuxPartition { + pub source: PartitionID, + pub dest: PathBuf, + pub fs: String, + pub options: String, +} + /// Describes the OS found on a partition. #[derive(Debug, Clone)] pub enum OS { Windows(String), Linux { info: OsRelease, - partitions: Vec, - targets: Vec, + partitions: Vec }, MacOs(String) } @@ -48,16 +55,34 @@ pub enum OS { /// /// If the installed operating system is Linux, it will also report back the location /// of the home partition. -pub fn detect_os_from_device<'a, F: Into>>(device: &Path, fs: F) -> Option { +pub fn detect_os_from_device<'a>(device: &Path, subvol: Option<&str>, fs: impl Into>) -> Option { info!("detecting OS from device: {:?}", device); // Create a temporary directoy where we will mount the FS. TempDir::new("distinst").ok().and_then(|tempdir| { // Mount the FS to the temporary directory let base = tempdir.path(); - Mount::new(device, base, fs, MountFlags::empty(), None) - .map(|m| m.into_unmount_drop(UnmountFlags::DETACH)) - .ok() - .and_then(|_mount| detect_os_from_path(base)) + + let data = if let Some(subvol) = subvol { + ["subvol=", subvol].concat() + } else { + String::new() + }; + + let fs = fs.into(); + + info!("mounting {:?} {:?} {}", device, fs, data); + + let mount = Mount::builder() + .data(&*data) + .fstype(fs) + .mount_autodrop(device, base, UnmountFlags::DETACH); + + if let Err(why) = mount { + error!("failed to mount device for probing: {:?}", why); + return None + } + + detect_os_from_path(base) }) } @@ -83,8 +108,10 @@ pub fn detect_linux(base: &Path) -> Option { if path.exists() { info!("found OS Release: {}", std::fs::read_to_string(&path).unwrap()); if let Ok(info) = OsRelease::new_from(path) { - let (partitions, targets) = find_linux_parts(base); - return Some(OS::Linux { info, partitions, targets }); + return Some(OS::Linux { + info, + partitions: find_linux_parts(base) + }); } } @@ -110,33 +137,36 @@ pub fn detect_windows(base: &Path) -> Option { .map(|| OS::Windows("Windows".into())) } -fn find_linux_parts(base: &Path) -> (Vec, Vec) { +fn find_linux_parts(base: &Path) -> Vec { let mut partitions = Vec::new(); - let mut targets = Vec::new(); if let Ok(fstab) = open(base.join("etc/fstab")) { - for entry in BufReader::new(fstab).lines() { - if let Ok(entry) = entry { - let entry = entry.trim(); - if entry.starts_with('#') || entry.is_empty() { - continue; - } + for entry in BufReader::new(fstab).lines().flatten() { + let entry = entry.trim(); + if entry.starts_with('#') || entry.is_empty() { + continue; + } - let mut fields = entry.split_whitespace(); - let source = fields.next(); - let target = fields.next(); + let mut fields = entry.split_whitespace(); + let source = fields.next(); + let dest = fields.next(); + let fs = fields.next(); + let options = fields.next(); - if let Some(target) = target { - if let Some(Ok(path)) = source.map(|s| s.parse::()) { - partitions.push(path); - targets.push(PathBuf::from(String::from(target))); - } + if let Some(((dest, fs), options)) = dest.zip(fs).zip(options) { + if let Some(Ok(source)) = source.map(|s| s.parse::()) { + partitions.push(LinuxPartition { + source, + dest: PathBuf::from(dest.to_owned()), + fs: fs.to_owned(), + options: options.to_owned() + }) } } } } - (partitions, targets) + partitions } fn parse_plist(file: R) -> Option { diff --git a/debian/source/options b/debian/source/options new file mode 100644 index 00000000..c0bc9d77 --- /dev/null +++ b/debian/source/options @@ -0,0 +1,3 @@ +tar-ignore = "vendor" +tar-ignore = "target" +tar-ignore = ".git" diff --git a/ffi/build.rs b/ffi/build.rs index 0176ae1d..5b06ccee 100644 --- a/ffi/build.rs +++ b/ffi/build.rs @@ -14,7 +14,7 @@ fn main() { fs::File::create(target_dir.join("distinst.pc.stub")) .expect("failed to create pc.stub") - .write_all(&pkg_config.as_bytes()) + .write_all(pkg_config.as_bytes()) .expect("failed to write pc.stub"); cbindgen::generate(env::var("CARGO_MANIFEST_DIR").unwrap()) diff --git a/ffi/distinst.vapi b/ffi/distinst.vapi index 199003e5..136f6064 100644 --- a/ffi/distinst.vapi +++ b/ffi/distinst.vapi @@ -491,55 +491,6 @@ namespace Distinst { ESP } - /** - * Partition builders are supplied as inputs to the `add_partition` method. - */ - [CCode (has_type_id = false, unref_function = "")] - public class PartitionBuilder { - /** - * Creates a new partition builder which has it's start and end sectors defined, as well - * as the file system to assign to it. - */ - public PartitionBuilder (uint64 start_sector, uint64 end_sector, FileSystem filesystem); - - /** - * Defines a label for the new partition. - */ - public PartitionBuilder name (string name); - - /** - * Specifies where the new partition should be mounted. - */ - public PartitionBuilder mount (string target); - - /** - * Defines if the partition is either primary or logical. - */ - public PartitionBuilder partition_type (PartitionType part_type); - - /** - * Adds a partition flag to the new partition. - */ - public PartitionBuilder flag (PartitionFlag flag); - - /** - * Assigns this new partition to a logical volume group. - * - * If the encryption parameter is not set, this will be a LVM partition. - * Otherwise, a LUKS partition will be created with the information in in the - * encryption parameter, and a LVM partition will be assigned on top of that. - */ - public PartitionBuilder logical_volume (string volume_group, LvmEncryption? encryption); - - /** - * Species that this partition will contain a keyfile that belongs to the associated ID. - * - * Note that this partition should also have a mount target, or otherwise - * an error will occur. - */ - public PartitionBuilder associate_keyfile (string keyfile_id); - } - [SimpleType] [CCode (has_type_id = false)] public struct PartitionUsage { @@ -761,11 +712,6 @@ namespace Distinst { */ public unowned Partition[] list_partitions (); - /** - * Adds a new partition to the physical device from a partition builder. - */ - public int add_partition (PartitionBuilder partition); - /** * Specifies to format a partition at the given partition ID with the specified * file system. @@ -911,11 +857,6 @@ namespace Distinst { */ public unowned Partition get_partition_by_path (string path); - /** - * Adds a new partition to the physical device from a partition builder. - */ - public int add_partition (PartitionBuilder partition); - /** * Sets the remove bit on the specified logical volume * @@ -937,7 +878,7 @@ namespace Distinst { * Defines the configuration options to use when creating a new LUKS partition. */ [CCode (has_type_id = false, destroy_function = "", unref_function = "")] - public struct LvmEncryption { + public struct LuksEncryption { /** * Defines the name of the new PV that the LUKS partition will expose * IE: "cryptdata" set here will create a new device map at `/dev/mapper/cryptdata` @@ -1041,7 +982,7 @@ namespace Distinst { * - 5 indicates that the decrypted partition lacks a LVM volume group * - 6 indicates that the specified LUKS partition at `path` was not found */ - public int decrypt_partition (string path, LvmEncryption encryption); + public int decrypt_partition (string path, LuksEncryption encryption); /** * Finds the partition block path and associated partition information diff --git a/ffi/src/disk.rs b/ffi/src/disk.rs index 33d6e0d9..b7b1f09c 100644 --- a/ffi/src/disk.rs +++ b/ffi/src/disk.rs @@ -9,7 +9,7 @@ use std::{ use distinst::{ BlockDeviceExt, DecryptionError, Disk, DiskExt, Disks, FileSystem, LogicalDevice, - LvmEncryption, PartitionBuilder, PartitionInfo, PartitionTable, PartitionTableExt, Sector, + LuksEncryption, PartitionBuilder, PartitionInfo, PartitionTable, PartitionTableExt, Sector, SectorExt, }; @@ -17,9 +17,9 @@ use super::{get_str, null_check}; use crate::ffi::AsMutPtr; use crate::filesystem::DISTINST_FILE_SYSTEM; use crate::gen_object_ptr; -use crate::lvm::{DistinstLvmDevice, DistinstLvmEncryption}; +use crate::lvm::{DistinstLvmDevice, DistinstLuksEncryption}; use crate::partition::{ - DistinstPartition, DistinstPartitionAndDiskPath, DistinstPartitionBuilder, + DistinstPartition, DistinstPartitionAndDiskPath, DISTINST_PARTITION_TABLE, }; use crate::partition_identity::PartitionID; @@ -263,153 +263,6 @@ pub unsafe extern "C" fn distinst_disk_get_partition_table( disk.get_partition_table().into() } -#[no_mangle] -pub unsafe extern "C" fn distinst_disk_mklabel( - disk: *mut DistinstDisk, - table: DISTINST_PARTITION_TABLE, -) -> libc::c_int { - if null_check(disk).is_err() { - return -1; - } - - let disk = &mut *(disk as *mut Disk); - - let table = match table { - DISTINST_PARTITION_TABLE::GPT => PartitionTable::Gpt, - DISTINST_PARTITION_TABLE::MSDOS => PartitionTable::Msdos, - _ => return -1, - }; - - if let Err(why) = disk.mklabel(table) { - info!("unable to write partition table on {}: {}", disk.path().display(), why); - -1 - } else { - 0 - } -} - -#[no_mangle] -pub unsafe extern "C" fn distinst_disk_add_partition( - disk: *mut DistinstDisk, - partition: *mut DistinstPartitionBuilder, -) -> libc::c_int { - if null_check(disk).or_else(|_| null_check(partition)).is_err() { - return -1; - } - - let disk = &mut *(disk as *mut Disk); - - if let Err(why) = disk.add_partition(*Box::from_raw(partition as *mut PartitionBuilder)) { - info!("unable to add partition: {}", why); - -1 - } else { - 0 - } -} - -#[no_mangle] -pub unsafe extern "C" fn distinst_disk_remove_partition( - disk: *mut DistinstDisk, - partition: libc::c_int, -) -> libc::c_int { - if null_check(disk).is_err() { - return -1; - } - - let disk = &mut *(disk as *mut Disk); - - if let Err(why) = disk.remove_partition(partition) { - info!("unable to remove partition: {}", why); - -1 - } else { - 0 - } -} - -#[no_mangle] -pub unsafe extern "C" fn distinst_disk_resize_partition( - disk: *mut DistinstDisk, - partition: libc::c_int, - end: u64, -) -> libc::c_int { - if null_check(disk).is_err() { - return 0; - } - - let disk = &mut *(disk as *mut Disk); - - if let Err(why) = disk.resize_partition(partition, end) { - info!("libdistinst: unable to resize partition: {}", why); - -1 - } else { - 0 - } -} - -#[no_mangle] -pub unsafe extern "C" fn distinst_disk_move_partition( - disk: *mut DistinstDisk, - partition: libc::c_int, - start: u64, -) -> libc::c_int { - if null_check(disk).is_err() { - return -1; - } - - let disk = &mut *(disk as *mut Disk); - - if let Err(why) = disk.move_partition(partition, start) { - info!("unable to remove partition: {}", why); - -1 - } else { - 0 - } -} - -#[no_mangle] -pub unsafe extern "C" fn distinst_disk_format_partition( - disk: *mut DistinstDisk, - partition: libc::c_int, - fs: DISTINST_FILE_SYSTEM, -) -> libc::c_int { - if null_check(disk).is_err() { - return -1; - } - - let disk = &mut *(disk as *mut Disk); - - let fs = match Option::::from(fs) { - Some(fs) => fs, - None => { - info!("file system type required"); - return -1; - } - }; - - if let Err(why) = disk.format_partition(partition, fs) { - info!("unable to remove partition: {}", why); - -1 - } else { - 0 - } -} - -#[no_mangle] -pub unsafe extern "C" fn distinst_disk_commit(disk: *mut DistinstDisk) -> libc::c_int { - if null_check(disk).is_err() { - return -1; - } - - let disk = &mut *(disk as *mut Disk); - - if let Err(why) = disk.commit() { - info!("unable to commit changes to disk: {}", why); - -1 - } else { - 0 - } -} - #[repr(C)] pub struct DistinstDisks; @@ -651,7 +504,7 @@ pub unsafe extern "C" fn distinst_disks_find_partition( pub unsafe extern "C" fn distinst_disks_decrypt_partition( disks: *mut DistinstDisks, path: *const libc::c_char, - enc: *mut DistinstLvmEncryption, + enc: *mut DistinstLuksEncryption, ) -> libc::c_int { if null_check(disks) .or_else(|_| null_check(path)) @@ -669,9 +522,9 @@ pub unsafe extern "C" fn distinst_disks_decrypt_partition( if password.is_none() && keydata.is_none() { 3 } else { - let enc = LvmEncryption::new(pv.into(), password, keydata); + let mut enc = LuksEncryption::new(pv.into(), password, keydata, FileSystem::Ext4); let disks = &mut *(disks as *mut Disks); - match disks.decrypt_partition(&Path::new(path), &enc) { + match disks.decrypt_partition(&Path::new(path), &mut enc) { Ok(_) => 0, Err(why) => { error!("decryption error: {}", why); diff --git a/ffi/src/lvm.rs b/ffi/src/lvm.rs index 0e834482..e39752b7 100644 --- a/ffi/src/lvm.rs +++ b/ffi/src/lvm.rs @@ -7,7 +7,7 @@ use crate::ffi::AsMutPtr; use libc; use super::{ - get_str, null_check, DistinstDisks, DistinstPartition, DistinstPartitionBuilder, DistinstSector, + get_str, null_check, DistinstDisks, DistinstPartition, DistinstSector, }; use std::{os::unix::ffi::OsStrExt, path::Path, ptr}; @@ -213,50 +213,6 @@ pub unsafe extern "C" fn distinst_lvm_device_get_partition_by_path( .as_mut_ptr() as *mut DistinstPartition } -#[no_mangle] -pub unsafe extern "C" fn distinst_lvm_device_add_partition( - device: *mut DistinstLvmDevice, - partition: *mut DistinstPartitionBuilder, -) -> libc::c_int { - if null_check(device).is_err() { - return -1; - } - - let device = &mut *(device as *mut LogicalDevice); - - if let Err(why) = device.add_partition(*Box::from_raw(partition as *mut PartitionBuilder)) { - error!("unable to add partition: {}", why); - -1 - } else { - 0 - } -} - -#[no_mangle] -pub unsafe extern "C" fn distinst_lvm_device_remove_partition( - device: *mut DistinstLvmDevice, - volume: *const libc::c_char, -) -> libc::c_int { - if null_check(device).is_err() { - return -1; - } - - get_str(volume).ok().map_or(1, |volume| { - let device = &mut *(device as *mut LogicalDevice); - device.remove_partition(volume).ok().map_or(2, |_| 0) - }) -} - -#[no_mangle] -pub unsafe extern "C" fn distinst_lvm_device_clear_partitions(device: *mut DistinstLvmDevice) { - if null_check(device).is_err() { - return; - } - - let device = &mut *(device as *mut LogicalDevice); - device.clear_partitions(); -} - #[no_mangle] pub unsafe extern "C" fn distinst_lvm_device_list_partitions( device: *const DistinstLvmDevice, @@ -295,7 +251,7 @@ pub unsafe extern "C" fn distinst_lvm_device_contains_mount( } #[repr(C)] -pub struct DistinstLvmEncryption { +pub struct DistinstLuksEncryption { /// The PV field is not optional pub physical_volume: *mut libc::c_char, /// The password field is optional @@ -306,8 +262,8 @@ pub struct DistinstLvmEncryption { #[no_mangle] pub unsafe extern "C" fn distinst_lvm_encryption_copy( - src: *const DistinstLvmEncryption, - dst: *mut DistinstLvmEncryption, + src: *const DistinstLuksEncryption, + dst: *mut DistinstLuksEncryption, ) { if null_check(src).or_else(|_| null_check(dst)).is_err() { return; diff --git a/ffi/src/partition.rs b/ffi/src/partition.rs index c206097e..14328d8d 100644 --- a/ffi/src/partition.rs +++ b/ffi/src/partition.rs @@ -3,14 +3,14 @@ use libc; use std::{ffi::CString, io, os::unix::ffi::OsStrExt, path::PathBuf, ptr}; use distinst::{ - BlockDeviceExt, Bootloader, FileSystem, LvmEncryption, PartitionBuilder, PartitionExt, + BlockDeviceExt, Bootloader, FileSystem, LuksEncryption, PartitionBuilder, PartitionExt, PartitionFlag, PartitionInfo, PartitionTable, PartitionType, }; use crate::filesystem::DISTINST_FILE_SYSTEM; use crate::gen_object_ptr; use crate::get_str; use crate::null_check; -use crate::DistinstLvmEncryption; +use crate::DistinstLuksEncryption; #[repr(C)] #[derive(Debug, Clone, Copy)] @@ -147,149 +147,6 @@ impl From for PartitionFlag { } } -#[repr(C)] -pub struct DistinstPartitionBuilder; - -#[no_mangle] -pub unsafe extern "C" fn distinst_partition_builder_new( - start_sector: u64, - end_sector: u64, - filesystem: DISTINST_FILE_SYSTEM, -) -> *mut DistinstPartitionBuilder { - let filesystem: FileSystem = match filesystem.into() { - Some(filesystem) => filesystem, - None => { - error!("distinst_partition_builder_new: filesystem is NONE"); - return ptr::null_mut(); - } - }; - - gen_object_ptr(PartitionBuilder::new(start_sector, end_sector, filesystem)) - as *mut DistinstPartitionBuilder -} - -#[no_mangle] -pub unsafe extern "C" fn distinst_partition_builder_destroy( - builder: *mut DistinstPartitionBuilder, -) { - if builder.is_null() { - error!("DistinstPartitionBuilder was to be destroyed even though it is null"); - } else { - Box::from_raw(builder as *mut PartitionBuilder); - } -} - -/// Converts a `DistinstPartitionBuilder` into a `PartitionBuilder`, executes a given action with -/// that `PartitionBuilder`, then converts it back into a `DistinstPartitionBuilder`, returning the -/// exit status of the function. -unsafe fn builder_action PartitionBuilder>( - builder: *mut DistinstPartitionBuilder, - action: F, -) -> *mut DistinstPartitionBuilder { - if null_check(builder).is_err() { - builder - } else { - gen_object_ptr(action(*Box::from_raw(builder as *mut PartitionBuilder))) - as *mut DistinstPartitionBuilder - } -} - -#[no_mangle] -pub unsafe extern "C" fn distinst_partition_builder_name( - builder: *mut DistinstPartitionBuilder, - name: *const libc::c_char, -) -> *mut DistinstPartitionBuilder { - match get_str(name) { - Ok(string) => builder_action(builder, move |builder| builder.name(string.into())), - Err(_) => builder, - } -} - -#[no_mangle] -pub unsafe extern "C" fn distinst_partition_builder_mount( - builder: *mut DistinstPartitionBuilder, - target: *const libc::c_char, -) -> *mut DistinstPartitionBuilder { - match get_str(target) { - Ok(string) => { - builder_action(builder, move |builder| builder.mount(PathBuf::from(string.to_string()))) - } - Err(_) => builder, - } -} - -#[no_mangle] -pub unsafe extern "C" fn distinst_partition_builder_associate_keyfile( - builder: *mut DistinstPartitionBuilder, - keyid: *const libc::c_char, -) -> *mut DistinstPartitionBuilder { - match get_str(keyid) { - Ok(string) => { - builder_action(builder, move |builder| builder.associate_keyfile(string.into())) - } - Err(_) => builder, - } -} - -#[no_mangle] -pub unsafe extern "C" fn distinst_partition_builder_partition_type( - builder: *mut DistinstPartitionBuilder, - part_type: DISTINST_PARTITION_TYPE, -) -> *mut DistinstPartitionBuilder { - builder_action(builder, |builder| builder.partition_type(part_type.into())) -} - -#[no_mangle] -pub unsafe extern "C" fn distinst_partition_builder_flag( - builder: *mut DistinstPartitionBuilder, - flag: DISTINST_PARTITION_FLAG, -) -> *mut DistinstPartitionBuilder { - builder_action(builder, |builder| builder.flag(flag.into())) -} - -#[no_mangle] -pub unsafe extern "C" fn distinst_partition_builder_logical_volume( - builder: *mut DistinstPartitionBuilder, - group: *const libc::c_char, - encryption: *mut DistinstLvmEncryption, -) -> *mut DistinstPartitionBuilder { - let group = match get_str(group) { - Ok(string) => string.to_string(), - Err(_) => return builder, - }; - - let encryption = if encryption.is_null() { - None - } else { - let pv = match get_str((*encryption).physical_volume) { - Ok(string) => string.to_string(), - Err(_) => return builder, - }; - - let password = if (*encryption).password.is_null() { - None - } else { - match get_str((*encryption).password) { - Ok(string) => Some(string.to_string()), - Err(_) => return builder, - } - }; - - let keydata = if (*encryption).keydata.is_null() { - None - } else { - match get_str((*encryption).keydata) { - Ok(string) => Some(string.to_string()), - Err(_) => return builder, - } - }; - - Some(LvmEncryption::new(pv, password, keydata)) - }; - - builder_action(builder, |builder| builder.logical_volume(group, encryption)) -} - #[repr(C)] pub struct DistinstPartition; @@ -380,7 +237,7 @@ pub unsafe extern "C" fn distinst_partition_get_mount_point( } let part = &*(partition as *const PartitionInfo); - if let Some(ref mount) = part.mount_point { + if let Some(ref mount) = part.mount_point.get(0) { let mount = mount.as_os_str(); *len = mount.len() as libc::c_int; return mount.as_bytes().as_ptr(); diff --git a/rust-toolchain b/rust-toolchain index 21998d3c..bb120e87 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -1.47.0 +1.59.0 diff --git a/src/auto/accounts.rs b/src/auto/accounts.rs index a427c881..319f83c0 100644 --- a/src/auto/accounts.rs +++ b/src/auto/accounts.rs @@ -1,7 +1,6 @@ //! User account information will be collected here. -use super::{mount_and_then, ReinstallError}; -use disk_types::FileSystem; +use super::ReinstallError; use std::{collections::HashMap, ffi::OsStr, os::unix::ffi::OsStrExt, path::Path}; use crate::misc::read; @@ -30,21 +29,19 @@ pub(crate) fn lines, Vec)>>(input: &[u } impl AccountFiles { - pub fn new(device: &Path, fs: FileSystem) -> Result { + pub fn new(base: &Path) -> Result { info!("retrieving user account data"); - mount_and_then(device, fs, |base| { - read(base.join("etc/passwd")) - .and_then(|p| read(base.join("etc/group")).map(|g| (p, g))) - .and_then(|(p, g)| read(base.join("etc/shadow")).map(|s| (p, g, s))) - .and_then(|(p, g, s)| read(base.join("etc/gshadow")).map(|gs| (p, g, s, gs))) - .map(|(ref passwd, ref group, ref shadow, ref gshadow)| AccountFiles { - passwd: lines(passwd), - group: lines(group), - shadow: lines(shadow), - gshadow: lines(gshadow), - }) - .map_err(|why| ReinstallError::AccountsObtain { why, step: "get" }) - }) + read(base.join("etc/passwd")) + .and_then(|p| read(base.join("etc/group")).map(|g| (p, g))) + .and_then(|(p, g)| read(base.join("etc/shadow")).map(|s| (p, g, s))) + .and_then(|(p, g, s)| read(base.join("etc/gshadow")).map(|gs| (p, g, s, gs))) + .map(|(ref passwd, ref group, ref shadow, ref gshadow)| AccountFiles { + passwd: lines(passwd), + group: lines(group), + shadow: lines(shadow), + gshadow: lines(gshadow), + }) + .map_err(|why| ReinstallError::AccountsObtain { why, step: "get" }) } pub fn get(&self, home: &OsStr) -> Option { @@ -63,15 +60,14 @@ impl AccountFiles { } user_fields.and_then(|(user, group_id, home, passwd)| { - let user_string = String::from_utf8_lossy(&user); + let user_string = String::from_utf8_lossy(user); info!( "found user '{}' from home path at {}", user_string, String::from_utf8_lossy(home) ); - let user: &[u8] = &user; - let group = self.group.iter().find(|&(_, value)| group_has_id(&value, group_id)).map( + let group = self.group.iter().find(|&(_, value)| group_has_id(value, group_id)).map( |(group, value)| { info!( "found group '{}' associated with '{}'", @@ -85,7 +81,7 @@ impl AccountFiles { let secondary_groups = self .group .iter() - .filter(|&(_, value)| group_has_user(&value, user)) + .filter(|&(_, value)| group_has_user(value, user)) .inspect(|&(group, _)| { info!( "{} has a secondary group: '{}'", diff --git a/src/auto/mod.rs b/src/auto/mod.rs index b85407d2..d5297389 100644 --- a/src/auto/mod.rs +++ b/src/auto/mod.rs @@ -13,10 +13,8 @@ pub use self::{options::*, retain::delete_old_install}; use disk_types::FileSystem; use std::{ io, - path::{Path, PathBuf}, + path::PathBuf, }; -use sys_mount::{Mount, MountFlags, Unmount, UnmountFlags}; -use tempdir::TempDir; #[derive(Debug, Fail)] pub enum ReinstallError { @@ -49,23 +47,3 @@ pub enum ReinstallError { impl From for ReinstallError { fn from(why: io::Error) -> ReinstallError { ReinstallError::IO { why } } } - -fn mount_and_then(device: &Path, fs: FileSystem, mut action: F) -> Result -where - F: FnMut(&Path) -> Result, -{ - let fs: &str = match fs { - FileSystem::Fat16 | FileSystem::Fat32 => { - return Err(ReinstallError::InvalidFilesystem { part: device.to_path_buf(), fs }); - } - fs => fs.into(), - }; - - TempDir::new("distinst").map_err(|why| ReinstallError::TempDir { why }).and_then(|tempdir| { - let base = tempdir.path(); - Mount::new(device, base, fs, MountFlags::empty(), None) - .map(|m| m.into_unmount_drop(UnmountFlags::DETACH)) - .map_err(|why| ReinstallError::PartitionMount { why }) - .and_then(|_mount| action(base)) - }) -} diff --git a/src/auto/options/apply.rs b/src/auto/options/apply.rs index 6d3c95d5..2ecf1d93 100644 --- a/src/auto/options/apply.rs +++ b/src/auto/options/apply.rs @@ -54,16 +54,14 @@ fn set_mount_by_identity( fn generate_encryption( password: Option, -) -> Result, InstallOptionError> { + filesystem: FileSystem +) -> Result, InstallOptionError> { let value = match password { Some(pass) => { - let (root, encrypted_vg) = generate_unique_id("data", &[]) - .and_then(|r| generate_unique_id("cryptdata", &[]).map(|e| (r, e))) + let encrypted_pv = generate_unique_id("cryptdata", &[]) .map_err(|why| InstallOptionError::GenerateID { why })?; - let root_vg = root; - let enc = LvmEncryption::new(encrypted_vg, Some(pass), None); - Some((enc, root_vg)) + Some(LuksEncryption::new(encrypted_pv, Some(pass), None, filesystem)) } None => None, }; @@ -123,11 +121,7 @@ fn alongside_config( AlongsideMethod::Free(ref region) => (region.start + 1, region.end - 1), }; - let (lvm, root_vg) = match generate_encryption(password)? { - Some((enc, root)) => (Some((enc, root.clone())), Some(root)), - None => (None, None), - }; - + let root_encryption = generate_encryption(password, Btrfs)?; let bootloader = Bootloader::detect(); if bootloader == Bootloader::Efi { @@ -158,7 +152,7 @@ fn alongside_config( )?; start = recovery_end; - } else if lvm.is_some() { + } else if root_encryption.is_some() { // BIOS systems with an encrypted root must have a separate boot partition. let boot_end = start + DEFAULT_ESP_SECTORS; @@ -173,11 +167,14 @@ fn alongside_config( } // Configure optionally-encrypted root volume - if let Some((enc, root_vg)) = lvm { + if let Some(encryption) = root_encryption { device.add_partition( - PartitionBuilder::new(start, end, Lvm) + PartitionBuilder::new(start, end, Luks) .partition_type(PartitionType::Primary) - .logical_volume(root_vg, Some(enc)), + .encryption(encryption) + .name("cryptdata".into()) + .subvolume("/", "@root") + .subvolume("/home", "@home") )?; } else { let swap = end - DEFAULT_SWAP_SECTORS; @@ -190,30 +187,17 @@ fn alongside_config( end }; - device.add_partition(PartitionBuilder::new(start, end, Ext4).mount("/".into()))?; + device.add_partition( + PartitionBuilder::new(start, end, Btrfs) + .name("Pop".into()) + .subvolume("/", "@root") + .subvolume("/home", "@home") + )?; } disks.add(device); disks.initialize_volume_groups()?; - if let Some(root_vg) = root_vg { - let lvm_device = disks - .get_logical_device_mut(&root_vg) - .ok_or(InstallOptionError::LogicalDeviceNotFound { vg: root_vg })?; - - let start = lvm_device.get_sector(Sector::Start); - let swap = lvm_device.get_sector(Sector::UnitFromEnd(DEFAULT_SWAP_SECTORS)); - let end = lvm_device.get_sector(Sector::End); - - lvm_device - .add_partition( - PartitionBuilder::new(start, swap, Ext4).name("root".into()).mount("/".into()), - ) - .and_then(|_| { - lvm_device.add_partition(PartitionBuilder::new(swap, end, Swap).name("swap".into())) - })?; - } - Ok(()) } @@ -234,21 +218,46 @@ fn upgrade_config(disks: &mut Disks, option: &RecoveryOption) -> Result<(), Inst /// Apply a `refresh` config to `disks`. fn refresh_config(disks: &mut Disks, option: &RefreshOption) -> Result<(), InstallOptionError> { - info!("applying refresh install config"); - set_mount_by_identity(disks, &PartitionID::new_uuid(option.root_part.clone()), "/")?; + info!("applying refresh install config: {:#?}", option); + info!("disk configuration: {:#?}", disks); + + { + let root = &option.root; + let subvolume = root.options.split(',') + .find_map(|o| o.strip_prefix("subvol=")); + + if let Some(subvol) = subvolume { + debug!("setting root subvol"); + disks.set_subvolume(&root.source, subvol, "/"); + } else { + debug!("setting root"); + set_mount_by_identity(disks, &root.source, "/")?; + } + } + if let Some(ref home) = option.home_part { - set_mount_by_identity(disks, home, "/home")?; + debug!("home = {}", home.options); + let subvolume = home.options.split(',') + .find_map(|o| o.strip_prefix("subvol=")); + + if let Some(subvol) = subvolume { + debug!("setting home subvol"); + disks.set_subvolume(&home.source, subvol, "/home"); + } else { + debug!("setting home"); + set_mount_by_identity(disks, &home.source, "/home")?; + } } if let Some(ref efi) = option.efi_part { - set_mount_by_identity(disks, efi, "/boot/efi")?; + set_mount_by_identity(disks, &efi.source, "/boot/efi")?; } else if Bootloader::detect() == Bootloader::Efi { return Err(InstallOptionError::RefreshWithoutEFI); } if let Some(ref recovery) = option.recovery_part { - mount_recovery_partid(disks, recovery)?; + mount_recovery_partid(disks, &recovery.source)?; } Ok(()) @@ -282,10 +291,7 @@ fn recovery_config( let mut tmp = Disks::default(); mem::swap(&mut tmp, disks); - let (lvm, root_vg) = match generate_encryption(password)? { - Some((enc, root)) => (Some((enc, root.clone())), Some(root)), - None => (None, None), - }; + let luks = generate_encryption(password, Btrfs)?; let mut recovery_device: Disk = { let mut recovery_path = option.parse_recovery_id().get_device_path().ok_or_else(|| { @@ -370,32 +376,28 @@ fn recovery_config( recovery_device.remove_partition(id)?; - if let Some((enc, root)) = lvm { + if let Some(enc) = luks { recovery_device.add_partition( - PartitionBuilder::new(start, end, Luks).logical_volume(root, Some(enc)), + PartitionBuilder::new(start, end, Luks) + .encryption(enc) + .name("cryptdata".into()) + .subvolume("/", "@root") + .subvolume("/home", "@home"), )?; } else { recovery_device - .add_partition(PartitionBuilder::new(start, end, Ext4).mount("/".into()))?; + .add_partition( + PartitionBuilder::new(start, end, Btrfs) + .name("Pop".into()) + .subvolume("/", "@root") + .subvolume("/home", "@home") + )?; } } disks.add(recovery_device); disks.initialize_volume_groups()?; - if let Some(root_vg) = root_vg { - let lvm_device = disks - .get_logical_device_mut(&root_vg) - .ok_or(InstallOptionError::LogicalDeviceNotFound { vg: root_vg })?; - - let start = lvm_device.get_sector(Sector::Start); - let end = lvm_device.get_sector(Sector::End); - - lvm_device.add_partition( - PartitionBuilder::new(start, end, Ext4).name("root".into()).mount("/".into()), - )?; - } - Ok(()) } @@ -416,10 +418,7 @@ fn erase_config( let swap_sector = Sector::UnitFromEnd(DEFAULT_SWAP_SECTORS); let end_sector = Sector::End; - let (lvm, root_vg) = match generate_encryption(password)? { - Some((enc, root)) => (Some((enc, root.clone())), Some(root)), - None => (None, None), - }; + let luks = generate_encryption(password, Btrfs)?; { let mut device = Disk::from_name(&option.device) @@ -458,7 +457,7 @@ fn erase_config( .mklabel(PartitionTable::Msdos) // This is used to ensure LVM installs will work with BIOS .and_then(|_| { - if lvm.is_some() { + if luks.is_some() { let start = device.get_sector(start_sector); let end = device.get_sector(boot_sector); device @@ -480,12 +479,18 @@ fn erase_config( // Configure optionally-encrypted root volume result .and_then(|(start, end)| { - device.add_partition(if let Some((enc, root_vg)) = lvm { - PartitionBuilder::new(start, end, Lvm) + device.add_partition(if let Some(enc) = luks { + PartitionBuilder::new(start, end, Luks) .partition_type(PartitionType::Primary) - .logical_volume(root_vg, Some(enc)) + .encryption(enc) + .name("cryptdata".into()) + .subvolume("/", "@root") + .subvolume("/home", "@home") } else { - PartitionBuilder::new(start, end, Ext4).mount("/".into()) + PartitionBuilder::new(start, end, Btrfs) + .name("Pop".into()) + .subvolume("/", "@root") + .subvolume("/home", "@home") }) }) // Configure swap partition @@ -500,18 +505,7 @@ fn erase_config( disks.initialize_volume_groups()?; - if let Some(root_vg) = root_vg { - let lvm_device = disks - .get_logical_device_mut(&root_vg) - .ok_or(InstallOptionError::LogicalDeviceNotFound { vg: root_vg })?; - - let start = lvm_device.get_sector(start_sector); - let end = lvm_device.get_sector(end_sector); - - lvm_device.add_partition( - PartitionBuilder::new(start, end, Ext4).name("root".into()).mount("/".into()), - )?; - } + dbg!(disks); Ok(()) } diff --git a/src/auto/options/mod.rs b/src/auto/options/mod.rs index 39d6c3ab..631fc98c 100644 --- a/src/auto/options/mod.rs +++ b/src/auto/options/mod.rs @@ -11,9 +11,8 @@ pub use self::{ }; use super::super::*; -use disk_types::PartitionExt; +use disk_types::{FileSystem, PartitionExt}; -use os_release::OS_RELEASE; use partition_identity::PartitionID; use std::path::PathBuf; @@ -36,7 +35,6 @@ impl InstallOptions { let mut alongside_options = Vec::new(); let recovery_option = detect_recovery(); - let os_release = OS_RELEASE.as_ref().expect("OS_RELEASE fetch failed"); { let erase_options = &mut erase_options; @@ -44,7 +42,20 @@ impl InstallOptions { let mut check_partition = |part: &PartitionInfo| -> Option { // We're only going to find Linux on a Linux-compatible file system. - if let Some(os) = part.probe_os() { + let inner_fs = match part.encryption.as_ref() { + Some(encryption) => { + Some(encryption.filesystem) + }, + None => part.filesystem + }; + + let subvol = if let Some(FileSystem::Btrfs) = inner_fs { + Some("@root") + } else { + None + }; + + if let Some(os) = part.probe_os(subvol) { info!( "found OS on {:?}: {}", part.get_device_path(), @@ -56,14 +67,14 @@ impl InstallOptions { ); // Only consider Linux installs for refreshing. - if let OS::Linux { ref info, ref partitions, ref targets } = os { - let home = targets.iter().position(|t| t == Path::new("/home")); - let efi = targets.iter().position(|t| t == Path::new("/boot/efi")); - let recovery = targets.iter().position(|t| t == Path::new("/recovery")); + if let OS::Linux { ref info, ref partitions } = os { + let efi_part = partitions.iter().find(|t| t.dest == Path::new("/boot/efi")).cloned(); + + let root = partitions.iter().find(|t| t.dest == Path::new("/")).cloned()?; info!( "found refresh option {}on {:?}", - if efi.is_some() { "with EFI partition " } else { "" }, + if efi_part.is_some() { "with EFI partition " } else { "" }, part.get_device_path() ); @@ -72,9 +83,10 @@ impl InstallOptions { root_part: PartitionID::get_uuid(part.get_device_path()) .expect("root device did not have uuid") .id, - home_part: home.map(|pos| partitions[pos].clone()), - efi_part: efi.map(|pos| partitions[pos].clone()), - recovery_part: recovery.map(|pos| partitions[pos].clone()), + root, + home_part: partitions.iter().find(|t| t.dest == Path::new("/home")).cloned(), + efi_part, + recovery_part: partitions.iter().find(|t| t.dest == Path::new("/recovery")).cloned(), can_retain_old: if let Ok(used) = part.sectors_used() { part.get_sectors() - used > required_space } else { @@ -90,19 +102,21 @@ impl InstallOptions { }; for device in disks.get_physical_devices() { - if device.is_read_only() || device.contains_mount("/", &disks) { + if device.is_read_only() || device.contains_mount("/", disks) { continue; } - + eprintln!("device: {:?}", device.get_device_path()); let mut last_end_sector = 1024; for part in device.get_partitions() { + let os = check_partition(part); + if let Ok(used) = part.sectors_used() { let sectors = part.get_sectors(); let free = sectors - used; - let os = check_partition(part); + if required_space + shrink_overhead < free { info!( "found shrinkable partition on {:?}: {} free of {}", @@ -164,8 +178,8 @@ impl InstallOptions { } let skip = !Path::new("/cdrom/recovery.conf").exists() - && (device.contains_mount("/", &disks) - || device.contains_mount("/cdrom", &disks)); + && (device.contains_mount("/", disks) + || device.contains_mount("/cdrom", disks)); if skip { info!("install options: skipping options on {:?}", device.get_device_path()); @@ -179,7 +193,7 @@ impl InstallOptions { model: { let model = device.get_model(); if model.is_empty() { - device.get_serial().replace("_", " ") + device.get_serial().replace('_', " ") } else { model.into() } diff --git a/src/auto/options/refresh_option.rs b/src/auto/options/refresh_option.rs index d15983d1..adca8c00 100644 --- a/src/auto/options/refresh_option.rs +++ b/src/auto/options/refresh_option.rs @@ -1,22 +1,22 @@ use os_release::OsRelease; -use partition_identity::PartitionID; use std::fmt; #[derive(Debug)] pub struct RefreshOption { pub os_release: OsRelease, pub root_part: String, - pub home_part: Option, - pub efi_part: Option, - pub recovery_part: Option, + pub root: os_detect::LinuxPartition, + pub home_part: Option, + pub efi_part: Option, + pub recovery_part: Option, pub can_retain_old: bool, } impl fmt::Display for RefreshOption { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let root_part: String = - match PartitionID::new_uuid(self.root_part.clone()).get_device_path() { - Some(uuid) => uuid.to_string_lossy().into(), + match self.root.source.get_device_path() { + Some(path) => path.to_string_lossy().into(), None => "None".into(), }; diff --git a/src/auto/retain.rs b/src/auto/retain.rs index c75f38e9..dfec6f1d 100644 --- a/src/auto/retain.rs +++ b/src/auto/retain.rs @@ -1,10 +1,9 @@ //! Retain users when reinstalling, keeping their home folder and user account. use crate::bootloader::Bootloader; -use disk_types::FileSystem; use crate::disks::Disks; -use super::{mount_and_then, AccountFiles, ReinstallError, UserData}; +use super::{AccountFiles, ReinstallError, UserData}; use crate::misc; use std::{ @@ -19,83 +18,76 @@ use std::{ }; /// Removes all files in the chroot at `/`, except for `/home`. -pub fn remove_root(root_path: &Path, root_fs: FileSystem) -> Result<(), ReinstallError> { +pub fn remove_root(base: &Path) -> Result<(), ReinstallError> { info!("removing all files except /home. This may take a while..."); - mount_and_then(root_path, root_fs, |base| { - read_and_exclude(base, &[OsStr::new("home")], |entry| { - if entry.is_dir() { - fs::remove_dir_all(entry)?; - } else { - fs::remove_file(entry)?; - } + read_and_exclude(base, &[OsStr::new("home")], |entry| { + if entry.is_dir() { + let _ = fs::remove_dir_all(entry); + } else { + let _ = fs::remove_file(entry); + } - Ok(()) - }) + Ok(()) }) } /// Migrate the original system to the `/linux.old/` directory, excluding `/home`. -pub fn move_root(root_path: &Path, root_fs: FileSystem) -> Result<(), ReinstallError> { - mount_and_then(root_path, root_fs, |base| { - let old_root = base.join("linux.old"); - - // Remove an old, old root if it already exists. - if old_root.exists() { - info!("removing original /linux.old directory. This may take a while..."); - fs::remove_dir_all(&old_root)?; - } +pub fn move_root(base: &Path) -> Result<(), ReinstallError> { + let old_root = base.join("linux.old"); - info!("moving original system to /linux.old"); - fs::create_dir(&old_root)?; + // Remove an old, old root if it already exists. + if old_root.exists() { + info!("removing original /linux.old directory. This may take a while..."); + let _ = fs::remove_dir_all(&old_root); + } - // Migrate the current root system to the old root path. - let exclude = &[OsStr::new("home"), OsStr::new("linux.old")]; - read_and_exclude(base, exclude, |entry| { - let filename = entry.file_name().expect("root entry without file name"); - fs::rename(entry, base.join("linux.old").join(filename))?; - Ok(()) - }) + info!("moving original system to /linux.old"); + fs::create_dir(&old_root)?; + + // Migrate the current root system to the old root path. + let exclude = &[OsStr::new("home"), OsStr::new("linux.old")]; + read_and_exclude(base, exclude, |entry| { + let filename = entry.file_name().expect("root entry without file name"); + info!("moving {:?} to linux.old", entry); + let _ = fs::rename(entry, base.join("linux.old").join(filename)); + Ok(()) }) } /// If a refresh install fails, this can be used to restore the original system. -pub fn recover_root(root_path: &Path, root_fs: FileSystem) -> Result<(), ReinstallError> { +pub fn recover_root(base: &Path) -> Result<(), ReinstallError> { info!("attempting to restore the original system"); - mount_and_then(root_path, root_fs, |base| { - // Remove files installed by the installer. - read_and_exclude(base, &[OsStr::new("home"), OsStr::new("linux.old")], |entry| { - if entry.is_dir() { - fs::remove_dir_all(entry)?; - } else { - fs::remove_file(entry)?; - } + // Remove files installed by the installer. + read_and_exclude(base, &[OsStr::new("home"), OsStr::new("linux.old")], |entry| { + if entry.is_dir() { + let _ = fs::remove_dir_all(entry); + } else { + let _ = fs::remove_file(entry); + } - Ok(()) - })?; + Ok(()) + })?; - // Restore original files. - let old_root = base.join("linux.old"); - read_and_exclude(&old_root, &[], |entry| { - let filename = entry.file_name().expect("root entry without file name"); - fs::rename(entry, base.join(filename))?; - Ok(()) - }) + // Restore original files. + let old_root = base.join("linux.old"); + read_and_exclude(&old_root, &[], |entry| { + let filename = entry.file_name().expect("root entry without file name"); + let _ = fs::rename(entry, base.join(filename)); + Ok(()) }) } /// Delete the /linux.old directory withint the given device. -pub fn delete_old_install(root_path: &Path, root_fs: FileSystem) -> Result<(), ReinstallError> { - info!("removing the /linux.old directory at {:?}. This may take a while...", root_path); - mount_and_then(root_path, root_fs, |base| { - let old_root = base.join("linux.old"); - - // Remove an old, old root if it already exists. - if old_root.exists() { - fs::remove_dir_all(&old_root)?; - } +pub fn delete_old_install(base: &Path) -> Result<(), ReinstallError> { + info!("removing the /linux.old directory at {:?}. This may take a while...", base); + let old_root = base.join("linux.old"); - Ok(()) - }) + // Remove an old, old root if it already exists. + if old_root.exists() { + let _ = fs::remove_dir_all(&old_root); + } + + Ok(()) } /// Checks to see if the backup install has a chance to succeed, before starting it. @@ -103,7 +95,7 @@ pub fn validate_backup_conditions>( disks: &Disks, path: P, ) -> Result<(), ReinstallError> { - partition_configuration_is_valid(&disks).and_then(|_| install_media_exists(path.as_ref())) + partition_configuration_is_valid(disks).and_then(|_| install_media_exists(path.as_ref())) } /// Validate that the configuration in the disks structure is valid for installation. @@ -129,17 +121,15 @@ fn read_and_exclude Result<(), ReinstallError>>( exclude: &[&OsStr], mut func: F, ) -> Result<(), ReinstallError> { - for entry in path.read_dir()? { - if let Ok(entry) = entry { - let entry = entry.path(); - if let Some(filename) = entry.file_name() { - if exclude.contains(&filename) { - continue; - } + for entry in path.read_dir()?.flatten() { + let entry = entry.path(); + if let Some(filename) = entry.file_name() { + if exclude.contains(&filename) { + continue; } - - func(&entry)?; } + + func(&entry)?; } Ok(()) @@ -155,153 +145,147 @@ pub struct Backup<'a> { impl<'a> Backup<'a> { /// Create a backup from key data on the given device. pub fn new( - device: &Path, - fs: FileSystem, - is_root: bool, + base: &Path, account_files: &'a AccountFiles, ) -> Result, ReinstallError> { - mount_and_then(device, fs, |base| { - info!("collecting list of user accounts"); - let dir = if is_root { base.join("home").read_dir() } else { base.read_dir() }; - - let users = dir? - .filter_map(|entry| entry.ok()) - .map(|name| name.file_name()) - .inspect(|name| { - info!("found user account: {}", name.clone().into_string().unwrap()) - }) - .collect::>(); - - info!("retaining localtime information"); - let localtime = exists_and_then(&base, "etc/localtime", |localtime| { - localtime.canonicalize().ok().and_then(|ref p| get_timezone_path(p)) - }); - - info!("retaining timezone information"); - let timezone = - exists_and_then(&base, "etc/timezone", |timezone| misc::read(&timezone).ok()); - - info!("retaining /etc/NetworkManager/system-connections/"); - let networks = base.join("etc/NetworkManager/system-connections/").read_dir().ok().map( - |directory| { - directory - .flat_map(|entry| entry.ok()) - .filter(|entry| entry.path().is_file()) - .filter_map(|conn| { - misc::read(conn.path()).ok().map(|data| (conn.file_name(), data)) - }) - .collect::)>>() - }, - ); - - let users = users.iter().filter_map(|user| account_files.get(user)).collect::>(); - - Ok(Backup { users, localtime, timezone, networks }) - }) + info!("collecting list of user accounts"); + let dir = base.join("home").read_dir(); + + let users = dir? + .filter_map(|entry| entry.ok()) + .map(|name| name.file_name()) + .inspect(|name| { + info!("found user account: {}", name.clone().into_string().unwrap()) + }) + .collect::>(); + + info!("retaining localtime information"); + let localtime = exists_and_then(base, "etc/localtime", |localtime| { + localtime.canonicalize().ok().and_then(|ref p| get_timezone_path(p)) + }); + + info!("retaining timezone information"); + let timezone = + exists_and_then(base, "etc/timezone", |timezone| misc::read(&timezone).ok()); + + info!("retaining /etc/NetworkManager/system-connections/"); + let networks = base.join("etc/NetworkManager/system-connections/").read_dir().ok().map( + |directory| { + directory + .flat_map(|entry| entry.ok()) + .filter(|entry| entry.path().is_file()) + .filter_map(|conn| { + misc::read(conn.path()).ok().map(|data| (conn.file_name(), data)) + }) + .collect::)>>() + }, + ); + + let users = users.iter().filter_map(|user| account_files.get(user)).collect::>(); + + Ok(Backup { users, localtime, timezone, networks }) } /// Restores the backup to the given device. The device will be opened using the specified file /// system. - pub fn restore(&self, device: &Path, fs: FileSystem) -> Result<(), ReinstallError> { - mount_and_then(device, fs, |base| { - info!("appending user account data to new install"); - let (passwd, group, shadow, gshadow) = ( - base.join("etc/passwd"), - base.join("etc/group"), - base.join("etc/shadow"), - base.join("etc/gshadow"), - ); - - let (mut passwd, mut group, mut shadow, mut gshadow) = open(&passwd, true) - .and_then(|p| open(&group, false).map(|g| (p, g))) - .and_then(|(p, g)| open(&shadow, true).map(|s| (p, g, s))) - .and_then(|(p, g, s)| open(&gshadow, true).map(|gs| (p, g, s, gs))) - .map_err(|why| ReinstallError::AccountsObtain { why, step: "append" })?; - - group.seek(SeekFrom::End(0))?; - - fn append(entry: &[u8]) -> Vec { - let mut entry = entry.to_owned(); - entry.push(b'\n'); - entry - } + pub fn restore(&self, base: &Path) -> Result<(), ReinstallError> { + info!("appending user account data to new install"); + let (passwd, group, shadow, gshadow) = ( + base.join("etc/passwd"), + base.join("etc/group"), + base.join("etc/shadow"), + base.join("etc/gshadow"), + ); + + let (mut passwd, mut group, mut shadow, mut gshadow) = open(&passwd, true) + .and_then(|p| open(&group, false).map(|g| (p, g))) + .and_then(|(p, g)| open(&shadow, true).map(|s| (p, g, s))) + .and_then(|(p, g, s)| open(&gshadow, true).map(|gs| (p, g, s, gs))) + .map_err(|why| ReinstallError::AccountsObtain { why, step: "append" })?; + + group.seek(SeekFrom::End(0))?; + + fn append(entry: &[u8]) -> Vec { + let mut entry = entry.to_owned(); + entry.push(b'\n'); + entry + } - for user in &self.users { - let _ = passwd.write_all(&append(user.passwd)); - let _ = group.write_all(&append(user.group)); - let _ = shadow.write_all(&append(user.shadow)); - let _ = gshadow.write_all(&append(user.gshadow)); - - if !user.secondary_groups.is_empty() { - group.seek(SeekFrom::Start(0))?; - let groups_data = { - let mut buffer = Vec::with_capacity( - group.metadata().ok().map_or(0, |x| x.len()) as usize, - ); - group.read_to_end(&mut buffer)?; - buffer - }; - - let mut groups = - super::accounts::lines::, Vec)>>(&groups_data); - for &group in &user.secondary_groups { - for entry in &mut groups { - if entry.0.as_slice() == group { - if entry.1[entry.1.len() - 1] != b':' { - entry.1.push(b','); - } - entry.1.extend_from_slice(user.user); + for user in &self.users { + let _ = passwd.write_all(&append(user.passwd)); + let _ = group.write_all(&append(user.group)); + let _ = shadow.write_all(&append(user.shadow)); + let _ = gshadow.write_all(&append(user.gshadow)); + + if !user.secondary_groups.is_empty() { + group.seek(SeekFrom::Start(0))?; + let groups_data = { + let mut buffer = Vec::with_capacity( + group.metadata().ok().map_or(0, |x| x.len()) as usize, + ); + group.read_to_end(&mut buffer)?; + buffer + }; + + let mut groups = + super::accounts::lines::, Vec)>>(&groups_data); + for &group in &user.secondary_groups { + for entry in &mut groups { + if entry.0.as_slice() == group { + if entry.1[entry.1.len() - 1] != b':' { + entry.1.push(b','); } + entry.1.extend_from_slice(user.user); } } - - let mut serialized = groups.into_iter().map(|(_, entry)| entry).fold( - Vec::new(), - |mut acc, entry| { - acc.extend_from_slice(&entry); - acc.push(b'\n'); - acc - }, - ); - - // Remove the last newline from the buffer. - serialized.pop(); - let serialized = serialized; - - // Write the serialized buffer to the group file. - group.seek(SeekFrom::Start(0))?; - group.set_len(0)?; - group.write_all(&serialized)?; } - } - if let Some(ref tz) = self.localtime { - info!("restoring /etc/localtime symlink to {:?}", tz); - let path = base.join("etc/localtime"); - if path.exists() { - fs::remove_file(&path)?; - } - - symlink(Path::new(tz), path)?; + let mut serialized = groups.into_iter().map(|(_, entry)| entry).fold( + Vec::new(), + |mut acc, entry| { + acc.extend_from_slice(&entry); + acc.push(b'\n'); + acc + }, + ); + + // Remove the last newline from the buffer. + serialized.pop(); + let serialized = serialized; + + // Write the serialized buffer to the group file. + group.seek(SeekFrom::Start(0))?; + group.set_len(0)?; + group.write_all(&serialized)?; } + } - if let Some(ref tz) = self.timezone { - info!("restoring /etc/timezone with {}", String::from_utf8_lossy(tz)); - misc::create(base.join("etc/timezone")).and_then(|mut file| file.write_all(tz))?; + if let Some(ref tz) = self.localtime { + info!("restoring /etc/localtime symlink to {:?}", tz); + let path = base.join("etc/localtime"); + if path.exists() { + fs::remove_file(&path)?; } - if let Some(ref networks) = self.networks { - info!("restoring NetworkManager configuration"); - let network_conf_dir = &base.join("etc/NetworkManager/system-connections/"); - let _ = fs::create_dir_all(&network_conf_dir); + symlink(Path::new(tz), path)?; + } - for &(ref connection, ref data) in networks { - create_network_conf(network_conf_dir, connection, data); - } + if let Some(ref tz) = self.timezone { + info!("restoring /etc/timezone with {}", String::from_utf8_lossy(tz)); + misc::create(base.join("etc/timezone")).and_then(|mut file| file.write_all(tz))?; + } + + if let Some(ref networks) = self.networks { + info!("restoring NetworkManager configuration"); + let network_conf_dir = &base.join("etc/NetworkManager/system-connections/"); + let _ = fs::create_dir_all(&network_conf_dir); + + for &(ref connection, ref data) in networks { + create_network_conf(network_conf_dir, connection, data); } + } - Ok(()) - }) + Ok(()) } } diff --git a/src/installer/mod.rs b/src/installer/mod.rs index 1f730565..4bc4532e 100644 --- a/src/installer/mod.rs +++ b/src/installer/mod.rs @@ -14,7 +14,7 @@ use crate::auto::{ delete_old_install, move_root, recover_root, remove_root, validate_backup_conditions, AccountFiles, Backup, ReinstallError, }; -use disk_types::BlockDeviceExt; +use disk_types::{BlockDeviceExt, FileSystem}; use crate::disks::{Bootloader, Disks}; use crate::errors::IoContext; use crate::external::luks::deactivate_logical_devices; @@ -139,6 +139,7 @@ impl Installer { /// /// If `config.old_root` is set, then home at that location will be retained. pub fn install(&mut self, mut disks: Disks, config: &Config) -> io::Result<()> { + debug!("Installing to {:#?}", disks); let mut recovery_conf = if Path::new("/cdrom/recovery.conf").exists() { Some(RecoveryEnv::new()?) } else { @@ -148,12 +149,34 @@ impl Installer { disks.remove_untouched_disks(); let steps = &mut InstallerState::new(self); + // If a btrfs root is defined without subvolumes, switch it to using subvolumes. + let contains_home = disks.find_partition(Path::new("/home")).is_some(); + for partition in disks.get_partitions_mut() { + if let Some(FileSystem::Btrfs) = partition.filesystem { + if let Some(mount) = partition.target.as_deref() { + if Path::new("/") == mount { + partition.target = None; + partition.subvolumes.insert(Path::new("/").into(), "@root".into()); + + if !contains_home { + partition.subvolumes.insert(Path::new("/home").into(), "@home".into()); + } + + break + } + } + } + } + + debug!("AFTER {:#?}", disks); + Self::backup(disks, config, steps, |mut disks, config, steps| { if !hostname::is_valid(&config.hostname) { return Err(io::Error::new(io::ErrorKind::InvalidInput, "hostname is not valid")); } let bootloader = Bootloader::detect(); + debug!("BEFORE VERIFY: {:#?}", disks); disks .verify_partitions(bootloader) .with_context(|err| format!("partition validation: {}", err))?; @@ -232,8 +255,8 @@ impl Installer { /// Create a backup of key data on the system, execute the given functi on, and then restore /// that backup. If a backup is not requested for the configuration, then it will just /// execute the given function. - fn backup io::Result<()>>( - disks: Disks, + fn backup io::Result<()>>( + mut disks: Disks, config: &Config, steps: &mut InstallerState, mut func: F, @@ -241,6 +264,9 @@ impl Installer { let account_files; let mut old_backup = None; + let temp = Path::new("/tmp/distinst"); + let _ = std::fs::create_dir_all(temp); + let backup = if let Some(ref old_root_uuid) = config.old_root { info!("installing while retaining home"); @@ -248,11 +274,7 @@ impl Installer { .get_partition_by_id(&PartitionID::new_uuid(old_root_uuid.clone())) .ok_or(ReinstallError::NoRootPartition)?; - let new_root = disks - .get_partition_with_target(Path::new("/")) - .ok_or(ReinstallError::NoRootPartition)?; - - let (home, home_is_root) = disks + let (home, _) = disks .get_partition_with_target(Path::new("/home")) .map_or((old_root, true), |p| (p, false)); @@ -260,29 +282,26 @@ impl Installer { return Err(ReinstallError::ReformattingHome.into()); } - let home_path = home.get_device_path(); - let root_path = new_root.get_device_path().to_path_buf(); - let root_fs = new_root.filesystem.ok_or_else(|| ReinstallError::NoFilesystem)?; let old_root_path = old_root.get_device_path(); - let old_root_fs = old_root.filesystem.ok_or_else(|| ReinstallError::NoFilesystem)?; - let home_fs = home.filesystem.ok_or_else(|| ReinstallError::NoFilesystem)?; + let old_root_fs = old_root.filesystem.ok_or(ReinstallError::NoFilesystem)?; - account_files = AccountFiles::new(old_root_path, old_root_fs)?; + let _mounts = disks.mount_all_targets(&temp)?; + account_files = AccountFiles::new(temp)?; let backup = steps.apply(Step::Backup, "backing up", |steps| { let mut callback = percent!(steps); - let backup = Backup::new(home_path, home_fs, home_is_root, &account_files)?; + let backup = Backup::new(temp, &account_files)?; callback(25); validate_backup_conditions(&disks, &config.squashfs)?; callback(50); if config.flags & KEEP_OLD_ROOT != 0 { - move_root(old_root_path, old_root_fs)?; + move_root(temp)?; old_backup = Some((old_root_path.to_path_buf(), old_root_fs)); } else { - remove_root(old_root_path, old_root_fs)?; + remove_root(temp)?; } callback(100); @@ -290,28 +309,29 @@ impl Installer { Ok(backup) })?; - Some((backup, root_path, root_fs)) + Some(backup) } else { None }; // Do the destructive action of reinstalling the system. - if let Err(why) = func(disks, config, steps) { + if let Err(why) = func(&mut disks, config, steps) { error!("errored while installing system: {}", why); - if let Some((path, fs)) = old_backup { - recover_root(&path, fs)?; - } + let _mounts = disks.mount_all_targets(temp)?; + recover_root(temp)?; return Err(why); } // Then restore the backup, if it exists. - if let Some((backup, root_path, root_fs)) = backup { + + if let Some(backup) = backup { info!("applying backup"); - backup.restore(&root_path, root_fs)?; + let _mounts = disks.mount_all_targets(temp)?; + backup.restore(temp)?; - if let Err(why) = delete_old_install(&root_path, root_fs) { + if let Err(why) = delete_old_install(temp) { warn!("failed to delete old install: {}", why); } } diff --git a/src/installer/steps/configure/chroot_conf.rs b/src/installer/steps/configure/chroot_conf.rs index 31bcde19..a886e4f8 100644 --- a/src/installer/steps/configure/chroot_conf.rs +++ b/src/installer/steps/configure/chroot_conf.rs @@ -69,7 +69,7 @@ impl<'a> ChrootConfigurator<'a> { } /// Configure the bootloader on the system. - pub fn bootloader(&self) -> io::Result<()> { + pub fn bootloader(&self, options: Option<&str>) -> io::Result<()> { info!("configuring bootloader"); let result = self .chroot @@ -89,9 +89,28 @@ impl<'a> ChrootConfigurator<'a> { .run(); match result { - Ok(()) => Ok(()), + Ok(()) => { + if let Some(options) = options { + self.chroot.command("kernelstub", &["-a", options]).run()?; + } + + Ok(()) + }, // If kernelstub was not found, use grub instead. Err(ref e) if e.kind() == io::ErrorKind::NotFound => { + // Update the grub config to define the rootflags option. + if let Some(options) = options { + let path = self.chroot.path.join("etc/default/grub"); + + let mut config = std::fs::read_to_string(&path) + .with_context(|err| format!("failed to read grub config: {}", err))?; + + config = config.replace("GRUB_CMDLINE_LINUX=\"", &["GRUB_CMDLINE_LINUX=\"", options].concat()); + + std::fs::write(&path, config.as_bytes()) + .with_context(|err| format!("failed to update grub config: {}", err))?; + } + let args: &[&str] = &[]; self.chroot.command("update-grub", args).run() } @@ -289,10 +308,15 @@ impl<'a> ChrootConfigurator<'a> { /// Set the keyboard layout so that the layout will function, even within the decryption screen. pub fn keyboard_layout(&self, config: &Config) -> io::Result<()> { info!("configuring keyboard layout"); + // Ensure that localectl writes to the chroot, instead. + let source = self.chroot.path.join("etc"); + let _etc_mount = - Mount::new(&self.chroot.path.join("etc"), "/etc", "none", MountFlags::BIND, None)? - .into_unmount_drop(UnmountFlags::DETACH); + Mount::builder() + .flags(MountFlags::BIND) + .fstype("none") + .mount_autodrop(source, "/etc", UnmountFlags::DETACH)?; self.chroot .command( @@ -534,11 +558,4 @@ options {2} boot=casper hostname=recovery userfullname=Recovery username=recover let args: &[&str] = &[]; self.chroot.command("ln", args).arg(region.path()).arg("/etc/timezone").run() } - - pub fn update_initramfs(&self) -> io::Result<()> { - self.chroot - .command("update-initramfs", &["-u"]) - .run() - .with_context(|why| format!("failed to update initramfs: {}", why)) - } } diff --git a/src/installer/steps/configure/mod.rs b/src/installer/steps/configure/mod.rs index 38055e1d..714760db 100644 --- a/src/installer/steps/configure/mod.rs +++ b/src/installer/steps/configure/mod.rs @@ -306,7 +306,8 @@ pub fn configure, S: AsRef, F: FnMut(i3 callback(75); - chroot.bootloader().with_context(|why| format!("error installing bootloader: {}", why))?; + chroot.bootloader(disks.rootflags().as_deref()) + .with_context(|why| format!("error installing bootloader: {}", why))?; callback(80); diff --git a/src/installer/steps/mod.rs b/src/installer/steps/mod.rs index de738fd9..de6f79b7 100644 --- a/src/installer/steps/mod.rs +++ b/src/installer/steps/mod.rs @@ -46,10 +46,11 @@ pub fn mount_efivars(mount_dir: &Path) -> io::Result>> fn mount_bind_if_exists(source: &Path, target: &Path) -> io::Result>> { if source.exists() { let _ = fs::create_dir_all(&target); - Ok(Some( - Mount::new(source, &target, "none", MountFlags::BIND, None)? - .into_unmount_drop(UnmountFlags::empty()), - )) + let mount = Mount::builder() + .fstype("none") + .flags(MountFlags::BIND) + .mount_autodrop(source, target, UnmountFlags::empty())?; + Ok(Some(mount)) } else { Ok(None) } diff --git a/src/installer/traits.rs b/src/installer/traits.rs index ec3ef102..9ca0b7f1 100644 --- a/src/installer/traits.rs +++ b/src/installer/traits.rs @@ -22,6 +22,9 @@ pub trait InstallerDiskOps: Sync { /// Reports file systems that need to be supported in the install. fn get_support_flags(&self) -> FileSystemSupport; + + /// Gives a rootflags option if it's required by the installation + fn rootflags(&self) -> Option; } impl InstallerDiskOps for Disks { @@ -31,7 +34,7 @@ impl InstallerDiskOps for Disks { info!("generating /etc/crypttab & /etc/fstab in memory"); let mut crypttab = OsString::with_capacity(1024); - let mut fstab = OsString::with_capacity(1024); + let mut fstab = String::with_capacity(1024); let partitions = physical .iter() @@ -56,7 +59,7 @@ impl InstallerDiskOps for Disks { let mut crypt_ids: Vec = Vec::new(); for (is_unencrypted, luks_parent, partition) in partitions { - if let Some(&(_, Some(ref enc))) = partition.volume_group.as_ref() { + if let Some(enc) = partition.encryption.as_ref() { let password: Cow<'static, OsStr> = match (enc.password.is_some(), enc.keydata.as_ref()) { (true, None) => Cow::Borrowed(OsStr::new("none")), @@ -73,38 +76,77 @@ impl InstallerDiskOps for Disks { }; let ppath = partition.get_device_path(); - let luks_path = luks_parent.as_ref().map_or(ppath, |x| &x); - - for logical in logical { - if let Some(ref parent) = logical.luks_parent { - if parent == ppath { - if logical.partitions.iter().any(|p| p.target.is_some()) { - match PartitionID::get_uuid(luks_path) { - Some(uuid) => { - let id = hasher(&enc.physical_volume); - if !crypt_ids.contains(&id) { - crypt_ids.push(id); - - crypttab.push(&enc.physical_volume); - crypttab.push(" UUID="); - crypttab.push(&uuid.id); - crypttab.push(" "); - crypttab.push(&password); - crypttab.push(" luks\n"); + + if partition.lvm_vg.is_some() { + let luks_path = luks_parent.as_ref().map_or(ppath, |x| &x); + for logical in logical { + if let Some(ref parent) = logical.luks_parent { + if parent == ppath { + if logical.partitions.iter().any(|p| p.target.is_some()) { + match PartitionID::get_uuid(luks_path) { + Some(uuid) => { + let id = hasher(&enc.physical_volume); + if !crypt_ids.contains(&id) { + crypt_ids.push(id); + + crypttab.push(&enc.physical_volume); + crypttab.push(" UUID="); + crypttab.push(&uuid.id); + crypttab.push(" "); + crypttab.push(&password); + crypttab.push(" luks\n"); + } } + None => warn!( + "unable to find UUID for {} -- skipping", + ppath.display() + ), } - None => warn!( - "unable to find UUID for {} -- skipping", - ppath.display() - ), } + break; } - break; } } } - if let Some(blockinfo) = partition.get_block_info() { - blockinfo.write_entry(&mut fstab); + + if let Some(mut blockinfo) = partition.get_block_info() { + use std::path::Path; + + let child_id = PartitionID::get_uuid(&Path::new(&["/dev/mapper/", &enc.physical_volume].concat())); + let id = PartitionID::get_uuid(&partition.device_path); + + match id.zip(child_id) { + Some((uuid, child_uuid)) => { + crypttab.push(&enc.physical_volume); + crypttab.push(" UUID="); + crypttab.push(&uuid.id); + crypttab.push(" "); + crypttab.push(&password); + crypttab.push(" luks\n"); + + blockinfo.uid = child_uuid; + blockinfo.fs = enc.filesystem.into(); + + if enc.filesystem == FileSystem::Btrfs { + for (target, subvol) in &partition.subvolumes { + blockinfo.options = ["subvol=", &*subvol].concat().into(); + blockinfo.mount = Some(target.clone()); + blockinfo.write(&mut fstab); + } + + continue + } + } + None => { + warn!( + "unable to find UUID for {} -- skipping", + ppath.display() + ); + continue; + } + } + + blockinfo.write(&mut fstab); } } else if partition.is_swap() { if is_unencrypted { @@ -122,7 +164,7 @@ impl InstallerDiskOps for Disks { " /dev/urandom swap,plain,offset=1024,cipher=aes-xts-plain64,size=512\n", ); - fstab.push( + fstab.push_str( &["/dev/mapper/", &unique_id, " none swap defaults 0 0\n"] .concat(), ); @@ -133,47 +175,78 @@ impl InstallerDiskOps for Disks { ), } } else { - fstab.push(partition.get_device_path()); - fstab.push(" none swap defaults 0 0\n"); + let path = partition.get_device_path().to_str().expect("device with non-UTF8 path"); + fstab.push_str(path); + fstab.push_str(" none swap defaults 0 0\n"); + } + } else if let Some(mut blockinfo) = partition.get_block_info() { + if partition.filesystem == Some(FileSystem::Btrfs) { + for (target, subvol) in &partition.subvolumes { + blockinfo.options = ["subvol=", &*subvol].concat().into(); + blockinfo.mount = Some(target.clone()); + blockinfo.write(&mut fstab); + } + + continue } - } else if let Some(blockinfo) = partition.get_block_info() { - blockinfo.write_entry(&mut fstab); + + blockinfo.write(&mut fstab); } } info!("generated the following crypttab data:\n{}", crypttab.to_string_lossy(),); - info!("generated the following fstab data:\n{}", fstab.to_string_lossy()); + info!("generated the following fstab data:\n{}", fstab); crypttab.shrink_to_fit(); fstab.shrink_to_fit(); - (crypttab, fstab) + (crypttab, OsString::from(fstab)) } fn get_block_info_of(&self, path: &str) -> io::Result { - self.get_partitions() - .filter_map(|part| part.get_block_info()) - .find(|entry| entry.mount() == path) - .into_io_result(|| "root partition not found") + self.find_partition(path.as_ref()) + .and_then(|(_, part)| part.get_block_info()) + .into_io_result(|| format!("get_block_info_of: partition {} found", path)) + } fn get_support_flags(&self) -> FileSystemSupport { let mut flags = FileSystemSupport::empty(); - for partition in self.get_partitions() { - match partition.filesystem { - Some(Btrfs) => flags |= FileSystemSupport::BTRFS, - Some(Ext2) | Some(Ext3) | Some(Ext4) => flags |= FileSystemSupport::EXT4, - Some(F2fs) => flags |= FileSystemSupport::F2FS, - Some(Fat16) | Some(Fat32) => flags |= FileSystemSupport::FAT, - Some(Ntfs) => flags |= FileSystemSupport::NTFS, - Some(Xfs) => flags |= FileSystemSupport::XFS, - Some(Luks) => flags |= FileSystemSupport::LUKS, - Some(Lvm) => flags |= FileSystemSupport::LVM, - _ => continue, + let mut check = |fs| { + match fs { + Btrfs => flags |= FileSystemSupport::BTRFS, + Ext2 | Ext3 | Ext4 => flags |= FileSystemSupport::EXT4, + F2fs => flags |= FileSystemSupport::F2FS, + Fat16 | Fat32 => flags |= FileSystemSupport::FAT, + Ntfs => flags |= FileSystemSupport::NTFS, + Xfs => flags |= FileSystemSupport::XFS, + Luks => flags |= FileSystemSupport::LUKS, + Lvm => flags |= FileSystemSupport::LVM, + _ => (), }; + }; + + for partition in self.get_partitions() { + if let Some(fs) = partition.filesystem { + check(fs); + } + + if let Some(fs) = partition.encryption.as_ref().map(|e| e.filesystem) { + check(fs); + } } flags } + + fn rootflags(&self) -> Option { + let root = std::path::Path::new("/"); + self.find_partition(root) + .expect("no root partition") + .1 + .subvolumes + .get(root) + .map(|subvol| ["rootflags=subvol=", &*subvol].concat()) + } } diff --git a/src/lib.rs b/src/lib.rs index 697ffdc9..9321b74f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -178,7 +178,8 @@ fn mount_efi(efi_id: &str, target_dir: &Path) -> anyhow::Result