Revision b146b9b3
Added by Christian McDonald almost 4 years ago
src/usr/local/pfSense/include/Services/Filesystem/DF.php | ||
---|---|---|
1 |
<?php |
|
2 |
/* |
|
3 |
* DF.php |
|
4 |
* |
|
5 |
* part of pfSense (https://www.pfsense.org) |
|
6 |
* Copyright (c) 2021 Rubicon Communications, LLC (Netgate) |
|
7 |
* All rights reserved. |
|
8 |
* |
|
9 |
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
10 |
* you may not use this file except in compliance with the License. |
|
11 |
* You may obtain a copy of the License at |
|
12 |
* |
|
13 |
* http://www.apache.org/licenses/LICENSE-2.0 |
|
14 |
* |
|
15 |
* Unless required by applicable law or agreed to in writing, software |
|
16 |
* distributed under the License is distributed on an "AS IS" BASIS, |
|
17 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
18 |
* See the License for the specific language governing permissions and |
|
19 |
* limitations under the License. |
|
20 |
*/ |
|
21 |
|
|
22 |
namespace pfSense\Services\Filesystem; |
|
23 |
|
|
24 |
use mikehaertl\shellcommand\Command; |
|
25 |
|
|
26 |
use Symfony\Contracts\Cache\ItemInterface; |
|
27 |
use Symfony\Component\Cache\Adapter\AbstractAdapter; |
|
28 |
use Symfony\Component\Cache\Adapter\PhpFilesAdapter; |
|
29 |
|
|
30 |
// Pull in pfSense globals |
|
31 |
require_once('globals.inc'); |
|
32 |
|
|
33 |
final class DF { |
|
34 |
private const DF_PATH = '/bin/df'; |
|
35 |
|
|
36 |
private const DF_CACHE_KEY = 'DF'; |
|
37 |
|
|
38 |
private $cache = null; |
|
39 |
|
|
40 |
public function __construct(AbstractAdapter $cache = null) { |
|
41 |
global $g; |
|
42 |
|
|
43 |
if (is_null($cache) || (!($cache instanceof AbstractAdapter))) { |
|
44 |
$cache = new PhpFilesAdapter( |
|
45 |
$namespace = $g['product_name'], |
|
46 |
$defaultLifetime = 30, |
|
47 |
$directory = "{$g['tmp_path']}/symfony-cache" |
|
48 |
); |
|
49 |
} |
|
50 |
|
|
51 |
$this->cache = $cache; |
|
52 |
} |
|
53 |
|
|
54 |
public function getCache() { |
|
55 |
return $this->cache; |
|
56 |
} |
|
57 |
|
|
58 |
public function setCache(AbstractAdapter $cache) { |
|
59 |
$this->cache = $cache; |
|
60 |
|
|
61 |
return $this; |
|
62 |
} |
|
63 |
|
|
64 |
public function flushCache() { |
|
65 |
$this->getCache()->delete(self::DF_CACHE_KEY); |
|
66 |
} |
|
67 |
|
|
68 |
public function getDfData($flush = false) { |
|
69 |
if ($flush) { |
|
70 |
$this->flushCache(); |
|
71 |
} |
|
72 |
|
|
73 |
return $this->getCache()->get(self::DF_CACHE_KEY, function (ItemInterface $item, &$save) { |
|
74 |
$item->expiresAfter(30); |
|
75 |
|
|
76 |
$cmd = new Command(self::DF_PATH); |
|
77 |
|
|
78 |
$cmd->addArg('--libxo=json')->addArg('-h')->addArg('-T'); |
|
79 |
|
|
80 |
$cmd->execute(); |
|
81 |
|
|
82 |
$save = ($cmd->getExitCode() === 0) && !empty($cmd->getOutput()); |
|
83 |
|
|
84 |
$retArray = $save ? json_decode($cmd->getOutput(), true) : array(); |
|
85 |
|
|
86 |
array_walk_recursive($retArray, function (&$x) { $x = trim($x); }); |
|
87 |
|
|
88 |
return $retArray; |
|
89 |
}); |
|
90 |
} |
|
91 |
} |
|
92 |
|
|
93 |
?> |
src/usr/local/pfSense/include/Services/Filesystem/Filesystem.php | ||
---|---|---|
21 | 21 |
|
22 | 22 |
namespace pfSense\Services\Filesystem; |
23 | 23 |
|
24 |
use Nette\Utils\Arrays; |
|
25 |
use Nette\Utils\Strings; |
|
24 |
use Nette\Utils\{ |
|
25 |
Arrays, |
|
26 |
Strings |
|
27 |
}; |
|
26 | 28 |
|
27 | 29 |
final class Filesystem { |
30 |
private $parent = null; |
|
31 |
|
|
28 | 32 |
private $filesystem = []; |
29 | 33 |
|
30 |
public function __construct(array $filesystem) { |
|
31 |
$this->filesystem = $filesystem; |
|
34 |
private $children = []; |
|
35 |
|
|
36 |
public function __construct(?Filesystem $parent, $filesystem) { |
|
37 |
$this->_setParent($parent); |
|
38 |
|
|
39 |
$this->_setFilesystem($filesystem); |
|
40 |
|
|
41 |
$this->_initChildren(); |
|
32 | 42 |
} |
33 | 43 |
|
34 |
public function getProperty($key, $default = null) { |
|
35 |
return Arrays::Get($this->filesystem, $key, $default); |
|
44 |
public function getBasename() { |
|
45 |
$basename = $this->getPath(); |
|
46 |
|
|
47 |
if ($this->hasParent()) { |
|
48 |
|
|
49 |
if (Strings::startsWith($this->getPath(), $this->getParentPath())) { |
|
50 |
|
|
51 |
$basename = Strings::substring($basename, Strings::length($this->getParentPath())); |
|
52 |
|
|
53 |
} |
|
54 |
|
|
55 |
} |
|
56 |
|
|
57 |
return $basename; |
|
36 | 58 |
} |
37 | 59 |
|
38 | 60 |
public function getName() { |
39 |
return $this->getProperty('name'); |
|
61 |
return $this->_getProperty('name');
|
|
40 | 62 |
} |
41 | 63 |
|
42 |
public function getType() { |
|
43 |
return $this->getProperty('type'); |
|
64 |
public function hasParent() { |
|
65 |
$parent = $this->getParent(); |
|
66 |
|
|
67 |
return (!is_null($parent) && ($parent instanceof self)); |
|
44 | 68 |
} |
45 | 69 |
|
46 |
public function getUsedPercent() {
|
|
47 |
return $this->getProperty('used-percent');
|
|
70 |
public function getParent() {
|
|
71 |
return $this->parent;
|
|
48 | 72 |
} |
49 | 73 |
|
50 |
public function getPath() { |
|
51 |
return $this->getProperty('mounted-on');
|
|
74 |
public function getParentPath() {
|
|
75 |
return $this->hasParent() ? $this->getParent()->getPath() : null;
|
|
52 | 76 |
} |
53 | 77 |
|
54 |
public function getUsed() {
|
|
55 |
return $this->getProperty('used');
|
|
78 |
public function getPath() {
|
|
79 |
return $this->_getProperty('mounted-on');
|
|
56 | 80 |
} |
57 | 81 |
|
58 | 82 |
public function getSize() { |
59 |
return $this->getProperty('blocks'); |
|
83 |
return $this->_getProperty('blocks');
|
|
60 | 84 |
} |
61 | 85 |
|
62 |
public function getParentPath() {
|
|
63 |
return dirname($this->getPath(), 1);
|
|
86 |
public function getType() {
|
|
87 |
return $this->_getProperty('type');
|
|
64 | 88 |
} |
65 | 89 |
|
66 |
public function getHtmlClass() {
|
|
67 |
return Strings::webalize("root{$this->getPath()}");
|
|
90 |
public function getUsed() {
|
|
91 |
return $this->_getProperty('used');
|
|
68 | 92 |
} |
69 | 93 |
|
70 |
public function getParentHtmlClass() { |
|
71 |
return Strings::webalize("root{$this->getParentPath()}"); |
|
94 |
public function getUsedPercent() { |
|
95 |
return $this->_getProperty('used-percent'); |
|
96 |
} |
|
97 |
|
|
98 |
public function getHtmlClass(string $prefix = null, $parentPath = false) : string { |
|
99 |
$parent = $this->getParent(); |
|
100 |
|
|
101 |
$prefix = $this->hasParent() ? "{$parent->getHtmlClass($prefix)}-" : "{$prefix}root"; |
|
102 |
|
|
103 |
$suffix = $parentPath ? null : $this->getBasename(); |
|
104 |
|
|
105 |
return Strings::webalize("{$prefix}{$suffix}"); |
|
106 |
} |
|
107 |
|
|
108 |
public function getParentHtmlClass(string $prefix = null) : string { |
|
109 |
return $this->getHtmlClass($prefix, true); |
|
72 | 110 |
} |
73 | 111 |
|
74 | 112 |
public function isRoot() { |
75 | 113 |
return Strings::compare($this->getPath(), '/'); |
76 | 114 |
} |
115 |
|
|
116 |
public function getChildrenAndSelf() { |
|
117 |
$filesystems = [$this,]; |
|
118 |
|
|
119 |
foreach ($this->getChildren() as $child) { |
|
120 |
$children = $child->getChildrenAndSelf(); |
|
121 |
|
|
122 |
$filesystems = array_merge($filesystems, $children); |
|
123 |
} |
|
124 |
|
|
125 |
return $filesystems; |
|
126 |
} |
|
127 |
|
|
128 |
public function hasChildren() { |
|
129 |
return !empty($this->children); |
|
130 |
} |
|
131 |
|
|
132 |
public function getChildren() { |
|
133 |
if (empty($this->children)) { |
|
134 |
$this->_initChildren(); |
|
135 |
} |
|
136 |
|
|
137 |
return $this->children; |
|
138 |
} |
|
139 |
|
|
140 |
private function _getProperty($key, $default = null) { |
|
141 |
return Arrays::get($this->filesystem, $key, $default); |
|
142 |
} |
|
143 |
|
|
144 |
private function _initChildren() { |
|
145 |
$this->children = array_map(function($child) { |
|
146 |
return $this->_getNewFilesystemObject($child); |
|
147 |
}, $this->_getProperty('children')); |
|
148 |
} |
|
149 |
|
|
150 |
private function _setFilesystem($filesystem) { |
|
151 |
$this->filesystem = $filesystem; |
|
152 |
|
|
153 |
return $this; |
|
154 |
} |
|
155 |
|
|
156 |
private function _setParent(?Filesystem $parent) { |
|
157 |
$this->parent = $parent; |
|
158 |
|
|
159 |
return $this; |
|
160 |
} |
|
161 |
|
|
162 |
private function _getNewFilesystemObject($filesystem) { |
|
163 |
return (new Filesystem($this, $filesystem)); |
|
164 |
} |
|
77 | 165 |
} |
78 | 166 |
|
79 | 167 |
?> |
src/usr/local/pfSense/include/Services/Filesystem/Filesystems.php | ||
---|---|---|
21 | 21 |
|
22 | 22 |
namespace pfSense\Services\Filesystem; |
23 | 23 |
|
24 |
use Nette\Utils\Arrays; |
|
25 |
use Nette\Utils\Strings; |
|
24 |
use pfSense\Services\Filesystem\Provider\{ |
|
25 |
AbstractProvider, |
|
26 |
SystemProvider |
|
27 |
}; |
|
28 |
|
|
29 |
use Nette\Utils\{ |
|
30 |
Arrays, |
|
31 |
Strings |
|
32 |
}; |
|
26 | 33 |
|
27 | 34 |
final class Filesystems { |
28 | 35 |
private $filesystems = []; |
29 | 36 |
|
30 |
private $df = null;
|
|
37 |
private $provider = null;
|
|
31 | 38 |
|
32 |
public function __construct(DF $df = null) { |
|
33 |
if (is_null($df) || (!($df instanceof DF))) { |
|
34 |
$df = new DF(); |
|
39 |
public function __construct(AbstractProvider $provider = null) { |
|
40 |
if (is_null($provider) |
|
41 |
|| (!($df instanceof AbstractProvider))) { |
|
42 |
$provider = new SystemProvider(); |
|
35 | 43 |
} |
36 | 44 |
|
37 |
$this->df = $df;
|
|
45 |
$this->setProvider($provider);
|
|
38 | 46 |
|
39 | 47 |
$this->_initFilesystems(); |
40 | 48 |
} |
41 | 49 |
|
42 |
public function getDf() { |
|
43 |
return $this->df; |
|
44 |
} |
|
45 |
|
|
46 |
public function setDf(Df $df) { |
|
47 |
$this->__construct($df); |
|
50 |
public function setProvider(AbstractProvider $provider) { |
|
51 |
$this->provider = $provider; |
|
48 | 52 |
|
49 | 53 |
return $this; |
50 | 54 |
} |
51 | 55 |
|
52 |
public function getFilesystems(...$types) { |
|
53 |
$types = (is_array($types[0])) ? $types[0] : $types; |
|
56 |
public function getProvider() { |
|
57 |
return $this->provider; |
|
58 |
} |
|
54 | 59 |
|
55 |
return array_values(array_filter($this->filesystems, function ($fs) use ($types) { |
|
56 |
return (empty($types) || in_array($fs->getProperty('type'), $types)); |
|
57 |
})); |
|
60 |
public function flushProviderCache() { |
|
61 |
$this->getProvider()->flushCache(); |
|
58 | 62 |
} |
59 | 63 |
|
60 | 64 |
public function getRootFilesystem() { |
61 |
foreach ($this->getFilesystems() as $fs) {
|
|
65 |
foreach ($this->_getFilesystemsTree() as $fs) {
|
|
62 | 66 |
if ($fs->isRoot()) { |
63 | 67 |
return $fs; |
64 | 68 |
} |
... | ... | |
70 | 74 |
public function getNonRootFilesystems(...$types) { |
71 | 75 |
$types = (is_array($types[0])) ? $types[0] : $types; |
72 | 76 |
|
73 |
return array_values(array_filter($this->getFilesystems($types), function ($fs) {
|
|
77 |
return array_filter($this->getFilesystemsFlattened($types), function ($fs) {
|
|
74 | 78 |
return !$fs->isRoot(); |
75 |
}));
|
|
79 |
}); |
|
76 | 80 |
} |
77 | 81 |
|
78 | 82 |
public function getMounts(...$types) { |
79 | 83 |
$types = (is_array($types[0])) ? $types[0] : $types; |
80 | 84 |
|
81 | 85 |
return array_map(function($fs) { |
82 |
return $fs->getProperty('mounted-on');
|
|
83 |
}, $this->getFilesystems($types)); |
|
86 |
return $fs->getPath();
|
|
87 |
}, $this->getFilesystemsFlattened($types));
|
|
84 | 88 |
} |
85 | 89 |
|
86 |
private function _initFilesystems() { |
|
87 |
$df = $this->getDf()->getDfData(); |
|
90 |
public function getFilesystemsFlattened(...$types) { |
|
91 |
$types = (is_array($types[0])) ? $types[0] : $types; |
|
92 |
|
|
93 |
$filesystems = []; |
|
88 | 94 |
|
89 |
$filesystems = Arrays::get($df, ['storage-system-information', 'filesystem'], array()); |
|
95 |
foreach($this->_getFilesystemsTree() as $filesystem) { |
|
96 |
$filtered = array_filter($filesystem->getChildrenAndSelf(), function($fs) use ($types) { |
|
97 |
return (empty($types) || in_array($fs->getType(), $types)); |
|
98 |
}); |
|
90 | 99 |
|
91 |
foreach ($filesystems as $filesystem) { |
|
92 |
$filesystem = $this->_getNewFilesystemObject($filesystem); |
|
93 |
|
|
94 |
$this->filesystems[$filesystem->getProperty('mounted-on')] = $filesystem; |
|
100 |
$filesystems = array_merge($filesystems, $filtered); |
|
95 | 101 |
} |
96 | 102 |
|
97 |
usort($this->filesystems, function ($fs1, $fs2) { |
|
98 |
return $fs1->getProperty('mounted-on') <=> $fs2->getProperty('mounted-on'); |
|
99 |
}); |
|
103 |
return $filesystems; |
|
104 |
} |
|
105 |
|
|
106 |
public function _getFilesystemsTree() { |
|
107 |
if (empty($this->filesystems)){ |
|
108 |
$this->_initFilesystems(); |
|
109 |
} |
|
110 |
|
|
111 |
return $this->filesystems; |
|
112 |
} |
|
113 |
|
|
114 |
private function _initFilesystems() { |
|
115 |
$this->filesystems = array_map(function($filesystem) { |
|
116 |
return $this->_getNewFilesystemObject($filesystem); |
|
117 |
}, $this->getProvider()->getFilesystems()); |
|
100 | 118 |
} |
101 | 119 |
|
102 | 120 |
private function _getNewFilesystemObject($filesystem) { |
103 |
return (new Filesystem($filesystem)); |
|
121 |
return (new Filesystem(null, $filesystem));
|
|
104 | 122 |
} |
105 | 123 |
} |
106 | 124 |
|
src/usr/local/pfSense/include/Services/Filesystem/Provider/AbstractProvider.php | ||
---|---|---|
1 |
<?php |
|
2 |
/* |
|
3 |
* AbstractProvider.php |
|
4 |
* |
|
5 |
* part of pfSense (https://www.pfsense.org) |
|
6 |
* Copyright (c) 2021 Rubicon Communications, LLC (Netgate) |
|
7 |
* All rights reserved. |
|
8 |
* |
|
9 |
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
10 |
* you may not use this file except in compliance with the License. |
|
11 |
* You may obtain a copy of the License at |
|
12 |
* |
|
13 |
* http://www.apache.org/licenses/LICENSE-2.0 |
|
14 |
* |
|
15 |
* Unless required by applicable law or agreed to in writing, software |
|
16 |
* distributed under the License is distributed on an "AS IS" BASIS, |
|
17 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
18 |
* See the License for the specific language governing permissions and |
|
19 |
* limitations under the License. |
|
20 |
*/ |
|
21 |
|
|
22 |
namespace pfSense\Services\Filesystem\Provider; |
|
23 |
|
|
24 |
use mikehaertl\shellcommand\Command; |
|
25 |
|
|
26 |
use Nette\Utils\{ |
|
27 |
Arrays, |
|
28 |
Strings |
|
29 |
}; |
|
30 |
|
|
31 |
use Symfony\{ |
|
32 |
Contracts\Cache\ItemInterface, |
|
33 |
Component\Cache\Adapter\AbstractAdapter, |
|
34 |
Component\Cache\Adapter\PhpFilesAdapter |
|
35 |
}; |
|
36 |
|
|
37 |
abstract class AbstractProvider { |
|
38 |
private $cacheAdapter = null; |
|
39 |
|
|
40 |
public function __construct(AbstractAdapter $cacheAdapter = null) { |
|
41 |
if (is_null($cacheAdapter) || (!($cacheAdapter instanceof AbstractAdapter))) { |
|
42 |
require_once('globals.inc'); |
|
43 |
|
|
44 |
global $g; |
|
45 |
|
|
46 |
$tmpPath = Arrays::get($g, 'tmp_path', '/tmp'); |
|
47 |
|
|
48 |
$cacheAdapter = new PhpFilesAdapter( |
|
49 |
$namespace = 'filesystem', |
|
50 |
$defaultLifetime = 10, |
|
51 |
$directory = "{$tmpPath}/symfony-cache" |
|
52 |
); |
|
53 |
} |
|
54 |
|
|
55 |
$this->setCacheAdapter($cacheAdapter); |
|
56 |
} |
|
57 |
|
|
58 |
public function setCacheAdapter(AbstractAdapter $cacheAdapter) { |
|
59 |
$this->cacheAdapter = $cacheAdapter; |
|
60 |
|
|
61 |
return $this; |
|
62 |
} |
|
63 |
|
|
64 |
public function getCacheAdapter() { |
|
65 |
return $this->cacheAdapter; |
|
66 |
} |
|
67 |
|
|
68 |
abstract function getFilesystems(); |
|
69 |
} |
|
70 |
|
|
71 |
?> |
src/usr/local/pfSense/include/Services/Filesystem/Provider/SystemProvider.php | ||
---|---|---|
1 |
<?php |
|
2 |
/* |
|
3 |
* SystemProvider.php |
|
4 |
* |
|
5 |
* part of pfSense (https://www.pfsense.org) |
|
6 |
* Copyright (c) 2021 Rubicon Communications, LLC (Netgate) |
|
7 |
* All rights reserved. |
|
8 |
* |
|
9 |
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
10 |
* you may not use this file except in compliance with the License. |
|
11 |
* You may obtain a copy of the License at |
|
12 |
* |
|
13 |
* http://www.apache.org/licenses/LICENSE-2.0 |
|
14 |
* |
|
15 |
* Unless required by applicable law or agreed to in writing, software |
|
16 |
* distributed under the License is distributed on an "AS IS" BASIS, |
|
17 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
18 |
* See the License for the specific language governing permissions and |
|
19 |
* limitations under the License. |
|
20 |
*/ |
|
21 |
|
|
22 |
namespace pfSense\Services\Filesystem\Provider; |
|
23 |
|
|
24 |
use mikehaertl\shellcommand\Command; |
|
25 |
|
|
26 |
use Nette\Utils\{ |
|
27 |
Arrays, |
|
28 |
Strings |
|
29 |
}; |
|
30 |
|
|
31 |
use Symfony\{ |
|
32 |
Contracts\Cache\ItemInterface, |
|
33 |
Component\Cache\Adapter\AbstractAdapter, |
|
34 |
Component\Cache\Adapter\PhpFilesAdapter |
|
35 |
}; |
|
36 |
|
|
37 |
final class SystemProvider extends AbstractProvider { |
|
38 |
private const DF_BINARY_PATH = '/bin/df'; |
|
39 |
|
|
40 |
public function getFilesystems() { |
|
41 |
$roots = []; |
|
42 |
|
|
43 |
foreach ($this->_queryFilesystemProvider() as $idx => $filesystem) { |
|
44 |
$path = Arrays::get($filesystem, 'mounted-on', null); |
|
45 |
|
|
46 |
$filesystems[$path] = $filesystem; |
|
47 |
|
|
48 |
$filesystems[$path]['children'] = []; |
|
49 |
|
|
50 |
$parent = $this->_getParentFilesystemPath($path); |
|
51 |
|
|
52 |
$filesystems[$parent]['children'][$path] = &Arrays::getRef($filesystems, $path); |
|
53 |
|
|
54 |
if (is_null($parent)) { |
|
55 |
$roots[$path] = $path; |
|
56 |
} |
|
57 |
} |
|
58 |
|
|
59 |
return array_filter($filesystems, function($filesystem) use ($roots) { |
|
60 |
return array_key_exists($filesystem, $roots); |
|
61 |
}, ARRAY_FILTER_USE_KEY); |
|
62 |
} |
|
63 |
|
|
64 |
public function flushCache() { |
|
65 |
$this->getCacheAdapter()->prune(); |
|
66 |
} |
|
67 |
public function _getParentFilesystemPath($path) { |
|
68 |
$filesystems = $this->_queryFilesystemProvider(); |
|
69 |
|
|
70 |
foreach (array_reverse($filesystems) as $filesystem) { |
|
71 |
$mount = Arrays::get($filesystem, 'mounted-on', null); |
|
72 |
|
|
73 |
if (!Strings::compare($path, $mount) |
|
74 |
&& Strings::startsWith($path, $mount)) { |
|
75 |
return $mount; |
|
76 |
} |
|
77 |
} |
|
78 |
} |
|
79 |
|
|
80 |
private function _queryFilesystemProvider() { |
|
81 |
$cacheKey = Strings::webalize(__METHOD__); |
|
82 |
|
|
83 |
return $this->getCacheAdapter()->get($cacheKey, function (ItemInterface $item, &$save) { |
|
84 |
$cmd = new Command(self::DF_BINARY_PATH); |
|
85 |
|
|
86 |
$cmd->addArg('--libxo=json')->addArg('-h')->addArg('-T'); |
|
87 |
|
|
88 |
$cmd->execute(); |
|
89 |
|
|
90 |
$save = ($cmd->getExitCode() === 0) && !empty($cmd->getOutput()); |
|
91 |
|
|
92 |
$retArray = $save ? json_decode($cmd->getOutput(), true) : array(); |
|
93 |
|
|
94 |
array_walk_recursive($retArray, function (&$x) { $x = trim($x); }); |
|
95 |
|
|
96 |
$filesystems = Arrays::get($retArray, ['storage-system-information', 'filesystem'], array()); |
|
97 |
|
|
98 |
usort($filesystems, function($a, $b) { |
|
99 |
return (Arrays::get($a, 'mounted-on', null) <=> Arrays::get($b, 'mounted-on', null)); |
|
100 |
}); |
|
101 |
|
|
102 |
return $filesystems; |
|
103 |
}); |
|
104 |
} |
|
105 |
} |
|
106 |
|
|
107 |
?> |
src/usr/local/www/widgets/include/disks.inc | ||
---|---|---|
21 | 21 |
|
22 | 22 |
require_once('vendor/autoload.php'); |
23 | 23 |
|
24 |
use pfSense\Services\Filesystem\DF; |
|
25 |
use pfSense\Services\Filesystem\Filesystem; |
|
26 |
use pfSense\Services\Filesystem\Filesystems; |
|
24 |
use pfSense\Services\Filesystem\{ |
|
25 |
Filesystem, |
|
26 |
Filesystems, |
|
27 |
Provider\SystemProvider, |
|
28 |
}; |
|
27 | 29 |
|
28 | 30 |
use Nette\Utils\Html; |
29 | 31 |
|
... | ... | |
35 | 37 |
'disk_filter' => null, |
36 | 38 |
'autoshow_threshold' => 75); |
37 | 39 |
|
40 |
// Initialize the Filesystems service |
|
41 |
$filesystems = new Filesystems(); |
|
42 |
|
|
38 | 43 |
function disks_do_widget_settings_post($post, $user_settings) { |
39 |
global $disks_types, $disks_widget_defaults; |
|
44 |
global $disks_types, $disks_widget_defaults, $filesystems;
|
|
40 | 45 |
|
41 | 46 |
// start with widget defaults |
42 | 47 |
$pconfig = $disks_widget_defaults; |
... | ... | |
57 | 62 |
|
58 | 63 |
// Check if the posted disk_filter is valid, if so set it... |
59 | 64 |
if (!empty($disk_filter) && is_array($disk_filter)) { |
60 |
$valid_mounts = (new Filesystems())->getMounts($disks_types);
|
|
65 |
$valid_mounts = $filesystems->getMounts($disks_types);
|
|
61 | 66 |
|
62 | 67 |
// Filter out any invalid mounts |
63 | 68 |
$disk_filter = array_filter($disk_filter, function($mount) use ($valid_mounts) { |
... | ... | |
164 | 169 |
} |
165 | 170 |
|
166 | 171 |
function disk_compose_root_filesystem_row() { |
167 |
$fs = (new Filesystems())->getRootFilesystem(); |
|
172 |
global $filesystems; |
|
173 |
|
|
174 |
$fs = $filesystems->getRootFilesystem(); |
|
168 | 175 |
|
169 | 176 |
$tr = Html::el('tr'); |
170 | 177 |
|
... | ... | |
193 | 200 |
} |
194 | 201 |
|
195 | 202 |
function disks_compose_widget_user_body($widget_config) { |
196 |
global $disks_types; |
|
203 |
global $disks_types, $filesystems;
|
|
197 | 204 |
|
198 | 205 |
$has_user_row = false; |
199 | 206 |
|
... | ... | |
202 | 209 |
$disk_filter = explode(',', $widget_config['disk_filter']); |
203 | 210 |
|
204 | 211 |
$autoshow_threshold = $widget_config['autoshow_threshold']; |
205 |
|
|
206 |
$fss = (new Filesystems())->getNonRootFilesystems($disks_types); |
|
207 | 212 |
|
208 |
foreach ($fss as $fs) {
|
|
213 |
foreach ($filesystems->getNonRootFilesystems($disks_types) as $fs) {
|
|
209 | 214 |
if (in_array($fs->getPath(), $disk_filter) |
210 | 215 |
|| (($autoshow_threshold != 0) && ($fs->getUsedPercent() >= $autoshow_threshold))) { |
211 | 216 |
$has_user_row = true; |
... | ... | |
239 | 244 |
} |
240 | 245 |
|
241 | 246 |
function disks_compose_widget_tree_body() { |
242 |
global $disks_types; |
|
247 |
global $disks_types, $filesystems;
|
|
243 | 248 |
|
244 | 249 |
$tbody = Html::el('tbody'); |
245 | 250 |
|
246 | 251 |
$tbody->addHtml(disk_compose_root_filesystem_row()); |
247 | 252 |
|
248 |
$fss = (new Filesystems())->getNonRootFilesystems($disks_types); |
|
249 |
|
|
250 |
foreach ($fss as $fs) { |
|
253 |
foreach ($filesystems->getNonRootFilesystems($disks_types) as $fs) { |
|
251 | 254 |
$tr = Html::el('tr'); |
252 | 255 |
|
253 | 256 |
$tr->setAttribute('class', "treegrid-{$fs->getHtmlClass()} treegrid-parent-{$fs->getParentHtmlClass()}"); |
... | ... | |
278 | 281 |
} |
279 | 282 |
|
280 | 283 |
function disks_get_nonroot_filesystems() { |
281 |
global $disks_types; |
|
284 |
global $disks_types, $filesystems;
|
|
282 | 285 |
|
283 |
return (new Filesystems())->getNonRootFilesystems($disks_types);
|
|
286 |
return $filesystems->getNonRootFilesystems($disks_types);
|
|
284 | 287 |
} |
285 | 288 |
|
286 | 289 |
function disks_cache_invalidate($force = false, $chancef = 0.1) { |
290 |
global $filesystems; |
|
291 |
|
|
287 | 292 |
if (((rand() / getrandmax()) < $chancef) || $force) { |
288 |
(new DF)->flushCache();
|
|
293 |
$filesystems->flushProviderCache();
|
|
289 | 294 |
} |
290 | 295 |
} |
291 | 296 |
|
src/usr/local/www/widgets/widgets/disks.widget.php | ||
---|---|---|
28 | 28 |
// Widget includes |
29 | 29 |
require_once('/usr/local/www/widgets/include/disks.inc'); |
30 | 30 |
|
31 |
// Randomly invalidate the cache on page refresh... |
|
32 |
disks_cache_invalidate(false, 0.1); |
|
33 |
|
|
34 | 31 |
global $disks_widget_defaults; |
35 | 32 |
|
36 | 33 |
$widgetkey = (isset($_POST['widgetkey'])) ? $_POST['widgetkey'] : $widgetkey; |
... | ... | |
38 | 35 |
// Now overide any defaults with user settings |
39 | 36 |
$widget_config = array_replace($disks_widget_defaults, (array) $user_settings['widgets'][$widgetkey]); |
40 | 37 |
|
38 |
// Randomly invalidate the cache, 25% chance. |
|
39 |
disks_cache_invalidate(false, 0.25); |
|
40 |
|
|
41 | 41 |
// Are we handling an ajax refresh? |
42 | 42 |
if (isset($_POST['ajax'])) { |
43 |
disks_cache_invalidate(true); |
|
44 |
|
|
45 | 43 |
print(disks_compose_widget_table($widget_config)); |
46 | 44 |
|
47 | 45 |
// We are done here... |
Also available in: Unified diff
Fix Disks widget UI on UFS systems
```
PHP 7.4.22 | 10 parallel jobs
............................................................ 60/279 (21 %)
............................................................ 120/279 (43 %)
............................................................ 180/279 (64 %)
............................................................ 240/279 (86 %)
....................................... 279/279 (100 %)
Checked 279 files in 0.9 seconds
No syntax error found
```