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:
@@ -12,6 +12,7 @@ path = "src/main.rs"
|
||||
[dependencies]
|
||||
ente-card = { path = "../ente-card" }
|
||||
ente-bus = { path = "../ente-bus" }
|
||||
ente-cas = { path = "../ente-cas" }
|
||||
nix = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
|
||||
@@ -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)");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user