diff --git a/src/uu/mktemp/src/mktemp.rs b/src/uu/mktemp/src/mktemp.rs index 5e3b8aa58..f84f00a00 100644 --- a/src/uu/mktemp/src/mktemp.rs +++ b/src/uu/mktemp/src/mktemp.rs @@ -44,6 +44,8 @@ const TMPDIR_ENV_VAR: &str = "TMPDIR"; #[cfg(windows)] const TMPDIR_ENV_VAR: &str = "TMP"; +const FALLBACK_TMPDIR: &str = "/tmp"; + #[derive(Error, Debug)] enum MkTempError { #[error("{}", translate!("mktemp-error-persist-file", "path" => .0.quote()))] @@ -119,14 +121,12 @@ impl Options { Some(d) => d.clone(), // Otherwise use $TMPDIR if set, else use the system's default // temporary directory. - None => env::var(TMPDIR_ENV_VAR) - .ok() - .map_or_else(env::temp_dir, PathBuf::from), + None => get_tmpdir_env_or_default(), }); let (tmpdir, template) = match matches.get_one::(ARG_TEMPLATE) { // If no template argument is given, `--tmpdir` is implied. None => { - let tmpdir = Some(tmpdir.unwrap_or_else(env::temp_dir)); + let tmpdir = Some(tmpdir.unwrap_or_else(get_tmpdir_env_or_default)); let template = DEFAULT_TEMPLATE; (tmpdir, OsString::from(template)) } @@ -595,6 +595,14 @@ fn exec(dir: &Path, prefix: &str, rand: usize, suffix: &str, make_dir: bool) -> Ok(path) } +/// Reads from `TMPDIR_ENV_VAR` but defaults to /tmp if value is set to empty string. +fn get_tmpdir_env_or_default() -> PathBuf { + match env::var_os(TMPDIR_ENV_VAR) { + Some(val) if val.is_empty() => PathBuf::from(FALLBACK_TMPDIR), + _ => env::temp_dir(), + } +} + /// Create a temporary file or directory /// /// Behavior is determined by the `options` parameter, see [`Options`] for details. diff --git a/tests/by-util/test_mktemp.rs b/tests/by-util/test_mktemp.rs index cedcb4927..306f147d8 100644 --- a/tests/by-util/test_mktemp.rs +++ b/tests/by-util/test_mktemp.rs @@ -862,6 +862,63 @@ fn test_nonexistent_tmpdir_env_var() { } } +#[test] +fn test_empty_tmpdir_env_var() { + #[cfg(not(any(windows, target_os = "android")))] + { + let result = new_ucmd!().env(TMPDIR, "").succeeds(); + assert!(result.stdout_str().starts_with("/tmp")); + } + + #[cfg(any(windows, target_os = "android"))] + { + let result = new_ucmd!().env(TMPDIR, "").fails(); + result.no_stdout(); + let stderr = result.stderr_str(); + assert!( + stderr.starts_with("mktemp: failed to create file via template"), + "{stderr}" + ); + #[cfg(windows)] + assert!( + stderr.ends_with("/tmp\\tmp.XXXXXXXXXX': No such file or directory\n"), + "{stderr}", + ); + #[cfg(target_os = "android")] + assert!( + stderr.ends_with("/tmp/tmp.XXXXXXXXXX': No such file or directory\n"), + "{stderr}", + ); + } + + #[cfg(not(any(windows, target_os = "android")))] + { + let result = new_ucmd!().env(TMPDIR, "").arg("-d").succeeds(); + assert!(result.stdout_str().starts_with("/tmp")); + } + + #[cfg(any(windows, target_os = "android"))] + { + let result = new_ucmd!().env(TMPDIR, "").arg("-d").fails(); + result.no_stdout(); + let stderr = result.stderr_str(); + assert!( + stderr.starts_with("mktemp: failed to create directory via template"), + "{stderr}" + ); + #[cfg(windows)] + assert!( + stderr.ends_with("/tmp\\tmp.XXXXXXXXXX': No such file or directory\n"), + "{stderr}", + ); + #[cfg(target_os = "android")] + assert!( + stderr.ends_with("/tmp/tmp.XXXXXXXXXX': No such file or directory\n"), + "{stderr}", + ); + } +} + #[test] fn test_nonexistent_dir_prefix() { #[cfg(not(windows))]