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
+56 -4
View File
@@ -10,7 +10,8 @@
use ente_bus::{BusClient, BusRequest, BusResponse};
use ente_card::Capability;
use std::os::fd::{AsRawFd, OwnedFd};
use std::path::Path;
use std::path::{Path, PathBuf};
use std::sync::Mutex;
use tokio::io::unix::AsyncFd;
use tokio::signal::unix::{signal, SignalKind};
use tracing::{debug, info, warn};
@@ -102,16 +103,65 @@ fn spawn_listener(async_fd: AsyncFd<OwnedFdWrap>, source: &'static str) {
});
}
/// Mutex sobre el archivo index para escrituras concurrentes desde
/// múltiples listeners (journal + syslog).
static INDEX_FILE: Mutex<()> = Mutex::new(());
/// Path del index file: `$XDG_DATA_HOME/ente/journal/index.log` (default
/// `~/.local/share/ente/journal/index.log`).
fn index_path() -> PathBuf {
let base = if let Ok(d) = std::env::var("XDG_DATA_HOME") { d }
else if let Ok(h) = std::env::var("HOME") { format!("{h}/.local/share") }
else { "/var/lib".into() };
PathBuf::from(base).join("ente").join("journal").join("index.log")
}
fn now_ms() -> u128 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_millis())
.unwrap_or(0)
}
/// Persiste el blob crudo al CAS y appendea una línea al index:
/// `<timestamp_ms>:<source>:<unit>:<sha_hex>`. Errores se logean pero
/// no abortan — perder un mensaje no debe romper journald.
fn persist_to_cas(buf: &[u8], source: &'static str, unit: Option<&str>) {
let sha = match ente_cas::store(buf) {
Ok(s) => s,
Err(e) => { warn!(?e, "CAS store falló"); return; }
};
let line = format!(
"{}:{}:{}:{}\n",
now_ms(), source, unit.unwrap_or("-"), ente_cas::hex(&sha)
);
let path = index_path();
let _guard = INDEX_FILE.lock().unwrap();
if let Some(parent) = path.parent() {
let _ = std::fs::create_dir_all(parent);
}
use std::io::Write;
let mut f = match std::fs::OpenOptions::new()
.create(true).append(true)
.open(&path)
{
Ok(f) => f,
Err(e) => { warn!(?e, path = %path.display(), "abrir index"); return; }
};
if let Err(e) = f.write_all(line.as_bytes()) {
warn!(?e, "write index");
}
}
/// Decodifica best-effort. Formato journald nativo: lines de "KEY=value"
/// (binario para values con newlines, pero raro). Formato syslog: texto
/// con prefijo "<priority>tag: message".
fn handle_message(buf: &[u8], source: &'static str) {
if let Ok(s) = std::str::from_utf8(buf) {
// Heurística: si tiene '=' en alguna línea, asumir journald.
if s.contains('=') && s.lines().any(|l| l.contains('=')) {
let mut message = None;
let mut priority = None;
let mut unit = None;
let mut unit: Option<String> = None;
for line in s.lines() {
if let Some((k, v)) = line.split_once('=') {
match k {
@@ -122,16 +172,18 @@ fn handle_message(buf: &[u8], source: &'static str) {
}
}
}
persist_to_cas(buf, source, unit.as_deref());
if let Some(msg) = message {
info!(target: "journal", source, ?priority, ?unit, "{msg}");
} else {
debug!(source, len = buf.len(), "journal native sin MESSAGE");
}
} else {
// Syslog
persist_to_cas(buf, source, None);
info!(target: "syslog", source, "{}", s.trim_end());
}
} else {
persist_to_cas(buf, source, None);
debug!(source, len = buf.len(), "journal binario (no UTF-8)");
}
}