Show custom systemd services
This commit is contained in:
+152
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user