') { $storePoint = '/'; $currentSource = $wantedSource; } else { $storePoint = CONFIG_VMSTORE_DIR; $currentSource = false; } // Collect free space information foreach ($task['data']['list'] as $entry) { // StorePoint is either the actual directory of the vmstore, or / if we use internal storage if ($entry['mountPoint'] === $storePoint) { $storeUsage = $entry; } // Always report free space on system disk if ($entry['mountPoint'] === '/') { $systemUsage = $entry; } // Record what's mounted at destination, regardless of config, to indicate something is wrong if ($entry['mountPoint'] === CONFIG_VMSTORE_DIR) { $currentSource = $entry['fileSystem']; // If internal/local storage is used but there is a mount on CONFIG_VMSTORE_DIR, // we assume it's on purpose like a second hdd and use that if ($wantedSource === '') { $wantedSource = $currentSource; $storeUsage = $entry; } } } return true; } /** * Get timestamp of the available updates. This is an estimate; the downloaded apt data usually * preserves the Last-Modified timestamp from the HTTP download of the according data. Note * that this list gets updated whenever any available package changes, so it does not necessarily * mean that any currently installed package can be updated when the list changes. */ public static function getAptLastDbUpdateTime(): int { $osRelease = parse_ini_file('/etc/os-release'); $updateDbTime = 0; foreach (glob('/var/lib/apt/lists/*_dists_' . ($osRelease['VERSION_CODENAME'] ?? '') . '*_InRelease', GLOB_NOSORT) as $f) { $b = basename($f); if (preg_match('/dists_[a-z]+(?:[\-_](?:updates|security))?_InRelease$/', $b)) { $updateDbTime = max($updateDbTime, filemtime($f)); } } return $updateDbTime; } /** * Get timestamp when the apt database was last attempted to be updated. This does not * imply that the operation was successful. */ public static function getAptLastUpdateAttemptTime(): int { return (int)filemtime('/var/lib/apt/lists/partial'); } /** * Get when the dpkg database was last changed, i.e. when a package was last installed, updated or removed. * This is an estimate as it just looks at the modification time of relevant files. It is possible these * files get modified for other reasons. */ public static function getDpkgLastPackageChanges(): int { return (int)filemtime(file_exists('/var/log/dpkg.log') ? '/var/log/dpkg.log' : '/var/lib/dpkg/status'); } /** * Get list of packages that have been updated, but require a reboot of the system * to fully take effect. * @return string[] */ public static function getPackagesRequiringReboot(): array { if (!file_exists('/run/reboot-required.pkgs')) return []; $lines = file('/run/reboot-required.pkgs', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); return array_unique($lines); } /** * Get a task struct querying upgradable packages. This adds * a hook to the task to cache the number of upgradable packages * that are security upgrades, so it is preferred to call this * wrapper instead of running the task directly. */ public static function getUpgradableTask() { $task = Taskmanager::submit('AptGetUpgradable'); if (Taskmanager::isTask($task)) { TaskmanagerCallback::addCallback($task, 'ssUpgradable'); } return $task; } /** * Called from Taskmanager callback after invoking getUpgradableTask(). */ public static function setUpgradableData(array $task) { if (Taskmanager::isFailed($task) || !Taskmanager::isFinished($task) || !isset($task['data']['packages'])) return; $count = 0; foreach ($task['data']['packages'] as $package) { if (substr($package['source'], -9) === '-security') { $count++; } } error_log("Upgradable security count: $count, total count: " . count($task['data']['packages'])); Property::set(self::PROP_UPGRADABLE_COUNT, $count . '|' . count($task['data']['packages']), 61); } /** * Get number of packages that can be upgraded and are security updates. * This is a cached value and should be updated at least once an hour. */ public static function getUpgradableSecurityCount(): int { $str = Property::get(self::PROP_UPGRADABLE_COUNT); if ($str === false) return 0; $p = explode('|', $str); if (empty($p) || !is_numeric($p[0])) return 0; return (int)$p[0]; } }