argument('target') ?: '/'; $data = $this->probe($target); // Persistiert (DB + Redis) über dein Settings-Model Setting::set('health.disk', $data); Setting::set('health.disk_updated_at', now()->toIso8601String()); $this->info(sprintf( 'Storage %s → total:%dGB used:%dGB free_user:%dGB free+5%%:%dGB (%%used:%d)', $data['mount'], $data['total_gb'], $data['used_gb'], $data['free_gb'], $data['free_plus_reserve_gb'], $data['percent_used_total'], )); return self::SUCCESS; } protected function probe(string $target): array { $line = trim((string) @shell_exec('df -kP ' . escapeshellarg($target) . ' 2>/dev/null | tail -n1')); $device = $mount = ''; $totalKb = $usedKb = $availKb = 0; if ($line !== '') { $p = preg_split('/\s+/', $line); if (count($p) >= 6) { $device = $p[0]; $totalKb = (int) $p[1]; // TOTAL (inkl. Reserve) $usedKb = (int) $p[2]; // Used $availKb = (int) $p[3]; // Avail (User-sicht) $mount = $p[5]; } } $toGiB = static fn($kb) => (int) round(max(0, (int)$kb) / (1024*1024)); $totalGb = $toGiB($totalKb); $freeGb = $toGiB($availKb); // user-verfügbar $usedGb = max(0, $totalGb - $freeGb); // belegt inkl. Reserve $res5Gb = (int) round($totalGb * 0.05); // 5% von Gesamt $freePlusReserveGb = min($totalGb, $freeGb + $res5Gb); $percentUsed = $totalGb > 0 ? (int) round($usedGb * 100 / $totalGb) : 0; return [ 'device' => $device ?: 'unknown', 'mount' => $mount ?: $target, 'total_gb' => $totalGb, 'used_gb' => $usedGb, // inkl. Reserve 'free_gb' => $freeGb, // User-sicht 'reserve5_gb' => $res5Gb, // Info 'free_plus_reserve_gb' => $freePlusReserveGb, // ← das willst du anzeigen 'percent_used_total' => $percentUsed, // fürs Donut (~15%) ]; } }