makeInitrdNGTool: better errors

It's extremely frustrating seeing "Error: Os { code: 13, kind:
PermissionDenied, message: "Permission denied" }" without any hint as to
where exactly that occurred.

This commit fixes that by adding context to most errors.

+68 -23
+23
pkgs/build-support/kernel/make-initrd-ng/Cargo.lock
··· 9 9 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 10 10 11 11 [[package]] 12 + name = "eyre" 13 + version = "0.6.8" 14 + source = "registry+https://github.com/rust-lang/crates.io-index" 15 + checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" 16 + dependencies = [ 17 + "indenter", 18 + "once_cell", 19 + ] 20 + 21 + [[package]] 12 22 name = "goblin" 13 23 version = "0.5.3" 14 24 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 20 30 ] 21 31 22 32 [[package]] 33 + name = "indenter" 34 + version = "0.3.3" 35 + source = "registry+https://github.com/rust-lang/crates.io-index" 36 + checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" 37 + 38 + [[package]] 23 39 name = "log" 24 40 version = "0.4.17" 25 41 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 32 48 name = "make-initrd-ng" 33 49 version = "0.1.0" 34 50 dependencies = [ 51 + "eyre", 35 52 "goblin", 36 53 ] 54 + 55 + [[package]] 56 + name = "once_cell" 57 + version = "1.17.1" 58 + source = "registry+https://github.com/rust-lang/crates.io-index" 59 + checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" 37 60 38 61 [[package]] 39 62 name = "plain"
+1
pkgs/build-support/kernel/make-initrd-ng/Cargo.toml
··· 7 7 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 8 9 9 [dependencies] 10 + eyre = "0.6.8" 10 11 goblin = "0.5.0"
+44 -23
pkgs/build-support/kernel/make-initrd-ng/src/main.rs
··· 3 3 use std::ffi::{OsStr, OsString}; 4 4 use std::fs; 5 5 use std::hash::Hash; 6 + use std::io::{BufRead, BufReader}; 6 7 use std::iter::FromIterator; 7 - use std::io::{BufRead, BufReader, Error}; 8 8 use std::os::unix; 9 9 use std::path::{Component, Path, PathBuf}; 10 10 use std::process::Command; 11 11 12 + use eyre::Context; 12 13 use goblin::{elf::Elf, Object}; 13 14 14 15 struct NonRepeatingQueue<T> { ··· 87 88 } 88 89 } 89 90 90 - fn copy_file<P: AsRef<Path> + AsRef<OsStr>, S: AsRef<Path> + AsRef<OsStr>>( 91 + fn copy_file< 92 + P: AsRef<Path> + AsRef<OsStr> + std::fmt::Debug, 93 + S: AsRef<Path> + AsRef<OsStr> + std::fmt::Debug, 94 + >( 91 95 source: P, 92 96 target: S, 93 97 queue: &mut NonRepeatingQueue<Box<Path>>, 94 - ) -> Result<(), Error> { 95 - fs::copy(&source, &target)?; 98 + ) -> eyre::Result<()> { 99 + fs::copy(&source, &target) 100 + .wrap_err_with(|| format!("failed to copy {:?} to {:?}", source, target))?; 96 101 97 - let contents = fs::read(&source)?; 102 + let contents = 103 + fs::read(&source).wrap_err_with(|| format!("failed to read from {:?}", source))?; 98 104 99 105 if let Ok(Object::Elf(e)) = Object::parse(&contents) { 100 106 add_dependencies(source, e, queue); 101 107 102 108 // Make file writable to strip it 103 - let mut permissions = fs::metadata(&target)?.permissions(); 109 + let mut permissions = fs::metadata(&target) 110 + .wrap_err_with(|| format!("failed to get metadata for {:?}", target))? 111 + .permissions(); 104 112 permissions.set_readonly(false); 105 - fs::set_permissions(&target, permissions)?; 113 + fs::set_permissions(&target, permissions) 114 + .wrap_err_with(|| format!("failed to set readonly flag to false for {:?}", target))?; 106 115 107 116 // Strip further than normal 108 117 if let Ok(strip) = env::var("STRIP") { ··· 121 130 Ok(()) 122 131 } 123 132 124 - fn queue_dir<P: AsRef<Path>>( 133 + fn queue_dir<P: AsRef<Path> + std::fmt::Debug>( 125 134 source: P, 126 135 queue: &mut NonRepeatingQueue<Box<Path>>, 127 - ) -> Result<(), Error> { 128 - for entry in fs::read_dir(source)? { 136 + ) -> eyre::Result<()> { 137 + for entry in 138 + fs::read_dir(&source).wrap_err_with(|| format!("failed to read dir {:?}", source))? 139 + { 129 140 let entry = entry?; 130 141 // No need to recurse. The queue will bring us back round here on its own. 131 142 queue.push_back(Box::from(entry.path().as_path())); ··· 138 149 root: &Path, 139 150 p: &Path, 140 151 queue: &mut NonRepeatingQueue<Box<Path>>, 141 - ) -> Result<(), Error> { 152 + ) -> eyre::Result<()> { 142 153 let mut source = PathBuf::new(); 143 154 let mut target = Path::new(root).to_path_buf(); 144 155 let mut iter = p.components().peekable(); ··· 161 172 Component::Normal(name) => { 162 173 target.push(name); 163 174 source.push(name); 164 - let typ = fs::symlink_metadata(&source)?.file_type(); 175 + let typ = fs::symlink_metadata(&source) 176 + .wrap_err_with(|| format!("failed to get symlink metadata for {:?}", source))? 177 + .file_type(); 165 178 if typ.is_file() && !target.exists() { 166 179 copy_file(&source, &target, queue)?; 167 180 168 181 if let Some(filename) = source.file_name() { 169 182 source.set_file_name(OsString::from_iter([ 170 - OsStr::new("."), 171 - filename, 172 - OsStr::new("-wrapped"), 183 + OsStr::new("."), 184 + filename, 185 + OsStr::new("-wrapped"), 173 186 ])); 174 187 175 188 let wrapped_path = source.as_path(); ··· 178 191 } 179 192 } 180 193 } else if typ.is_symlink() { 181 - let link_target = fs::read_link(&source)?; 194 + let link_target = fs::read_link(&source) 195 + .wrap_err_with(|| format!("failed to resolve symlink of {:?}", source))?; 182 196 183 197 // Create the link, then push its target to the queue 184 198 if !target.exists() { 185 - unix::fs::symlink(&link_target, &target)?; 199 + unix::fs::symlink(&link_target, &target).wrap_err_with(|| { 200 + format!("failed to symlink {:?} to {:?}", link_target, target) 201 + })?; 186 202 } 187 203 source.pop(); 188 204 source.push(link_target); ··· 196 212 break; 197 213 } else if typ.is_dir() { 198 214 if !target.exists() { 199 - fs::create_dir(&target)?; 215 + fs::create_dir(&target) 216 + .wrap_err_with(|| format!("failed to create dir {:?}", target))?; 200 217 } 201 218 202 219 // Only recursively copy if the directory is the target object 203 220 if iter.peek().is_none() { 204 - queue_dir(&source, queue)?; 221 + queue_dir(&source, queue) 222 + .wrap_err_with(|| format!("failed to queue dir {:?}", source))?; 205 223 } 206 224 } 207 225 } ··· 211 229 Ok(()) 212 230 } 213 231 214 - fn main() -> Result<(), Error> { 232 + fn main() -> eyre::Result<()> { 215 233 let args: Vec<String> = env::args().collect(); 216 - let input = fs::File::open(&args[1])?; 234 + let input = 235 + fs::File::open(&args[1]).wrap_err_with(|| format!("failed to open file {:?}", &args[1]))?; 217 236 let output = &args[2]; 218 237 let out_path = Path::new(output); 219 238 ··· 235 254 let link_path = Path::new(&link_string); 236 255 let mut link_parent = link_path.to_path_buf(); 237 256 link_parent.pop(); 238 - fs::create_dir_all(link_parent)?; 239 - unix::fs::symlink(obj_path, link_path)?; 257 + fs::create_dir_all(&link_parent) 258 + .wrap_err_with(|| format!("failed to create directories to {:?}", link_parent))?; 259 + unix::fs::symlink(obj_path, link_path) 260 + .wrap_err_with(|| format!("failed to symlink {:?} to {:?}", obj_path, link_path))?; 240 261 } 241 262 } 242 263 while let Some(obj) = queue.pop_front() {