Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions lib/OperatingSystems/FreeBSD.php
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,8 @@ public function getDiskInfo(): array {
$matches = [];
// `df -P` prints one record per line with the mount point last, so the mount
// point is everything after the capacity column. Used and Capacity are loose
// because nothing reads them and `df` prints "-" for filesystems without
// usage numbers.
// because nothing reads them and `df` prints "-" in those two columns when
// it has no usage numbers.
$pattern = '/^(?<Filesystem>\S+)[ \t]+(?<Type>\S+)[ \t]+(?<Blocks>\d+)[ \t]+(?<Used>\S+)[ \t]+(?<Available>\d+)[ \t]+(?<Capacity>\S+)[ \t]+(?<Mounted>\S.*?)[ \t\r]*$/m';

$result = preg_match_all($pattern, $disks, $matches);
Expand All @@ -204,13 +204,17 @@ public function getDiskInfo(): array {
continue;
}

$blocks = (int)$matches['Blocks'][$i];
$available = (int)$matches['Available'][$i];
// Clamped: more available than total would give a negative size
$used = max(0, $blocks - $available);

$disk = new Disk();
$disk->setDevice($filesystem);
$disk->setFs($matches['Type'][$i]);
$used = (int)((int)$matches['Blocks'][$i] - (int)$matches['Available'][$i]);
$disk->setUsed((int)ceil($used / 1024));
$disk->setAvailable((int)floor((int)$matches['Available'][$i] / 1024));
$disk->setPercent(round(($used * 100 / (int)$matches['Blocks'][$i]), 2) . '%');
$disk->setAvailable((int)floor($available / 1024));
$disk->setPercent($blocks > 0 ? (string)round($used * 100 / $blocks, 2) . '%' : '0%');
$disk->setMount($matches['Mounted'][$i]);

$data[] = $disk;
Expand Down
15 changes: 10 additions & 5 deletions lib/OperatingSystems/Linux.php
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,8 @@ public function getDiskInfo(): array {
$matches = [];
// `df -P` prints one record per line with the mount point last, so the mount
// point is everything after the capacity column. Used and Capacity are loose
// because nothing reads them and `df` prints "-" for filesystems without
// usage numbers.
// because nothing reads them and `df` prints "-" in those two columns when
// it has no usage numbers.
$pattern = '/^(?<Filesystem>\S+)[ \t]+(?<Type>\S+)[ \t]+(?<Blocks>\d+)[ \t]+(?<Used>\S+)[ \t]+(?<Available>\d+)[ \t]+(?<Capacity>\S+)[ \t]+(?<Mounted>\S.*?)[ \t\r]*$/m';

$result = preg_match_all($pattern, $disks, $matches);
Expand All @@ -224,13 +224,18 @@ public function getDiskInfo(): array {
continue;
}

$blocks = (int)$matches['Blocks'][$i];
$available = (int)$matches['Available'][$i];
// Clamped: more available than total would give a negative size
$used = max(0, $blocks - $available);

$disk = new Disk();
$disk->setDevice($filesystem);
$disk->setFs($matches['Type'][$i]);
$used = (int)((int)$matches['Blocks'][$i] - (int)$matches['Available'][$i]);
$disk->setUsed((int)ceil($used / 1024));
$disk->setAvailable((int)floor((int)$matches['Available'][$i] / 1024));
$disk->setPercent(round(($used * 100 / (int)$matches['Blocks'][$i]), 2) . '%');
$disk->setAvailable((int)floor($available / 1024));
// busybox df lists zero-block filesystems, coreutils does not
$disk->setPercent($blocks > 0 ? (string)round($used * 100 / $blocks, 2) . '%' : '0%');
$disk->setMount($matches['Mounted'][$i]);

$data[] = $disk;
Expand Down
4 changes: 4 additions & 0 deletions tests/data/freebsd_df_tp_edge_cases
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Filesystem Type 1024-blocks Used Available Capacity Mounted on
/dev/gpt/rootfs ufs 56422560 6205468 47321220 12% /
empty nullfs 0 0 0 0% /mnt/empty
inverted zfs 1000 0 2000 0% /tank
4 changes: 4 additions & 0 deletions tests/data/linux_df_tp_edge_cases
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Filesystem Type 1024-blocks Used Available Capacity Mounted on
/dev/vda1 ext4 56422560 6205468 47321220 12% /
nsfs nsfs 0 0 0 0% /run/snapd/ns
inverted zfs 1000 0 2000 0% /tank
34 changes: 34 additions & 0 deletions tests/lib/FreeBSDTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,40 @@ public function testGetNetworkInterfacesError(): void {
$this->assertEquals($expected, $actual);
}

public function testGetDiskInfoZeroCapacityAndInvertedUsage(): void {
$this->os->method('executeCommand')
->with('df -TPk')
->willReturn(file_get_contents(__DIR__ . '/../data/freebsd_df_tp_edge_cases'));

$disk1 = new Disk();
$disk1->setDevice('/dev/gpt/rootfs');
$disk1->setFs('ufs');
$disk1->setUsed(8889);
$disk1->setAvailable(46212);
$disk1->setPercent('16.13%');
$disk1->setMount('/');

// Zero blocks: used to be a DivisionByZeroError
$disk2 = new Disk();
$disk2->setDevice('empty');
$disk2->setFs('nullfs');
$disk2->setUsed(0);
$disk2->setAvailable(0);
$disk2->setPercent('0%');
$disk2->setMount('/mnt/empty');

// More available than total: used is clamped
$disk3 = new Disk();
$disk3->setDevice('inverted');
$disk3->setFs('zfs');
$disk3->setUsed(0);
$disk3->setAvailable(1);
$disk3->setPercent('0%');
$disk3->setMount('/tank');

$this->assertEquals([$disk1, $disk2, $disk3], $this->os->getDiskInfo());
}

public function testSupported(): void {
$this->assertFalse($this->os->supported());
}
Expand Down
40 changes: 37 additions & 3 deletions tests/lib/LinuxTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -235,17 +235,51 @@ public function testGetDiskInfo(): void {
$this->assertEquals([$disk1, $disk2, $disk3, $disk4, $disk5, $disk6, $disk7], $this->os->getDiskInfo());
}

public function testGetDiskInfoZeroCapacityAndInvertedUsage(): void {
$this->os->method('executeCommand')
->with('df -TPk')
->willReturn(file_get_contents(__DIR__ . '/../data/linux_df_tp_edge_cases'));

$disk1 = new Disk();
$disk1->setDevice('/dev/vda1');
$disk1->setFs('ext4');
$disk1->setUsed(8889);
$disk1->setAvailable(46212);
$disk1->setPercent('16.13%');
$disk1->setMount('/');

// Zero blocks: used to be a DivisionByZeroError
$disk2 = new Disk();
$disk2->setDevice('nsfs');
$disk2->setFs('nsfs');
$disk2->setUsed(0);
$disk2->setAvailable(0);
$disk2->setPercent('0%');
$disk2->setMount('/run/snapd/ns');

// More available than total: used is clamped
$disk3 = new Disk();
$disk3->setDevice('inverted');
$disk3->setFs('zfs');
$disk3->setUsed(0);
$disk3->setAvailable(1);
$disk3->setPercent('0%');
$disk3->setMount('/tank');

$this->assertEquals([$disk1, $disk2, $disk3], $this->os->getDiskInfo());
}

public function testGetDiskInfoNoCommandOutput(): void {
$this->os->method('executeCommand')
->with('df -TP')
->willThrowException(new RuntimeException('No output for command "df -TP"'));
->with('df -TPk')
->willThrowException(new RuntimeException('No output for command "df -TPk"'));

$this->assertEquals([], $this->os->getDiskInfo());
}

public function testGetDiskInfoInvalidCommandOutput(): void {
$this->os->method('executeCommand')
->with('df -TP')
->with('df -TPk')
->willReturn('invalid_data');

$this->assertEquals([], $this->os->getDiskInfo());
Expand Down
2 changes: 0 additions & 2 deletions tests/psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@
<InvalidOperand>
<code><![CDATA[$lines[0] / 1024 / 1024]]></code>
<code><![CDATA[($lines[1] * ($lines[2] + $lines[3] + $lines[4])) / 1024 / 1024]]></code>
<code><![CDATA[round(($used * 100 / (int)$matches['Blocks'][$i]), 2)]]></code>
</InvalidOperand>
</file>
<file src="lib/OperatingSystems/Linux.php">
Expand All @@ -62,7 +61,6 @@
</ForbiddenCode>
<InvalidOperand>
<code><![CDATA[$speed / 1000]]></code>
<code><![CDATA[round(($used * 100 / (int)$matches['Blocks'][$i]), 2)]]></code>
</InvalidOperand>
</file>
<file src="lib/Os.php">
Expand Down
Loading