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