From cb707c3ce431891e189a7ebd071cc8d7ead450e5 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 6 Oct 2024 13:02:16 +0200 Subject: [PATCH 1/4] Update edition and rustfmt. --- Cargo.toml | 1 + src/bin/installer_tui.rs | 225 +++++++++++++++----------- src/config/file.rs | 18 +-- src/config/general.rs | 2 +- src/config/package.rs | 2 +- src/disk_wrapper.rs | 36 ++--- src/lib.rs | 337 +++++++++++++++++++++++---------------- 7 files changed, 360 insertions(+), 261 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8f7f9c4b02..00f8749401 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ license = "MIT" authors = ["Jeremy Soller "] repository = "https://gitlab.redox-os.org/redox-os/installer" default-run = "redox_installer" +edition = "2018" [[bin]] name = "redox_installer" diff --git a/src/bin/installer_tui.rs b/src/bin/installer_tui.rs index 99efbad390..4976003867 100644 --- a/src/bin/installer_tui.rs +++ b/src/bin/installer_tui.rs @@ -1,5 +1,6 @@ extern crate arg_parser; -#[macro_use] extern crate failure; +#[macro_use] +extern crate failure; extern crate pkgar; extern crate pkgar_core; extern crate pkgar_keys; @@ -8,17 +9,17 @@ extern crate serde; extern crate termion; extern crate toml; -use pkgar::{PackageHead, ext::EntryExt}; +use pkgar::{ext::EntryExt, PackageHead}; use pkgar_core::PackageSrc; use pkgar_keys::PublicKeyFile; -use redox_installer::{Config, with_whole_disk, DiskOption}; +use redox_installer::{with_whole_disk, Config, DiskOption}; use std::{ ffi::OsStr, fs, io::{self, Read, Write}, - os::unix::fs::{MetadataExt, OpenOptionsExt, symlink}, + os::unix::fs::{symlink, MetadataExt, OpenOptionsExt}, path::Path, - process + process, }; use termion::input::TermRead; @@ -29,52 +30,54 @@ fn disk_paths(_paths: &mut Vec<(String, u64)>) {} fn disk_paths(paths: &mut Vec<(String, u64)>) { let mut schemes = Vec::new(); match fs::read_dir("/scheme") { - Ok(entries) => for entry_res in entries { - if let Ok(entry) = entry_res { - let path = entry.path(); - if let Ok(path_str) = path.into_os_string().into_string() { - let scheme = path_str.trim_start_matches(':').trim_matches('/'); - if scheme.starts_with("disk") { - if scheme == "disk/live" { - // Skip live disks - continue; - } + Ok(entries) => { + for entry_res in entries { + if let Ok(entry) = entry_res { + let path = entry.path(); + if let Ok(path_str) = path.into_os_string().into_string() { + let scheme = path_str.trim_start_matches(':').trim_matches('/'); + if scheme.starts_with("disk") { + if scheme == "disk/live" { + // Skip live disks + continue; + } - schemes.push(format!("{}:", scheme)); + schemes.push(format!("{}:", scheme)); + } } } } - }, + } Err(err) => { eprintln!("installer_tui: failed to list schemes: {}", err); } } for scheme in schemes { - let is_dir = fs::metadata(&scheme) - .map(|x| x.is_dir()) - .unwrap_or(false); + let is_dir = fs::metadata(&scheme).map(|x| x.is_dir()).unwrap_or(false); if is_dir { match fs::read_dir(&scheme) { - Ok(entries) => for entry_res in entries { - if let Ok(entry) = entry_res { - if let Ok(file_name) = entry.file_name().into_string() { - if file_name.contains('p') { - // Skip partitions - continue; - } + Ok(entries) => { + for entry_res in entries { + if let Ok(entry) = entry_res { + if let Ok(file_name) = entry.file_name().into_string() { + if file_name.contains('p') { + // Skip partitions + continue; + } - if let Ok(path) = entry.path().into_os_string().into_string() { - if let Ok(metadata) = entry.metadata() { - let size = metadata.len(); - if size > 0 { - paths.push((path, size)); + if let Ok(path) = entry.path().into_os_string().into_string() { + if let Ok(metadata) = entry.metadata() { + let size = metadata.len(); + if size > 0 { + paths.push((path, size)); + } } } } } } - }, + } Err(err) => { eprintln!("installer_tui: failed to list '{}': {}", scheme, err); } @@ -105,11 +108,15 @@ fn format_size(size: u64) -> String { fn copy_file(src: &Path, dest: &Path, buf: &mut [u8]) -> Result<(), failure::Error> { if let Some(parent) = dest.parent() { // Parent may be a symlink - if ! parent.is_symlink() { + if !parent.is_symlink() { match fs::create_dir_all(&parent) { Ok(()) => (), Err(err) => { - return Err(format_err!("failed to create directory {}: {}", parent.display(), err)); + return Err(format_err!( + "failed to create directory {}: {}", + parent.display(), + err + )); } } } @@ -118,36 +125,63 @@ fn copy_file(src: &Path, dest: &Path, buf: &mut [u8]) -> Result<(), failure::Err let metadata = match fs::symlink_metadata(&src) { Ok(ok) => ok, Err(err) => { - return Err(format_err!("failed to read metadata of {}: {}", src.display(), err)); - }, + return Err(format_err!( + "failed to read metadata of {}: {}", + src.display(), + err + )); + } }; if metadata.file_type().is_symlink() { let real_src = match fs::read_link(&src) { Ok(ok) => ok, Err(err) => { - return Err(format_err!("failed to read link {}: {}", src.display(), err)); + return Err(format_err!( + "failed to read link {}: {}", + src.display(), + err + )); } }; match symlink(&real_src, &dest) { Ok(()) => (), Err(err) => { - return Err(format_err!("failed to copy link {} ({}) to {}: {}", src.display(), real_src.display(), dest.display(), err)); - }, + return Err(format_err!( + "failed to copy link {} ({}) to {}: {}", + src.display(), + real_src.display(), + dest.display(), + err + )); + } } } else { let mut src_file = match fs::File::open(&src) { Ok(ok) => ok, Err(err) => { - return Err(format_err!("failed to open file {}: {}", src.display(), err)); + return Err(format_err!( + "failed to open file {}: {}", + src.display(), + err + )); } }; - let mut dest_file = match fs::OpenOptions::new().write(true).create_new(true).mode(metadata.mode()).open(&dest) { + let mut dest_file = match fs::OpenOptions::new() + .write(true) + .create_new(true) + .mode(metadata.mode()) + .open(&dest) + { Ok(ok) => ok, Err(err) => { - return Err(format_err!("failed to create file {}: {}", dest.display(), err)); + return Err(format_err!( + "failed to create file {}: {}", + dest.display(), + err + )); } }; @@ -155,7 +189,11 @@ fn copy_file(src: &Path, dest: &Path, buf: &mut [u8]) -> Result<(), failure::Err let count = match src_file.read(buf) { Ok(ok) => ok, Err(err) => { - return Err(format_err!("failed to read file {}: {}", src.display(), err)); + return Err(format_err!( + "failed to read file {}: {}", + src.display(), + err + )); } }; @@ -166,7 +204,11 @@ fn copy_file(src: &Path, dest: &Path, buf: &mut [u8]) -> Result<(), failure::Err match dest_file.write_all(&buf[..count]) { Ok(()) => (), Err(err) => { - return Err(format_err!("failed to write file {}: {}", dest.display(), err)); + return Err(format_err!( + "failed to write file {}: {}", + dest.display(), + err + )); } } } @@ -175,7 +217,11 @@ fn copy_file(src: &Path, dest: &Path, buf: &mut [u8]) -> Result<(), failure::Err Ok(()) } -fn package_files(root_path: &Path, config: &mut Config, files: &mut Vec) -> Result<(), pkgar::Error> { +fn package_files( + root_path: &Path, + config: &mut Config, + files: &mut Vec, +) -> Result<(), pkgar::Error> { //TODO: Remove packages from config where all files are located (and have valid shasum?) config.packages.clear(); @@ -189,18 +235,15 @@ fn package_files(root_path: &Path, config: &mut Config, files: &mut Vec) if pkg_path.extension() == Some(OsStr::new("pkgar_head")) { let mut pkg = PackageHead::new(&pkg_path, &root_path, &pkey)?; for entry in pkg.read_entries()? { - files.push( - entry - .check_path()? - .to_str().unwrap() - .to_string() - ); + files.push(entry.check_path()?.to_str().unwrap().to_string()); } files.push( pkg_path - .strip_prefix(root_path).unwrap() - .to_str().unwrap() - .to_string() + .strip_prefix(root_path) + .unwrap() + .to_str() + .unwrap() + .to_string(), ); } } @@ -227,7 +270,7 @@ fn choose_disk() -> String { Ok(0) => { eprintln!("installer_tui: failed to read line: end of input"); process::exit(1); - }, + } Ok(_) => (), Err(err) => { eprintln!("installer_tui: failed to read line: {}", err); @@ -242,7 +285,7 @@ fn choose_disk() -> String { } else { eprintln!("{} not from 1 to {}", i, paths.len()); } - }, + } Err(err) => { eprintln!("invalid input: {}", err); } @@ -262,7 +305,7 @@ fn choose_password() -> Option { eprintln!(); if password.is_empty() { - return None; + return None; } Some(password) @@ -311,53 +354,51 @@ fn main() { password_opt: password_opt.as_ref().map(|x| x.as_bytes()), efi_partition_size: None, }; - let res = with_whole_disk(&disk_path, &disk_option, |mount_path| -> Result<(), failure::Error> { - let mut config: Config = Config::from_file(&root_path.join("filesystem.toml"))?; + let res = with_whole_disk( + &disk_path, + &disk_option, + |mount_path| -> Result<(), failure::Error> { + let mut config: Config = Config::from_file(&root_path.join("filesystem.toml"))?; - // Copy filesystem.toml, which is not packaged - let mut files = vec![ - "filesystem.toml".to_string(), - ]; + // Copy filesystem.toml, which is not packaged + let mut files = vec!["filesystem.toml".to_string()]; - // Copy files from locally installed packages - if let Err(err) = package_files(&root_path, &mut config, &mut files) { - return Err(format_err!("failed to read package files: {}", err)); - } + // Copy files from locally installed packages + if let Err(err) = package_files(&root_path, &mut config, &mut files) { + return Err(format_err!("failed to read package files: {}", err)); + } - // Perform config install (after packages have been converted to files) - eprintln!("configuring system"); - let cookbook: Option<&'static str> = None; - redox_installer::install_dir(config, mount_path, cookbook).map_err(|err| { - io::Error::new( - io::ErrorKind::Other, - err - ) - })?; + // Perform config install (after packages have been converted to files) + eprintln!("configuring system"); + let cookbook: Option<&'static str> = None; + redox_installer::install_dir(config, mount_path, cookbook) + .map_err(|err| io::Error::new(io::ErrorKind::Other, err))?; - // Sort and remove duplicates - files.sort(); - files.dedup(); + // Sort and remove duplicates + files.sort(); + files.dedup(); - // Install files - let mut buf = vec![0; 4 * MIB as usize]; - for (i, name) in files.iter().enumerate() { - eprintln!("copy {} [{}/{}]", name, i, files.len()); + // Install files + let mut buf = vec![0; 4 * MIB as usize]; + for (i, name) in files.iter().enumerate() { + eprintln!("copy {} [{}/{}]", name, i, files.len()); - let src = root_path.join(name); - let dest = mount_path.join(name); - copy_file(&src, &dest, &mut buf)?; - } + let src = root_path.join(name); + let dest = mount_path.join(name); + copy_file(&src, &dest, &mut buf)?; + } - eprintln!("finished installing, unmounting filesystem"); + eprintln!("finished installing, unmounting filesystem"); - Ok(()) - }); + Ok(()) + }, + ); match res { Ok(()) => { eprintln!("installer_tui: installed successfully"); process::exit(0); - }, + } Err(err) => { eprintln!("installer_tui: failed to install: {}", err); process::exit(1); diff --git a/src/config/file.rs b/src/config/file.rs index 7672f908d5..d56758bcba 100644 --- a/src/config/file.rs +++ b/src/config/file.rs @@ -1,12 +1,11 @@ - -use Result; +use crate::Result; use libc::{gid_t, uid_t}; -use std::io::{Error, Write}; use std::ffi::{CString, OsStr}; use std::fs::{self, File}; +use std::io::{Error, Write}; use std::os::unix::ffi::OsStrExt; -use std::os::unix::fs::{PermissionsExt, symlink}; +use std::os::unix::fs::{symlink, PermissionsExt}; use std::path::Path; //type Result = std::result::Result; @@ -48,8 +47,7 @@ pub struct FileConfig { impl FileConfig { pub(crate) fn create>(&self, prefix: P) -> Result<()> { let path = self.path.trim_start_matches('/'); - let target_file = prefix.as_ref() - .join(path); + let target_file = prefix.as_ref().join(path); if self.directory { println!("Create directory {}", target_file.display()); @@ -76,11 +74,9 @@ impl FileConfig { fn apply_perms>(&self, target: P) -> Result<()> { let path = target.as_ref(); - let mode = self.mode.unwrap_or_else(|| if self.directory { - 0o0755 - } else { - 0o0644 - }); + let mode = self + .mode + .unwrap_or_else(|| if self.directory { 0o0755 } else { 0o0644 }); let uid = self.uid.unwrap_or(!0); let gid = self.gid.unwrap_or(!0); diff --git a/src/config/general.rs b/src/config/general.rs index 3e26d3772e..c50d48fadb 100644 --- a/src/config/general.rs +++ b/src/config/general.rs @@ -3,7 +3,7 @@ pub struct GeneralConfig { pub prompt: Option, // Allow config to specify cookbook recipe or binary package as default pub repo_binary: Option, - pub filesystem_size: Option, //MiB + pub filesystem_size: Option, //MiB pub efi_partition_size: Option, //MiB } diff --git a/src/config/package.rs b/src/config/package.rs index 5f37196fe5..bbbfdc57ce 100644 --- a/src/config/package.rs +++ b/src/config/package.rs @@ -7,7 +7,7 @@ pub enum PackageConfig { version: Option, git: Option, path: Option, - } + }, } impl Default for PackageConfig { diff --git a/src/disk_wrapper.rs b/src/disk_wrapper.rs index 5697e07a0c..dd5a70b826 100644 --- a/src/disk_wrapper.rs +++ b/src/disk_wrapper.rs @@ -21,10 +21,7 @@ enum Buffer<'a> { impl DiskWrapper { pub fn open>(path: P) -> Result { - let disk = OpenOptions::new() - .read(true) - .write(true) - .open(path)?; + let disk = OpenOptions::new().read(true).write(true).open(path)?; let metadata = disk.metadata()?; let size = metadata.len(); // TODO: get real block size: disk_metadata.blksize() works on disks but not image files @@ -71,24 +68,27 @@ impl DiskWrapper { let remaining = buf_len.checked_sub(i).unwrap(); let len = cmp::min( remaining, - self.block.len().checked_sub(offset.try_into().unwrap()).unwrap() + self.block + .len() + .checked_sub(offset.try_into().unwrap()) + .unwrap(), ); - self.disk.seek(SeekFrom::Start(block.checked_mul(block_len).unwrap()))?; + self.disk + .seek(SeekFrom::Start(block.checked_mul(block_len).unwrap()))?; self.disk.read_exact(&mut self.block)?; match buf { Buffer::Read(read) => { - read[i..i.checked_add(len).unwrap()].copy_from_slice( - &self.block[offset..offset.checked_add(len).unwrap()] - ); - }, + read[i..i.checked_add(len).unwrap()] + .copy_from_slice(&self.block[offset..offset.checked_add(len).unwrap()]); + } Buffer::Write(write) => { - self.block[offset..offset.checked_add(len).unwrap()].copy_from_slice( - &write[i..i.checked_add(len).unwrap()] - ); + self.block[offset..offset.checked_add(len).unwrap()] + .copy_from_slice(&write[i..i.checked_add(len).unwrap()]); - self.disk.seek(SeekFrom::Start(block.checked_mul(block_len).unwrap()))?; + self.disk + .seek(SeekFrom::Start(block.checked_mul(block_len).unwrap()))?; self.disk.write_all(&mut self.block)?; } } @@ -112,12 +112,8 @@ impl Seek for DiskWrapper { let current: i64 = self.seek.try_into().unwrap(); let end: i64 = self.size.try_into().unwrap(); self.seek = match pos { - SeekFrom::Start(offset) => { - cmp::min(self.size, offset) - }, - SeekFrom::End(offset) => { - cmp::max(0, cmp::min(end, end.wrapping_add(offset))) as u64 - }, + SeekFrom::Start(offset) => cmp::min(self.size, offset), + SeekFrom::End(offset) => cmp::max(0, cmp::min(end, end.wrapping_add(offset))) as u64, SeekFrom::Current(offset) => { cmp::max(0, cmp::min(end, current.wrapping_add(offset))) as u64 } diff --git a/src/lib.rs b/src/lib.rs index 86f730405c..161c750431 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,27 +14,26 @@ extern crate termion; mod config; mod disk_wrapper; -pub use config::Config; -pub use config::file::FileConfig; -pub use config::package::PackageConfig; -use disk_wrapper::DiskWrapper; +pub use crate::config::file::FileConfig; +pub use crate::config::package::PackageConfig; +pub use crate::config::Config; +use crate::disk_wrapper::DiskWrapper; -use failure::{Error, err_msg}; -use rand::{RngCore, rngs::OsRng}; +use failure::{err_msg, Error}; +use pkgutils::{Package, Repo}; +use rand::{rngs::OsRng, RngCore}; use redoxfs::{unmount_path, Disk, DiskIo, FileSystem}; use termion::input::TermRead; -use pkgutils::{Repo, Package}; use std::{ collections::BTreeMap, - env, - fs, + env, fs, io::{self, Seek, SeekFrom, Write}, path::Path, process, sync::mpsc::channel, - time::{SystemTime, UNIX_EPOCH}, thread, + time::{SystemTime, UNIX_EPOCH}, }; pub(crate) type Result = std::result::Result; @@ -50,10 +49,7 @@ const REMOTE: &'static str = "https://static.redox-os.org/pkg"; fn get_target() -> String { env::var("TARGET").unwrap_or( - option_env!("TARGET").map_or( - "x86_64-unknown-redox".to_string(), - |x| x.to_string() - ) + option_env!("TARGET").map_or("x86_64-unknown-redox".to_string(), |x| x.to_string()), ) } @@ -104,37 +100,54 @@ fn install_packages>(config: &Config, dest: &str, cookbook: Option if let Some(cookbook) = cookbook { let dest_pkg = format!("{}/pkg", dest); - if ! Path::new(&dest_pkg).exists() { + if !Path::new(&dest_pkg).exists() { fs::create_dir(&dest_pkg).unwrap(); } for (packagename, package) in &config.packages { - let pkgar_path = format!("{}/{}/repo/{}/{}.pkgar", - env::current_dir().unwrap().to_string_lossy(), - cookbook.as_ref(), target, packagename); + let pkgar_path = format!( + "{}/{}/repo/{}/{}.pkgar", + env::current_dir().unwrap().to_string_lossy(), + cookbook.as_ref(), + target, + packagename + ); let from_remote = match (config.general.repo_binary, package) { (Some(true), PackageConfig::Empty) => true, - (Some(true), PackageConfig::Spec { version: None, git: None, path: None }) => true, + ( + Some(true), + PackageConfig::Spec { + version: None, + git: None, + path: None, + }, + ) => true, (_, PackageConfig::Build(rule)) if rule == "binary" => true, - _ => false + _ => false, }; if from_remote { println!("Installing package from remote: {}", packagename); repo.fetch(&packagename).unwrap().install(dest).unwrap(); } else if Path::new(&pkgar_path).exists() { println!("Installing package from local repo: {}", packagename); - let public_path = format!("{}/{}/build/id_ed25519.pub.toml", - env::current_dir().unwrap().to_string_lossy(), - cookbook.as_ref()); + let public_path = format!( + "{}/{}/build/id_ed25519.pub.toml", + env::current_dir().unwrap().to_string_lossy(), + cookbook.as_ref() + ); pkgar::extract(&public_path, &pkgar_path, dest).unwrap(); let head_path = format!("{}/{}.pkgar_head", dest_pkg, packagename); pkgar::split(&public_path, &pkgar_path, &head_path, Option::<&str>::None).unwrap(); } else { println!("Installing package tar.gz from local repo: {}", packagename); - let path = format!("{}/{}/repo/{}/{}.tar.gz", - env::current_dir().unwrap().to_string_lossy(), - cookbook.as_ref(), target, packagename); + let path = format!( + "{}/{}/repo/{}/{}.tar.gz", + env::current_dir().unwrap().to_string_lossy(), + cookbook.as_ref(), + target, + packagename + ); Package::from_path(&path).unwrap().install(dest).unwrap(); } } @@ -146,26 +159,32 @@ fn install_packages>(config: &Config, dest: &str, cookbook: Option } } -pub fn install_dir, S: AsRef>(config: Config, output_dir: P, cookbook: Option) -> Result<()> { +pub fn install_dir, S: AsRef>( + config: Config, + output_dir: P, + cookbook: Option, +) -> Result<()> { //let mut context = liner::Context::new(); macro_rules! prompt { - ($dst:expr, $def:expr, $($arg:tt)*) => (if config.general.prompt.unwrap_or(true) { - Err(io::Error::new( - io::ErrorKind::Other, - "prompt not currently supported" - )) - // match unwrap_or_prompt($dst, &mut context, &format!($($arg)*)) { - // Ok(res) => if res.is_empty() { - // Ok($def) - // } else { - // Ok(res) - // }, - // Err(err) => Err(err) - // } - } else { - Ok($dst.unwrap_or($def)) - }) + ($dst:expr, $def:expr, $($arg:tt)*) => { + if config.general.prompt.unwrap_or(true) { + Err(io::Error::new( + io::ErrorKind::Other, + "prompt not currently supported", + )) + // match unwrap_or_prompt($dst, &mut context, &format!($($arg)*)) { + // Ok(res) => if res.is_empty() { + // Ok($def) + // } else { + // Ok(res) + // }, + // Err(err) => Err(err) + // } + } else { + Ok($dst.unwrap_or($def)) + } + }; } let output_dir = output_dir.as_ref(); @@ -192,7 +211,8 @@ pub fn install_dir, S: AsRef>(config: Config, output_dir: P, } else if config.general.prompt.unwrap_or(true) { prompt_password( &format!("{}: enter password: ", username), - &format!("{}: confirm password: ", username))? + &format!("{}: confirm password: ", username), + )? } else { String::new() }; @@ -209,9 +229,26 @@ pub fn install_dir, S: AsRef>(config: Config, output_dir: P, next_gid = gid + 1; } - let name = prompt!(user.name, username.clone(), "{}: name (GECOS) [{}]: ", username, username)?; - let home = prompt!(user.home, format!("/home/{}", username), "{}: home [/home/{}]: ", username, username)?; - let shell = prompt!(user.shell, "/bin/ion".to_string(), "{}: shell [/bin/ion]: ", username)?; + let name = prompt!( + user.name, + username.clone(), + "{}: name (GECOS) [{}]: ", + username, + username + )?; + let home = prompt!( + user.home, + format!("/home/{}", username), + "{}: home [/home/{}]: ", + username, + username + )?; + let shell = prompt!( + user.shell, + "/bin/ion".to_string(), + "{}: shell [/bin/ion]: ", + username + )?; println!("Adding user {}:", username); println!("\tPassword: {}", password); @@ -230,7 +267,8 @@ pub fn install_dir, S: AsRef>(config: Config, output_dir: P, uid: Some(uid), gid: Some(gid), recursive_chown: true, - }.create(&output_dir)?; + } + .create(&output_dir)?; if uid >= 1000 { // Create XDG user dirs @@ -259,7 +297,8 @@ pub fn install_dir, S: AsRef>(config: Config, output_dir: P, uid: Some(uid), gid: Some(gid), recursive_chown: false, - }.create(&output_dir)?; + } + .create(&output_dir)?; } FileConfig { path: format!("{}/.config/user-dirs.dirs", home), @@ -272,19 +311,24 @@ XDG_PICTURES_DIR="$HOME/Pictures" XDG_PUBLICSHARE_DIR="$HOME/Public" XDG_TEMPLATES_DIR="$HOME/Templates" XDG_VIDEOS_DIR="$HOME/Videos" -"#.to_string(), +"# + .to_string(), symlink: false, directory: false, mode: Some(0o0600), uid: Some(uid), gid: Some(gid), recursive_chown: false, - }.create(&output_dir)?; + } + .create(&output_dir)?; } let password = hash_password(&password)?; - passwd.push_str(&format!("{};{};{};{};{};{}\n", username, uid, gid, name, home, shell)); + passwd.push_str(&format!( + "{};{};{};{};{};{}\n", + username, uid, gid, name, home, shell + )); shadow.push_str(&format!("{};{}\n", username, password)); groups.push((username.clone(), gid, vec![username])); } @@ -312,7 +356,8 @@ XDG_VIDEOS_DIR="$HOME/Videos" uid: None, gid: None, recursive_chown: false, - }.create(&output_dir)?; + } + .create(&output_dir)?; } if !shadow.is_empty() { @@ -325,7 +370,8 @@ XDG_VIDEOS_DIR="$HOME/Videos" uid: Some(0), gid: Some(0), recursive_chown: false, - }.create(&output_dir)?; + } + .create(&output_dir)?; } if !groups.is_empty() { @@ -350,16 +396,17 @@ XDG_VIDEOS_DIR="$HOME/Videos" uid: None, gid: None, recursive_chown: false, - }.create(&output_dir)?; + } + .create(&output_dir)?; } Ok(()) } -pub fn with_redoxfs(disk: D, password_opt: Option<&[u8]>, callback: F) - -> Result where - D: Disk + Send + 'static, - F: FnOnce(&Path) -> Result +pub fn with_redoxfs(disk: D, password_opt: Option<&[u8]>, callback: F) -> Result +where + D: Disk + Send + 'static, + F: FnOnce(&Path) -> Result, { let mount_path = if cfg!(target_os = "redox") { format!("file.redox_installer_{}", process::id()) @@ -368,35 +415,27 @@ pub fn with_redoxfs(disk: D, password_opt: Option<&[u8]>, callback: F) }; if cfg!(not(target_os = "redox")) { - if ! Path::new(&mount_path).exists() { + if !Path::new(&mount_path).exists() { fs::create_dir(&mount_path)?; } } let ctime = SystemTime::now().duration_since(UNIX_EPOCH)?; - let fs = FileSystem::create( - disk, - password_opt, - ctime.as_secs(), - ctime.subsec_nanos() - ).map_err(syscall_error)?; + let fs = FileSystem::create(disk, password_opt, ctime.as_secs(), ctime.subsec_nanos()) + .map_err(syscall_error)?; let (tx, rx) = channel(); let join_handle = { let mount_path = mount_path.clone(); thread::spawn(move || { - let res = redoxfs::mount( - fs, - &mount_path, - |real_path| { - tx.send(Ok(real_path.to_owned())).unwrap(); - } - ); + let res = redoxfs::mount(fs, &mount_path, |real_path| { + tx.send(Ok(real_path.to_owned())).unwrap(); + }); match res { Ok(()) => (), Err(err) => { tx.send(Err(err)).unwrap(); - }, + } }; }) }; @@ -406,10 +445,13 @@ pub fn with_redoxfs(disk: D, password_opt: Option<&[u8]>, callback: F) Ok(real_path) => callback(&real_path), Err(err) => return Err(err.into()), }, - Err(_) => return Err(io::Error::new( - io::ErrorKind::NotConnected, - "redoxfs thread did not send a result" - ).into()), + Err(_) => { + return Err(io::Error::new( + io::ErrorKind::NotConnected, + "redoxfs thread did not send a result", + ) + .into()) + } }; unmount_path(&mount_path)?; @@ -423,7 +465,11 @@ pub fn with_redoxfs(disk: D, password_opt: Option<&[u8]>, callback: F) res } -pub fn fetch_bootloaders>(config: &Config, cookbook: Option, live: bool) -> Result<(Vec, Vec)> { +pub fn fetch_bootloaders>( + config: &Config, + cookbook: Option, + live: bool, +) -> Result<(Vec, Vec)> { let bootloader_dir = format!("/tmp/redox_installer_bootloader_{}", process::id()); if Path::new(&bootloader_dir).exists() { @@ -434,7 +480,9 @@ pub fn fetch_bootloaders>(config: &Config, cookbook: Option, li let mut bootloader_config = Config::default(); bootloader_config.general = config.general.clone(); - bootloader_config.packages.insert("bootloader".to_string(), PackageConfig::default()); + bootloader_config + .packages + .insert("bootloader".to_string(), PackageConfig::default()); install_packages(&bootloader_config, &bootloader_dir, cookbook.as_ref()); let boot_dir = Path::new(&bootloader_dir).join("boot"); @@ -466,10 +514,10 @@ pub fn fetch_bootloaders>(config: &Config, cookbook: Option, li } //TODO: make bootloaders use Option, dynamically create BIOS and EFI partitions -pub fn with_whole_disk(disk_path: P, disk_option: &DiskOption, callback: F) - -> Result where - P: AsRef, - F: FnOnce(&Path) -> Result +pub fn with_whole_disk(disk_path: P, disk_option: &DiskOption, callback: F) -> Result +where + P: AsRef, + F: FnOnce(&Path) -> Result, { let target = get_target(); @@ -495,7 +543,6 @@ pub fn with_whole_disk(disk_path: P, disk_option: &DiskOption, callback } }; - // Calculate partition offsets let gpt_reserved = 34 * 512; // GPT always reserves 34 512-byte sectors let mibi = 1024 * 1024; @@ -506,7 +553,11 @@ pub fn with_whole_disk(disk_path: P, disk_option: &DiskOption, callback // Second megabyte of the disk is reserved for EFI partition let efi_start = bios_end + 1; - let efi_size = if let Some(size) = disk_option.efi_partition_size { size as u64 } else { 1 }; + let efi_size = if let Some(size) = disk_option.efi_partition_size { + size as u64 + } else { + 1 + }; let efi_end = efi_start + (efi_size * mibi / block_size) - 1; // The rest of the disk is RedoxFS, reserving the GPT table mirror at the end of disk @@ -516,7 +567,10 @@ pub fn with_whole_disk(disk_path: P, disk_option: &DiskOption, callback // Format and install BIOS partition { // Write BIOS bootloader to disk - eprintln!("Write bootloader with size {:#x}", disk_option.bootloader_bios.len()); + eprintln!( + "Write bootloader with size {:#x}", + disk_option.bootloader_bios.len() + ); disk_file.seek(SeekFrom::Start(0))?; disk_file.write_all(&disk_option.bootloader_bios)?; @@ -536,37 +590,46 @@ pub fn with_whole_disk(disk_path: P, disk_option: &DiskOption, callback // Add BIOS boot partition let mut partitions = BTreeMap::new(); let mut partition_id = 1; - partitions.insert(partition_id, gpt::partition::Partition { - part_type_guid: gpt::partition_types::BIOS, - part_guid: uuid::Uuid::new_v4(), - first_lba: bios_start, - last_lba: bios_end, - flags: 0, // TODO - name: "BIOS".to_string(), - }); + partitions.insert( + partition_id, + gpt::partition::Partition { + part_type_guid: gpt::partition_types::BIOS, + part_guid: uuid::Uuid::new_v4(), + first_lba: bios_start, + last_lba: bios_end, + flags: 0, // TODO + name: "BIOS".to_string(), + }, + ); partition_id += 1; // Add EFI boot partition - partitions.insert(partition_id, gpt::partition::Partition { - part_type_guid: gpt::partition_types::EFI, - part_guid: uuid::Uuid::new_v4(), - first_lba: efi_start, - last_lba: efi_end, - flags: 0, // TODO - name: "EFI".to_string(), - }); + partitions.insert( + partition_id, + gpt::partition::Partition { + part_type_guid: gpt::partition_types::EFI, + part_guid: uuid::Uuid::new_v4(), + first_lba: efi_start, + last_lba: efi_end, + flags: 0, // TODO + name: "EFI".to_string(), + }, + ); partition_id += 1; // Add RedoxFS partition - partitions.insert(partition_id, gpt::partition::Partition { - //TODO: Use REDOX_REDOXFS type (needs GPT crate changes) - part_type_guid: gpt::partition_types::LINUX_FS, - part_guid: uuid::Uuid::new_v4(), - first_lba: redoxfs_start, - last_lba: redoxfs_end, - flags: 0, - name: "REDOX".to_string(), - }); + partitions.insert( + partition_id, + gpt::partition::Partition { + //TODO: Use REDOX_REDOXFS type (needs GPT crate changes) + part_type_guid: gpt::partition_types::LINUX_FS, + part_guid: uuid::Uuid::new_v4(), + first_lba: redoxfs_start, + last_lba: redoxfs_end, + flags: 0, + name: "REDOX".to_string(), + }, + ); eprintln!("Writing GPT tables: {:#?}", partitions); @@ -581,13 +644,13 @@ pub fn with_whole_disk(disk_path: P, disk_option: &DiskOption, callback { let disk_efi_start = efi_start * block_size; let disk_efi_end = (efi_end + 1) * block_size; - let mut disk_efi = fscommon::StreamSlice::new( - &mut disk_file, - disk_efi_start, - disk_efi_end, - )?; + let mut disk_efi = + fscommon::StreamSlice::new(&mut disk_file, disk_efi_start, disk_efi_end)?; - eprintln!("Formatting EFI partition with size {:#x}", disk_efi_end - disk_efi_start); + eprintln!( + "Formatting EFI partition with size {:#x}", + disk_efi_end - disk_efi_start + ); fatfs::format_volume(&mut disk_efi, fatfs::FormatVolumeOptions::new())?; eprintln!("Opening EFI partition"); @@ -601,7 +664,11 @@ pub fn with_whole_disk(disk_path: P, disk_option: &DiskOption, callback let efi_dir = root_dir.open_dir("EFI")?; efi_dir.create_dir("BOOT")?; - eprintln!("Writing EFI/BOOT/{} file with size {:#x}", bootloader_efi_name, disk_option.bootloader_efi.len()); + eprintln!( + "Writing EFI/BOOT/{} file with size {:#x}", + bootloader_efi_name, + disk_option.bootloader_efi.len() + ); let boot_dir = efi_dir.open_dir("BOOT")?; let mut file = boot_dir.create_file(bootloader_efi_name)?; file.truncate()?; @@ -609,40 +676,38 @@ pub fn with_whole_disk(disk_path: P, disk_option: &DiskOption, callback } // Format and install RedoxFS partition - eprintln!("Installing to RedoxFS partition with size {:#x}", (redoxfs_end - redoxfs_start) * block_size); + eprintln!( + "Installing to RedoxFS partition with size {:#x}", + (redoxfs_end - redoxfs_start) * block_size + ); let disk_redoxfs = DiskIo(fscommon::StreamSlice::new( disk_file, redoxfs_start * block_size, - (redoxfs_end + 1) * block_size + (redoxfs_end + 1) * block_size, )?); - with_redoxfs( - disk_redoxfs, - disk_option.password_opt, - callback - ) + with_redoxfs(disk_redoxfs, disk_option.password_opt, callback) } -pub fn install(config: Config, output: P, cookbook: Option, live: bool) - -> Result<()> where - P: AsRef, - S: AsRef, +pub fn install(config: Config, output: P, cookbook: Option, live: bool) -> Result<()> +where + P: AsRef, + S: AsRef, { println!("Install {:#?} to {}", config, output.as_ref().display()); if output.as_ref().is_dir() { install_dir(config, output, cookbook) } else { - let (bootloader_bios, bootloader_efi) = fetch_bootloaders(&config, cookbook.as_ref(), live)?; + let (bootloader_bios, bootloader_efi) = + fetch_bootloaders(&config, cookbook.as_ref(), live)?; let disk_option = DiskOption { bootloader_bios: &bootloader_bios, bootloader_efi: &bootloader_efi, password_opt: None, efi_partition_size: config.general.efi_partition_size, }; - with_whole_disk(output, &disk_option, - move |mount_path| { - install_dir(config, mount_path, cookbook) - } - ) + with_whole_disk(output, &disk_option, move |mount_path| { + install_dir(config, mount_path, cookbook) + }) } } From bfe70c409f49657ff89cebaaf6683aecd3645a0e Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 6 Oct 2024 13:02:44 +0200 Subject: [PATCH 2/4] 2021 edition. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 00f8749401..b0ad144a59 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT" authors = ["Jeremy Soller "] repository = "https://gitlab.redox-os.org/redox-os/installer" default-run = "redox_installer" -edition = "2018" +edition = "2021" [[bin]] name = "redox_installer" From 66d66a537c2bd206399e711b9221d3d36a589cdc Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 6 Oct 2024 13:08:17 +0200 Subject: [PATCH 3/4] Switch from failure to anyhow. --- Cargo.lock | 71 +++++------------------ Cargo.toml | 2 +- src/bin/installer_tui.rs | 118 +++++++++++++-------------------------- src/config/mod.rs | 11 ++-- src/lib.rs | 27 +++------ 5 files changed, 66 insertions(+), 163 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5ff74dbcb2..e22280c45b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -68,6 +68,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "anyhow" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" + [[package]] name = "arg_parser" version = "0.1.0" @@ -502,28 +508,6 @@ dependencies = [ "version_check 0.9.4", ] -[[package]] -name = "failure" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" -dependencies = [ - "backtrace", - "failure_derive", -] - -[[package]] -name = "failure_derive" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "synstructure", -] - [[package]] name = "fatfs" version = "0.3.6" @@ -1165,9 +1149,9 @@ dependencies = [ name = "redox_installer" version = "0.2.24" dependencies = [ + "anyhow", "arg_parser", "cc", - "failure", "fatfs", "fscommon", "gpt", @@ -1443,7 +1427,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn", ] [[package]] @@ -1511,17 +1495,6 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "syn" version = "2.0.68" @@ -1533,18 +1506,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "synstructure" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "unicode-xid", -] - [[package]] name = "tar" version = "0.4.41" @@ -1627,7 +1588,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn", ] [[package]] @@ -1753,12 +1714,6 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - [[package]] name = "untrusted" version = "0.6.2" @@ -1901,7 +1856,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.68", + "syn", "wasm-bindgen-shared", ] @@ -1923,7 +1878,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2171,5 +2126,5 @@ checksum = "125139de3f6b9d625c39e2efdd73d41bdac468ccd556556440e322be0e1bbd91" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn", ] diff --git a/Cargo.toml b/Cargo.toml index b0ad144a59..5b0fa219d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,9 +25,9 @@ name = "redox_installer" path = "src/lib.rs" [dependencies] +anyhow = "1.0.89" arg_parser = "0.1.0" cc = "=1.0.99" # Hack for ring 0.13.5 not building -failure = "0.1.8" fatfs = "0.3.0" fscommon = "0.1.1" gpt = "3.0.0" diff --git a/src/bin/installer_tui.rs b/src/bin/installer_tui.rs index 4976003867..9df1453981 100644 --- a/src/bin/installer_tui.rs +++ b/src/bin/installer_tui.rs @@ -1,14 +1,4 @@ -extern crate arg_parser; -#[macro_use] -extern crate failure; -extern crate pkgar; -extern crate pkgar_core; -extern crate pkgar_keys; -extern crate redox_installer; -extern crate serde; -extern crate termion; -extern crate toml; - +use anyhow::{anyhow, bail, Result}; use pkgar::{ext::EntryExt, PackageHead}; use pkgar_core::PackageSrc; use pkgar_keys::PublicKeyFile; @@ -105,18 +95,14 @@ fn format_size(size: u64) -> String { } } -fn copy_file(src: &Path, dest: &Path, buf: &mut [u8]) -> Result<(), failure::Error> { +fn copy_file(src: &Path, dest: &Path, buf: &mut [u8]) -> Result<()> { if let Some(parent) = dest.parent() { // Parent may be a symlink if !parent.is_symlink() { match fs::create_dir_all(&parent) { Ok(()) => (), Err(err) => { - return Err(format_err!( - "failed to create directory {}: {}", - parent.display(), - err - )); + bail!("failed to create directory {}: {}", parent.display(), err); } } } @@ -125,11 +111,7 @@ fn copy_file(src: &Path, dest: &Path, buf: &mut [u8]) -> Result<(), failure::Err let metadata = match fs::symlink_metadata(&src) { Ok(ok) => ok, Err(err) => { - return Err(format_err!( - "failed to read metadata of {}: {}", - src.display(), - err - )); + bail!("failed to read metadata of {}: {}", src.display(), err); } }; @@ -137,35 +119,27 @@ fn copy_file(src: &Path, dest: &Path, buf: &mut [u8]) -> Result<(), failure::Err let real_src = match fs::read_link(&src) { Ok(ok) => ok, Err(err) => { - return Err(format_err!( - "failed to read link {}: {}", - src.display(), - err - )); + bail!("failed to read link {}: {}", src.display(), err); } }; match symlink(&real_src, &dest) { Ok(()) => (), Err(err) => { - return Err(format_err!( + bail!( "failed to copy link {} ({}) to {}: {}", src.display(), real_src.display(), dest.display(), err - )); + ); } } } else { let mut src_file = match fs::File::open(&src) { Ok(ok) => ok, Err(err) => { - return Err(format_err!( - "failed to open file {}: {}", - src.display(), - err - )); + bail!("failed to open file {}: {}", src.display(), err); } }; @@ -177,11 +151,7 @@ fn copy_file(src: &Path, dest: &Path, buf: &mut [u8]) -> Result<(), failure::Err { Ok(ok) => ok, Err(err) => { - return Err(format_err!( - "failed to create file {}: {}", - dest.display(), - err - )); + bail!("failed to create file {}: {}", dest.display(), err); } }; @@ -189,11 +159,7 @@ fn copy_file(src: &Path, dest: &Path, buf: &mut [u8]) -> Result<(), failure::Err let count = match src_file.read(buf) { Ok(ok) => ok, Err(err) => { - return Err(format_err!( - "failed to read file {}: {}", - src.display(), - err - )); + bail!("failed to read file {}: {}", src.display(), err); } }; @@ -204,11 +170,7 @@ fn copy_file(src: &Path, dest: &Path, buf: &mut [u8]) -> Result<(), failure::Err match dest_file.write_all(&buf[..count]) { Ok(()) => (), Err(err) => { - return Err(format_err!( - "failed to write file {}: {}", - dest.display(), - err - )); + bail!("failed to write file {}: {}", dest.display(), err); } } } @@ -354,45 +316,41 @@ fn main() { password_opt: password_opt.as_ref().map(|x| x.as_bytes()), efi_partition_size: None, }; - let res = with_whole_disk( - &disk_path, - &disk_option, - |mount_path| -> Result<(), failure::Error> { - let mut config: Config = Config::from_file(&root_path.join("filesystem.toml"))?; + let res = with_whole_disk(&disk_path, &disk_option, |mount_path| -> Result<()> { + let mut config: Config = Config::from_file(&root_path.join("filesystem.toml"))?; - // Copy filesystem.toml, which is not packaged - let mut files = vec!["filesystem.toml".to_string()]; + // Copy filesystem.toml, which is not packaged + let mut files = vec!["filesystem.toml".to_string()]; - // Copy files from locally installed packages - if let Err(err) = package_files(&root_path, &mut config, &mut files) { - return Err(format_err!("failed to read package files: {}", err)); - } + // Copy files from locally installed packages + package_files(&root_path, &mut config, &mut files) + // TODO: implement Error trait + .map_err(|err| anyhow!("failed to read package files: {err}"))?; - // Perform config install (after packages have been converted to files) - eprintln!("configuring system"); - let cookbook: Option<&'static str> = None; - redox_installer::install_dir(config, mount_path, cookbook) - .map_err(|err| io::Error::new(io::ErrorKind::Other, err))?; + // Perform config install (after packages have been converted to files) + eprintln!("configuring system"); + let cookbook: Option<&'static str> = None; + redox_installer::install_dir(config, mount_path, cookbook) + .map_err(|err| io::Error::new(io::ErrorKind::Other, err))?; - // Sort and remove duplicates - files.sort(); - files.dedup(); + // Sort and remove duplicates + files.sort(); + files.dedup(); - // Install files - let mut buf = vec![0; 4 * MIB as usize]; - for (i, name) in files.iter().enumerate() { - eprintln!("copy {} [{}/{}]", name, i, files.len()); + // Install files + let mut buf = vec![0; 4 * MIB as usize]; + for (i, name) in files.iter().enumerate() { + eprintln!("copy {} [{}/{}]", name, i, files.len()); - let src = root_path.join(name); - let dest = mount_path.join(name); - copy_file(&src, &dest, &mut buf)?; - } + let src = root_path.join(name); + let dest = mount_path.join(name); + copy_file(&src, &dest, &mut buf)?; + } - eprintln!("finished installing, unmounting filesystem"); + eprintln!("finished installing, unmounting filesystem"); - Ok(()) - }, - ); + Ok(()) + }); match res { Ok(()) => { diff --git a/src/config/mod.rs b/src/config/mod.rs index 5f11eff2c5..577a7b0d0d 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -3,6 +3,9 @@ use std::fs; use std::mem; use std::path::{Path, PathBuf}; +use anyhow::bail; +use anyhow::Result; + pub mod file; pub mod general; pub mod package; @@ -25,16 +28,16 @@ pub struct Config { } impl Config { - pub fn from_file(path: &Path) -> Result { + pub fn from_file(path: &Path) -> Result { let mut config: Config = match fs::read_to_string(&path) { Ok(config_data) => match toml::from_str(&config_data) { Ok(config) => config, Err(err) => { - return Err(format_err!("{}: failed to decode: {}", path.display(), err)); + bail!("{}: failed to decode: {}", path.display(), err); } }, Err(err) => { - return Err(format_err!("{}: failed to read: {}", path.display(), err)); + bail!("{}: failed to read: {}", path.display(), err); } }; @@ -43,7 +46,7 @@ impl Config { let mut configs = mem::take(&mut config.include) .into_iter() .map(|path| Config::from_file(&config_dir.join(path))) - .collect::, failure::Error>>()?; + .collect::>>()?; configs.push(config); // Put ourself last to ensure that it overwrites anything else. config = configs.remove(0); diff --git a/src/lib.rs b/src/lib.rs index 161c750431..4059746f41 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,15 +1,5 @@ #[macro_use] extern crate serde_derive; -extern crate argon2; -extern crate libc; -extern crate liner; -#[macro_use] -extern crate failure; -extern crate pkgutils; -extern crate rand; -extern crate redoxfs; -extern crate syscall; -extern crate termion; mod config; mod disk_wrapper; @@ -19,7 +9,7 @@ pub use crate::config::package::PackageConfig; pub use crate::config::Config; use crate::disk_wrapper::DiskWrapper; -use failure::{err_msg, Error}; +use anyhow::{bail, Result}; use pkgutils::{Package, Repo}; use rand::{rngs::OsRng, RngCore}; use redoxfs::{unmount_path, Disk, DiskIo, FileSystem}; @@ -36,8 +26,6 @@ use std::{ time::{SystemTime, UNIX_EPOCH}, }; -pub(crate) type Result = std::result::Result; - pub struct DiskOption<'a> { pub bootloader_bios: &'a [u8], pub bootloader_efi: &'a [u8], @@ -62,7 +50,7 @@ fn hash_password(password: &str) -> Result { let hash = argon2::hash_encoded(password.as_bytes(), salt.as_bytes(), &config)?; Ok(hash) } else { - Ok("".to_string()) + Ok("".into()) } } @@ -84,11 +72,10 @@ fn prompt_password(prompt: &str, confirm_prompt: &str) -> Result { let confirm_password = stdin.read_passwd(&mut stdout)?; // Note: Actually comparing two Option values - if confirm_password == password { - Ok(password.unwrap_or("".to_string())) - } else { - Err(err_msg("passwords do not match")) + if confirm_password != password { + bail!("passwords do not match"); } + Ok(password.unwrap_or("".to_string())) } //TODO: error handling @@ -526,7 +513,7 @@ where "i686-unknown-redox" => "BOOTIA32.EFI", "x86_64-unknown-redox" => "BOOTX64.EFI", _ => { - return Err(format_err!("target '{}' not supported", target)); + bail!("target '{target}' not supported"); } }; @@ -539,7 +526,7 @@ where 512 => gpt::disk::LogicalBlockSize::Lb512, _ => { // TODO: support (and test) other block sizes - return Err(format_err!("block size {} not supported", block_size)); + bail!("block size {block_size} not supported"); } }; From 098fd8bbc9a0189cde680307b841fa470d654aad Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 6 Oct 2024 17:12:08 +0200 Subject: [PATCH 4/4] Support local binary packages. --- src/bin/installer.rs | 4 +- src/config/package.rs | 3 + src/lib.rs | 177 +++++++++++++++++++++++++----------------- 3 files changed, 113 insertions(+), 71 deletions(-) diff --git a/src/bin/installer.rs b/src/bin/installer.rs index 19adcd3c7c..3e95be5418 100644 --- a/src/bin/installer.rs +++ b/src/bin/installer.rs @@ -114,6 +114,7 @@ fn main() { version: None, git: None, path: None, + pkg_path: None, } => false, _ => true, }) @@ -143,7 +144,8 @@ fn main() { }; if let Some(path) = parser.args.get(0) { - if let Err(err) = redox_installer::install(config, path, cookbook, parser.found("live")) + if let Err(err) = + redox_installer::install(config, path, cookbook.as_deref(), parser.found("live")) { writeln!(stderr, "installer: failed to install: {}", err).unwrap(); process::exit(1); diff --git a/src/config/package.rs b/src/config/package.rs index bbbfdc57ce..46c222c948 100644 --- a/src/config/package.rs +++ b/src/config/package.rs @@ -3,10 +3,13 @@ pub enum PackageConfig { Empty, Build(String), + + // TODO: Sum type Spec { version: Option, git: Option, path: Option, + pkg_path: Option, }, } diff --git a/src/lib.rs b/src/lib.rs index 4059746f41..03773eeb0c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -79,7 +79,7 @@ fn prompt_password(prompt: &str, confirm_prompt: &str) -> Result { } //TODO: error handling -fn install_packages>(config: &Config, dest: &str, cookbook: Option) { +fn install_packages(config: &Config, dest: &str, cookbook: Option<&str>) { let target = &get_target(); let mut repo = Repo::new(target); @@ -93,63 +93,99 @@ fn install_packages>(config: &Config, dest: &str, cookbook: Option for (packagename, package) in &config.packages { let pkgar_path = format!( - "{}/{}/repo/{}/{}.pkgar", - env::current_dir().unwrap().to_string_lossy(), - cookbook.as_ref(), - target, - packagename + "{cwd}/{cookbook}/repo/{target}/{packagename}.pkgar", + cwd = env::current_dir().unwrap().to_string_lossy(), ); - let from_remote = match (config.general.repo_binary, package) { - (Some(true), PackageConfig::Empty) => true, + + enum Rule<'a> { + RemotePrebuilt, + LocalPrebuilt { pkg_path: &'a str }, + Build, + } + + let rule = match (config.general.repo_binary, package) { ( Some(true), - PackageConfig::Spec { + PackageConfig::Empty + | PackageConfig::Spec { version: None, git: None, path: None, + pkg_path: None, }, - ) => true, - (_, PackageConfig::Build(rule)) if rule == "binary" => true, - _ => false, - }; - if from_remote { - println!("Installing package from remote: {}", packagename); - repo.fetch(&packagename).unwrap().install(dest).unwrap(); - } else if Path::new(&pkgar_path).exists() { - println!("Installing package from local repo: {}", packagename); - let public_path = format!( - "{}/{}/build/id_ed25519.pub.toml", - env::current_dir().unwrap().to_string_lossy(), - cookbook.as_ref() - ); - pkgar::extract(&public_path, &pkgar_path, dest).unwrap(); + ) => { + // prebuilt + Rule::RemotePrebuilt + } + (_, PackageConfig::Build(rule)) if rule == "binary" => Rule::RemotePrebuilt, + ( + _, + PackageConfig::Spec { + pkg_path: Some(pkg_path), + .. + }, + ) => Rule::LocalPrebuilt { + pkg_path: &*pkg_path, + }, - let head_path = format!("{}/{}.pkgar_head", dest_pkg, packagename); - pkgar::split(&public_path, &pkgar_path, &head_path, Option::<&str>::None).unwrap(); - } else { - println!("Installing package tar.gz from local repo: {}", packagename); - let path = format!( - "{}/{}/repo/{}/{}.tar.gz", - env::current_dir().unwrap().to_string_lossy(), - cookbook.as_ref(), - target, - packagename - ); - Package::from_path(&path).unwrap().install(dest).unwrap(); + _ => Rule::Build, + }; + + match rule { + Rule::LocalPrebuilt { pkg_path } => { + println!( + "Installing package from local pkgar file: {packagename} <- `{pkg_path}`" + ); + Package::from_path(pkg_path).unwrap().install(dest).unwrap(); + } + Rule::RemotePrebuilt => { + println!("Installing package from remote: {packagename}"); + repo.fetch(&packagename).unwrap().install(dest).unwrap(); + } + Rule::Build if Path::new(&pkgar_path).exists() => { + println!("Installing package from local repo: {}", packagename); + let public_path = format!( + "{cwd}/{cookbook}/build/id_ed25519.pub.toml", + cwd = env::current_dir().unwrap().to_string_lossy(), + ); + pkgar::extract(&public_path, &pkgar_path, dest).unwrap(); + + let head_path = format!("{dest_pkg}/{packagename}.pkgar_head"); + pkgar::split(&public_path, &pkgar_path, &head_path, Option::<&str>::None) + .unwrap(); + } + Rule::Build => { + println!("Installing package tar.gz from local repo: {packagename}"); + let path = format!( + "{cwd}/{cookbook}/repo/{target}/{packagename}.tar.gz", + cwd = env::current_dir().unwrap().to_string_lossy(), + ); + Package::from_path(&path).unwrap().install(dest).unwrap(); + } } } } else { - for (packagename, _package) in &config.packages { - println!("Installing package from remote: {}", packagename); - repo.fetch(&packagename).unwrap().install(dest).unwrap(); + for (packagename, package) in &config.packages { + let mut package = if let PackageConfig::Spec { + pkg_path: Some(override_path), + .. + } = package + { + println!("Installing package from local file: {}", packagename); + Package::from_path(override_path).unwrap() + } else { + println!("Installing package from remote: {}", packagename); + repo.fetch(&packagename).unwrap() + }; + package.install(dest).unwrap(); } } } -pub fn install_dir, S: AsRef>( +pub fn install_dir( config: Config, - output_dir: P, - cookbook: Option, + output_dir: impl AsRef, + cookbook: Option<&str>, ) -> Result<()> { //let mut context = liner::Context::new(); @@ -237,13 +273,13 @@ pub fn install_dir, S: AsRef>( username )?; - println!("Adding user {}:", username); - println!("\tPassword: {}", password); - println!("\tUID: {}", uid); - println!("\tGID: {}", gid); - println!("\tName: {}", name); - println!("\tHome: {}", home); - println!("\tShell: {}", shell); + println!("Adding user {username}:"); + println!("\tPassword: {password}"); + println!("\tUID: {uid}"); + println!("\tGID: {gid}"); + println!("\tName: {name}"); + println!("\tHome: {home}"); + println!("\tShell: {shell}"); FileConfig { path: home.clone(), @@ -312,11 +348,8 @@ XDG_VIDEOS_DIR="$HOME/Videos" let password = hash_password(&password)?; - passwd.push_str(&format!( - "{};{};{};{};{};{}\n", - username, uid, gid, name, home, shell - )); - shadow.push_str(&format!("{};{}\n", username, password)); + passwd.push_str(&format!("{username};{uid};{gid};{name};{home};{shell}\n",)); + shadow.push_str(&format!("{username};{password}\n")); groups.push((username.clone(), gid, vec![username])); } @@ -368,8 +401,8 @@ XDG_VIDEOS_DIR="$HOME/Videos" use std::fmt::Write; writeln!(groups_data, "{name};x;{gid};{}", members.join(",")).unwrap(); - println!("Adding group {}:", name); - println!("\tGID: {}", gid); + println!("Adding group {name}:"); + println!("\tGID: {gid}"); println!("\tMembers: {}", members.join(", ")); } @@ -452,9 +485,9 @@ where res } -pub fn fetch_bootloaders>( +pub fn fetch_bootloaders( config: &Config, - cookbook: Option, + cookbook: Option<&str>, live: bool, ) -> Result<(Vec, Vec)> { let bootloader_dir = format!("/tmp/redox_installer_bootloader_{}", process::id()); @@ -470,7 +503,7 @@ pub fn fetch_bootloaders>( bootloader_config .packages .insert("bootloader".to_string(), PackageConfig::default()); - install_packages(&bootloader_config, &bootloader_dir, cookbook.as_ref()); + install_packages(&bootloader_config, &bootloader_dir, cookbook); let boot_dir = Path::new(&bootloader_dir).join("boot"); let bios_path = boot_dir.join(if live { @@ -562,8 +595,9 @@ where disk_file.write_all(&disk_option.bootloader_bios)?; // Replace MBR tables with protective MBR + // TODO: div_ceil let mbr_blocks = ((disk_size + block_size - 1) / block_size) - 1; - eprintln!("Writing protective MBR with disk blocks {:#x}", mbr_blocks); + eprintln!("Writing protective MBR with disk blocks {mbr_blocks:#x}"); gpt::mbr::ProtectiveMBR::with_lb_size(mbr_blocks as u32) .update_conservative(&mut disk_file)?; @@ -618,7 +652,7 @@ where }, ); - eprintln!("Writing GPT tables: {:#?}", partitions); + eprintln!("Writing GPT tables: {partitions:#?}"); // Initialize GPT table gpt_disk.update_partitions(partitions)?; @@ -675,18 +709,13 @@ where with_redoxfs(disk_redoxfs, disk_option.password_opt, callback) } -pub fn install(config: Config, output: P, cookbook: Option, live: bool) -> Result<()> -where - P: AsRef, - S: AsRef, -{ - println!("Install {:#?} to {}", config, output.as_ref().display()); +fn install_inner(config: Config, output: &Path, cookbook: Option<&str>, live: bool) -> Result<()> { + println!("Install {config:#?} to {}", output.display()); - if output.as_ref().is_dir() { + if output.is_dir() { install_dir(config, output, cookbook) } else { - let (bootloader_bios, bootloader_efi) = - fetch_bootloaders(&config, cookbook.as_ref(), live)?; + let (bootloader_bios, bootloader_efi) = fetch_bootloaders(&config, cookbook, live)?; let disk_option = DiskOption { bootloader_bios: &bootloader_bios, bootloader_efi: &bootloader_efi, @@ -698,3 +727,11 @@ where }) } } +pub fn install( + config: Config, + output: impl AsRef, + cookbook: Option<&str>, + live: bool, +) -> Result<()> { + install_inner(config, output.as_ref(), cookbook, live) +}