elphel_functions_include.php 8.96 KB
Newer Older
1 2
<?php
/*!***************************************************************************
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
3 4
*! FILE NAME  : elphel_functions_include.php
*! DESCRIPTION: various functions
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
*! Copyright (C) 2016 Elphel, Inc
*! -----------------------------------------------------------------------------**
*!
*!  This program 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.
*!
*!  This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
*! -----------------------------------------------------------------------------**
*/

/*
* Contents:
*     * OTHER
*     * LOG AND XML RESPONSE
*     * PARALLEL HTTP REQUESTS
*     * DEVICES
*/


// OTHER
function get_uptime(){
	exec('cat /proc/uptime',$output,$retval);
	return floatval(explode(" ",trim($output[0]))[0]);
}

// LOG AND XML RESPONSE
function colorize($string, $color, $bold) {
	$color = strtoupper($color);
	$attr = array();
	switch ($color) {
		case 'RED':     $attr[]='31'; break;
		case'GREEN':    $attr[]='32'; break;
		case 'YELLOW':  $attr[]='33'; break;
		case 'BLUE':	$attr[]='34'; break;
		case 'MAGENTA':	$attr[]='35'; break;
		case 'CYAN':	$attr[]='36'; break;
		case 'GRAY':	$attr[]='37'; break;
	}
	if ($bold)	$attr[] = '1';
	return sprintf("\x1b[%sm%s\x1b[0m",implode(';',$attr), $string);
}

function log_open(){
	$GLOBALS['logFile'] = fopen ( $GLOBALS['logFilePath'], "a" );
}

/** Log message and optionally print to console */
function log_msg($msg,         ///< message to print
		         $mode = -1)   ///< -1 - print only short messages, 0 - never print, 1 - always print, 2 print in bold red (error), 3 - bold white, 4 - bold yellow (warning)
{
// do not output log when in HTTP request mode
	$ut=get_uptime();
	if (($mode != 0) && !array_key_exists ('REQUEST_METHOD', $_SERVER) && (($mode > 0) || (strlen ($msg) < $GLOBALS['LOG_MAX_ECHO']))) {
		switch ($mode) {
			case 2:
				$emsg = colorize($msg,'RED',1); // bold red
				break;
			case 3:
				$emsg = colorize($msg,'',1);    // bold white
				break;
			case 4 :
				$emsg = colorize($msg, 'YELLOW', 1); // bold white
				break;
			default:
				$emsg = $msg;
		}
		printf(colorize(sprintf("[%8.2f] autocampars: ",$ut),"GREEN",0).$emsg."\n");
	}
	fwrite ($GLOBALS['logFile'], sprintf("%08.2f autocampars: %s\n",$ut,$msg)); // date ("F j, Y, G:i:s")
}
function log_error($msg) {
	log_msg ($msg, 2);
	log_close ();
	exit (1);
}
function log_close() {
	log_msg ("Log file saved as " . $GLOBALS['logFilePath'], 3);
	log_msg ("----------------------------------------------", 0);
	fclose ($GLOBALS['logFile']);
	unset ($GLOBALS['logFile']); // to catch errors
}

/** Closes log file, optianally responxds with XML (if in HTTP mode), exits with 0/1 */
function respond_xml($result,$error=null,$color_mode = 3){ // default white bold
	if (array_key_exists('REQUEST_METHOD',$_SERVER)){
		$xml = new SimpleXMLElement("<?xml version='1.0'  standalone='yes'?><Document/>");
		if ($result !== ""){ //"" will not be loged/output
			if (is_string($result) && ((count($result)==0) || ($result[0] != '"'))){
				$result = '"'.$result.'"';
			}
			$xml->addChild ('result',$result);
		}
		if ($error){
			$xml->addChild ('error','"'.$error.'"');
		}
		$rslt=$xml->asXML();
		header("Content-Type: text/xml");
		header("Content-Length: ".strlen($rslt)."\n");
		header("Pragma: no-cache\n");
		printf($rslt);
	}
114

115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
	if (isset($GLOBALS['logFile'])){
		if ($result !== ""){ //"" will not be loged/output
			log_msg(''.$result,$color_mode);
		}
		if ($error){
			log_error($error);
		} else {
			log_close();
			exit (0);
		}
	}
}

// PARALLEL HTTP REQUESTS

// Using parallel requests, PHP has to be configured '--with-curl=' (and libcurl should be installed)
131
function curl_multi_start($urls, $with_headers=0) {
132 133 134 135 136 137 138 139 140
	// numprime is needed to actually send the request and remote starts executing it
	// Not really clear - what it should be
	$numprime = 4; // magic number, see http://lampe2e.blogspot.com/2015/03/making-stuff-faster-with-curlmultiexec.html
	$curl_mh = curl_multi_init ();
	$aCurlHandles = array ();
	foreach ($urls as $url) {
		$ch = curl_init ();
		curl_setopt ($ch, CURLOPT_URL, $url);
		curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
141
		curl_setopt ($ch, CURLOPT_HEADER, $with_headers);
142 143 144 145 146 147 148 149 150 151 152 153
		$aCurlHandles[] = $ch;
		curl_multi_add_handle ($curl_mh, $ch);
	}
	$curl_active = count ($urls);
	for($x = 0; $x < $numprime && $curl_active; $x++) {
		curl_multi_exec ($curl_mh, $curl_active);
		// we wait for a bit to allow stuff TCP handshakes to complete and so forth...
		usleep (10000);
//		echo ".";
	}
	return array ("mh" => $curl_mh,"handles" => $aCurlHandles);
}
154 155

