Incomplete uninstallations leave the system in a tricky state #34
Labels
No labels
Compat/Breaking
Context/drive-by
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Status
Abandoned
Status
Blocked
Status/Fixed On Main
Status
Need More Info
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
lix-project/lix-installer#34
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
To reproduce (on macOS):
/nix./nix-installer uninstallThe uninstallation will fail because
/nixis still in use (as the working directory of the shell from which the uninstaller was invoked) and can't be unmounted/deleted.Attempting to uninstall again will fail more spectacularly because some of the steps will have been reverted already.
I'm puzzled by why this happens, as there's a very clear attempt in the
uninstallcommand to mitigate this:if let Ok(current_dir) = std::env::current_dir() {let mut components = current_dir.components();let should_be_root = components.next();let maybe_nix = components.next();if should_be_root == Some(std::path::Component::RootDir)&& maybe_nix == Some(std::path::Component::Normal(std::ffi::OsStr::new("nix"))){tracing::debug!("Changing current directory to be outside of `/nix`");std::env::set_current_dir("/").wrap_err("Uninstall process was run from `/nix` folder, but could not change directory away from `/nix`, please change the current directory and try again.")?;}}// During install, `nix-installer` will store a copy of itself in `/nix/nix-installer`// If the user opted to run that particular copy of `nix-installer` to do this uninstall,// well, we have a problem, since the binary would delete itself.// Instead, detect if we're in that location, if so, move the binary and `execv` it.if let Ok(current_exe) = std::env::current_exe() {if current_exe.as_path() == Path::new("/nix/nix-installer") {tracing::debug!("Detected uninstall from `/nix/nix-installer`, moving executable and re-executing");let temp = std::env::temp_dir();let random_trailer: String = {const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\abcdefghijklmnopqrstuvwxyz\0123456789";const PASSWORD_LEN: usize = 16;let mut rng = rand::thread_rng();(0..PASSWORD_LEN).map(|_| {let idx = rng.gen_range(0..CHARSET.len());CHARSET[idx] as char}).collect()};let temp_exe = temp.join(&format!("nix-installer-{random_trailer}"));tokio::fs::copy(¤t_exe, &temp_exe).await.wrap_err("Copying nix-installer to tempdir")?;let args = std::env::args();let mut arg_vec_cstring = vec![];for arg in args {arg_vec_cstring.push(CString::new(arg).wrap_err("Making arg into C string")?);}let temp_exe_cstring = CString::new(temp_exe.to_string_lossy().into_owned()).wrap_err("Making C string of executable path")?;tracing::trace!("Execv'ing `{temp_exe_cstring:?} {arg_vec_cstring:?}`");nix::unistd::execv(&temp_exe_cstring, &arg_vec_cstring)Does it fail despite that? Is it some kind of issue with
std::env::set_current_dir?