diff --git a/src/bin/fish.rs b/src/bin/fish.rs index 6f390688e..8a2777e01 100644 --- a/src/bin/fish.rs +++ b/src/bin/fish.rs @@ -408,7 +408,9 @@ fn throwing_main() -> i32 { threads::init(); // Safety: single-threaded. - unsafe { set_libc_locales() }; + unsafe { + set_libc_locales(/*log_ok=*/ false) + }; fish::wutil::gettext::initialize_gettext(); diff --git a/src/builtins/fish_indent.rs b/src/builtins/fish_indent.rs index ffb8bea72..bb48c7617 100644 --- a/src/builtins/fish_indent.rs +++ b/src/builtins/fish_indent.rs @@ -890,7 +890,9 @@ fn throwing_main() -> i32 { let mut streams = IoStreams::new(&mut out, &mut err, &io_chain); streams.stdin_fd = STDIN_FILENO; // Safety: single-threaded. - unsafe { set_libc_locales() }; + unsafe { + set_libc_locales(/*log_ok=*/ false) + }; crate::wutil::gettext::initialize_gettext(); env_init(None, true, false); diff --git a/src/env_dispatch.rs b/src/env_dispatch.rs index fd8bcc881..c8c33e11d 100644 --- a/src/env_dispatch.rs +++ b/src/env_dispatch.rs @@ -17,10 +17,7 @@ use crate::wchar::prelude::*; use crate::wutil::fish_wcstoi; use crate::{function, terminal}; -use std::borrow::Cow; use std::collections::HashMap; -use std::ffi::{CStr, CString}; -use std::ptr; use std::sync::atomic::{AtomicBool, Ordering}; /// List of all locale environment variable names that might trigger (re)initializing of the locale @@ -502,16 +499,6 @@ pub fn read_terminfo_database(vars: &EnvStack) { fn init_locale(vars: &EnvStack) { let _guard = crate::locale::LOCALE_LOCK.lock().unwrap(); - let old_msg_locale: CString = { - let old = unsafe { libc::setlocale(libc::LC_MESSAGES, ptr::null()) }; - assert_ne!(old, ptr::null_mut()); - // We have to make a copy because the subsequent setlocale() call to change the locale will - // invalidate the pointer from this setlocale() call. - - // safety: `old` is not a null-pointer, and should be a reference to the currently set locale - unsafe { CStr::from_ptr(old.cast()) }.to_owned() - }; - for var_name in LOCALE_VARIABLES { let var = vars .getf_unless_empty(var_name, EnvMode::EXPORT) @@ -525,40 +512,15 @@ fn init_locale(vars: &EnvStack) { } } - let user_locale = { - // Safety: we hold the locale lock. - let loc = unsafe { set_libc_locales() }; - if loc.is_none() { - FLOG!(env_locale, "user has an invalid locale configured"); - } - loc - }; + // Safety: we hold the locale lock. + if !unsafe { + set_libc_locales(/*log_ok=*/ true) + } { + FLOG!(env_locale, "user has an invalid locale configured"); + } // Update cached locale information. crate::common::fish_setlocale(); - FLOG!( - env_locale, - "init_locale() setlocale():", - user_locale - .map(CStr::to_string_lossy) - .unwrap_or(Cow::Borrowed("(null)")) - ); - - let new_msg_loc_ptr = unsafe { libc::setlocale(libc::LC_MESSAGES, std::ptr::null()) }; - // should never fail - assert_ne!(new_msg_loc_ptr, ptr::null_mut()); - // safety: we just asserted it is not a null-pointer. - let new_msg_locale = unsafe { CStr::from_ptr(new_msg_loc_ptr) }; - FLOG!( - env_locale, - "Old LC_MESSAGES locale:", - old_msg_locale.to_string_lossy() - ); - FLOG!( - env_locale, - "New LC_MESSAGES locale:", - new_msg_locale.to_string_lossy() - ); #[cfg(feature = "localize-messages")] crate::wutil::gettext::update_locale_from_env(vars); diff --git a/src/locale.rs b/src/locale.rs index 169c2e29c..d50a4bbf5 100644 --- a/src/locale.rs +++ b/src/locale.rs @@ -8,10 +8,35 @@ /// # Safety /// Call this either before starting any locale-using thread, or while holding a lock on the /// above mutex. -pub unsafe fn set_libc_locales() -> Option<&'static CStr> { - let opaque_locale_str = setlocale(libc::LC_ALL, Some(c"")); - setlocale(libc::LC_CTYPE, Some(c"C.UTF-8")); - opaque_locale_str +pub unsafe fn set_libc_locales(log_ok: bool) -> bool { + let mut ok = true; + let mut set = |category_name, category, value| { + let locale_string = setlocale(category, Some(value)); + if log_ok { + crate::flog::FLOG!( + env_locale, + match locale_string { + Some(locale_string) => { + format!("Set {category_name} to {}", locale_string.to_string_lossy()) + } + None => { + format!("Failed to set {category_name}",) + } + }, + ); + } + ok &= locale_string.is_some(); + }; + let from_environment = c""; + // For wcwidth(3p) + set("LC_CTYPE", libc::LC_CTYPE, c"C.UTF-8"); + // For strerror(3p) and strsignal(3p) + set("LC_MESSAGES", libc::LC_MESSAGES, from_environment); + // For builtin printf + set("LC_NUMERIC", libc::LC_NUMERIC, from_environment); + // For "history --show-time" + set("LC_TIME", libc::LC_TIME, from_environment); + ok } fn setlocale(category: libc::c_int, locale: Option<&CStr>) -> Option<&'static CStr> { diff --git a/src/tests/prelude.rs b/src/tests/prelude.rs index 19ae60f26..74a0d6f13 100644 --- a/src/tests/prelude.rs +++ b/src/tests/prelude.rs @@ -27,7 +27,9 @@ pub fn test_init() -> impl ScopeGuarding { std::fs::create_dir_all(&test_dir).unwrap(); set_current_dir(&test_dir).unwrap(); // Safety: all tests that access locale should go through the enclosing function. - unsafe { set_libc_locales() }; + unsafe { + set_libc_locales(/*log_ok=*/ false) + }; topic_monitor_init(); crate::threads::init(); proc_init();