Persistencia setters, compat-resolved, journald→CAS, compat-polkit
- hostnamed: SetHostname llama sethostname(2) + cache. SetStaticHostname
escribe atómico a /etc/hostname (tmp + fsync + rename, perms 0644).
Set{Pretty,Icon,Chassis,Deployment,Location} mergean k=v en
/etc/machine-info preservando otras keys. Validación: hostname RFC 1123
+ chassis enum.
- timedated: SetTimezone valida que /usr/share/zoneinfo/<tz> exista,
hace symlink atómico a /etc/localtime.
- localed: SetLocale valida formato KEY=value, escribe a /etc/locale.conf.
- compat-resolved (nuevo): org.freedesktop.resolve1.Manager con
ResolveHostname (vía tokio::lookup_host) y ResolveAddress (getnameinfo).
ResolveRecord devuelve NotSupported.
- journald-compat: persiste cada datagram al CAS por SHA. Append a
~/.local/share/ente/journal/index.log con
timestamp_ms:source:unit:sha_hex. Mutex serializa escrituras.
- compat-polkit (nuevo): org.freedesktop.PolicyKit1.Authority always-yes.
CheckAuthorization/CheckAuthorizationByAsync responden true,false,{}.
EnumerateActions vacío. Loguea action_id + pid/uid del subject.
7 compat-shims operativos en paralelo.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -154,38 +154,67 @@ impl HostnameManager {
|
||||
// ----- Setters: forward al bus interno y guardan en cache -----
|
||||
|
||||
async fn set_hostname(&self, name: String, _interactive: bool) -> fdo::Result<()> {
|
||||
info!(%name, "SetHostname → bus interno (stub)");
|
||||
*self.transient_hostname.lock().unwrap() = Some(name);
|
||||
if !is_valid_hostname(&name) {
|
||||
return Err(fdo::Error::InvalidArgs(format!("hostname inválido: {name:?}")));
|
||||
}
|
||||
// sethostname(2) cambia sólo el running kernel value.
|
||||
let cstr = std::ffi::CString::new(name.clone())
|
||||
.map_err(|e| fdo::Error::Failed(format!("CString: {e}")))?;
|
||||
let r = unsafe { libc::sethostname(cstr.as_ptr(), name.len()) };
|
||||
if r != 0 {
|
||||
warn!(error = %std::io::Error::last_os_error(), %name, "sethostname syscall falló (¿CAP_SYS_ADMIN?)");
|
||||
// No es fatal — guardamos transient para que el property lea el valor nuevo.
|
||||
}
|
||||
*self.transient_hostname.lock().unwrap() = Some(name.clone());
|
||||
info!(%name, "SetHostname aplicado");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_static_hostname(&self, name: String, _interactive: bool) -> fdo::Result<()> {
|
||||
info!(%name, "SetStaticHostname (stub: no persistimos a /etc)");
|
||||
if !is_valid_hostname(&name) {
|
||||
return Err(fdo::Error::InvalidArgs(format!("hostname inválido: {name:?}")));
|
||||
}
|
||||
atomic_write("/etc/hostname", format!("{name}\n").as_bytes())
|
||||
.map_err(|e| fdo::Error::Failed(format!("write /etc/hostname: {e}")))?;
|
||||
info!(%name, "SetStaticHostname → /etc/hostname");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_pretty_hostname(&self, name: String, _interactive: bool) -> fdo::Result<()> {
|
||||
info!(%name, "SetPrettyHostname (stub)");
|
||||
update_machine_info("PRETTY_HOSTNAME", &name)
|
||||
.map_err(|e| fdo::Error::Failed(format!("machine-info: {e}")))?;
|
||||
info!(%name, "SetPrettyHostname → /etc/machine-info");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_icon_name(&self, name: String, _interactive: bool) -> fdo::Result<()> {
|
||||
info!(%name, "SetIconName (stub)");
|
||||
update_machine_info("ICON_NAME", &name)
|
||||
.map_err(|e| fdo::Error::Failed(format!("machine-info: {e}")))?;
|
||||
info!(%name, "SetIconName → /etc/machine-info");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_chassis(&self, chassis: String, _interactive: bool) -> fdo::Result<()> {
|
||||
info!(%chassis, "SetChassis (stub)");
|
||||
if !matches!(chassis.as_str(), "desktop"|"laptop"|"server"|"tablet"|"handset"|"watch"|"embedded"|"vm"|"container") {
|
||||
return Err(fdo::Error::InvalidArgs(format!("chassis inválido: {chassis}")));
|
||||
}
|
||||
update_machine_info("CHASSIS", &chassis)
|
||||
.map_err(|e| fdo::Error::Failed(format!("machine-info: {e}")))?;
|
||||
info!(%chassis, "SetChassis → /etc/machine-info");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_deployment(&self, deployment: String, _interactive: bool) -> fdo::Result<()> {
|
||||
info!(%deployment, "SetDeployment (stub)");
|
||||
update_machine_info("DEPLOYMENT", &deployment)
|
||||
.map_err(|e| fdo::Error::Failed(format!("machine-info: {e}")))?;
|
||||
info!(%deployment, "SetDeployment → /etc/machine-info");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_location(&self, location: String, _interactive: bool) -> fdo::Result<()> {
|
||||
info!(%location, "SetLocation (stub)");
|
||||
update_machine_info("LOCATION", &location)
|
||||
.map_err(|e| fdo::Error::Failed(format!("machine-info: {e}")))?;
|
||||
info!(%location, "SetLocation → /etc/machine-info");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -226,6 +255,58 @@ fn read_dmi(path: &str) -> String {
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
/// RFC 1123 + extra: ASCII alfanumérico, dash, dot. Longitud 1..253.
|
||||
/// Rechaza vacíos, espacios, control chars.
|
||||
fn is_valid_hostname(s: &str) -> bool {
|
||||
if s.is_empty() || s.len() > 253 { return false; }
|
||||
s.chars().all(|c|
|
||||
c.is_ascii_alphanumeric() || c == '-' || c == '.' || c == '_'
|
||||
)
|
||||
}
|
||||
|
||||
/// Escritura atómica via tmp + rename. fsync del directorio para
|
||||
/// garantizar durabilidad post-crash. Permisos 0644.
|
||||
fn atomic_write(path: &str, content: &[u8]) -> std::io::Result<()> {
|
||||
use std::io::Write;
|
||||
use std::os::unix::fs::OpenOptionsExt;
|
||||
let p = std::path::Path::new(path);
|
||||
if let Some(parent) = p.parent() { let _ = std::fs::create_dir_all(parent); }
|
||||
let tmp = p.with_extension("tmp");
|
||||
{
|
||||
let mut f = std::fs::OpenOptions::new()
|
||||
.create(true).write(true).truncate(true)
|
||||
.mode(0o644)
|
||||
.open(&tmp)?;
|
||||
f.write_all(content)?;
|
||||
f.sync_all()?;
|
||||
}
|
||||
std::fs::rename(&tmp, p)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Lee /etc/machine-info, actualiza/inserta una clave, escribe atómico.
|
||||
fn update_machine_info(key: &str, value: &str) -> std::io::Result<()> {
|
||||
let path = "/etc/machine-info";
|
||||
let existing = std::fs::read_to_string(path).unwrap_or_default();
|
||||
let mut found = false;
|
||||
let mut out = String::new();
|
||||
for line in existing.lines() {
|
||||
if let Some((k, _)) = line.split_once('=') {
|
||||
if k.trim() == key {
|
||||
out.push_str(&format!("{key}={value}\n"));
|
||||
found = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
out.push_str(line);
|
||||
out.push('\n');
|
||||
}
|
||||
if !found {
|
||||
out.push_str(&format!("{key}={value}\n"));
|
||||
}
|
||||
atomic_write(path, out.as_bytes())
|
||||
}
|
||||
|
||||
async fn announce_to_fractal() {
|
||||
if let Ok(mut client) = BusClient::from_env().await {
|
||||
let req = BusRequest::Announce {
|
||||
|
||||
Reference in New Issue
Block a user