Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
19.35% covered (danger)
19.35%
6 / 31
50.00% covered (danger)
50.00%
2 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
ProcessSignaler
19.35% covered (danger)
19.35%
6 / 31
50.00% covered (danger)
50.00%
2 / 4
87.53
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isRunning
14.29% covered (danger)
14.29%
2 / 14
0.00% covered (danger)
0.00%
0 / 1
20.74
 stopPid
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 sendSignal
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2
3declare(strict_types=1);
4/**
5 * SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
6 * SPDX-License-Identifier: AGPL-3.0-or-later
7 */
8
9namespace OCA\Libresign\Service\Process;
10
11use Psr\Log\LoggerInterface;
12
13class ProcessSignaler {
14    public function __construct(
15        private LoggerInterface $logger,
16    ) {
17    }
18
19    public function isRunning(int $pid): bool {
20        if ($pid <= 0) {
21            return false;
22        }
23
24        if (function_exists('posix_kill')) {
25            return @posix_kill($pid, 0);
26        }
27
28        if (!function_exists('exec')) {
29            return false;
30        }
31
32        try {
33            exec(sprintf('kill -0 %d 2>/dev/null', $pid), $output, $exitCode);
34            return $exitCode === 0;
35        } catch (\Throwable $e) {
36            $this->logger->debug('Failed to probe process status', [
37                'pid' => $pid,
38                'error' => $e->getMessage(),
39            ]);
40            return false;
41        }
42    }
43
44    public function stopPid(int $pid, int $signal = SIGTERM): bool {
45        if ($pid <= 0) {
46            return false;
47        }
48
49        return $this->sendSignal($pid, $signal);
50    }
51
52    protected function sendSignal(int $pid, int $signal): bool {
53        if (function_exists('posix_kill')) {
54            return @posix_kill($pid, $signal);
55        }
56
57        if (!function_exists('exec')) {
58            return false;
59        }
60
61        try {
62            exec(sprintf('kill -%d %d 2>/dev/null', $signal, $pid), $output, $exitCode);
63            return $exitCode === 0;
64        } catch (\Throwable $e) {
65            $this->logger->debug('Failed to terminate process', [
66                'pid' => $pid,
67                'signal' => $signal,
68                'error' => $e->getMessage(),
69            ]);
70            return false;
71        }
72    }
73
74}