PageRenderTime 943ms CodeModel.GetById 156ms app.highlight 504ms RepoModel.GetById 167ms app.codeStats 2ms

/pts-core/objects/client/pts_client.php

https://github.com/atlassianhlechner/phoronix-test-suite
PHP | 1839 lines | 1491 code | 236 blank | 112 comment | 373 complexity | fd0160af7de50f23ddf7906f8e2e517f MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2
   3/*
   4	Phoronix Test Suite
   5	URLs: http://www.phoronix.com, http://www.phoronix-test-suite.com/
   6	Copyright (C) 2008 - 2014, Phoronix Media
   7	Copyright (C) 2008 - 2014, Michael Larabel
   8
   9	This program is free software; you can redistribute it and/or modify
  10	it under the terms of the GNU General Public License as published by
  11	the Free Software Foundation; either version 3 of the License, or
  12	(at your option) any later version.
  13
  14	This program is distributed in the hope that it will be useful,
  15	but WITHOUT ANY WARRANTY; without even the implied warranty of
  16	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17	GNU General Public License for more details.
  18
  19	You should have received a copy of the GNU General Public License
  20	along with this program. If not, see <http://www.gnu.org/licenses/>.
  21*/
  22
  23class pts_client
  24{
  25	public static $display = false;
  26	private static $current_command = null;
  27	protected static $lock_pointers = null;
  28	private static $forked_pids = array();
  29
  30	public static function create_lock($lock_file)
  31	{
  32		if(isset(self::$lock_pointers[$lock_file]) || is_writable(dirname($lock_file)) == false || disk_free_space(dirname($lock_file)) < 1024)
  33		{
  34			return false;
  35		}
  36
  37		self::$lock_pointers[$lock_file] = fopen($lock_file, 'w');
  38		chmod($lock_file, 0644);
  39		return self::$lock_pointers[$lock_file] != false && flock(self::$lock_pointers[$lock_file], LOCK_EX | LOCK_NB);
  40	}
  41	public static function init()
  42	{
  43		set_time_limit(0);
  44		pts_define_directories(); // Define directories
  45
  46		if(function_exists('cli_set_process_title'))
  47		{
  48			cli_set_process_title('Phoronix Test Suite');
  49		}
  50
  51		if(defined('QUICK_START') && QUICK_START)
  52		{
  53			return true;
  54		}
  55
  56		pts_define('PHP_BIN', pts_client::read_env('PHP_BIN'));
  57		pts_define('PTS_INIT_TIME', time());
  58
  59		if(!defined('PHP_VERSION_ID'))
  60		{
  61			// PHP_VERSION_ID is only available in PHP 5.2.6 and later
  62			$php_version = explode('.', PHP_VERSION);
  63			pts_define('PHP_VERSION_ID', ($php_version[0] * 10000 + $php_version[1] * 100 + $php_version[2]));
  64		}
  65
  66		$dir_init = array(PTS_USER_PATH);
  67		foreach($dir_init as $dir)
  68		{
  69			pts_file_io::mkdir($dir);
  70		}
  71
  72		if(PTS_IS_CLIENT)
  73		{
  74			pts_network::client_startup();
  75		}
  76
  77		self::core_storage_init_process();
  78
  79		if(!is_file(PTS_TEMP_STORAGE))
  80		{
  81			self::build_temp_cache();
  82		}
  83
  84		// XXX: technically the config init_files line shouldn't be needed since it should be dynamically called
  85		// pts_config::init_files();
  86		pts_define('PTS_TEST_INSTALL_DEFAULT_PATH', pts_client::parse_home_directory(pts_config::read_user_config('PhoronixTestSuite/Options/Installation/EnvironmentDirectory', '~/.phoronix-test-suite/installed-tests/')));
  87		pts_define('PTS_SAVE_RESULTS_PATH', pts_client::parse_home_directory(pts_config::read_user_config('PhoronixTestSuite/Options/Testing/ResultsDirectory', '~/.phoronix-test-suite/test-results/')));
  88		self::extended_init_process();
  89
  90		$openbenchmarking = pts_storage_object::read_from_file(PTS_CORE_STORAGE, 'openbenchmarking');
  91		$openbenchmarking_account_settings = pts_storage_object::read_from_file(PTS_CORE_STORAGE, 'openbenchmarking_account_settings');
  92
  93		if($openbenchmarking != null)
  94		{
  95			// OpenBenchmarking.org Account
  96			pts_openbenchmarking_client::init_account($openbenchmarking, $openbenchmarking_account_settings);
  97		}
  98
  99		return true;
 100	}
 101	public static function module_framework_init()
 102	{
 103		// Process initially called when PTS starts up
 104		// Check for modules to auto-load from the configuration file
 105		$load_modules = pts_config::read_user_config('PhoronixTestSuite/Options/Modules/LoadModules', null);
 106
 107		if(!empty($load_modules))
 108		{
 109			foreach(pts_strings::comma_explode($load_modules) as $module)
 110			{
 111				$module_r = pts_strings::trim_explode('=', $module);
 112
 113				if(count($module_r) == 2)
 114				{
 115					// TODO: end up hooking this into pts_module::read_variable() rather than using the real env
 116					pts_client::set_environment_variable($module_r[0], $module_r[1]);
 117				}
 118				else
 119				{
 120					pts_module_manager::attach_module($module);
 121				}
 122			}
 123		}
 124
 125		// Check for modules to load manually in PTS_MODULES
 126		if(($load_modules = pts_client::read_env('PTS_MODULES')) !== false)
 127		{
 128			foreach(pts_strings::comma_explode($load_modules) as $module)
 129			{
 130				if(!pts_module_manager::is_module_attached($module))
 131				{
 132					pts_module_manager::attach_module($module);
 133				}
 134			}
 135		}
 136
 137		// Detect modules to load automatically
 138		pts_module_manager::detect_modules_to_load();
 139
 140		// Clean-up modules list
 141		pts_module_manager::clean_module_list();
 142
 143		// Reset counter
 144		pts_module_manager::set_current_module(null);
 145
 146		// Load the modules
 147		$module_store_list = array();
 148		foreach(pts_module_manager::attached_modules() as $module)
 149		{
 150			$class_vars = get_class_vars($module);
 151			$module_store_vars = isset($class_vars['module_store_vars']) ? $class_vars['module_store_vars'] : null;
 152
 153			if(is_array($module_store_vars))
 154			{
 155				foreach($module_store_vars as $store_var)
 156				{
 157					if(!in_array($store_var, $module_store_list))
 158					{
 159						array_push($module_store_list, $store_var);
 160					}
 161				}
 162			}
 163		}
 164
 165		// Should any of the module options be saved to the results?
 166		foreach($module_store_list as $var)
 167		{
 168			$var_value = pts_client::read_env($var);
 169
 170			if(!empty($var_value))
 171			{
 172				pts_module_manager::var_store_add($var, $var_value);
 173			}
 174		}
 175
 176		pts_module_manager::module_process('__startup');
 177		pts_define('PTS_STARTUP_TASK_PERFORMED', true);
 178		register_shutdown_function(array('pts_module_manager', 'module_process'), '__shutdown');
 179	}
 180	public static function environmental_variables()
 181	{
 182		// The PTS environmental variables passed during the testing process, etc
 183		static $env_variables = null;
 184
 185		if($env_variables == null)
 186		{
 187			$env_variables = array(
 188			'PTS_VERSION' => PTS_VERSION,
 189			'PTS_CODENAME' => PTS_CODENAME,
 190			'PTS_DIR' => PTS_PATH,
 191			'PHP_BIN' => PHP_BIN,
 192			'NUM_CPU_CORES' => phodevi::read_property('cpu', 'core-count'),
 193			'NUM_CPU_NODES' => phodevi::read_property('cpu', 'node-count'),
 194			'NUM_CPU_JOBS' => (phodevi::read_property('cpu', 'core-count') * 2),
 195			'SYS_MEMORY' => phodevi::read_property('memory', 'capacity'),
 196			'VIDEO_MEMORY' => phodevi::read_property('gpu', 'memory-capacity'),
 197			'VIDEO_WIDTH' => pts_arrays::first_element(phodevi::read_property('gpu', 'screen-resolution')),
 198			'VIDEO_HEIGHT' => pts_arrays::last_element(phodevi::read_property('gpu', 'screen-resolution')),
 199			'VIDEO_MONITOR_COUNT' => phodevi::read_property('monitor', 'count'),
 200			'VIDEO_MONITOR_LAYOUT' => phodevi::read_property('monitor', 'layout'),
 201			'VIDEO_MONITOR_SIZES' => phodevi::read_property('monitor', 'modes'),
 202			'OPERATING_SYSTEM' => phodevi::read_property('system', 'vendor-identifier'),
 203			'OS_VERSION' => phodevi::read_property('system', 'os-version'),
 204			'OS_ARCH' => phodevi::read_property('system', 'kernel-architecture'),
 205			'OS_TYPE' => phodevi::operating_system(),
 206			'THIS_RUN_TIME' => PTS_INIT_TIME,
 207			'DEBUG_REAL_HOME' => pts_client::user_home_directory()
 208			);
 209
 210			if(!pts_client::executable_in_path('cc') && pts_client::executable_in_path('gcc'))
 211			{
 212				// This helps some test profiles build correctly if they don't do a cc check internally
 213				$env_variables['CC'] = 'gcc';
 214			}
 215		}
 216
 217		return $env_variables;
 218	}
 219	public static function test_install_root_path()
 220	{
 221		if(getenv('PTS_TEST_INSTALL_ROOT_PATH') != false && is_dir(getenv('PTS_TEST_INSTALL_ROOT_PATH')) && is_writable(getenv('PTS_TEST_INSTALL_ROOT_PATH')))
 222		{
 223			return getenv('PTS_TEST_INSTALL_ROOT_PATH');
 224		}
 225		else
 226		{
 227			return PTS_TEST_INSTALL_DEFAULT_PATH;
 228		}
 229	}
 230	public static function user_run_save_variables()
 231	{
 232		static $runtime_variables = null;
 233
 234		if($runtime_variables == null)
 235		{
 236			$runtime_variables = array(
 237			'VIDEO_RESOLUTION' => phodevi::read_property('gpu', 'screen-resolution-string'),
 238			'VIDEO_CARD' => phodevi::read_name('gpu'),
 239			'VIDEO_DRIVER' => phodevi::read_property('system', 'display-driver-string'),
 240			'OPENGL_DRIVER' => str_replace('(', '', phodevi::read_property('system', 'opengl-driver')),
 241			'OPERATING_SYSTEM' => phodevi::read_property('system', 'operating-system'),
 242			'PROCESSOR' => phodevi::read_name('cpu'),
 243			'MOTHERBOARD' => phodevi::read_name('motherboard'),
 244			'CHIPSET' => phodevi::read_name('chipset'),
 245			'KERNEL_VERSION' => phodevi::read_property('system', 'kernel'),
 246			'COMPILER' => phodevi::read_property('system', 'compiler'),
 247			'HOSTNAME' => phodevi::read_property('system', 'hostname')
 248			);
 249		}
 250
 251		return $runtime_variables;
 252	}
 253	public static function save_test_result($save_to = null, $save_results = null, $render_graphs = true, $result_identifier = null)
 254	{
 255		// Saves PTS result file
 256		if(substr($save_to, -4) != '.xml')
 257		{
 258			$save_to .= '.xml';
 259		}
 260
 261		$save_to_dir = pts_client::setup_test_result_directory($save_to);
 262
 263		if($save_to == null || $save_results == null)
 264		{
 265			$bool = false;
 266		}
 267		else
 268		{
 269			$save_name = basename($save_to, '.xml');
 270
 271			if($save_name == 'composite' && $render_graphs)
 272			{
 273				pts_client::generate_result_file_graphs($save_results, $save_to_dir);
 274			}
 275
 276			$bool = file_put_contents(PTS_SAVE_RESULTS_PATH . $save_to, $save_results);
 277
 278			if($result_identifier != null && (pts_config::read_bool_config('PhoronixTestSuite/Options/Testing/SaveSystemLogs', 'TRUE') || (pts_c::$test_flags & pts_c::batch_mode) || (pts_c::$test_flags & pts_c::auto_mode)))
 279			{
 280				// Save verbose system information here
 281				$system_log_dir = $save_to_dir . '/system-logs/' . $result_identifier . '/';
 282				pts_file_io::mkdir($system_log_dir, 0777, true);
 283
 284				// Backup system files
 285				// TODO: move out these files/commands to log out to respective Phodevi components so only what's relevant will be logged
 286				$system_log_files = array(
 287					'/var/log/Xorg.0.log',
 288					'/proc/cpuinfo',
 289					'/proc/meminfo',
 290					'/proc/modules',
 291					'/proc/mounts',
 292					'/proc/cmdline',
 293					'/proc/version',
 294					'/etc/X11/xorg.conf',
 295					'/sys/kernel/debug/dri/0/radeon_pm_info',
 296					'/sys/kernel/debug/dri/0/i915_capabilities',
 297					'/sys/kernel/debug/dri/0/i915_cur_delayinfo',
 298					'/sys/kernel/debug/dri/0/i915_drpc_info',
 299					'/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies',
 300					);
 301
 302				/*
 303				if(phodevi::is_linux())
 304				{
 305					// the kernel config file might just be too large to upload for now
 306					array_push($system_log_files, '/boot/config-' . php_uname('r'));
 307				}
 308				*/
 309
 310				foreach($system_log_files as $file)
 311				{
 312					if(is_file($file) && is_readable($file))
 313					{
 314						// copy() can't be used in this case since it will result in a blank file for /proc/ file-system
 315						$file_contents = file_get_contents($file);
 316						$file_contents = pts_strings::remove_line_timestamps($file_contents);
 317						file_put_contents($system_log_dir . basename($file), $file_contents);
 318					}
 319				}
 320
 321				// Generate logs from system commands to backup
 322				$system_log_commands = array(
 323					'lspci -mmkvvvnn',
 324					'lscpu',
 325					'cc -v',
 326					'lsusb',
 327					'lsmod',
 328					'sensors',
 329					'dmesg',
 330					'vdpauinfo',
 331					'cpufreq-info',
 332					'glxinfo',
 333					'clinfo',
 334					'uname -a',
 335					// 'udisks --dump',
 336					'upower --dump',
 337					);
 338
 339				if(phodevi::is_bsd())
 340				{
 341					array_push($system_log_commands, 'sysctl -a');
 342					array_push($system_log_commands, 'kenv');
 343				}
 344				if(is_readable('/dev/mem'))
 345				{
 346					array_push($system_log_commands, 'dmidecode');
 347				}
 348
 349				foreach($system_log_commands as $command_string)
 350				{
 351					$command = explode(' ', $command_string);
 352
 353					if(($command_bin = pts_client::executable_in_path($command[0])))
 354					{
 355						$cmd_output = shell_exec('cd ' . dirname($command_bin) . ' && ./' . $command_string . ' 2>&1');
 356
 357						// Try to filter out any serial numbers, etc.
 358						phodevi_vfs::cleanse_file($cmd_output, $command[0]);
 359						$cmd_output = pts_strings::remove_line_timestamps($cmd_output);
 360
 361						file_put_contents($system_log_dir . $command[0], $cmd_output);
 362					}
 363				}
 364
 365				// Dump some common / important environmental variables
 366				$environment_variables = array(
 367					'PATH' => null,
 368					'CFLAGS' => null,
 369					'CXXFLAGS' => null,
 370					'LD_LIBRARY_PATH' => null,
 371					'CC' => null,
 372					'CXX' => null,
 373					'LIBGL_DRIVERS_PATH' => null
 374					);
 375
 376				foreach($environment_variables as $variable => &$value)
 377				{
 378					$v = getenv($variable);
 379
 380					if($v != null)
 381					{
 382						$value = $v;
 383					}
 384					else
 385					{
 386						unset($environment_variables[$variable]);
 387					}
 388				}
 389
 390				if(!empty($environment_variables))
 391				{
 392					$variable_dump = null;
 393					foreach($environment_variables as $variable => $value)
 394					{
 395						$variable_dump .= $variable . '=' . $value . PHP_EOL;
 396					}
 397					file_put_contents($system_log_dir . 'environment-variables', $variable_dump);
 398				}
 399			}
 400		}
 401
 402		return $bool;
 403	}
 404	public static function save_result_file(&$result_file_writer, $save_name)
 405	{
 406		// Save the test file
 407		// TODO: clean this up with pts_client::save_test_result
 408		$j = 1;
 409		while(is_file(PTS_SAVE_RESULTS_PATH . $save_name . '/test-' . $j . '.xml'))
 410		{
 411			$j++;
 412		}
 413
 414		$real_name = $save_name . '/test-' . $j . '.xml';
 415
 416		pts_client::save_test_result($real_name, $result_file_writer->get_xml());
 417
 418		if(!is_file(PTS_SAVE_RESULTS_PATH . $save_name . '/composite.xml'))
 419		{
 420			pts_client::save_test_result($save_name . '/composite.xml', file_get_contents(PTS_SAVE_RESULTS_PATH . $real_name), true, $result_file_writer->get_result_identifier());
 421		}
 422		else
 423		{
 424			// Merge Results
 425			$merged_results = pts_merge::merge_test_results(file_get_contents(PTS_SAVE_RESULTS_PATH . $save_name . '/composite.xml'), file_get_contents(PTS_SAVE_RESULTS_PATH . $real_name));
 426			pts_client::save_test_result($save_name . '/composite.xml', $merged_results, true, $result_file_writer->get_result_identifier());
 427		}
 428
 429		return $real_name;
 430	}
 431	public static function init_display_mode($flags = 0)
 432	{
 433		if(PTS_IS_WEB_CLIENT && !defined('PHOROMATIC_SERVER'))
 434		{
 435			self::$display = new pts_web_display_mode();
 436			return;
 437		}
 438
 439		$env_mode = ($flags & pts_c::debug_mode) ? 'BASIC' : false;
 440
 441		switch(($env_mode != false || ($env_mode = pts_client::read_env('PTS_DISPLAY_MODE')) != false ? $env_mode : pts_config::read_user_config('PhoronixTestSuite/Options/General/DefaultDisplayMode', 'DEFAULT')))
 442		{
 443			case 'BASIC':
 444				self::$display = new pts_basic_display_mode();
 445				break;
 446			case 'BATCH':
 447			case 'CONCISE':
 448				self::$display = new pts_concise_display_mode();
 449				break;
 450			case 'DEFAULT':
 451			default:
 452				self::$display = new pts_concise_display_mode();
 453				break;
 454		}
 455	}
 456	private static function extended_init_process()
 457	{
 458		// Extended Initalization Process
 459		$directory_check = array(
 460			PTS_TEST_INSTALL_DEFAULT_PATH,
 461			PTS_SAVE_RESULTS_PATH,
 462			PTS_MODULE_LOCAL_PATH,
 463			PTS_MODULE_DATA_PATH,
 464			PTS_DOWNLOAD_CACHE_PATH,
 465			PTS_OPENBENCHMARKING_SCRATCH_PATH,
 466			PTS_TEST_PROFILE_PATH,
 467			PTS_TEST_SUITE_PATH,
 468			PTS_TEST_PROFILE_PATH . 'local/',
 469			PTS_TEST_SUITE_PATH . 'local/'
 470			);
 471
 472		foreach($directory_check as $dir)
 473		{
 474			pts_file_io::mkdir($dir);
 475		}
 476
 477		// Setup PTS Results Viewer
 478		pts_file_io::mkdir(PTS_SAVE_RESULTS_PATH . 'pts-results-viewer');
 479
 480		foreach(pts_file_io::glob(PTS_RESULTS_VIEWER_PATH . '*') as $result_viewer_file)
 481		{
 482			copy($result_viewer_file, PTS_SAVE_RESULTS_PATH . 'pts-results-viewer/' . basename($result_viewer_file));
 483		}
 484
 485		copy(PTS_CORE_STATIC_PATH . 'images/pts-106x55.png', PTS_SAVE_RESULTS_PATH . 'pts-results-viewer/pts-106x55.png');
 486
 487		// Setup ~/.phoronix-test-suite/xsl/
 488		pts_file_io::mkdir(PTS_USER_PATH . 'xsl/');
 489		copy(PTS_CORE_STATIC_PATH . 'xsl/pts-test-installation-viewer.xsl', PTS_USER_PATH . 'xsl/' . 'pts-test-installation-viewer.xsl');
 490		copy(PTS_CORE_STATIC_PATH . 'xsl/pts-user-config-viewer.xsl', PTS_USER_PATH . 'xsl/' . 'pts-user-config-viewer.xsl');
 491		copy(PTS_CORE_STATIC_PATH . 'images/pts-308x160.png', PTS_USER_PATH . 'xsl/' . 'pts-logo.png');
 492
 493		// pts_compatibility ops here
 494
 495		pts_client::init_display_mode();
 496	}
 497	public static function program_requirement_checks($only_show_required = false)
 498	{
 499		$extension_checks = pts_needed_extensions();
 500
 501		$printed_required_header = false;
 502		$printed_optional_header = false;
 503		foreach($extension_checks as $extension)
 504		{
 505			if($extension[1] == false)
 506			{
 507				if($extension[0] == 1)
 508				{
 509					// Oops, this extension is required
 510					if($printed_required_header == false)
 511					{
 512						echo PHP_EOL . 'The following PHP extensions are REQUIRED by the Phoronix Test Suite:' . PHP_EOL . PHP_EOL;
 513						$printed_required_header = true;
 514					}
 515				}
 516				else
 517				{
 518					if($only_show_required && $printed_required_header == false)
 519					{
 520						continue;
 521					}
 522
 523					// This extension is missing but optional
 524					if($printed_optional_header == false)
 525					{
 526						echo PHP_EOL . ($printed_required_header ? null : 'NOTICE: ') . 'The following PHP extensions are OPTIONAL but recommended:' . PHP_EOL . PHP_EOL;
 527						$printed_optional_header = true;
 528					}
 529				}
 530
 531				echo sprintf('%-8ls %-30ls' . PHP_EOL, $extension[2], $extension[3]);
 532			}
 533		}
 534
 535		if($printed_required_header || $printed_optional_header)
 536		{
 537			echo PHP_EOL;
 538
 539			if($printed_required_header)
 540			{
 541				exit;
 542			}
 543		}
 544	}
 545	private static function build_temp_cache()
 546	{
 547		$pso = pts_storage_object::recover_from_file(PTS_TEMP_STORAGE);
 548
 549		if($pso == false)
 550		{
 551			$pso = new pts_storage_object();
 552		}
 553
 554		$pso->add_object('environmental_variables_for_modules', pts_module_manager::modules_environmental_variables());
 555		$pso->add_object('command_alias_list', pts_documentation::client_commands_aliases());
 556
 557		$pso->save_to_file(PTS_TEMP_STORAGE);
 558	}
 559	private static function core_storage_init_process()
 560	{
 561		$pso = pts_storage_object::recover_from_file(PTS_CORE_STORAGE);
 562
 563		if($pso == false)
 564		{
 565			$pso = new pts_storage_object(true, true);
 566		}
 567
 568		// OpenBenchmarking.org - GSID
 569		$global_gsid = $pso->read_object('global_system_id');
 570		$global_gsid_e = $pso->read_object('global_system_id_e');
 571		$global_gsid_p = $pso->read_object('global_system_id_p');
 572
 573		if(empty($global_gsid) || pts_openbenchmarking::is_valid_gsid_format($global_gsid) == false)
 574		{
 575			// Global System ID for anonymous uploads, etc
 576			$requested_gsid = true;
 577			$global_gsid = pts_openbenchmarking_client::request_gsid();
 578
 579			if(is_array($global_gsid))
 580			{
 581				$pso->add_object('global_system_id', $global_gsid['gsid']); // GSID
 582				$pso->add_object('global_system_id_p', $global_gsid['gsid_p']); // GSID_P
 583				$pso->add_object('global_system_id_e', $global_gsid['gsid_e']); // GSID_E
 584				pts_define('PTS_GSID', $global_gsid['gsid']);
 585				pts_define('PTS_GSID_E', $global_gsid['gsid_e']);
 586			}
 587		}
 588		else if(pts_openbenchmarking::is_valid_gsid_e_format($global_gsid_e) == false || pts_openbenchmarking::is_valid_gsid_p_format($global_gsid_p) == false)
 589		{
 590			pts_define('PTS_GSID', $global_gsid);
 591			$requested_gsid = false;
 592			$global_gsid = pts_openbenchmarking_client::retrieve_gsid();
 593
 594			if(is_array($global_gsid))
 595			{
 596				$pso->add_object('global_system_id_p', $global_gsid['gsid_p']); // GSID_P
 597				$pso->add_object('global_system_id_e', $global_gsid['gsid_e']); // GSID_E
 598				pts_define('PTS_GSID_E', $global_gsid['gsid_e']);
 599			}
 600		}
 601		else
 602		{
 603			pts_define('PTS_GSID', $global_gsid);
 604			pts_define('PTS_GSID_E', $global_gsid_e);
 605			$requested_gsid = false;
 606		}
 607
 608		// Last Run Processing
 609		$last_core_version = $pso->read_object('last_core_version');
 610		pts_define('FIRST_RUN_ON_PTS_UPGRADE', ($last_core_version != PTS_CORE_VERSION));
 611
 612		if(FIRST_RUN_ON_PTS_UPGRADE || ($pso->read_object('last_php_version') != PTS_PHP_VERSION))
 613		{
 614			// Report any missing/recommended extensions
 615			self::program_requirement_checks();
 616		}
 617
 618		if(FIRST_RUN_ON_PTS_UPGRADE)
 619		{
 620			if($requested_gsid == false)
 621			{
 622				pts_openbenchmarking_client::update_gsid();
 623			}
 624
 625			pts_client::build_temp_cache();
 626		}
 627		$pso->add_object('last_core_version', PTS_CORE_VERSION); // PTS version last run
 628		$pso->add_object('last_php_version', PTS_PHP_VERSION); // PHP version last run
 629
 630		//$last_pts_version = $pso->read_object('last_pts_version');
 631		// do something here with $last_pts_version if you want that information
 632		$pso->add_object('last_pts_version', PTS_VERSION); // PTS version last run
 633
 634		// Last Run Processing
 635		$last_run = $pso->read_object('last_run_time');
 636		pts_define('IS_FIRST_RUN_TODAY', (substr($last_run, 0, 10) != date('Y-m-d')));
 637		$pso->add_object('last_run_time', date('Y-m-d H:i:s')); // Time PTS was last run
 638
 639
 640		// User Agreement Checking
 641		$agreement_cs = $pso->read_object('user_agreement_cs');
 642
 643		$pso->add_object('user_agreement_cs', $agreement_cs); // User agreement check-sum
 644
 645		// Phodevi Cache Handling
 646		$phodevi_cache = $pso->read_object('phodevi_smart_cache');
 647
 648		if($phodevi_cache instanceof phodevi_cache && pts_flags::no_phodevi_cache() == false)
 649		{
 650			$phodevi_cache = $phodevi_cache->restore_cache(PTS_USER_PATH, PTS_CORE_VERSION);
 651			phodevi::set_device_cache($phodevi_cache);
 652
 653			if(($external_phodevi_cache = pts_client::read_env('EXTERNAL_PHODEVI_CACHE')))
 654			{
 655				if(is_dir($external_phodevi_cache) && is_file($external_phodevi_cache . '/core.pt2so'))
 656				{
 657					$external_phodevi_cache .= '/core.pt2so';
 658				}
 659
 660				if(is_file($external_phodevi_cache))
 661				{
 662					$external_phodevi_cache = pts_storage_object::force_recover_from_file($external_phodevi_cache);
 663
 664					if($external_phodevi_cache != false)
 665					{
 666						$external_phodevi_cache = $external_phodevi_cache->read_object('phodevi_smart_cache');
 667						$external_phodevi_cache = $external_phodevi_cache->restore_cache(null, PTS_CORE_VERSION);
 668
 669						if($external_phodevi_cache != false)
 670						{
 671							//unset($external_phodevi_cache['system']['operating-system']);
 672							//unset($external_phodevi_cache['system']['vendor-identifier']);
 673							phodevi::set_device_cache($external_phodevi_cache);
 674						}
 675					}
 676				}
 677			}
 678		}
 679
 680		// Archive to disk
 681		$pso->save_to_file(PTS_CORE_STORAGE);
 682	}
 683	public static function user_agreement_check($command)
 684	{
 685		$pso = pts_storage_object::recover_from_file(PTS_CORE_STORAGE);
 686
 687		if($pso == false)
 688		{
 689			return false;
 690		}
 691
 692		$config_md5 = $pso->read_object('user_agreement_cs');
 693		$current_md5 = md5_file(PTS_PATH . 'pts-core/user-agreement.txt');
 694
 695		if($config_md5 != $current_md5 || pts_config::read_user_config('PhoronixTestSuite/Options/OpenBenchmarking/AnonymousUsageReporting', 'UNKNOWN') == 'UNKNOWN')
 696		{
 697			$prompt_in_method = pts_client::check_command_for_function($command, 'pts_user_agreement_prompt');
 698			$user_agreement = file_get_contents(PTS_PATH . 'pts-core/user-agreement.txt');
 699
 700			if($prompt_in_method)
 701			{
 702				$user_agreement_return = call_user_func(array($command, 'pts_user_agreement_prompt'), $user_agreement);
 703
 704				if(is_array($user_agreement_return))
 705				{
 706					if(count($user_agreement_return) == 3)
 707					{
 708						list($agree, $usage_reporting, $hwsw_reporting) = $user_agreement_return;
 709					}
 710					else
 711					{
 712						$agree = array_shift($user_agreement_return);
 713						$usage_reporting = -1;
 714						$hwsw_reporting = -1;
 715					}
 716				}
 717				else
 718				{
 719					$agree = $user_agreement_return;
 720					$usage_reporting = -1;
 721					$hwsw_reporting = -1;
 722				}
 723			}
 724
 725			if($prompt_in_method == false || $usage_reporting == -1 || $hwsw_reporting == -1)
 726			{
 727				pts_client::$display->generic_heading('User Agreement');
 728				echo wordwrap($user_agreement, 65);
 729				$agree = pts_flags::user_agreement_skip() || pts_user_io::prompt_bool_input('Do you agree to these terms and wish to proceed', true);
 730
 731				if(pts_flags::no_openbenchmarking_reporting())
 732				{
 733					$usage_reporting = false;
 734					$hwsw_reporting = false;
 735				}
 736				else
 737				{
 738					$usage_reporting = $agree ? pts_user_io::prompt_bool_input('Enable anonymous usage / statistics reporting', true) : -1;
 739					$hwsw_reporting = $agree ? pts_user_io::prompt_bool_input('Enable anonymous statistical reporting of installed software / hardware', true) : -1;
 740				}
 741			}
 742
 743			if($agree)
 744			{
 745				echo PHP_EOL;
 746				$pso->add_object('user_agreement_cs', $current_md5);
 747				$pso->save_to_file(PTS_CORE_STORAGE);
 748			}
 749			else
 750			{
 751				pts_client::exit_client('In order to run the Phoronix Test Suite, you must agree to the listed terms.');
 752			}
 753
 754			pts_config::user_config_generate(array(
 755				'PhoronixTestSuite/Options/OpenBenchmarking/AnonymousUsageReporting' => pts_config::bool_to_string($usage_reporting),
 756				'PhoronixTestSuite/Options/OpenBenchmarking/AnonymousHardwareReporting' => pts_config::bool_to_string($hwsw_reporting),
 757				'PhoronixTestSuite/Options/OpenBenchmarking/AnonymousSoftwareReporting' => pts_config::bool_to_string($hwsw_reporting)
 758				));
 759		}
 760	}
 761	public static function swap_variables($user_str, $replace_call)
 762	{
 763		if(is_array($replace_call))
 764		{
 765			if(count($replace_call) != 2 || method_exists($replace_call[0], $replace_call[1]) == false)
 766			{
 767				echo PHP_EOL . 'Var Swap With Method Failed.' . PHP_EOL;
 768				return $user_str;
 769			}
 770		}
 771		else if(!function_exists($replace_call))
 772		{
 773			echo PHP_EOL . 'Var Swap With Function Failed.' . PHP_EOL;
 774			return $user_str;
 775		}
 776
 777		$offset = 0;
 778		$replace_call_return = false;
 779
 780		while($offset < strlen($user_str) && ($s = strpos($user_str, '$', $offset)) !== false)
 781		{
 782			$s++;
 783			$var_name = substr($user_str, $s, (($e = strpos($user_str, ' ', $s)) == false ? strlen($user_str) : $e) - $s);
 784
 785			if($replace_call_return === false)
 786			{
 787				$replace_call_return = call_user_func($replace_call);
 788			}
 789
 790			$var_replacement = isset($replace_call_return[$var_name]) ? $replace_call_return[$var_name] : null;
 791
 792			if($var_replacement != null)
 793			{
 794				$user_str = str_replace('$' . $var_name, $var_replacement, $user_str);
 795			}
 796			else
 797			{
 798				// echo "\nVariable Swap For $var_name Failed.\n";
 799			}
 800
 801			$offset = $s + strlen($var_replacement);
 802		}
 803
 804		return $user_str;
 805	}
 806	public static function setup_test_result_directory($save_to)
 807	{
 808		$save_to_dir = PTS_SAVE_RESULTS_PATH . $save_to;
 809
 810		if(strpos(basename($save_to_dir), '.'))
 811		{
 812			$save_to_dir = dirname($save_to_dir);
 813		}
 814
 815		if($save_to_dir != '.')
 816		{
 817			pts_file_io::mkdir($save_to_dir);
 818		}
 819
 820		file_put_contents($save_to_dir . '/index.html', '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><html><head><title>Phoronix Test Suite</title><meta http-equiv="REFRESH" content="0;url=composite.xml"></HEAD><BODY></BODY></HTML>');
 821
 822		return $save_to_dir;
 823	}
 824	public static function remove_installed_test(&$test_profile)
 825	{
 826		pts_file_io::delete($test_profile->get_install_dir(), null, true);
 827	}
 828	public static function exit_client($string = null, $exit_status = 0)
 829	{
 830		// Exit the Phoronix Test Suite client
 831		pts_define('PTS_EXIT', 1);
 832
 833		if($string != null)
 834		{
 835			echo PHP_EOL . $string . PHP_EOL;
 836		}
 837
 838		exit($exit_status);
 839	}
 840	public static function current_user()
 841	{
 842		// Current system user
 843		return ($pts_user = pts_openbenchmarking_client::user_name()) != null ? $pts_user : phodevi::read_property('system', 'username');
 844	}
 845	public static function user_home_directory()
 846	{
 847		// Gets the system user's home directory
 848		static $userhome = null;
 849
 850		if($userhome == null)
 851		{
 852			if(function_exists('posix_getpwuid') && function_exists('posix_getuid'))
 853			{
 854				$userinfo = posix_getpwuid(posix_getuid());
 855				$userhome = $userinfo['dir'];
 856			}
 857			else if(($home = pts_client::read_env('HOME')))
 858			{
 859				$userhome = $home;
 860			}
 861			else if(($home = pts_client::read_env('HOMEPATH')))
 862			{
 863				$userhome = pts_client::read_env('HOMEDRIVE') . $home;
 864			}
 865			else
 866			{
 867				echo PHP_EOL . 'ERROR: Cannot find home directory.' . PHP_EOL;
 868				$userhome = null;
 869			}
 870
 871			$userhome = pts_strings::add_trailing_slash($userhome);
 872		}
 873
 874		return $userhome;
 875	}
 876	public static function test_profile_debug_message($message)
 877	{
 878		$reported = false;
 879
 880		if((pts_c::$test_flags & pts_c::debug_mode))
 881		{
 882			pts_client::$display->test_run_instance_error($message);
 883			$reported = true;
 884		}
 885
 886		return $reported;
 887	}
 888	public static function parse_home_directory($path)
 889	{
 890		// Find home directory if needed
 891		if(strpos($path, '~/') !== false)
 892		{
 893			$path = str_replace('~/', pts_client::user_home_directory(), $path);
 894		}
 895
 896		return pts_strings::add_trailing_slash($path);
 897	}
 898	public static function xsl_results_viewer_graph_template()
 899	{
 900		$raw_xsl = file_get_contents(PTS_RESULTS_VIEWER_PATH . 'pts-results-viewer.xsl');
 901
 902		// System Tables
 903		$conversions = array('systems', 'detailed_component', 'radar', 'overview', 'visualize');
 904		foreach($conversions as $convert)
 905		{
 906			$graph_string = pts_svg_dom::html_embed_code('result-graphs/' . $convert . '.BILDE_EXTENSION', 'SVG', array('width' => 'auto', 'height' => 'auto'), true);
 907			$raw_xsl = str_replace('<!-- ' . strtoupper($convert) . ' TAG -->', $graph_string, $raw_xsl);
 908		}
 909
 910		// Result Graphs
 911		$graph_string = pts_svg_dom::html_embed_code('result-graphs/<xsl:number value="position()" />.BILDE_EXTENSION', 'SVG', array('width' => 'auto', 'height' => 'auto'), true);
 912		$raw_xsl = str_replace('<!-- GRAPH TAG -->', $graph_string, $raw_xsl);
 913
 914		return $raw_xsl;
 915	}
 916	public static function generate_result_file_graphs($test_results_identifier, $save_to_dir = false)
 917	{
 918		if($save_to_dir)
 919		{
 920			if(pts_file_io::mkdir($save_to_dir . '/result-graphs') == false)
 921			{
 922				// Directory must exist, so remove any old graph files first
 923				foreach(pts_file_io::glob($save_to_dir . '/result-graphs/*') as $old_file)
 924				{
 925					unlink($old_file);
 926				}
 927			}
 928		}
 929
 930		$result_file = new pts_result_file($test_results_identifier);
 931
 932		$generated_graphs = array();
 933		$generated_graph_tables = false;
 934
 935		// Render overview chart
 936		if($save_to_dir)
 937		{
 938			$chart = new pts_ResultFileTable($result_file);
 939			$chart->renderChart($save_to_dir . '/result-graphs/overview.BILDE_EXTENSION');
 940
 941			$intent = -1;
 942			if(($intent = pts_result_file_analyzer::analyze_result_file_intent($result_file, $intent, true)) || $result_file->get_system_count() == 1)
 943			{
 944				$chart = new pts_ResultFileCompactSystemsTable($result_file, $intent);
 945			}
 946			else
 947			{
 948				$chart = new pts_ResultFileSystemsTable($result_file);
 949			}
 950			$chart->renderChart($save_to_dir . '/result-graphs/systems.BILDE_EXTENSION');
 951			unset($chart);
 952
 953			if($intent && is_dir($save_to_dir . '/system-logs/'))
 954			{
 955				$chart = new pts_DetailedSystemComponentTable($result_file, $save_to_dir . '/system-logs/', $intent);
 956
 957				if($chart)
 958				{
 959					$chart->renderChart($save_to_dir . '/result-graphs/detailed_component.BILDE_EXTENSION');
 960				}
 961			}
 962		}
 963
 964		foreach($result_file->get_result_objects() as $key => $result_object)
 965		{
 966			$save_to = $save_to_dir;
 967
 968			if($save_to_dir && is_dir($save_to_dir))
 969			{
 970				$save_to .= '/result-graphs/' . ($key + 1) . '.BILDE_EXTENSION';
 971
 972				if(PTS_IS_CLIENT)
 973				{
 974					if($result_file->is_multi_way_comparison() || pts_client::read_env('GRAPH_GROUP_SIMILAR'))
 975					{
 976						$table_keys = array();
 977						$titles = $result_file->get_test_titles();
 978
 979						foreach($titles as $this_title_index => $this_title)
 980						{
 981							if($this_title == $titles[$key])
 982							{
 983								array_push($table_keys, $this_title_index);
 984							}
 985						}
 986					}
 987					else
 988					{
 989						$table_keys = $key;
 990					}
 991
 992					$chart = new pts_ResultFileTable($result_file, null, $table_keys);
 993					$chart->renderChart($save_to_dir . '/result-graphs/' . ($key + 1) . '_table.BILDE_EXTENSION');
 994					unset($chart);
 995					$generated_graph_tables = true;
 996				}
 997			}
 998
 999			$graph = pts_render::render_graph($result_object, $result_file, $save_to);
1000			array_push($generated_graphs, $graph);
1001		}
1002
1003		// Generate mini / overview graphs
1004		if($save_to_dir)
1005		{
1006			$graph = new pts_OverviewGraph($result_file);
1007
1008			if($graph->doSkipGraph() == false)
1009			{
1010				$graph->renderGraph();
1011
1012				// Check to see if skip_graph was realized during the rendering process
1013				if($graph->doSkipGraph() == false)
1014				{
1015					$graph->svg_dom->output($save_to_dir . '/result-graphs/visualize.BILDE_EXTENSION');
1016				}
1017			}
1018			unset($graph);
1019
1020			$graph = new pts_RadarOverviewGraph($result_file);
1021
1022			if($graph->doSkipGraph() == false)
1023			{
1024				$graph->renderGraph();
1025
1026				// Check to see if skip_graph was realized during the rendering process
1027				if($graph->doSkipGraph() == false)
1028				{
1029					$graph->svg_dom->output($save_to_dir . '/result-graphs/radar.BILDE_EXTENSION');
1030				}
1031			}
1032			unset($graph);
1033
1034			/*
1035			// TODO XXX: just stuffing some debug code here temporarily while working on block diagram code...
1036			$graph = new pts_BlockDiagramGraph($result_file);
1037			$graph->renderGraph();
1038			$graph->svg_dom->output($save_to_dir . '/result-graphs/blocks.BILDE_EXTENSION');
1039			*/
1040		}
1041
1042		// Save XSL
1043		if(count($generated_graphs) > 0 && $save_to_dir)
1044		{
1045			file_put_contents($save_to_dir . '/pts-results-viewer.xsl', pts_client::xsl_results_viewer_graph_template($generated_graph_tables));
1046		}
1047
1048		return $generated_graphs;
1049	}
1050
1051	public static function process_shutdown_tasks()
1052	{
1053		// TODO: possibly do something like posix_getpid() != pts_client::$startup_pid in case shutdown function is called from a child process
1054		// Generate Phodevi Smart Cache
1055		if(pts_flags::no_phodevi_cache() == false && pts_client::read_env('EXTERNAL_PHODEVI_CACHE') == false)
1056		{
1057			if(pts_config::read_bool_config('PhoronixTestSuite/Options/General/UsePhodeviCache', 'TRUE'))
1058			{
1059				pts_storage_object::set_in_file(PTS_CORE_STORAGE, 'phodevi_smart_cache', phodevi::get_phodevi_cache_object(PTS_USER_PATH, PTS_CORE_VERSION));
1060			}
1061			else
1062			{
1063				pts_storage_object::set_in_file(PTS_CORE_STORAGE, 'phodevi_smart_cache', null);
1064			}
1065		}
1066
1067		if(is_array(self::$lock_pointers))
1068		{
1069			foreach(array_keys(self::$lock_pointers) as $lock_file)
1070			{
1071				self::release_lock($lock_file);
1072			}
1073		}
1074
1075		foreach(self::$forked_pids as $pid)
1076		{
1077			if(is_dir('/proc/' . $pid) && function_exists('posix_kill'))
1078			{
1079				posix_kill($pid, SIGKILL);
1080			}
1081		}
1082	}
1083	public static function do_anonymous_usage_reporting()
1084	{
1085		return pts_config::read_bool_config('PhoronixTestSuite/Options/OpenBenchmarking/AnonymousUsageReporting', 0);
1086	}
1087	public static function release_lock($lock_file)
1088	{
1089		// Remove lock
1090		if(isset(self::$lock_pointers[$lock_file]) == false)
1091		{
1092			return false;
1093		}
1094
1095		if(is_resource(self::$lock_pointers[$lock_file]))
1096		{
1097			fclose(self::$lock_pointers[$lock_file]);
1098		}
1099
1100		pts_file_io::unlink($lock_file);
1101		unset(self::$lock_pointers[$lock_file]);
1102	}
1103	public static function check_command_for_function($option, $check_function)
1104	{
1105		$in_option = false;
1106
1107		if(is_file(PTS_COMMAND_PATH . $option . '.php'))
1108		{
1109			if(!class_exists($option, false) && is_file(PTS_COMMAND_PATH . $option . '.php'))
1110			{
1111				include(PTS_COMMAND_PATH . $option . '.php');
1112			}
1113
1114			if(method_exists($option, $check_function))
1115			{
1116				$in_option = true;
1117			}
1118		}
1119
1120		return $in_option;
1121	}
1122	public static function regenerate_graphs($result_file_identifier, $full_process_string = false, $extra_graph_attributes = null)
1123	{
1124		$save_to_dir = pts_client::setup_test_result_directory($result_file_identifier);
1125		$generated_graphs = pts_client::generate_result_file_graphs($result_file_identifier, $save_to_dir, false, $extra_graph_attributes);
1126		$generated = count($generated_graphs) > 0;
1127
1128		if($generated && $full_process_string)
1129		{
1130			echo PHP_EOL . $full_process_string . PHP_EOL;
1131			pts_client::display_web_page(PTS_SAVE_RESULTS_PATH . $result_file_identifier . '/index.html');
1132		}
1133
1134		return $generated;
1135	}
1136	public static function set_test_flags($test_flags = 0)
1137	{
1138		pts_c::$test_flags = $test_flags;
1139	}
1140	public static function execute_command($command, $pass_args = null)
1141	{
1142		if(!class_exists($command, false) && is_file(PTS_COMMAND_PATH . $command . '.php'))
1143		{
1144			include(PTS_COMMAND_PATH . $command . '.php');
1145		}
1146
1147		if(is_file(PTS_COMMAND_PATH . $command . '.php') && method_exists($command, 'argument_checks'))
1148		{
1149			$argument_checks = call_user_func(array($command, 'argument_checks'));
1150
1151			foreach($argument_checks as &$argument_check)
1152			{
1153				$function_check = $argument_check->get_function_check();
1154				$method_check = false;
1155
1156				if(is_array($function_check) && count($function_check) == 2)
1157				{
1158					$method_check = $function_check[0];
1159					$function_check = $function_check[1];
1160				}
1161
1162				if(substr($function_check, 0, 1) == '!')
1163				{
1164					$function_check = substr($function_check, 1);
1165					$return_fails_on = true;
1166				}
1167				else
1168				{
1169					$return_fails_on = false;
1170				}
1171
1172				
1173				if($method_check != false)
1174				{
1175					if(!method_exists($method_check, $function_check))
1176					{
1177						echo PHP_EOL . 'Method check fails.' . PHP_EOL;
1178						continue;
1179					}
1180
1181					$function_check = array($method_check, $function_check);
1182				}
1183				else if(!function_exists($function_check))
1184				{
1185					continue;
1186				}
1187
1188				if($argument_check->get_argument_index() == 'VARIABLE_LENGTH')
1189				{
1190					$return_value = null;
1191
1192					foreach($pass_args as $arg)
1193					{
1194						$return_value = call_user_func_array($function_check, array($arg));
1195
1196						if($return_value == true)
1197						{
1198							break;
1199						}
1200					}
1201
1202				}
1203				else
1204				{
1205					$return_value = call_user_func_array($function_check, array((isset($pass_args[$argument_check->get_argument_index()]) ? $pass_args[$argument_check->get_argument_index()] : null)));
1206				}
1207
1208				if($return_value == $return_fails_on)
1209				{
1210					$command_alias = defined($command . '::doc_use_alias') ? constant($command . '::doc_use_alias') : $command;
1211
1212					if((isset($pass_args[$argument_check->get_argument_index()]) && !empty($pass_args[$argument_check->get_argument_index()])) || ($argument_check->get_argument_index() == 'VARIABLE_LENGTH' && !empty($pass_args)))
1213					{
1214						trigger_error('Invalid Argument: ' . implode(' ', $pass_args), E_USER_ERROR);
1215					}
1216					else
1217					{
1218						trigger_error('Phoronix Test Suite Argument Missing.', E_USER_ERROR);
1219					}
1220
1221					echo PHP_EOL . 'CORRECT SYNTAX:' . PHP_EOL . 'phoronix-test-suite ' . str_replace('_', '-', $command_alias) . ' ' . implode(' ', $argument_checks) . PHP_EOL . PHP_EOL;
1222
1223					if(method_exists($command, 'invalid_command'))
1224					{
1225						call_user_func_array(array($command, 'invalid_command'), $pass_args);
1226						echo PHP_EOL;
1227					}
1228
1229					return false;
1230				}
1231				else
1232				{
1233					if($argument_check->get_function_return_key() != null && !isset($pass_args[$argument_check->get_function_return_key()]))
1234					{
1235						$pass_args[$argument_check->get_function_return_key()] = $return_value;
1236					}
1237				}
1238			}
1239		}
1240
1241		pts_module_manager::module_process('__pre_option_process', $command);
1242
1243		if(is_file(PTS_COMMAND_PATH . $command . '.php'))
1244		{
1245			self::$current_command = $command;
1246
1247			if(method_exists($command, 'run'))
1248			{
1249				call_user_func(array($command, 'run'), $pass_args);
1250			}
1251			else
1252			{
1253				echo PHP_EOL . 'There is an error in the requested command: ' . $command . PHP_EOL . PHP_EOL;
1254			}
1255		}
1256		else if(($t = pts_module::valid_run_command($command)) != false)
1257		{
1258			list($module, $module_command) = $t;
1259			pts_module_manager::set_current_module($module);
1260			pts_module_manager::run_command($module, $module_command, $pass_args);
1261			pts_module_manager::set_current_module(null);
1262		}
1263		echo PHP_EOL;
1264
1265		pts_module_manager::module_process('__post_option_process', $command);
1266	}
1267	public static function current_command()
1268	{
1269		return self::$current_command;
1270	}
1271	public static function terminal_width()
1272	{
1273		static $terminal_width = null;
1274
1275		if($terminal_width == null)
1276		{
1277			$chars = 80;
1278
1279			if(pts_client::read_env('TERMINAL_WIDTH') != false && is_numeric(pts_client::read_env('TERMINAL_WIDTH')) >= 80)
1280			{
1281					$terminal_width = pts_client::read_env('TERMINAL_WIDTH');
1282			}
1283			else if(pts_client::executable_in_path('stty'))
1284			{
1285				$terminal_width = explode(' ', trim(shell_exec('stty size 2>&1')));
1286
1287				if(count($terminal_width) == 2 && is_numeric($terminal_width[1]) && $terminal_width[1] >= 80)
1288				{
1289					$chars = $terminal_width[1];
1290				}
1291			}
1292			else if(pts_client::executable_in_path('tput'))
1293			{
1294				$terminal_width = trim(shell_exec('tput cols 2>&1'));
1295
1296				if(is_numeric($terminal_width) && $terminal_width > 1)
1297				{
1298					$chars = $terminal_width;
1299				}
1300			}
1301
1302			$terminal_width = $chars;
1303		}
1304
1305		return $terminal_width;
1306	}
1307	public static function user_hardware_software_reporting()
1308	{
1309		$hw_reporting = pts_config::read_bool_config('PhoronixTestSuite/Options/OpenBenchmarking/AnonymousHardwareReporting', 'FALSE');
1310		$sw_reporting = pts_config::read_bool_config('PhoronixTestSuite/Options/OpenBenchmarking/AnonymousSoftwareReporting', 'FALSE');
1311
1312		if($hw_reporting == false && $sw_reporting == false)
1313		{
1314			return;
1315		}
1316
1317		$hw = array();
1318		$sw = array();
1319		$pso = pts_storage_object::recover_from_file(PTS_CORE_STORAGE);
1320
1321		if($hw_reporting)
1322		{
1323			$hw = array();
1324			foreach(pts_openbenchmarking::stats_hardware_list() as $key => $value)
1325			{
1326				if(count($value) == 2)
1327				{
1328					$hw[$key] = phodevi::read_property($value[0], $value[1]);
1329				}
1330				else
1331				{
1332					$hw[$key] = phodevi::read_name($value[0]);
1333				}
1334			}
1335
1336			$hw_prev = $pso->read_object('global_reported_hw');
1337			$pso->add_object('global_reported_hw', $hw);
1338
1339			if(is_array($hw_prev))
1340			{
1341				$hw = array_diff_assoc($hw, $hw_prev);
1342			}
1343
1344			// Check the PCI devices
1345			$pci = phodevi::read_property('motherboard', 'pci-devices');
1346			$pci_prev = $pso->read_object('global_reported_pci');
1347			$pso->add_object('global_reported_pci', $pci);
1348
1349			if(!empty($pci_prev) && is_array($pci_prev) && is_array($pci))
1350			{
1351				if($pci == $pci_prev)
1352				{
1353					$pci = null;
1354				}
1355				else
1356				{
1357					$pci = array_diff($pci, $pci_prev);
1358				}
1359			}
1360
1361			if(!empty($pci))
1362			{
1363				pts_openbenchmarking_client::upload_pci_data($pci);
1364			}
1365
1366			// Check the USB devices
1367			$usb = phodevi::read_property('motherboard', 'usb-devices');
1368			$usb_prev = $pso->read_object('global_reported_usb');
1369			$pso->add_object('global_reported_usb', $usb);
1370
1371			if(!empty($usb_prev) && is_array($usb_prev) && is_array($usb) && $usb != $usb_prev)
1372			{
1373				pts_openbenchmarking_client::upload_usb_data($usb);
1374			}
1375		}
1376		if($sw_reporting)
1377		{
1378			$sw = array();
1379			foreach(pts_openbenchmarking::stats_software_list() as $key => $value)
1380			{
1381				if(count($value) == 2)
1382				{
1383					$sw[$key] = phodevi::read_property($value[0], $value[1]);
1384				}
1385				else
1386				{
1387					$sw[$key] = phodevi::read_name($value[0]);
1388				}
1389			}
1390			$sw_prev = $pso->read_object('global_reported_sw');
1391			$pso->add_object('global_reported_sw', $sw);
1392
1393			if(is_array($sw_prev))
1394			{
1395				$sw = array_diff_assoc($sw, $sw_prev);
1396			}
1397		}
1398
1399		$to_report = array_merge($hw, $sw);
1400		$pso->save_to_file(PTS_CORE_STORAGE);
1401
1402		if(!empty($to_report))
1403		{
1404			pts_openbenchmarking_client::upload_hwsw_data($to_report);
1405		}				
1406	}
1407	public static function is_process_running($process)
1408	{
1409		if(phodevi::is_linux())
1410		{
1411			// Checks if process is running on the system
1412			$running = shell_exec('ps -C ' . strtolower($process) . ' 2>&1');
1413			$running = trim(str_replace(array('PID', 'TTY', 'TIME', 'CMD'), '', $running));
1414		}
1415		else if(phodevi::is_solaris())
1416		{
1417			// Checks if process is running on the system
1418			$ps = shell_exec('ps -ef 2>&1');
1419			$running = strpos($ps, ' ' . strtolower($process)) != false ? 'TRUE' : null;
1420		}
1421		else if(pts_client::executable_in_path('ps') != false)
1422		{
1423			// Checks if process is running on the system
1424			$ps = shell_exec('ps -ax 2>&1');
1425			$running = strpos($ps, ' ' . strtolower($process)) != false ? 'TRUE' : null;
1426		}
1427		else
1428		{
1429			$running = null;
1430		}
1431
1432		return !empty($running);
1433	}
1434	public static function parse_value_string_double_identifier($value_string)
1435	{
1436		// i.e. with PRESET_OPTIONS='stream.run-type=Add'
1437		$values = array();
1438
1439		foreach(explode(';', $value_string) as $preset)
1440		{
1441			if(count($preset = pts_strings::trim_explode('=', $preset)) == 2)
1442			{
1443				$dot = strrpos($preset[0], '.');
1444				if($dot !== false && ($test = substr($preset[0], 0, $dot)) != null && ($option = substr($preset[0], ($dot + 1))) != null)
1445				{
1446					$values[$test][$option] = $preset[1];
1447				}
1448			}
1449		}
1450
1451		return $values;
1452	}
1453	public static function create_temporary_file()
1454	{
1455		return tempnam(pts_client::temporary_directory(), 'PTS');
1456	}
1457	public static function create_temporary_directory($prefix = null)
1458	{
1459		$tmpdir = pts_client::temporary_directory();
1460
1461		do
1462		{
1463			$randname = '/pts-' . $prefix . rand(0, 9999);
1464		}
1465		while(is_dir($tmpdir . $randname));
1466
1467		mkdir($tmpdir . $randname);
1468
1469		return $tmpdir . $randname . '/';
1470	}
1471	public static function temporary_directory()
1472	{
1473		if(PHP_VERSION_ID >= 50210)
1474		{
1475			$dir = sys_get_temp_dir();
1476		}
1477		else
1478		{
1479			$dir = '/tmp'; // Assume /tmp
1480		}
1481
1482		return $dir;
1483	}
1484	public static function read_env($var)
1485	{
1486		return getenv($var);
1487	}
1488	public static function pts_set_environment_variable($name, $value)
1489	{
1490		// Sets an environmental variable
1491		return getenv($name) == false && putenv($name . '=' . $value);
1492	}
1493	public static function shell_exec($exec, $extra_vars = null)
1494	{
1495		// Same as shell_exec() but with the PTS env variables added in
1496		// Convert pts_client::environmental_variables() into shell export variable syntax
1497
1498		$var_string = '';
1499		$extra_vars = ($extra_vars == null ? pts_client::environmental_variables() : array_merge(pts_client::environmental_variables(), $extra_vars));
1500
1501		foreach(array_keys($extra_vars) as $key)
1502		{
1503			$var_string .= 'export ' . $key . '=' . $extra_vars[$key] . ';';
1504		}
1505
1506		$var_string .= ' ';
1507
1508		return shell_exec($var_string . $exec);
1509	}
1510	public static function executable_in_path($executable)
1511	{
1512		static $cache = null;
1513
1514		if(!isset($cache[$executable]))
1515		{
1516			$paths = pts_strings::trim_explode((phodevi::is_windows() ? ';' : ':'), (($path = pts_client::read_env('PATH')) == false ? '/usr/bin:/usr/local/bin' : $path));
1517			$executable_path = false;
1518
1519			foreach($paths as $path)
1520			{
1521				$path = pts_strings::add_trailing_slash($path);
1522
1523				if(is_executable($path . $executable))
1524				{
1525					$executable_path = $path . $executable;
1526					break;
1527				}
1528			}
1529
1530			$cache[$executable] = $executable_path;
1531		}
1532
1533		return $cache[$executable];
1534	}
1535	public static function display_web_page($URL, $alt_text = null, $default_open = true, $auto_open = false)
1536	{
1537		if(((pts_c::$test_flags & pts_c::auto_mode) && $auto_open == false && $default_open == false) || (pts_client::read_env('DISPLAY') == false && pts_client::read_env('WAYLAND_DISPLAY') == false && phodevi::is_windows() == false && phodevi::is_macosx() == false) || defined('PHOROMATIC_PROCESS'))
1538		{
1539			return;
1540		}
1541
1542		if($auto_open == false)
1543		{
1544			$view_results = pts_user_io::prompt_bool_input(($alt_text == null ? 'Do you want to view the results in your web browser' : $alt_text), $default_open);
1545		}
1546		else
1547		{
1548			$view_results = true;
1549		}
1550
1551		if($view_results)
1552		{
1553			static $browser = null;
1554
1555			if($browser == null)
1556			{
1557				$config_browser = pts_config::read_user_config('PhoronixTestSuite/Options/General/DefaultBrowser', null);
1558
1559				if($config_browser != null && (is_executable($config_browser) || ($config_browser = pts_client::executable_in_path($config_browser))))
1560				{
1561					$browser = $config_browser;
1562				}
1563				else if(phodevi::is_windows())
1564				{
1565					$windows_browsers = array(
1566						'C:\Program Files (x86)\Mozilla Firefox\firefox.exe',
1567						'C:\Program Files\Internet Explorer\iexplore.exe'
1568						);
1569
1570					foreach($windows_browsers as $browser_test)
1571					{
1572						if(is_executable($browser_test))
1573						{
1574							$browser = $browser_test;
1575							break;
1576						}
1577					}
1578
1579					if(substr($URL, 0, 1) == '\\')
1580					{
1581						$URL = 'file:///C:' . str_replace('/', '\\', $URL);
1582					}
1583				}
1584				else
1585				{
1586					$possible_browsers = array('epiphany', 'firefox', 'mozilla', 'x-www-browser', 'open', 'xdg-open', 'iceweasel', 'konqueror');
1587
1588					foreach($possible_browsers as &$b)
1589					{
1590						if(($b = pts_client::executable_in_path($b)))
1591						{
1592							$browser = $b;
1593							break;
1594						}
1595					}
1596				}
1597			}
1598
1599			if($browser != null)
1600			{
1601				shell_exec($browser . ' "' . $URL . '" 2> /dev/null &');
1602			}
1603			else
1604			{
1605				echo PHP_EOL . 'No Web Browser Found.' . PHP_EOL;
1606			}
1607		}
1608	}
1609	public static function cache_hardware_calls()
1610	{
1611		phodevi::system_hardware(true);
1612		phodevi::supported_sensors();
1613		phodevi::unsupported_sensors();
1614	}
1615	public static function cache_software_calls()
1616	{
1617		phodevi::system_software(true);
1618	}
1619	public static function remove_saved_result_file($identifier)
1620	{
1621		pts_file_io::delete(PTS_SAVE_RESULTS_PATH . $identifier, null, true);
1622	}
1623	public static function saved_test_results()
1624	{
1625		$results = array();
1626		$ignore_ids = array();
1627
1628		foreach(pts_file_io::glob(PTS_SAVE_RESULTS_PATH . '*/composite.xml') as $result_file)
1629		{
1630			$identifier = basename(dirname($result_file));
1631
1632			if(!in_array($identifier, $ignore_ids))
1633			{
1634				array_push($results, $identifier);
1635			}
1636		}
1637
1638		return $results;
1639	}
1640	public static function timed_function($function, $function_parameters, $time, $continue_while_true_function = null, $continue_while_true_function_parameters)
1641	{
1642		if(($time < 0.5 && $time != -1) || $time > 300)
1643		{
1644			return;
1645		}
1646
1647		if(function_exists('pcntl_fork'))
1648		{
1649			$current_pid = function_exists('posix_getpid') ? posix_getpid() : -1;
1650			$pid = pcntl_fork();
1651
1652			if($pid == -1)
1653			{
1654				trigger_error('Could not fork ' . $function . '.', E_USER_ERROR);
1655			}
1656			else if($pid)
1657			{
1658				array_push(self::$forked_pids, $pid);
1659			}
1660			else
1661			{
1662				posix_setsid();
1663				$loop_continue = true;
1664				while($loop_continue && is_file(PTS_USER_LOCK) && ($continue_while_true_function === true || ($loop_continue = call_user_func_array($continue_while_true_function, $continue_while_true_function_parameters))))
1665				{
1666					call_user_func_array($function, $function_parameters);
1667
1668					if($time > 0)
1669					{
1670						sleep($time);
1671					}
1672					else if($time == -1)
1673					{
1674						$loop_continue = false;
1675					}
1676					if($current_pid != -1 && !is_dir('/proc/' . $current_pid))
1677					{
1678						exit;
1679					}
1680					clearstatcache();
1681				}
1682				posix_kill(posix_getpid(), SIGINT);
1683				exit(0);
1684			}
1685		}
1686		else
1687		{
1688			if(is_array($function))
1689			{
1690				$function = implode(':', $function);
1691			}
1692
1693			trigger_error('php-pcntl must be installed for calling ' . $function . '.', E_USER_ERROR);
1694		}
1695	}
1696	public static function fork($fork_function, $fork_function_parameters)
1697	{
1698		if(function_exis…

Large files files are truncated, but you can click here to view the full file