Show custom systemd services

This commit is contained in:
seo
2026-06-21 23:10:13 +09:00
parent 772010562a
commit cc5943df87
4 changed files with 215 additions and 2 deletions
+152
View File
@@ -1871,6 +1871,157 @@ function action_rows(int $limit = 80): array
return $stmt->fetchAll();
}
function custom_systemd_service_names(): array
{
$paths = glob('/etc/systemd/system/*.service') ?: [];
$names = [];
foreach ($paths as $path) {
if (is_link($path)) {
continue;
}
$name = basename($path);
if (preg_match('/^[A-Za-z0-9_.@:-]+\.service$/', $name)) {
$names[] = $name;
}
}
sort($names, SORT_NATURAL | SORT_FLAG_CASE);
return $names;
}
function parse_systemctl_show_records(string $out): array
{
$records = [];
$current = [];
foreach (preg_split('/\R/', trim($out)) as $line) {
if ($line === '') {
if (!empty($current['Id'])) {
$records[$current['Id']] = $current;
}
$current = [];
continue;
}
$parts = explode('=', $line, 2);
if (count($parts) === 2) {
$current[$parts[0]] = $parts[1];
}
}
if (!empty($current['Id'])) {
$records[$current['Id']] = $current;
}
return $records;
}
function systemd_service_logs(string $unit, int $limit = 12): array
{
$limit = max(1, min(50, $limit));
$cmd = [
'/usr/bin/journalctl',
'-u',
$unit,
'-n',
(string)$limit,
'--no-pager',
'--output=short-iso',
];
$result = sh($cmd, false, 4);
if ((int)$result['code'] !== 0) {
$result = sh($cmd, true, 4);
}
$lines = array_values(array_filter(
preg_split('/\R/', trim((string)$result['out'])),
static fn($line) => trim((string)$line) !== ''
));
return [
'ok' => (int)$result['code'] === 0,
'lines' => $lines,
'error' => (int)$result['code'] === 0 ? '' : (string)$result['out'],
];
}
function custom_systemd_services(): array
{
$cachePath = '/tmp/control-custom-services.json';
if (is_file($cachePath) && filemtime($cachePath) >= time() - 5) {
$cached = json_decode((string)@file_get_contents($cachePath), true);
if (is_array($cached)) {
return $cached;
}
}
$names = custom_systemd_service_names();
if (!$names) {
return [];
}
$show = sh(array_merge([
'/usr/bin/systemctl',
'show',
], $names, [
'--no-pager',
'-p',
'Id',
'-p',
'LoadState',
'-p',
'ActiveState',
'-p',
'SubState',
'-p',
'UnitFileState',
'-p',
'Description',
'-p',
'FragmentPath',
'-p',
'ActiveEnterTimestamp',
'-p',
'InactiveEnterTimestamp',
'-p',
'ExecMainPID',
'-p',
'NRestarts',
]), false, 6);
$records = parse_systemctl_show_records((string)$show['out']);
$rows = [];
foreach ($names as $name) {
$record = $records[$name] ?? [];
$logs = systemd_service_logs($name, 12);
$rows[] = [
'name' => $name,
'description' => (string)($record['Description'] ?? ''),
'load' => (string)($record['LoadState'] ?? ''),
'active' => (string)($record['ActiveState'] ?? 'unknown'),
'sub' => (string)($record['SubState'] ?? ''),
'enabled' => (string)($record['UnitFileState'] ?? ''),
'pid' => (int)($record['ExecMainPID'] ?? 0),
'restarts' => (int)($record['NRestarts'] ?? 0),
'active_enter' => (string)($record['ActiveEnterTimestamp'] ?? ''),
'inactive_enter' => (string)($record['InactiveEnterTimestamp'] ?? ''),
'fragment' => (string)($record['FragmentPath'] ?? ''),
'logs' => $logs['lines'],
'logs_ok' => $logs['ok'],
'logs_error' => $logs['ok'] ? '' : $logs['error'],
];
}
@file_put_contents($cachePath, json_encode($rows, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
return $rows;
}
function collect_snapshot(bool $applyFan = true): array
{
if ($applyFan) {
@@ -2008,6 +2159,7 @@ function collect_snapshot(bool $applyFan = true): array
'wifi' => wifi_data(),
'history' => $history,
'processes' => $processes,
'custom_services' => custom_systemd_services(),
'fan_spike' => $fanSpike,
'fan_spike_history' => fan_spike_history(100),
'ha_notify_history' => ha_notify_log_rows(20),