summaryrefslogtreecommitdiffstats
path: root/src/bootstrap/install.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/bootstrap/install.rs')
-rw-r--r--src/bootstrap/install.rs59
1 files changed, 49 insertions, 10 deletions
diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs
index b62aa9992..500b20b86 100644
--- a/src/bootstrap/install.rs
+++ b/src/bootstrap/install.rs
@@ -45,6 +45,23 @@ fn sanitize_sh(path: &Path) -> String {
}
}
+fn is_dir_writable_for_user(dir: &PathBuf) -> bool {
+ let tmp = dir.join(".tmp");
+ match fs::create_dir_all(&tmp) {
+ Ok(_) => {
+ fs::remove_dir_all(tmp).unwrap();
+ true
+ }
+ Err(e) => {
+ if e.kind() == std::io::ErrorKind::PermissionDenied {
+ false
+ } else {
+ panic!("Failed the write access check for the current user. {}", e);
+ }
+ }
+ }
+}
+
fn install_sh(
builder: &Builder<'_>,
package: &str,
@@ -56,6 +73,28 @@ fn install_sh(
let prefix = default_path(&builder.config.prefix, "/usr/local");
let sysconfdir = prefix.join(default_path(&builder.config.sysconfdir, "/etc"));
+ let destdir_env = env::var_os("DESTDIR").map(PathBuf::from);
+
+ // Sanity checks on the write access of user.
+ //
+ // When the `DESTDIR` environment variable is present, there is no point to
+ // check write access for `prefix` and `sysconfdir` individually, as they
+ // are combined with the path from the `DESTDIR` environment variable. In
+ // this case, we only need to check the `DESTDIR` path, disregarding the
+ // `prefix` and `sysconfdir` paths.
+ if let Some(destdir) = &destdir_env {
+ assert!(is_dir_writable_for_user(destdir), "User doesn't have write access on DESTDIR.");
+ } else {
+ assert!(
+ is_dir_writable_for_user(&prefix),
+ "User doesn't have write access on `install.prefix` path in the `config.toml`.",
+ );
+ assert!(
+ is_dir_writable_for_user(&sysconfdir),
+ "User doesn't have write access on `install.sysconfdir` path in `config.toml`."
+ );
+ }
+
let datadir = prefix.join(default_path(&builder.config.datadir, "share"));
let docdir = prefix.join(default_path(&builder.config.docdir, "share/doc/rust"));
let mandir = prefix.join(default_path(&builder.config.mandir, "share/man"));
@@ -68,13 +107,13 @@ fn install_sh(
let mut cmd = Command::new(SHELL);
cmd.current_dir(&empty_dir)
.arg(sanitize_sh(&tarball.decompressed_output().join("install.sh")))
- .arg(format!("--prefix={}", prepare_dir(prefix)))
- .arg(format!("--sysconfdir={}", prepare_dir(sysconfdir)))
- .arg(format!("--datadir={}", prepare_dir(datadir)))
- .arg(format!("--docdir={}", prepare_dir(docdir)))
- .arg(format!("--bindir={}", prepare_dir(bindir)))
- .arg(format!("--libdir={}", prepare_dir(libdir)))
- .arg(format!("--mandir={}", prepare_dir(mandir)))
+ .arg(format!("--prefix={}", prepare_dir(&destdir_env, prefix)))
+ .arg(format!("--sysconfdir={}", prepare_dir(&destdir_env, sysconfdir)))
+ .arg(format!("--datadir={}", prepare_dir(&destdir_env, datadir)))
+ .arg(format!("--docdir={}", prepare_dir(&destdir_env, docdir)))
+ .arg(format!("--bindir={}", prepare_dir(&destdir_env, bindir)))
+ .arg(format!("--libdir={}", prepare_dir(&destdir_env, libdir)))
+ .arg(format!("--mandir={}", prepare_dir(&destdir_env, mandir)))
.arg("--disable-ldconfig");
builder.run(&mut cmd);
t!(fs::remove_dir_all(&empty_dir));
@@ -84,16 +123,16 @@ fn default_path(config: &Option<PathBuf>, default: &str) -> PathBuf {
config.as_ref().cloned().unwrap_or_else(|| PathBuf::from(default))
}
-fn prepare_dir(mut path: PathBuf) -> String {
+fn prepare_dir(destdir_env: &Option<PathBuf>, mut path: PathBuf) -> String {
// The DESTDIR environment variable is a standard way to install software in a subdirectory
// while keeping the original directory structure, even if the prefix or other directories
// contain absolute paths.
//
// More information on the environment variable is available here:
// https://www.gnu.org/prep/standards/html_node/DESTDIR.html
- if let Some(destdir) = env::var_os("DESTDIR").map(PathBuf::from) {
+ if let Some(destdir) = destdir_env {
let without_destdir = path.clone();
- path = destdir;
+ path = destdir.clone();
// Custom .join() which ignores disk roots.
for part in without_destdir.components() {
if let Component::Normal(s) = part {