refresh(); $this->restoreStartingState(); } private function restoreStartingState(): void { if (!file_exists(self::STARTING_FLAG)) return; if ($this->running) { @unlink(self::STARTING_FLAG); return; } $elapsed = time() - (int) @file_get_contents(self::STARTING_FLAG); if ($elapsed > 180) { @unlink(self::STARTING_FLAG); return; } $this->starting = true; $this->startSecs = max(0, $elapsed); } public function refresh(): void { $this->lastError = ''; $this->lastSuccess = ''; $this->running = $this->serviceActive(); $this->enabled = $this->serviceEnabled(); $this->installed = true; $this->ramMb = $this->running ? $this->readRamMb() : null; [$this->dbDate, $this->dbVersion] = $this->readDbInfo(); } public function install(): void { $this->installing = true; $out = []; @exec('sudo -n /usr/local/sbin/mailwolt-clamav install 2>&1', $out, $rc); $this->installing = false; if ($rc !== 0) { $this->lastError = implode(' ', $out) ?: 'Installation fehlgeschlagen.'; } else { $this->dispatch('toast', type: 'success', badge: 'ClamAV', title: 'Installiert', text: 'ClamAV wurde installiert. Sie können ihn jetzt aktivieren.'); } $this->refresh(); } public function enable(): void { $this->lastError = ''; $this->lastSuccess = ''; [$ok, $msg] = $this->runCmd('enable'); if (!$ok) { $this->lastError = $msg; return; } file_put_contents(self::STARTING_FLAG, time()); $this->enabled = true; $this->starting = true; $this->startSecs = 0; } public function pollStatus(): void { if (!$this->starting) return; $this->startSecs += 3; $this->running = $this->serviceActive(); if ($this->running) { @unlink(self::STARTING_FLAG); $this->starting = false; $this->startSecs = 0; $this->enabled = $this->serviceEnabled(); $this->ramMb = $this->readRamMb(); $this->lastSuccess = 'ClamAV ist aktiv und läuft.'; } } public function disable(): void { [$ok, $msg] = $this->runCmd('disable'); if ($ok) $this->lastSuccess = 'ClamAV wurde gestoppt und deaktiviert.'; else $this->lastError = $msg; $this->running = $this->serviceActive(); $this->enabled = $this->serviceEnabled(); } public function updateDb(): void { [$ok, $msg] = $this->runCmd('freshclam'); if ($ok) $this->lastSuccess = 'Virensignaturen wurden aktualisiert.'; else $this->lastError = $msg; [$this->dbDate, $this->dbVersion] = $this->readDbInfo(); } private function runCmd(string $action): array { $out = []; $rc = null; exec('sudo -n /usr/local/sbin/mailwolt-clamav ' . escapeshellarg($action) . ' 2>&1', $out, $rc); \Log::info('ClamAV ' . $action, ['rc' => $rc, 'out' => $out]); $msg = implode(' ', $out) ?: 'Unbekannter Fehler (rc=' . $rc . ')'; return [$rc === 0, $msg]; } private function serviceActive(): bool { $exit = null; @exec('systemctl is-active --quiet clamav-daemon 2>/dev/null', $_, $exit); return $exit === 0; } private function serviceEnabled(): bool { $exit = null; @exec('systemctl is-enabled --quiet clamav-daemon 2>/dev/null', $_, $exit); return $exit === 0; } private function readRamMb(): ?int { $out = []; @exec("ps -C clamd -o rss= 2>/dev/null", $out); $kb = array_sum(array_map('intval', array_filter($out))); return $kb > 0 ? (int) round($kb / 1024) : null; } private function readDbInfo(): array { $paths = [ '/var/lib/clamav/main.cvd', '/var/lib/clamav/main.cld', '/var/lib/clamav/daily.cvd', '/var/lib/clamav/daily.cld', ]; $latest = 0; foreach ($paths as $p) { if (@file_exists($p)) { $mtime = @filemtime($p); if ($mtime > $latest) $latest = $mtime; } } if ($latest === 0) return ['—', '—']; $date = date('d.m.Y H:i', $latest); $ver = '—'; $out = []; @exec('sigtool --info /var/lib/clamav/daily.cld 2>/dev/null | grep "^Version:" | head -1', $out); if (empty($out)) { @exec('sigtool --info /var/lib/clamav/daily.cvd 2>/dev/null | grep "^Version:" | head -1', $out); } if (!empty($out[0])) { $ver = trim(str_replace('Version:', '', $out[0])); } return [$date, $ver]; } public function render() { return view('livewire.ui.security.clamav-manager'); } }