Skip to content

Commit 3009da3

Browse files
Merge pull request #43968 from exi/custom-binary-search-paths
feat: make search path for BinaryFinder customizable.
2 parents 2ba3f7e + ef7e857 commit 3009da3

File tree

3 files changed

+118
-10
lines changed

3 files changed

+118
-10
lines changed

config/config.sample.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2533,4 +2533,20 @@
25332533
* Defaults to ``true``
25342534
*/
25352535
'enable_non-accessible_features' => true,
2536+
2537+
/**
2538+
* Directories where nextcloud looks for binaries.
2539+
* This is used to find external binaries like libreoffice, sendmail, ffmpeg and more.
2540+
*
2541+
* Defaults to ``['/usr/local/sbin','/usr/local/bin','/usr/sbin','/usr/bin','/sbin','/bin','/opt/bin']``
2542+
*/
2543+
'binary_search_paths' => [
2544+
'/usr/local/sbin',
2545+
'/usr/local/bin',
2546+
'/usr/sbin',
2547+
'/usr/bin',
2548+
'/sbin',
2549+
'/bin',
2550+
'/opt/bin',
2551+
],
25362552
];

lib/private/BinaryFinder.php

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,28 @@
1111
use OCP\IBinaryFinder;
1212
use OCP\ICache;
1313
use OCP\ICacheFactory;
14+
use OCP\IConfig;
1415
use Symfony\Component\Process\ExecutableFinder;
1516

1617
/**
1718
* Service that find the binary path for a program
1819
*/
1920
class BinaryFinder implements IBinaryFinder {
21+
public const DEFAULT_BINARY_SEARCH_PATHS = [
22+
'/usr/local/sbin',
23+
'/usr/local/bin',
24+
'/usr/sbin',
25+
'/usr/bin',
26+
'/sbin',
27+
'/bin',
28+
'/opt/bin',
29+
];
2030
private ICache $cache;
2131

22-
public function __construct(ICacheFactory $cacheFactory) {
32+
public function __construct(
33+
ICacheFactory $cacheFactory,
34+
private IConfig $config,
35+
) {
2336
$this->cache = $cacheFactory->createLocal('findBinaryPath');
2437
}
2538

@@ -37,15 +50,10 @@ public function findBinaryPath(string $program) {
3750
if (\OCP\Util::isFunctionEnabled('exec')) {
3851
$exeSniffer = new ExecutableFinder();
3952
// Returns null if nothing is found
40-
$result = $exeSniffer->find($program, null, [
41-
'/usr/local/sbin',
42-
'/usr/local/bin',
43-
'/usr/sbin',
44-
'/usr/bin',
45-
'/sbin',
46-
'/bin',
47-
'/opt/bin',
48-
]);
53+
$result = $exeSniffer->find(
54+
$program,
55+
null,
56+
$this->config->getSystemValue('binary_search_paths', self::DEFAULT_BINARY_SEARCH_PATHS));
4957
if ($result === null) {
5058
$result = false;
5159
}

tests/lib/BinaryFinderTest.php

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
/**
5+
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
6+
* SPDX-License-Identifier: AGPL-3.0-or-later
7+
*/
8+
9+
namespace Test;
10+
11+
use OC\BinaryFinder;
12+
use OC\Memcache\ArrayCache;
13+
use OCP\ICache;
14+
use OCP\ICacheFactory;
15+
use OCP\IConfig;
16+
17+
class BinaryFinderTest extends TestCase {
18+
private ICache $cache;
19+
private ICacheFactory $cacheFactory;
20+
private $oldEnv;
21+
22+
protected function setUp(): void {
23+
$this->oldEnv = getenv('PATH');
24+
// BinaryFinder always includes the "PATH" environment variable into the search path,
25+
// which we want to avoid in this test because they are not usually found in webserver
26+
// deployments.
27+
putenv('PATH=""');
28+
$this->cacheFactory = $this->createMock(ICacheFactory::class);
29+
$this->cache = new ArrayCache();
30+
$this->cacheFactory->method('createLocal')->with('findBinaryPath')->willReturn($this->cache);
31+
}
32+
33+
protected function tearDown(): void {
34+
putenv('PATH=' . $this->oldEnv);
35+
}
36+
37+
public function testDefaultFindsCat() {
38+
$config = $this->createMock(IConfig::class);
39+
$config
40+
->method('getSystemValue')
41+
->with('binary_search_paths', $this->anything())
42+
->will($this->returnCallback(function ($key, $default) {
43+
return $default;
44+
}));
45+
$finder = new BinaryFinder($this->cacheFactory, $config);
46+
$this->assertEquals($finder->findBinaryPath('cat'), '/usr/bin/cat');
47+
$this->assertEquals($this->cache->get('cat'), '/usr/bin/cat');
48+
}
49+
50+
public function testDefaultDoesNotFindCata() {
51+
$config = $this->createMock(IConfig::class);
52+
$config
53+
->method('getSystemValue')
54+
->with('binary_search_paths', $this->anything())
55+
->will($this->returnCallback(function ($key, $default) {
56+
return $default;
57+
}));
58+
$finder = new BinaryFinder($this->cacheFactory, $config);
59+
$this->assertFalse($finder->findBinaryPath('cata'));
60+
$this->assertFalse($this->cache->get('cata'));
61+
}
62+
63+
public function testCustomPathFindsCat() {
64+
$config = $this->createMock(IConfig::class);
65+
$config
66+
->method('getSystemValue')
67+
->with('binary_search_paths', $this->anything())
68+
->willReturn(['/usr/bin']);
69+
$finder = new BinaryFinder($this->cacheFactory, $config);
70+
$this->assertEquals($finder->findBinaryPath('cat'), '/usr/bin/cat');
71+
$this->assertEquals($this->cache->get('cat'), '/usr/bin/cat');
72+
}
73+
74+
public function testWrongCustomPathDoesNotFindCat() {
75+
$config = $this->createMock(IConfig::class);
76+
$config
77+
->method('getSystemValue')
78+
->with('binary_search_paths')
79+
->willReturn(['/wrong']);
80+
$finder = new BinaryFinder($this->cacheFactory, $config);
81+
$this->assertFalse($finder->findBinaryPath('cat'));
82+
$this->assertFalse($this->cache->get('cat'));
83+
}
84+
}

0 commit comments

Comments
 (0)