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:
Sergio
2026-05-04 09:53:42 +00:00
parent 6ad6d08fa8
commit d88a9c5791
12 changed files with 683 additions and 15 deletions
+89 -8
View File
@@ -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 {