1<?php 2 3/* 4 Phoronix Test Suite 5 URLs: http://www.phoronix.com, http://www.phoronix-test-suite.com/ 6 Copyright (C) 2009 - 2019, Phoronix Media 7 Copyright (C) 2009 - 2019, Michael Larabel 8 phodevi.php: The object for interacting with the PTS device framework 9 10 This program is free software; you can redistribute it and/or modify 11 it under the terms of the GNU General Public License as published by 12 the Free Software Foundation; either version 3 of the License, or 13 (at your option) any later version. 14 15 This program is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 GNU General Public License for more details. 19 20 You should have received a copy of the GNU General Public License 21 along with this program. If not, see <http://www.gnu.org/licenses/>. 22*/ 23 24class phodevi extends phodevi_base 25{ 26 public static $vfs = false; 27 private static $device_cache = array(); 28 private static $smart_cache = array(); 29 private static $sensors = null; 30 31 private static $operating_system = null; 32 private static $graphics_detected = false; 33 private static $graphics = array( 34 'mesa' => false, 35 'ati' => false, 36 'nvidia' => false 37 ); 38 private static $operating_systems = array( 39 'linux' => false, 40 'macosx' => false, 41 'solaris' => false, 42 'bsd' => false, 43 'hurd' => false, 44 'minix' => false, 45 'windows' => false 46 ); 47 48 // A variable that modules can use to override Phodevi caching support, etc 49 public static $allow_phodevi_caching = true; 50 51 const no_caching = 1; 52 const std_caching = 2; 53 const smart_caching = 3; 54 55 public static function read_name($device) 56 { 57 return phodevi::read_property($device, 'identifier'); 58 } 59 public static function load_sensors() 60 { 61 if(!defined('PHP_VERSION_ID') || PHP_VERSION_ID < 50300) 62 { 63 // Phodevi sensors don't work prior to PHP 5.3 64 self::$sensors = array(); 65 return false; 66 } 67 68 foreach(glob(dirname(__FILE__) . '/sensors/*') as $sensor_obj_file) 69 { 70 $sensor_obj_name = basename($sensor_obj_file, '.php'); 71 72 if(!class_exists($sensor_obj_name, false)) 73 { 74 include($sensor_obj_file); 75 } 76 77 $type = call_user_func(array($sensor_obj_name, 'get_type')); 78 $sensor = call_user_func(array($sensor_obj_name, 'get_sensor')); 79 80 if($type != null && $sensor != null) 81 { 82 self::$sensors[$type][$sensor] = $sensor_obj_name; 83 } 84 } 85 } 86 public static function available_sensors($limit_sensors = false) 87 { 88 static $available_sensors = null; 89 90 if($limit_sensors != false) 91 { 92 return self::select_sensors($limit_sensors); 93 } 94 else if($available_sensors == null) 95 { 96 $available_sensors = array(); 97 98 foreach(self::$sensors as $sensor_type => &$sensor) 99 { 100 foreach(array_keys($sensor) as $sensor_senses) 101 { 102 array_push($available_sensors, array($sensor_type, $sensor_senses, self::$sensors[$sensor_type][$sensor_senses])); 103 } 104 } 105 } 106 107 return $available_sensors; 108 } 109 public static function select_sensors($limit_sensors = false) 110 { 111 if(!defined('PHP_VERSION_ID') || PHP_VERSION_ID < 50300) 112 { 113 // Phodevi sensors don't work prior to PHP 5.3 114 return array(); 115 } 116 117 $selected = array(); 118 foreach(self::available_sensors() as $sensor) 119 { 120 if($limit_sensors == false || (is_array($limit_sensors) && in_array($sensor[2], $limit_sensors))) 121 { 122 array_push($selected, $sensor); 123 } 124 } 125 126 return $selected; 127 } 128 public static function is_sensor_supported($sensor) 129 { 130 $supported = false; 131 $sensors = self::supported_sensors(); 132 foreach($sensors as $s) 133 { 134 if($s[0] == $sensor[0] && $s[1] == $sensor[1]) 135 { 136 $supported = true; 137 break; 138 } 139 } 140 141 return $supported; 142 } 143 public static function supported_sensors($limit_sensors = false) 144 { 145 static $supported_sensors = null; 146 147 if($limit_sensors != false) 148 { 149 return self::select_sensors($limit_sensors); 150 } 151 else if($supported_sensors == null) 152 { 153 $supported_sensors = array(); 154 foreach(self::available_sensors($limit_sensors) as $sensor) 155 { 156 if(self::sensor_supported($sensor)) 157 { 158 array_push($supported_sensors, $sensor); 159 } 160 } 161 } 162 163 return $supported_sensors; 164 } 165 public static function unsupported_sensors() 166 { 167 static $unsupported_sensors = null; 168 169 if($unsupported_sensors == null) 170 { 171 $unsupported_sensors = array(); 172 $supported_sensors = self::supported_sensors(); 173 174 foreach(self::available_sensors() as $sensor) 175 { 176 if(!in_array($sensor, $supported_sensors)) 177 { 178 array_push($unsupported_sensors, $sensor); 179 } 180 } 181 } 182 183 return $unsupported_sensors; 184 } 185 public static function read_sensor($sensor) 186 { 187 if($sensor instanceof phodevi_sensor) 188 { 189 $sensor_object = $sensor; 190 } 191 else 192 { 193 $sensor_object = new self::$sensors[$sensor[0]][$sensor[1]](null, null); 194 } 195 196 return $sensor_object->read_sensor(); 197 } 198 public static function read_sensor_object_unit(&$sensor_object) 199 { 200 $sensor = array($sensor_object->get_type(), $sensor_object->get_sensor(), get_class($sensor_object)); 201 return self::read_sensor_unit($sensor); 202 } 203 public static function read_sensor_object_unit_short(&$sensor_object) 204 { 205 $sensor_unit = self::read_sensor_object_unit($sensor_object); 206 207 switch($sensor_unit) 208 { 209 case 'Celsius': 210 $sensor_unit = 'C'; 211 break; 212 case 'Percent': 213 $sensor_unit = '%'; 214 break; 215 case 'Megabytes': 216 $sensor_unit = 'MB'; 217 break; 218 case 'Megahertz': 219 $sensor_unit = 'MHz'; 220 break; 221 case 'Volts': 222 $sensor_unit = 'V'; 223 break; 224 case 'Kilobytes/seconds': 225 $sensor_unit = 'KBps'; 226 break; 227 case 'Millivolts': 228 $sensor_unit = 'mV'; 229 break; 230 } 231 232 return $sensor_unit; 233 } 234 public static function read_sensor_unit($sensor) 235 { 236 return call_user_func(array(self::$sensors[$sensor[0]][$sensor[1]], 'get_unit')); 237 } 238 public static function sensor_supported($sensor) 239 { 240 $sensor_object = new self::$sensors[$sensor[0]][$sensor[1]](null, null); 241 242 return isset(self::$sensors[$sensor[0]][$sensor[1]]) && $sensor_object->support_check(); 243 } 244 public static function sensor_object_identifier(&$sensor_object) 245 { 246 $sensor = array($sensor_object->get_type(), $sensor_object->get_sensor(), get_class($sensor_object)); 247 return self::sensor_identifier($sensor) . ($sensor_object->get_instance() != 0 ? '.' . $sensor_object->get_instance() : null); 248 } 249 public static function sensor_identifier($sensor) 250 { 251 return $sensor[0] . '.' . $sensor[1]; 252 } 253 public static function sensor_object_name(&$sensor_object) 254 { 255 $sensor = array($sensor_object->get_type(), $sensor_object->get_sensor(), get_class($sensor_object)); 256 $name = self::sensor_name($sensor); 257 $params = $sensor_object->get_readable_device_name(); 258 259 if($params !== NULL) 260 { 261 $name .= ' (' . $params . ')'; 262 } 263 264 return $name; 265 } 266 public static function sensor_name($sensor) 267 { 268 $type = call_user_func(array(self::$sensors[$sensor[0]][$sensor[1]], 'get_type')); 269 $sensor = call_user_func(array(self::$sensors[$sensor[0]][$sensor[1]], 'get_sensor')); 270 271 if(strlen($type) < 4) 272 { 273 $formatted = strtoupper($type); 274 } 275 else 276 { 277 $formatted = ucwords($type); 278 } 279 280 switch($formatted) 281 { 282 case 'SYS': 283 $formatted = 'System'; 284 break; 285 case 'HDD': 286 $formatted = 'Drive'; 287 break; 288 } 289 290 $formatted .= ' '; 291 292 switch($sensor) 293 { 294 case 'temp': 295 $formatted .= 'Temperature'; 296 break; 297 case 'freq': 298 $formatted .= 'Frequency'; 299 break; 300 case 'memory': 301 $formatted .= 'Memory Usage'; 302 break; 303 case 'power': 304 $formatted .= 'Power Consumption'; 305 break; 306 default: 307 $formatted .= ucwords(str_replace('-', ' ', $sensor)); 308 break; 309 } 310 311 return $formatted; 312 } 313 public static function system_hardware($return_as_string = true) 314 { 315 return self::system_information_parse(self::available_hardware_devices(), $return_as_string); 316 } 317 public static function system_software($return_as_string = true) 318 { 319 return self::system_information_parse(self::available_software_components(), $return_as_string); 320 } 321 public static function system_centralized_view($return_as_string = true) 322 { 323 $core_count = phodevi::read_property('cpu', 'physical-core-count'); 324 $thread_count = phodevi::read_property('cpu', 'thread-count'); 325 326 $sys = array( 327 'Processor' => phodevi::read_property('cpu', 'model-and-speed'), 328 array( 329 'Core Count' => $core_count, 330 'Thread Count' => !empty($core_count) && $core_count == $thread_count ? '' : $thread_count, // don't show thread count if it's same as core count 331 'Extensions' => phodevi_cpu::instruction_set_extensions(), 332 // 'Virtualization' => (phodevi_cpu::virtualization_technology() ? phodevi_cpu::virtualization_technology() : ''), 333 'Cache Size' => phodevi::read_property('cpu', 'cache-size-string'), 334 'Microcode'=> phodevi::read_property('cpu', 'microcode-version'), 335 'Core Family' => phodevi::read_property('cpu', 'core-family-name'), 336 'Scaling Driver'=> phodevi::read_property('cpu', 'scaling-governor'), 337 ), 338 'Graphics' => phodevi::read_name('gpu'), 339 array( 340 'Frequency' => phodevi::read_property('gpu', 'frequency'), 341 'BAR1 / Visible vRAM' => phodevi::read_property('gpu', 'bar1-visible-vram'), 342 'OpenGL' => phodevi::read_property('system', 'opengl-driver'), 343 'Vulkan' => phodevi::read_property('system', 'vulkan-driver'), 344 'OpenCL' => phodevi::read_property('system', 'opencl-driver'), 345 'Display Driver' => phodevi::read_property('system', 'display-driver-string'), 346 'Monitor' => phodevi::read_name('monitor'), 347 'Screen' => phodevi::read_property('gpu', 'screen-resolution-string'), 348 ), 349 'Motherboard' => phodevi::read_name('motherboard'), 350 array( 351 'BIOS Version' => phodevi::read_property('motherboard', 'bios-version'), 352 'Chipset' => phodevi::read_name('chipset'), 353 'Audio' => phodevi::read_name('audio'), 354 'Network' => phodevi::read_name('network'), 355 'Platform Profile'=> phodevi::read_property('system', 'platform-profile'), 356 ), 357 'Memory' => phodevi::read_name('memory'), 358 array(), 359 'Disk' => phodevi::read_name('disk'), 360 array( 361 'File-System' => phodevi::read_property('system', 'filesystem'), 362 'Mount Options' => phodevi::read_property('disk', 'mount-options-string'), 363 //'Block Size' => phodevi::read_property('disk', 'block-size'), 364 'Disk Scheduler' => phodevi::read_property('disk', 'scheduler'), 365 'Disk Details' => phodevi::read_property('disk', 'extra-disk-details'), 366 ), 367 'Operating System' => phodevi::read_property('system', 'operating-system'), 368 array( 369 'Kernel' => phodevi::read_property('system', 'kernel-string'), 370 'Desktop' => phodevi::read_property('system', 'desktop-environment'), 371 'Display Server' => phodevi::read_property('system', 'display-server'), 372 'Compiler' => phodevi::read_property('system', 'compiler'), 373 'System Layer' => phodevi::read_property('system', 'system-layer'), 374 'Security' => phodevi::read_property('system', 'security-features'), 375 ) 376 ); 377 378 if($return_as_string) 379 { 380 $sys_string = null; 381 $tabled = array(); 382 foreach($sys as $key => &$in) 383 { 384 $space_in = 2; 385 if(is_array($in)) 386 { 387 $tabled = array(); 388 foreach($in as $key => $value) 389 { 390 if(!empty($value)) 391 { 392 if(isset($value[64]) && strpos($value, ' + ') !== false) 393 { 394 $values = explode(' + ', $value); 395 $tabled[] = array(pts_client::cli_just_bold($key) . ':' . str_repeat(' ', (20 - strlen($key))), array_shift($values)); 396 foreach($values as $value) 397 { 398 $tabled[] = array(pts_client::cli_just_bold(' '), '+ ' . $value); 399 } 400 } 401 else 402 { 403 $tabled[] = array(pts_client::cli_just_bold($key) . ':' . str_repeat(' ', (20 - strlen($key))), $value); 404 //$sys_string .= ' ' . strtoupper($key) . ':' . $value . PHP_EOL; 405 } 406 } 407 } 408 } 409 else 410 { 411 if(($x = strpos($in, ' ('))) 412 { 413 $in = substr($in, 0, $x); 414 } 415 416 if(!empty($tabled)) 417 { 418 $sys_string .= pts_user_io::display_text_table($tabled, ' ', 0, 17) . PHP_EOL; 419 } 420 421 if(isset($in[80]) && strpos($in, ' + ') !== false) 422 { 423 $values = explode(' + ', $in); 424 $sys_string .= PHP_EOL . ' ' . pts_client::cli_colored_text(strtoupper($key), 'gray', true) . ': ' . str_repeat(' ', (22 - strlen($key))) . pts_client::cli_colored_text(array_shift($values), 'green', true); 425 foreach($values as $value) 426 { 427 $sys_string .= PHP_EOL . str_repeat(' ', 22) . pts_client::cli_colored_text('+ ' . $value, 'green', true); 428 } 429 $sys_string .= PHP_EOL; 430 } 431 else 432 { 433 $sys_string .= PHP_EOL . ' ' . pts_client::cli_colored_text(strtoupper($key), 'gray', true) . ': ' . str_repeat(' ', (22 - strlen($key))) . pts_client::cli_colored_text($in, 'green', true) . PHP_EOL; 434 } 435 } 436 437 } 438 if(!empty($tabled)) 439 { 440 $sys_string .= pts_user_io::display_text_table($tabled, ' ', 0, 17) . PHP_EOL; 441 } 442 return $sys_string; 443 } 444 445 return $sys; 446 } 447 public static function system_id_string() 448 { 449 $extra = null; 450 foreach(array('CC', 'CXX', 'CFLAGS', 'CPPFLAGS', 'CXXFLAGS', 'USE_WINE') as $env) 451 { 452 $val = getenv($env); 453 454 if(!empty($val)) 455 { 456 $extra .= $env . '=' . $val . ';'; 457 } 458 } 459 460 $components = array(phodevi::read_property('cpu', 'model'), phodevi::read_property('system', 'operating-system'), phodevi::read_property('system', 'compiler'), $extra); 461 return base64_encode(implode('__', $components)); 462 } 463 public static function read_property($device, $read_property, $strip_string = true) 464 { 465 static $properties_table = array(); 466 $value = false; 467 468 if(!isset($properties_table[$device])) 469 { 470 $properties_table[$device] = call_user_func(array('phodevi_' . $device, 'properties')); 471 } 472 473 if(!isset($properties_table[$device][$read_property])) 474 { 475 echo 'NOTICE: ' . $read_property . ' does not exist for ' . $device . '.' . PHP_EOL; 476 } 477 478 if(!($properties_table[$device][$read_property] instanceof phodevi_device_property)) 479 { 480 return $properties_table[$device][$read_property]; 481 } 482 483 $cache_code = $properties_table[$device][$read_property]->cache_code(); 484 if($cache_code != phodevi::no_caching && phodevi::$allow_phodevi_caching && isset(self::$device_cache[$device][$read_property])) 485 { 486 $value = self::$device_cache[$device][$read_property]; 487 } 488 else 489 { 490 $dev_function_r = pts_arrays::to_array($properties_table[$device][$read_property]->get_device_function()); 491 $dev_function = $dev_function_r[0]; 492 $function_pass = array(); 493 494 for($i = 1; $i < count($dev_function_r); $i++) 495 { 496 array_push($function_pass, $dev_function_r[$i]); 497 } 498 if(method_exists('phodevi_' . $device, $dev_function)) 499 { 500 $value = call_user_func_array(array('phodevi_' . $device, $dev_function), $function_pass); 501 if(!is_array($value) && $value != null) 502 { 503 if($strip_string) 504 { 505 $value = pts_strings::strip_string($value); 506 } 507 if(function_exists('preg_replace')) 508 { 509 $value = preg_replace('/[^(\x20-\x7F)]*/','', $value); 510 } 511 } 512 513 if($cache_code != phodevi::no_caching) 514 { 515 self::$device_cache[$device][$read_property] = $value; 516 517 if($cache_code == phodevi::smart_caching) 518 { 519 // TODO: For now just copy the smart cache to other var, but come up with better yet efficient way 520 self::$smart_cache[$device][$read_property] = $value; 521 } 522 } 523 } 524 } 525 526 return $value; 527 } 528 public static function read_all_properties() 529 { 530 $all_properties = array(); 531 $components = array(); 532 foreach(glob(__DIR__ . '/components/phodevi_*.php') as $file) 533 { 534 $components[] = substr(basename($file, '.php'), 8); 535 } 536 537 foreach($components as $device) 538 { 539 $properties = call_user_func(array('phodevi_' . $device, 'properties')); 540 $all_properties[$device] = array(); 541 foreach($properties as $id => $property) 542 { 543 $dev_function_r = pts_arrays::to_array($property->get_device_function()); 544 $dev_function = $dev_function_r[0]; 545 $function_pass = array(); 546 547 for($i = 1; $i < count($dev_function_r); $i++) 548 { 549 array_push($function_pass, $dev_function_r[$i]); 550 } 551 if(method_exists('phodevi_' . $device, $dev_function)) 552 { 553 $value = call_user_func_array(array('phodevi_' . $device, $dev_function), $function_pass); 554 if(!is_array($value) && $value != null) 555 { 556 $value = pts_strings::strip_string($value); 557 if(function_exists('preg_replace')) 558 { 559 $value = preg_replace('/[^(\x20-\x7F)]*/','', $value); 560 } 561 } 562 $all_properties[$device][$id] = $value; 563 } 564 } 565 } 566 567 return $all_properties; 568 } 569 public static function set_property($device, $set_property, $pass_args = array()) 570 { 571 $return_value = false; 572 573 if(method_exists('phodevi_' . $device, 'set_property')) 574 { 575 $return_value = call_user_func(array('phodevi_' . $device, 'set_property'), $set_property, $pass_args); 576 } 577 578 return $return_value; 579 } 580 public static function create_vfs() 581 { 582 self::$vfs = new phodevi_vfs(); 583 } 584 public static function initial_setup() 585 { 586 // Operating System Detection 587 $supported_operating_systems = pts_types::operating_systems(); 588 $uname_s = strtolower(php_uname('s')); 589 590 foreach($supported_operating_systems as $os_check) 591 { 592 for($i = 0; $i < count($os_check); $i++) 593 { 594 if(strpos($uname_s, strtolower($os_check[$i])) !== false) // Check for OS 595 { 596 self::$operating_system = $os_check[0]; 597 self::$operating_systems[strtolower($os_check[0])] = true; 598 break; 599 } 600 } 601 602 if(self::$operating_system != null) 603 { 604 break; 605 } 606 } 607 608 if(self::operating_system() == false) 609 { 610 self::$operating_system = 'Unknown'; 611 } 612 613 self::load_sensors(); 614 } 615 private static function detect_graphics() 616 { 617 if(self::$graphics_detected == true) 618 { 619 return; 620 } 621 622 // OpenGL / graphics detection 623 $graphics_detection = array('NVIDIA', array('Mesa', 'SGI'), array('AMD')); 624 $opengl_driver = phodevi::read_property('system', 'opengl-vendor') . ' ' . phodevi::read_property('system', 'opengl-driver') . ' ' . phodevi::read_property('system', 'dri-display-driver'); 625 $opengl_driver = trim(str_replace('Corporation', '', $opengl_driver)); // Prevents a possible false positive for ATI being in CorporATIon 626 627 foreach($graphics_detection as $gpu_check) 628 { 629 if(!is_array($gpu_check)) 630 { 631 $gpu_check = array($gpu_check); 632 } 633 634 for($i = 0; $i < count($gpu_check); $i++) 635 { 636 if(stripos($opengl_driver, $gpu_check[$i]) !== false) // Check for GPU 637 { 638 self::$graphics[(strtolower($gpu_check[0]))] = true; 639 break; 640 } 641 } 642 } 643 644 self::$graphics_detected = true; 645 } 646 public static function set_device_cache($cache_array) 647 { 648 if(is_array($cache_array) && !empty($cache_array)) 649 { 650 self::$smart_cache = array_merge(self::$smart_cache, $cache_array); 651 self::$device_cache = array_merge(self::$device_cache, $cache_array); 652 } 653 } 654 public static function clear_cache() 655 { 656 self::$smart_cache = array(); 657 self::$device_cache = array(); 658 } 659 public static function get_phodevi_cache_object($store_dir, $client_version = 0) 660 { 661 return new phodevi_cache(self::$smart_cache, $store_dir, $client_version); 662 } 663 protected static function system_information_parse($component_array, $return_as_string = true) 664 { 665 // Returns string of hardware information 666 $info = array(); 667 668 foreach($component_array as $string => $id) 669 { 670 if(is_array($id) && count($id) == 2) 671 { 672 $value = self::read_property($id[0], $id[1]); 673 } 674 else 675 { 676 $value = self::read_name($id); 677 } 678 679 if($value != -1 && !empty($value)) 680 { 681 $info[$string] = $value; 682 } 683 } 684 685 if($return_as_string) 686 { 687 $info_array = $info; 688 $info = null; 689 690 foreach($info_array as $type => $value) 691 { 692 if($info != null) 693 { 694 $info .= ', '; 695 } 696 697 $info .= $type . ': ' . $value; 698 } 699 } 700 701 return $info; 702 } 703 public static function system_uptime() 704 { 705 // Returns the system's uptime in seconds 706 $uptime = 1; 707 708 if(phodevi::is_windows()) 709 { 710 $uptime = trim(shell_exec('powershell "((get-date) - (gcim Win32_OperatingSystem).LastBootUpTime).TotalSeconds"')); 711 $uptime = is_numeric($uptime) && $uptime > 1 ? round($uptime) : 1; 712 } 713 else if(is_file('/proc/uptime')) 714 { 715 $uptime = pts_strings::first_in_string(pts_file_io::file_get_contents('/proc/uptime')); 716 } 717 else if(($uptime_cmd = pts_client::executable_in_path('uptime')) != false) 718 { 719 $uptime_counter = 0; 720 $uptime_output = shell_exec($uptime_cmd . ' 2>&1'); 721 $uptime_output = substr($uptime_output, strpos($uptime_output, ' up') + 3); 722 $uptime_output = substr($uptime_output, 0, strpos($uptime_output, ' user')); 723 $uptime_output = substr($uptime_output, 0, strrpos($uptime_output, ',')) . ' '; 724 725 if(($day_end_pos = strpos($uptime_output, ' day')) !== false) 726 { 727 $day_output = substr($uptime_output, 0, $day_end_pos); 728 $day_output = substr($day_output, strrpos($day_output, ' ') + 1); 729 730 if(is_numeric($day_output)) 731 { 732 $uptime_counter += $day_output * 86400; 733 } 734 } 735 736 if(($mins_end_pos = strpos($uptime_output, ' mins')) !== false) 737 { 738 $mins_output = substr($uptime_output, 0, $mins_end_pos); 739 $mins_output = substr($mins_output, strrpos($mins_output, ' ') + 1); 740 741 if(is_numeric($mins_output)) 742 { 743 $uptime_counter += $mins_output * 60; 744 } 745 } 746 747 if(($time_split_pos = strpos($uptime_output, ':')) !== false) 748 { 749 $hours_output = substr($uptime_output, 0, $time_split_pos); 750 $hours_output = substr($hours_output, strrpos($hours_output, ' ') + 1); 751 $mins_output = substr($uptime_output, $time_split_pos + 1); 752 $mins_output = substr($mins_output, 0, strpos($mins_output, ' ')); 753 754 if(is_numeric($hours_output)) 755 { 756 $uptime_counter += $hours_output * 3600; 757 } 758 if(is_numeric($mins_output)) 759 { 760 $uptime_counter += $mins_output * 60; 761 } 762 } 763 764 if(is_numeric($uptime_counter) && $uptime_counter > 0) 765 { 766 $uptime = $uptime_counter; 767 } 768 } 769 770 return intval($uptime); 771 } 772 public static function reboot() 773 { 774 $reboot_cmd = ''; 775 776 if(phodevi::is_windows()) 777 { 778 $reboot_cmd = 'shutdown /r'; 779 } 780 else if(pts_client::executable_in_path('systemctl')) 781 { 782 $reboot_cmd = 'systemctl reboot'; 783 } 784 else if(pts_client::executable_in_path('reboot')) 785 { 786 $reboot_cmd = 'reboot'; 787 } 788 else if(pts_client::executable_in_path('shutdown')) 789 { 790 // macOS 791 $reboot_cmd = 'shutdown -r now'; 792 } 793 794 if($reboot_cmd) 795 { 796 shell_exec($reboot_cmd); 797 // Buffer in case reboot isn't immediate 798 echo PHP_EOL . PHP_EOL . 'Waiting for reboot...' . PHP_EOL; 799 sleep(600); 800 } 801 } 802 public static function shutdown() 803 { 804 // some systems like systemctl poweroff, others just like poweroff, but not consistent one method for all systems in testing 805 if(pts_client::executable_in_path('systemctl') && rand(0, 1) == 1) 806 { 807 // Try systemd's poweroff method first 808 shell_exec('systemctl poweroff'); 809 sleep(5); 810 } 811 if(pts_client::executable_in_path('poweroff')) 812 { 813 shell_exec('poweroff'); 814 sleep(5); 815 } 816 if(phodevi::is_windows()) 817 { 818 shell_exec('shutdown /s'); 819 sleep(5); 820 } 821 } 822 public static function cpu_arch_compatible($check_against) 823 { 824 $compatible = true; 825 $this_arch = phodevi::read_property('system', 'kernel-architecture'); 826 $check_against = pts_arrays::to_array($check_against); 827 828 if(isset($this_arch[2]) && substr($this_arch, -2) == '86') 829 { 830 $this_arch = 'x86'; 831 } 832 if(!in_array($this_arch, $check_against)) 833 { 834 $compatible = false; 835 } 836 if(phodevi::is_macos()) 837 { 838 $compatible = true; 839 } 840 841 return $compatible; 842 } 843 public static function is_vendor_string($vendor) 844 { 845 return isset($vendor[2]) && pts_strings::string_only_contains($vendor, (pts_strings::CHAR_LETTER | pts_strings::CHAR_NUMERIC | pts_strings::CHAR_DECIMAL | pts_strings::CHAR_SPACE | pts_strings::CHAR_DASH)) && !pts_strings::has_in_istring($vendor, array('manufacturer', 'vendor', 'unknown', 'generic', 'warning')) && (!isset($vendor[7]) || strpos($vendor, ' ') !== false || pts_strings::times_occurred($vendor, pts_strings::CHAR_NUMERIC) == 0) && pts_strings::string_contains($vendor, pts_strings::CHAR_LETTER) && (isset($vendor[4]) || pts_strings::times_occurred($vendor, pts_strings::CHAR_LETTER) > 1) && substr($vendor, -1) != '-'; 846 } 847 public static function is_product_string($product) 848 { 849 return phodevi::is_vendor_string($product) && !pts_strings::has_in_istring($product, array('VBOX', 'QEMU', 'Virtual', 'Family', '440BX', 'VMware', ' Gen', 'Core IGP')); 850 } 851 public static function opencl_support_detected() 852 { 853 $supported = true; 854 855 if(($clinfo = pts_client::executable_in_path('clinfo'))) 856 { 857 $clinfo = shell_exec($clinfo); 858 if(strpos($clinfo, 'Number of platforms 0') !== false) 859 { 860 $supported = false; 861 } 862 } 863 864 return $supported; 865 } 866 public static function vulkan_support_detected() 867 { 868 static $supported = -1; 869 870 if($supported !== -1) 871 { 872 return $supported; 873 } 874 $supported = true; 875 876 if(($vulkaninfo = pts_client::executable_in_path('vulkaninfo 2>&1'))) 877 { 878 $vulkaninfo = shell_exec($vulkaninfo); 879 if(strpos($vulkaninfo, 'Cannot create Vulkan instance') !== false) 880 { 881 $supported = false; 882 } 883 else if(strpos($vulkaninfo, 'failed with ERROR_INITIALIZATION_FAILED') !== false) 884 { 885 $supported = false; 886 } 887 } 888 889 return $supported; 890 } 891 public static function is_fake_device($str) 892 { 893 $string_check = array( 894 'Logical Volume', 895 'QEMU', 896 ' KVM', 897 'KVM ', 898 'Eng Sample', 899 'Unknown', 900 ' virt', 901 'virtual', 902 'svga', 903 ' VM', 904 'Storage ', 905 'Aspeed', 906 '440BX', 907 'Cirrus', 908 ); 909 910 foreach($string_check as $check) 911 { 912 if(stripos($str, $check) !== false) 913 { 914 return true; 915 } 916 } 917 918 $without_multiplier = $str; 919 if(($x = strpos($without_multiplier, ' x ')) !== false) 920 { 921 $without_multiplier = substr($without_multiplier, $x + 3); 922 } 923 if(!preg_match('~[0-9]+~', $without_multiplier)) 924 { 925 // No numbers at all in string so probably not a real device (e.g. some Virtual "Intel" CPU or similar components generic 926 return true; 927 } 928 929 return false; 930 } 931 public static function os_under_test($force_override = false, $force_value = null) 932 { 933 static $os_under_test = null; 934 if($force_override && !empty($force_value)) 935 { 936 $os_under_test = $force_value; 937 } 938 else if($os_under_test == null) 939 { 940 $os_under_test = self::operating_system(); 941 } 942 943 // The operating system under test 944 return $os_under_test; 945 } 946 public static function operating_system() 947 { 948 return self::$operating_system; 949 } 950 public static function is_linux() 951 { 952 return self::$operating_systems['linux']; 953 } 954 public static function is_minix() 955 { 956 return self::$operating_systems['minix']; 957 } 958 public static function is_solaris() 959 { 960 return self::$operating_systems['solaris']; 961 } 962 public static function is_bsd() 963 { 964 return self::$operating_systems['bsd']; 965 } 966 public static function is_macos() 967 { 968 return self::$operating_systems['macosx']; 969 } 970 public static function is_hurd() 971 { 972 return self::$operating_systems['hurd']; 973 } 974 public static function is_windows() 975 { 976 return self::$operating_systems['windows']; 977 } 978 public static function is_mesa_graphics() 979 { 980 self::detect_graphics(); 981 return self::$graphics['mesa']; 982 } 983 public static function is_nvidia_graphics() 984 { 985 self::detect_graphics(); 986 return self::$graphics['nvidia']; 987 } 988 public static function is_root() 989 { 990 return phodevi::read_property('system', 'username') == 'root' || is_writable('/root'); 991 } 992 public static function is_display_server_active() 993 { 994 if(phodevi::read_property('system', 'system-layer') == 'Docker') 995 { 996 // hopefully temp workaround XXX TODO 997 return false; 998 } 999 1000 return pts_client::read_env('DISPLAY') != false || pts_client::read_env('WAYLAND_DISPLAY') != false || phodevi::is_windows() || phodevi::is_macos(); 1001 } 1002} 1003 1004phodevi::create_vfs(); 1005 1006if(PTS_IS_CLIENT) 1007{ 1008 phodevi::initial_setup(); 1009} 1010 1011?> 1012