Source of file SystemHelper.php
Size: 19,975 Bytes - Last Modified: 2020-10-24T02:46:31+00:00
/home/travis/build/NextDom/nextdom-core/src/Helpers/SystemHelper.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627 | <?php /* This file is part of NextDom. * * NextDom is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * NextDom is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with NextDom. If not, see <http://www.gnu.org/licenses/>. */ namespace NextDom\Helpers; /** * Class SystemHelper * @package NextDom\Helpers */ class SystemHelper { /** * @var string Linux distribution name */ private static $distrib = null; /** * @var array Distribution specific commands */ private static $commands = [ 'suse' => ['cmd_check' => ' rpm -qa | grep ', 'cmd_install' => ' zypper in --non-interactive ', 'www-uid' => 'wwwrun', 'www-gid' => 'www', 'type' => 'zypper'], 'sles' => ['cmd_check' => ' rpm -qa | grep ', 'cmd_install' => ' zypper in --non-interactive ', 'www-uid' => 'wwwrun', 'www-gid' => 'www', 'type' => 'zypper'], 'redhat' => ['cmd_check' => ' rpm -qa | grep ', 'cmd_install' => ' yum install ', 'www-uid' => 'www-data', 'www-gid' => 'www-data', 'type' => 'yum'], 'fedora' => ['cmd_check' => ' rpm -qa | grep ', 'cmd_install' => ' dnf install ', 'www-uid' => 'www-data', 'www-gid' => 'www-data', 'type' => 'dnf'], 'debian' => ['cmd_check' => ' dpkg --get-selections | grep -v deinstall | grep ', 'cmd_install' => ' apt-get install -y ', 'www-uid' => 'www-data', 'www-gid' => 'www-data', 'type' => 'apt'], ]; /** * @return int */ public static function vsystem() { $status = 0; $args = func_get_args(); $format = $args[0]; $params = array_slice($args, 1); $cmd = vsprintf($format, $params); system($cmd, $status); return $status; } /** * Get command key * * @param string $commandKey Command key * * @return mixed */ public static function getCommand($commandKey = '') { $result = ''; if (isset(self::$commands[self::getDistrib()]) && isset(self::$commands[self::getDistrib()][$commandKey])) { $result = self::$commands[self::getDistrib()][$commandKey]; } if ($result == '') { if ($commandKey == 'www-uid') { $processUser = posix_getpwuid(posix_geteuid()); $result = $processUser['name']; } if ($commandKey == 'www-gid') { $processGroup = posix_getgrgid(posix_getegid()); $result = $processGroup['name']; } } return $result; } /** * Get distribution name * * @return string Distribution name */ public static function getDistrib(): string { self::loadCommand(); if (isset(self::$commands['custom'])) { return 'custom'; } if (self::$distrib === null) { self::$distrib = trim(shell_exec('grep CPE_NAME /etc/os-release | cut -d \'"\' -f 2 | cut -d : -f 3 ')); if (self::$distrib == '') { self::$distrib = trim(shell_exec('grep -e "^ID" /etc/os-release | cut -d \'=\' -f 2')); } if (self::$distrib == '' || !isset(self::$commands[self::$distrib])) { self::$distrib = 'debian'; } } return self::$distrib; } /** * Load system from system_cmd.json if file exists. * * @return array List of commands */ public static function loadCommand(): array { if (file_exists(NEXTDOM_DATA . '/config/system_cmd.json')) { $content = file_get_contents(NEXTDOM_DATA . '/config/system_cmd.json'); if (Utils::isJson($content)) { self::$commands['custom'] = json_decode($content, true); } } return self::$commands; } /** * Kill all process which using file * * @param string $filename * @throws \Exception */ public static function killProcessesWhichUsingFile(string $filename) { exec(SystemHelper::getCmdSudo() . 'fuser -k ' . $filename . ' > /dev/null 2>&1'); } /** * Get sudo command * * @return string * @throws \Exception */ public static function getCmdSudo(): string { if (!NextDomHelper::isCapable('sudo')) { return ''; } return 'sudo '; } /** * Kill all process which using port * * @param $port * @param string $protocol * @throws \Exception */ public static function killProcessesWhichUsingPort($port, $protocol = 'tcp') { exec(SystemHelper::getCmdSudo() . 'fuser -k ' . $port . '/' . $protocol . ' > /dev/null 2>&1'); } /** * Find a process * * @param string $find Pattern to find * @param mixed $without * @return array */ public static function ps(string $find, $without = null) { $return = []; $cmd = '(ps ax || ps w) | grep -ie "' . $find . '" | grep -v "grep"'; if ($without !== null) { if (!is_array($without)) { $without = [$without]; } foreach ($without as $value) { $cmd .= ' | grep -v "' . $value . '"'; } } $results = explode("\n", trim(shell_exec($cmd))); if (!is_array($results) || count($results) == 0) { return $return; } $order = ['pid', 'tty', 'stat', 'time', 'command']; foreach ($results as $result) { if (trim($result) == '') { continue; } $explodes = explode(" ", $result); $info = []; $i = 0; foreach ($explodes as $value) { if (trim($value) == '') { continue; } if (isset($order[$i])) { $info[$order[$i]] = trim($value); } else { $info[end($order)] = $info[end($order)] . ' ' . trim($value); } $i++; } $return[] = $info; } return $return; } /** * Kill process * * @param string $find Process to find * @param bool $forceKill Force kill flag * * @return mixed * @throws \Exception */ public static function kill($find = '', $forceKill = true) { if (trim($find) == '') { return null; } if (is_numeric($find)) { $kill = posix_kill($find, 15); if ($kill) { return true; } if ($forceKill) { usleep(100); $kill = posix_kill($find, 9); if ($kill) { return true; } usleep(100); exec(SystemHelper::getCmdSudo() . 'kill -9 ' . $find); } else { posix_kill($find, 15); } return null; } if ($forceKill) { $cmd = "(ps ax || ps w) | grep -ie '" . $find . "' | grep -v grep | awk '{print $1}' | xargs " . SystemHelper::getCmdSudo() . "kill -9 > /dev/null 2>&1"; } else { $cmd = "(ps ax || ps w) | grep -ie '" . $find . "' | grep -v grep | awk '{print $1}' | xargs " . SystemHelper::getCmdSudo() . "kill > /dev/null 2>&1"; } exec($cmd); return true; } /** * Get apache group id * * @return string Apache group id */ public static function getWWWGid(): string { return self::getWWWUid(); } /** * Get apache user id name * * @return string User id name */ public static function getWWWUid(): string { $distrib = self::getDistrib(); if ($distrib == 'debian') { return 'www-data'; } return 'apache'; } /** * Get proccessor cores count * * @return string */ public static function getProcessorCoresCount(): string { $cmd = "uname"; $os = strtolower(trim(shell_exec($cmd))); switch ($os) { case('linux'): $cmd = "cat /proc/cpuinfo | grep processor | wc -l"; break; case('freebsd'): $cmd = "sysctl -a | grep 'hw.ncpu' | cut -d ':' -f2"; break; default: unset($cmd); break; } if (isset($cmd) && $cmd != '') { $cpuCoreNb = intval(trim(shell_exec($cmd))); } return empty($cpuCoreNb) ? 1 : $cpuCoreNb; } /** * Get HTTP connections count * * @return string */ public static function getHttpConnectionsCount(): string { return shell_exec('ss -t | grep http | grep ESTAB | wc -l'); } /** * Get process count * * @return string Count */ public static function getProcessCount(): string { return shell_exec('ps -aux | wc -l'); } /** * Get uptime * * @return string */ public static function getUptime(): string { $uptime = preg_replace('/\.[0-9]+/', '', file_get_contents('/proc/uptime')); return intval($uptime); } /** * @return array */ public static function getMemInfo() { $data = explode("\n", file_get_contents("/proc/meminfo")); $meminfo = []; foreach ($data as $line) { $info = explode(":", $line); if (count($info) != 2) { continue; } $value = explode(' ', trim($info[1])); $meminfo[$info[0]] = trim($value[0]); } return $meminfo; } /** * Recursively delete given path * * @param $path * @return bool false when error occurs */ public static function rrmdir($path) { $status = 0; $cmd = sprintf("rm -rf %s", $path); system($cmd, $status); return ($status == 0); } /** * */ public static function consistency() { LogHelper::clear('consistency'); $cmd = __DIR__ . '/../../install/consistency.php'; $cmd .= ' >> ' . LogHelper::getPathToLog('consistency') . ' 2>&1 &'; self::php($cmd, true); } /** * Execute PHP command * * @param string $arguments * @param bool $elevatedPrivileges Use elevated privileges * * @return string Result of the command * @throws \Exception */ public static function php(string $arguments, $elevatedPrivileges = false) { $exec = ""; if ($elevatedPrivileges) { $exec .= self::getCmdSudo() . ' '; } $exec .= 'php ' . $arguments; return exec($exec); } /** * Stop a service * * @param string serviceName * @return string Result of the command * @throws \Exception */ public static function stopService(string $serviceName) { return exec(self::getCmdSudo() . ' service ' . $serviceName . ' stop'); } /** * Start a service * * @param string serviceName * @return string Result of the command * @throws \Exception */ public static function startService(string $serviceName) { return exec(self::getCmdSudo() . ' service ' . $serviceName . ' start'); } public static function getSystemInformations() { return shell_exec('uname -a'); } /** * */ public static function cleanFileSystemRight() { //nothing to do for NextDom } public static function getArch() { $arch = php_uname('m'); if($arch === 'x86_64') { return 'amd64'; } if($arch === 'aarch64') { return 'arm64'; } if($arch == 'armv7l' || $arch == 'armv6l') { return 'arm'; } return $arch; } public static function getInstalledPackages($packagesManager) { if (isset(self::$_installPackage[$packagesManager])) { return self::$_installPackage[$packagesManager]; } self::$_installPackage[$packagesManager] = array(); switch ($packagesManager) { case 'apt': $lines = explode("\n", shell_exec('dpkg -l | tail -n +6')); foreach ($lines as $line) { $infos = array_values(array_filter(explode(" ", $line))); if (!isset($infos[1])) { continue; } self::$_installPackage[$packagesManager][$infos[1]] = array( 'version' => $infos[2] ); } break; case 'pip2': $lines = explode("\n", shell_exec('pip2 list --format=columns | tail -n +3')); foreach ($lines as $line) { $infos = array_values(array_filter(explode(" ", $line))); if (!isset($infos[0]) || !isset($infos[1])) { continue; } self::$_installPackage[$packagesManager][$infos[0]] = array( 'version' => $infos[1] ); } break; case 'pip3': $lines = explode("\n", shell_exec('pip3 list --format=columns | tail -n +3')); foreach ($lines as $line) { $infos = array_values(array_filter(explode(" ", $line))); if (!isset($infos[0])) { continue; } self::$_installPackage[$packagesManager][$infos[0]] = array( 'version' => $infos[1] ); } break; } return self::$_installPackage[$packagesManager]; } public static function checkAndInstall($_packages, $_fix = false, $_foreground = false) { $return = []; foreach ($_packages as $type => $value) { $installPackage = self::getInstallPackage($type); foreach ($_packages[$type] as $package => $info) { $found = 0; $alternative_found = ''; $version = ''; if (isset($installPackage[$package])) { $found = 1; $version = $installPackage[$package]['version']; } elseif (isset($info['alternative'])) { foreach ($info['alternative'] as $alternative) { if (isset($installPackage[$alternative])) { $found = 2; $alternative_found = $alternative; $version = $installPackage[$alternative]['version']; break; } $keys = array_values(preg_grep($alternative, array_keys($installPackage))); if (is_array($keys) && count($keys) > 0) { $found = 2; $alternative_found = $keys[0]; $version = $installPackage[$keys[0]]['version']; break; } } } $needUpdate = false; if (isset($info['version']) && version_compare($version, $info['version']) < 0) { $found = 0; $needUpdate = true; } $return[$type . '::' . $package] = array( 'name' => $package, 'status' => $found, 'version' => $version, 'type' => $type, 'needUpdate' => $needUpdate, 'needVersion' => isset($info['version']) ? $info['version'] : '', 'alternative_found' => $alternative_found, 'optional' => isset($info['optional']) ? $info['optional'] : false, 'fix' => ($found == 0) ? self::installPackage($type, $package) : '' ); } } if (!$_fix) { return $return; } $cmd = "set -x\n"; $cmd .= " echo '*******************Begin of package installation******************'\n"; if ($_foreground) { if (self::checkInstallationLog() != '') { echo shell_exec(self::checkInstallationLog() . ' 2>&1'); } } else { $cmd .= self::checkInstallationLog(); } if ($_foreground) { echo shell_exec(self::getCmdSudo() . " apt update 2>&1"); } else { $cmd .= self::getCmdSudo() . " apt update\n"; } foreach ($return as $package => $info) { if ($info['status'] != 0 || $info['optional']) { continue; } if ($_foreground) { echo shell_exec(self::installPackage($info['type'], $info['name']) . ' 2>&1'); } else { $cmd .= self::installPackage($info['type'], $info['name']) . "\n"; } } if ($_foreground) { return; } $cmd .= " echo '*******************End of package installation******************'\n"; if (file_exists('/tmp/nextdom_fix_package')) { shell_exec(self::getCmdSudo() . ' rm /tmp/nextdom_fix_package'); } file_put_contents('/tmp/nextdom_fix_package', $cmd); self::launchScriptPackage(); } public static function launchScriptPackage() { if (count(self::ps('dpkg')) > 0 || count(self::ps('apt')) > 0) { throw new CoreException(__('Installation de package impossible car il y a déjà une installation en cours')); } shell_exec(self::getCmdSudo() . ' chmod +x /tmp/nextdom_fix_package'); if (class_exists('log')) { $log = LogHelper::getPathToLog('packages'); LogHelper::clear('packages'); } else { $log = '/tmp/nextdom_fix_package_log'; } if (exec('which at | wc -l') == 0) { exec(self::getCmdSudo() . '/bin/bash /tmp/nextdom_fix_package >> ' . $log . ' 2>&1 &'); } else { if (!file_exists($log)) { touch($log); } exec('echo "/bin/bash /tmp/nextdom_fix_package >> ' . $log . ' 2>&1" | ' . self::getCmdSudo() . ' at now'); } } public static function installPackage($packagesManager, $packageName) { switch ($packagesManager) { case 'apt': return self::getCmdSudo() . ' apt install -y ' . $packageName; case 'pip2': return self::getCmdSudo() . ' pip2 install ' . $packageName; case 'pip3': return self::getCmdSudo() . ' pip3 install ' . $packageName; } } public static function checkInstallationLog() { if (class_exists('log')) { $log = LogHelper::getPathToLog('packages'); } else { $log = '/tmp/nextdom_fix_package_log'; } if (file_exists($log)) { $data = file_get_contents($log); if (strpos($data, 'dpkg configure -a')) { return "sudo dpkg --configure -a --force-confdef\n"; } } return ''; } } |