function curl_multi_finish($data, $use_xml=true, $ntry=0, $echo = false, $with_headers = 0) {
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
	$curl_active = 1;
	$curl_mrc = CURLM_OK;
	$nrep = 0;
	$curl_mh = $data['mh'];
	while ($curl_active && $curl_mrc == CURLM_OK ) {
		if (curl_multi_select ($curl_mh) != -1) {
			do {
				$curl_mrc = curl_multi_exec ($curl_mh, $curl_active);
			} while ($curl_mrc == CURLM_CALL_MULTI_PERFORM );
		}
		if ($echo) echo colorize("$curl_active ",'YELLOW',1);
		$nrep++;
		if ($ntry && ($nrep > $ntry)) {
			break;
		}
	}
	$results = array ();
173
	$names = array ();
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
	if ($use_xml) {
		foreach ($data['handles'] as $i => $ch) {
			$xml = simplexml_load_string (curl_multi_getcontent ($ch));
			curl_multi_remove_handle ($curl_mh, $ch);
			$results[$i] = array ();
			foreach ($xml as $tag => $value) {
				$svalue = (string) $value;
				if (strlen ($svalue) > 0) {
					if ($svalue[0] == '"') $results[$i][$tag] = trim ($svalue, '"');
					else $results[$i][$tag] = (int) $svalue;
				}
			}
		}
	} else {
		foreach ($data['handles'] as $i => $ch) {
			$r = curl_multi_getcontent ($ch);
			curl_multi_remove_handle ($curl_mh, $ch);
191 192 193 194 195 196
			if ($with_headers==1){
				$hsize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
				$h = substr($r, 0, $hsize);
				$r = substr($r, $hsize);
				$names[] = curl_get_filename_from_header($h);
			}
197 198
			$results[] = $r;
		}
199 200 201
		if ($with_headers==1){
			$results = Array('names' => $names,'contents'=> $results);
		}
202 203 204 205 206
	}
	curl_multi_close ($curl_mh);
	return $results;
}

207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
function curl_get_filename_from_header($h){

	$h = explode("\n",$h);
	$res = "";
	if ($h){
		foreach($h as $e){
			if (strlen($e)!=0){
				$tmp = explode(":",$e);
				if ($tmp[0]=="Content-Disposition"){
					$tmp = explode(";",$tmp[1]);
					foreach($tmp as $t){
						$t = trim($t);
						$t = explode("=",$t);
						if ($t[0]=="filename"){
							$res = trim($t[1]," \t\n\r\0\x0B\"");
							break;
						}
					}
					break;
				}
			}
		}
	}

	return $res;

}

235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
// DEVICES

/** Get a list of suitable partitions. The list will contain SATA devices only and
 * will have the following format: "name" => "size_in_blocks".
 */
function get_partitions()
{
	$names = array();
	$regexp = '/([0-9]+) +(sd[a-z0-9]+$)/';
	exec("cat /proc/partitions", $partitions);

	// the first two elements of an array are table header and empty line delimiter, skip them
	for ($i = 2; $i < count($partitions); $i++) {
		// select SATA devices only
		if (preg_match($regexp, $partitions[$i], $name) == 1) {
			$names[$name[2]] = $name[1];
			$j++;
		}
	}
	return $names;
}

/** Get a list of disk devices which have file system and can be mounted. This function
 *  uses 'blkid' command from busybox.
259
 */
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
function get_mnt_dev()
{
	$partitions = get_partitions();
	$devices = array();
	$fs_types = array();
	foreach ($partitions as $partition => $size) {
		$res = array();
		$dev = "/dev/" . $partition;
		exec("blkid " . $dev, $res);
		if (!empty($res)) {
			$devices[$i] = preg_replace('/: +.*/', "", $res[0]);
			if (preg_match('/(?<=TYPE=")[a-z0-9]+(?=")/', $res[0], $fs) == 1)
				$fs_types[$i] = $fs[0];
			else
				$fs_types[$i] = "none";
			$i++;
		}
	}
278

279 280 281 282 283 284 285 286
	return array("devices" => $devices, "types" => $fs_types);
}

/** Get a list of devices whithout file system which can be used for raw disk storage from camogm. */
function get_raw_dev()
{
	$j = 0;
	$ret = get_mnt_dev();
287
	$devices = $ret["devices"];
288 289 290
	$types = $ret["types"];

	$names = get_partitions();
291 292

	// filter out partitions with file system
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
	$i = 0;
	$raw_devices = array();

	foreach ($names as $name => $size) {
		$found = false;
		foreach ($devices as $device) {
			if (strpos($device, $name) !== false)
				$found = true;
		}
		if ($found === false) {
			// current partition is not found in the blkid list, add it to raw devices
			$raw_devices["/dev/" . $name] = $size;
			$i++;
		}
	}
308

309 310 311 312 313 314 315 316 317 318 319 320
	//special case
	if (count($raw_devices)>1) {
            foreach($raw_devices as $k=>$v){
                if (preg_match('/sd[a-z][0-9]/',$k)==0) {
                    unset($raw_devices[$k]);
                }
            }
	}
	return $raw_devices;
}

?>