Project

General

Profile

Download (41.4 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php 
2
/*
3
	util.inc
4
	part of the pfSense project (http://www.pfsense.com)
5

    
6
	originally part of m0n0wall (http://m0n0.ch/wall)
7
	Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
8
	All rights reserved.
9

    
10
	Redistribution and use in source and binary forms, with or without
11
	modification, are permitted provided that the following conditions are met:
12

    
13
	1. Redistributions of source code must retain the above copyright notice,
14
	   this list of conditions and the following disclaimer.
15

    
16
	2. Redistributions in binary form must reproduce the above copyright
17
	   notice, this list of conditions and the following disclaimer in the
18
	   documentation and/or other materials provided with the distribution.
19

    
20
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
21
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
22
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
24
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
	POSSIBILITY OF SUCH DAMAGE.
30
*/
31

    
32
/*
33
	pfSense_BUILDER_BINARIES:	/bin/ps	/bin/kill	/usr/bin/killall	/sbin/ifconfig	/usr/bin/netstat
34
	pfSense_BUILDER_BINARIES:	/usr/bin/awk	/sbin/dmesg		/sbin/ping /usr/local/sbin/gzsig	/usr/sbin/arp
35
	pfSense_BUILDER_BINARIES:	/sbin/conscontrol	/sbin/devd	/bin/ps
36
	pfSense_MODULE:	utils
37
*/
38

    
39
/* kill a process by pid file */
40
function killbypid($pidfile) {
41
	return sigkillbypid($pidfile, "TERM");
42
}
43

    
44
function isvalidpid($pid) {
45
	$output = "";
46
	exec("/bin/pgrep -F {$pid}", $output, $retval);
47

    
48
        return (intval($retval) == 0);
49
}
50

    
51
function is_process_running($process) {
52
	$output = "";
53
	exec("/bin/pgrep -x {$process}", $output, $retval);
54

    
55
        return (intval($retval) == 0);
56
}
57

    
58
function isvalidproc($proc) {
59
	return is_process_running($proc);
60
}
61

    
62
/* sigkill a process by pid file */
63
/* return 1 for success and 0 for a failure */
64
function sigkillbypid($pidfile, $sig) {
65
	if (is_file($pidfile))
66
		return mwexec("/bin/pkill -{$sig} -F {$pidfile}", true);
67

    
68
	return 0;
69
}
70

    
71
/* kill a process by name */
72
function sigkillbyname($procname, $sig) {
73
	if(isvalidproc($procname))
74
		return mwexec("/usr/bin/killall -{$sig} " . escapeshellarg($procname), true);
75
}
76

    
77
/* kill a process by name */
78
function killbyname($procname) {
79
	if(isvalidproc($procname)) 
80
		mwexec("/usr/bin/killall " . escapeshellarg($procname));
81
}
82

    
83
function is_subsystem_dirty($subsystem = "") {
84
	global $g;
85

    
86
	if ($subsystem == "")
87
		return false;
88

    
89
	if (file_exists("{$g['varrun_path']}/{$subsystem}.dirty"))
90
		return true;
91

    
92
	return false;
93
}
94

    
95
function mark_subsystem_dirty($subsystem = "") {
96
	global $g;
97

    
98
	if (!file_put_contents("{$g['varrun_path']}/{$subsystem}.dirty", "DIRTY"))
99
		log_error("WARNING: Could not mark subsystem: {$subsytem} dirty");
100
}
101

    
102
function clear_subsystem_dirty($subsystem = "") {
103
	global $g;
104

    
105
	@unlink("{$g['varrun_path']}/{$subsystem}.dirty");
106
}
107

    
108
function config_lock() {
109
	return;
110
}
111
function config_unlock() {
112
	return;
113
}
114

    
115
/* lock configuration file */
116
function lock($lock, $op = LOCK_SH) {
117
	global $g, $cfglckkeyconsumers;
118
	if (!$lock)
119
		die("WARNING: You must give a name as parameter to lock() function.");
120
	if (!file_exists("{$g['tmp_path']}/{$lock}.lock"))
121
		@touch("{$g['tmp_path']}/{$lock}.lock");
122
	$cfglckkeyconsumers++;
123
	if ($fp = fopen("{$g['tmp_path']}/{$lock}.lock", "w")) {
124
		if (flock($fp, $op))
125
			return $fp;
126
		else
127
			fclose($fp);
128
	}
129
}
130

    
131
/* unlock configuration file */
132
function unlock($cfglckkey = 0) {
133
	global $g, $cfglckkeyconsumers;
134
	flock($cfglckkey, LOCK_UN);
135
	fclose($cfglckkey);
136
	return;
137
}
138

    
139
function send_event($cmd) {
140
	global $g;
141

    
142
	$try = 0;
143
	while ($try < 3) {
144
		$fd = @fsockopen($g['event_address']);
145
		if ($fd) {
146
			fwrite($fd, $cmd);
147
			$resp = fread($fd, 4096);
148
			if ($resp != "OK\n")
149
				log_error("send_event: sent {$cmd} got {$resp}");
150
			fclose($fd);
151
			$try = 3;
152
		} else
153
			mwexec_bg("/usr/bin/nice -n20 /usr/local/sbin/check_reload_status");
154
		$try++;
155
	}
156
}
157

    
158
function send_multiple_events($cmds) {
159
        global $g;
160

    
161
	if (!is_array($cmds))
162
		return;
163
        $fd = fsockopen($g['event_address']);
164
        if ($fd) {
165
		foreach ($cmds as $cmd) {
166
                	fwrite($fd, $cmd);
167
                	$resp = fread($fd, 4096);
168
                	if ($resp != "OK\n")
169
                        	log_error("send_event: sent {$cmd} got {$resp}");
170
		}
171
                fclose($fd);
172
        }
173
}
174

    
175
function refcount_init($reference) {
176
	$shmid = shmop_open($reference, "c", 0644, 10);
177
	shmop_write($shmid, 0, 0);
178
	shmop_close($shmid);
179
}
180

    
181
function refcount_reference($reference) {
182
	$shmid = @shmop_open($reference, "w", 0644, 10);
183
	if (!$shmid) {
184
		refcount_init($reference);
185
		$shmid = shmop_open($reference, "w", 0644, 10);
186
	}
187
	$shm_data = shmop_read($shmid, 0, 10);
188
	$shm_data = intval($shm_data) + 1;
189
	shmop_write($shmid, $shm_data, 0);
190
	shmop_close($shmid);
191
	
192
	return $shm_data;
193
}
194

    
195
function refcount_unreference($reference) {
196
	/* We assume that the shared memory exists. */
197
	$shmid = shmop_open($reference, "w", 0644, 10);
198
	$shm_data = shmop_read($shmid, 0, 10);
199
	$shm_data = intval($shm_data) - 1;
200
	if ($shm_data < 0) {
201
		//debug_backtrace();
202
		log_error("Reference {$reference} is going negative, not doing unreference.");
203
	} else
204
		shmop_write($shmid, $shm_data, 0);
205
	shmop_close($shmid);
206
	
207
	return $shm_data;
208
}
209

    
210
function is_module_loaded($module_name) {
211
	$running = `/sbin/kldstat | grep {$module_name} | /usr/bin/grep -v grep | /usr/bin/wc -l`;
212
	if (intval($running) >= 1)
213
		return true;
214
	else
215
		return false;
216
}
217

    
218
/* return the subnet address given a host address and a subnet bit count */
219
function gen_subnet($ipaddr, $bits) {
220
	if (!is_ipaddr($ipaddr) || !is_numeric($bits))
221
		return "";
222
	return long2ip(ip2long($ipaddr) & gen_subnet_mask_long($bits));
223
}
224

    
225
/* return the subnet address given a host address and a subnet bit count */
226
function gen_subnetv6($ipaddr, $bits) {
227
	if (!is_ipaddrv6($ipaddr) || !is_numeric($bits))
228
		return "";
229
	return Net_IPv6::getNetmask($ipaddr, $bits);
230
}
231

    
232
/* return the highest (broadcast) address in the subnet given a host address and a subnet bit count */
233
function gen_subnet_max($ipaddr, $bits) {
234
	if (!is_ipaddr($ipaddr) || !is_numeric($bits))
235
		return "";
236

    
237
	return long2ip32(ip2long($ipaddr) | ~gen_subnet_mask_long($bits));
238
}
239

    
240
/* Generate end number for a given ipv6 subnet mask
241
 * no, it does not perform math */
242
function gen_subnetv6_max($ipaddr, $bits) {
243
	if(!is_ipaddrv6($ipaddr))
244
		return false;
245
	
246
	$subnetstart = gen_subnetv6($ipaddr, $bits);
247
	/* we should have a expanded full ipv6 subnet starting at 0.
248
	 * Now split those by the semicolon so we can do 16 bit math */
249
	$parts = explode(":", $subnetstart);
250
	if(count($parts) <> 8)
251
		return false;
252

    
253
	/* reverse the array, we start with the lsb */
254
	$parts = array_reverse($parts);
255
	/* set the itteration count properly */
256
	$bitsleft = 128 - $bits;
257
	$i = 0;
258
	foreach($parts as $part) {
259
		/* foreach 16 bits we go to the next part */
260
		/* no this isn't proper hex math, neither does it overflow properly */
261
		while($bitsleft > 0) {
262
			if($part == "0") {
263
				$part = "f";
264
			} else {
265
				$part = $part . "f";
266
			}
267
			$bitsleft = $bitsleft - 4;
268
			$j++;
269
			if($j == 4) {
270
				$parts[$i] = $part;
271
				$j = 0;
272
				$i++;
273
				continue 2;
274
			}
275
		}
276
		$i++;
277
	}
278
	$parts = array_reverse($parts);
279
	$subnet_end = implode(":", $parts);
280
	return $subnet_end;
281
}
282

    
283
/* returns a subnet mask (long given a bit count) */
284
function gen_subnet_mask_long($bits) {
285
	$sm = 0;
286
	for ($i = 0; $i < $bits; $i++) {
287
		$sm >>= 1;
288
		$sm |= 0x80000000;
289
	}
290
	return $sm;
291
}
292

    
293
/* same as above but returns a string */
294
function gen_subnet_mask($bits) {
295
	return long2ip(gen_subnet_mask_long($bits));
296
}
297

    
298
/* Convert long int to IP address, truncating to 32-bits. */
299
function long2ip32($ip) {
300
	return long2ip($ip & 0xFFFFFFFF);
301
}
302

    
303
/* Convert IP address to long int, truncated to 32-bits to avoid sign extension on 64-bit platforms. */
304
function ip2long32($ip) {
305
	return ( ip2long($ip) & 0xFFFFFFFF );
306
}
307

    
308
/* Convert IP address to unsigned long int. */
309
function ip2ulong($ip) {
310
	return sprintf("%u", ip2long32($ip));
311
}
312

    
313
/* Find out how many IPs are contained within a given IP range
314
 *  e.g. 192.168.0.0 to 192.168.0.255 returns 256
315
 */
316
function ip_range_size($startip, $endip) {
317
	if (is_ipaddr($startip) && is_ipaddr($endip)) {
318
		// Operate as unsigned long because otherwise it wouldn't work
319
		//   when crossing over from 127.255.255.255 / 128.0.0.0 barrier
320
		return abs(ip2ulong($startip) - ip2ulong($endip)) + 1;
321
	}
322
	return -1;
323
}
324

    
325
/* Find the smallest possible subnet mask which can contain a given number of IPs
326
 *  e.g. 512 IPs can fit in a /23, but 513 IPs need a /22
327
 */
328
function find_smallest_cidr($number) {
329
	$smallest = 1;
330
	for ($b=32; $b > 0; $b--) {
331
		$smallest = ($number <= pow(2,$b)) ? $b : $smallest;
332
	}
333
	return (32-$smallest);
334
}
335

    
336
/* Return the previous IP address before the given address */
337
function ip_before($ip) {
338
	return long2ip32(ip2long($ip)-1);
339
}
340

    
341
/* Return the next IP address after the given address */
342
function ip_after($ip) {
343
	return long2ip32(ip2long($ip)+1);
344
}
345

    
346
/* Return true if the first IP is 'before' the second */
347
function ip_less_than($ip1, $ip2) {
348
	// Compare as unsigned long because otherwise it wouldn't work when
349
	//   crossing over from 127.255.255.255 / 128.0.0.0 barrier
350
	return ip2ulong($ip1) < ip2ulong($ip2);
351
}
352

    
353
/* Return true if the first IP is 'after' the second */
354
function ip_greater_than($ip1, $ip2) {
355
	// Compare as unsigned long because otherwise it wouldn't work
356
	//   when crossing over from 127.255.255.255 / 128.0.0.0 barrier
357
	return ip2ulong($ip1) > ip2ulong($ip2);
358
}
359

    
360
/* Convert a range of IPs to an array of subnets which can contain the range. */
361
function ip_range_to_subnet_array($startip, $endip) {
362
	if (!is_ipaddr($startip) || !is_ipaddr($endip)) {
363
		return array();
364
	}
365

    
366
	// Container for subnets within this range.
367
	$rangesubnets = array();
368

    
369
	// Figure out what the smallest subnet is that holds the number of IPs in the given range.
370
	$cidr = find_smallest_cidr(ip_range_size($startip, $endip));
371

    
372
	// Loop here to reduce subnet size and retest as needed. We need to make sure
373
	//   that the target subnet is wholly contained between $startip and $endip.
374
	for ($cidr; $cidr <= 32; $cidr++) {
375
		// Find the network and broadcast addresses for the subnet being tested.
376
		$targetsub_min = gen_subnet($startip, $cidr);
377
		$targetsub_max = gen_subnet_max($startip, $cidr);
378

    
379
		// Check best case where the range is exactly one subnet.
380
		if (($targetsub_min == $startip) && ($targetsub_max == $endip)) {
381
			// Hooray, the range is exactly this subnet!
382
			return array("{$startip}/{$cidr}");
383
		}
384

    
385
		// These remaining scenarios will find a subnet that uses the largest
386
		//  chunk possible of the range being tested, and leave the rest to be
387
		//  tested recursively after the loop.
388

    
389
		// Check if the subnet begins with $startip and ends before $endip
390
		if (($targetsub_min == $startip) && ip_less_than($targetsub_max, $endip)) {
391
			break;
392
		}
393

    
394
		// Check if the subnet ends at $endip and starts after $startip
395
		if (ip_greater_than($targetsub_min, $startip) && ($targetsub_max == $endip)) {
396
			break;
397
		}
398

    
399
		// Check if the subnet is between $startip and $endip
400
		if (ip_greater_than($targetsub_min, $startip) && ip_less_than($targetsub_max, $endip)) {
401
			break;
402
		}
403
	}
404

    
405
	// Some logic that will recursivly search from $startip to the first IP before the start of the subnet we just found.
406
	// NOTE: This may never be hit, the way the above algo turned out, but is left for completeness.
407
	if ($startip != $targetsub_min) {
408
		$rangesubnets = array_merge($rangesubnets, ip_range_to_subnet_array($startip, ip_before($targetsub_min)));
409
	}
410

    
411
	// Add in the subnet we found before, to preserve ordering
412
	$rangesubnets[] = "{$targetsub_min}/{$cidr}";
413

    
414
	// And some more logic that will search after the subnet we found to fill in to the end of the range.
415
	if ($endip != $targetsub_max) {
416
		$rangesubnets = array_merge($rangesubnets, ip_range_to_subnet_array(ip_after($targetsub_max), $endip));
417
	}
418
	return $rangesubnets;
419
}
420

    
421
function is_iprange($range) {
422
	if (substr_count($range, '-') != 1) {
423
		return false;
424
	}
425
	list($ip1, $ip2) = explode ('-', $range);
426
	return (is_ipaddr($ip1) && is_ipaddr($ip2));
427
}
428

    
429
function is_numericint($arg) {
430
	return (preg_match("/[^0-9]/", $arg) ? false : true);
431
}
432

    
433

    
434
/* returns true if $ipaddr is a valid dotted IPv4 address or a IPv6 */
435
function is_ipaddr($ipaddr) {
436
	if(is_ipaddrv4($ipaddr)) {
437
		return true;
438
	}
439
	if(is_ipaddrv6($ipaddr)) {
440
		return true;
441
	}
442
	return false;
443
}
444

    
445
/* returns true if $ipaddr is a valid IPv6 address */
446
function is_ipaddrv6($ipaddr) {
447
	$result = Net_IPv6::checkIPv6($ipaddr);
448
	return $result;
449
}
450

    
451
/* returns true if $ipaddr is a valid dotted IPv4 address */
452
function is_ipaddrv4($ipaddr) {
453
	if (!is_string($ipaddr))
454
		return false;
455

    
456
	$ip_long = ip2long($ipaddr);
457
	$ip_reverse = long2ip32($ip_long);
458

    
459
	if ($ipaddr == $ip_reverse)
460
		return true;
461
	else
462
		return false;
463
}
464

    
465
/* returns true if $ipaddr is a valid dotted IPv4 address or an alias thereof */
466
function is_ipaddroralias($ipaddr) {
467
	global $config;
468

    
469
	if (is_alias($ipaddr)) {
470
		if (is_array($config['aliases']['alias'])) {
471
			foreach ($config['aliases']['alias'] as $alias) {
472
                        	if ($alias['name'] == $ipaddr && $alias['type'] != "port")
473
					return true;
474
			}
475
                }
476
		return false;
477
	} else
478
		return is_ipaddr($ipaddr);
479

    
480
}
481

    
482
/* returns true if $subnet is a valid subnet in CIDR format */
483
function is_subnet($subnet) {
484
	if (!is_string($subnet))
485
		return false;
486

    
487
	list($hp,$np) = explode('/', $subnet);
488

    
489
	if (!is_ipaddr($hp))
490
		return false;
491

    
492
	if (!is_numeric($np) || ($np < 1) || ($np > 32))
493
		return false;
494

    
495
	return true;
496
}
497

    
498
/* returns true if $subnet is a valid subnet in CIDR format or an alias thereof */
499
function is_subnetoralias($subnet) {
500

    
501
	global $aliastable;
502

    
503
	if (isset($aliastable[$subnet]) && is_subnet($aliastable[$subnet]))
504
		return true;
505
	else
506
		return is_subnet($subnet);
507
}
508

    
509
/* returns true if $hostname is a valid hostname */
510
function is_hostname($hostname) {
511
	if (!is_string($hostname))
512
		return false;
513

    
514
	if (preg_match('/^(?:(?:[a-z0-9_]|[a-z0-9_][a-z0-9_\-]*[a-z0-9_])\.)*(?:[a-z0-9_]|[a-z0-9_][a-z0-9_\-]*[a-z0-9_])$/i', $hostname))
515
		return true;
516
	else
517
		return false;
518
}
519

    
520
/* returns true if $domain is a valid domain name */
521
function is_domain($domain) {
522
	if (!is_string($domain))
523
		return false;
524

    
525
	if (preg_match('/^(?:(?:[a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])\.)*(?:[a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])$/i', $domain))
526
		return true;
527
	else
528
		return false;
529
}
530

    
531
/* returns true if $macaddr is a valid MAC address */
532
function is_macaddr($macaddr) {
533
	return preg_match('/^[0-9A-F]{2}(?=([:]?))(?:\\1[0-9A-F]{2}){5}$/i', $macaddr) == 1 ? true : false;
534
}
535

    
536
/* returns true if $name is a valid name for an alias */
537
/* returns NULL if a reserved word is used */
538
function is_validaliasname($name) {
539
	/* Array of reserved words */
540
	$reserved = array("port", "pass");
541
	if (in_array($name, $reserved, true))
542
		return; /* return NULL */
543

    
544
	if (!preg_match("/[^a-zA-Z0-9_]/", $name))
545
		return true;
546
	else
547
		return false;
548
}
549

    
550
/* returns true if $port is a valid TCP/UDP port */
551
function is_port($port) {
552
	$tmpports = explode(":", $port);
553
	foreach($tmpports as $tmpport) {
554
		if (getservbyname($tmpport, "tcp") || getservbyname($tmpport, "udp"))
555
                	continue;
556
		if (!ctype_digit($tmpport))
557
			return false;
558
		else if ((intval($tmpport) < 1) || (intval($tmpport) > 65535))
559
			return false;
560
	}
561
	return true;
562
}
563

    
564
/* returns true if $portrange is a valid TCP/UDP portrange ("<port>:<port>") */
565
function is_portrange($portrange) {
566
        $ports = explode(":", $portrange);
567

    
568
        if(count($ports) == 2 && is_port($ports[0]) && is_port($ports[1]))
569
                return true;
570
        else
571
                return false;
572
}
573

    
574
/* returns true if $port is a valid port number or an alias thereof */
575
function is_portoralias($port) {
576
	global $config;
577

    
578
        if (is_alias($port)) {
579
                if (is_array($config['aliases']['alias'])) {
580
                        foreach ($config['aliases']['alias'] as $alias) {
581
                                if ($alias['name'] == $port && $alias['type'] == "port")
582
                                        return true;
583
                        }
584
                }
585
                return false;
586
        } else
587
                return is_port($port);
588
}
589

    
590
/* returns true if $val is a valid shaper bandwidth value */
591
function is_valid_shaperbw($val) {
592
	return (preg_match("/^(\d+(?:\.\d+)?)([MKG]?b|%)$/", $val));
593
}
594

    
595
/* return the configured carp interface list */
596
function get_configured_carp_interface_list() {
597
	global $config;
598

    
599
	$iflist = array();
600

    
601
	if(is_array($config['virtualip']['vip'])) {
602
                $viparr = &$config['virtualip']['vip'];
603
                foreach ($viparr as $vip) {
604
                        switch ($vip['mode']) {
605
                        case "carp":
606
                        case "carpdev-dhcp":
607
				$vipif = "vip" . $vip['vhid'];
608
                        	$iflist[$vipif] = $vip['subnet'];
609
                                break;
610
                        }
611
                }
612
        }
613

    
614
	return $iflist;
615
}
616

    
617
/* return the configured IP aliases list */
618
function get_configured_ip_aliases_list() {
619
        global $config;
620

    
621
        $alias_list=array();
622

    
623
        if(is_array($config['virtualip']['vip'])) {
624
                $viparr = &$config['virtualip']['vip'];
625
                foreach ($viparr as $vip) {
626
                        if ($vip['mode']=="ipalias") {
627
                                $alias_list[$vip['subnet']] = $vip['interface'];
628
                        }
629
                }
630
        }
631

    
632
        return $alias_list;
633
}
634

    
635

    
636
/* comparison function for sorting by the order in which interfaces are normally created */
637
function compare_interface_friendly_names($a, $b) {
638
	if ($a == $b)
639
		return 0;
640
	else if ($a == 'wan')
641
		return -1;
642
	else if ($b == 'wan')
643
		return 1;
644
	else if ($a == 'lan')
645
		return -1;
646
	else if ($b == 'lan')
647
		return 1;
648

    
649
	return strnatcmp($a, $b);
650
}
651

    
652
/* return the configured interfaces list. */
653
function get_configured_interface_list($only_opt = false, $withdisabled = false) {
654
	global $config;
655

    
656
	$iflist = array();
657

    
658
	/* if list */
659
	foreach($config['interfaces'] as $if => $ifdetail) {
660
		if ($only_opt && ($if == "wan" || $if == "lan"))
661
			continue;
662
		if (isset($ifdetail['enable']) || $withdisabled == true)
663
			$iflist[$if] = $if;
664
	}
665

    
666
	return $iflist;
667
}
668

    
669
/* return the configured interfaces list. */
670
function get_configured_interface_list_by_realif($only_opt = false, $withdisabled = false) {
671
	global $config;
672

    
673
	$iflist = array();
674

    
675
	/* if list */
676
	foreach($config['interfaces'] as $if => $ifdetail) {
677
		if ($only_opt && ($if == "wan" || $if == "lan"))
678
			continue;
679
		if (isset($ifdetail['enable']) || $withdisabled == true) {
680
			$tmpif = get_real_interface($if);
681
			if (!empty($tmpif))
682
				$iflist[$tmpif] = $if;
683
		}
684
	}
685

    
686
	return $iflist;
687
}
688

    
689
/* return the configured interfaces list with their description. */
690
function get_configured_interface_with_descr($only_opt = false, $withdisabled = false) {
691
	global $config;
692

    
693
	$iflist = array();
694

    
695
	/* if list */
696
	foreach($config['interfaces'] as $if => $ifdetail) {
697
		if ($only_opt && ($if == "wan" || $if == "lan"))
698
			continue;
699
		if (isset($ifdetail['enable']) || $withdisabled == true) {
700
			if(empty($ifdetail['descr']))
701
				$iflist[$if] = strtoupper($if);
702
			else
703
				$iflist[$if] = strtoupper($ifdetail['descr']);
704
		}
705
	}
706

    
707
	return $iflist;
708
}
709

    
710
/*
711
 *   get_configured_ip_addresses() - Return a list of all configured
712
 *   interfaces IP Addresses
713
 *
714
 */
715
function get_configured_ip_addresses() {
716
	require_once("interfaces.inc");
717
	$ip_array = array();
718
	$interfaces = get_configured_interface_list();
719
	if(is_array($interfaces)) {
720
		foreach($interfaces as $int) {
721
			$ipaddr = get_interface_ip($int);
722
			$ip_array[$int] = $ipaddr;
723
		}
724
	}
725
	$interfaces = get_configured_carp_interface_list();
726
	if(is_array($interfaces)) 
727
		foreach($interfaces as $int => $ipaddr) 
728
			$ip_array[$int] = $ipaddr;
729
	return $ip_array;
730
}
731

    
732
/*
733
 *   get_interface_list() - Return a list of all physical interfaces
734
 *   along with MAC and status.
735
 *
736
 *   $mode = "active" - use ifconfig -lu
737
 *           "media"  - use ifconfig to check physical connection
738
 *			status (much slower)
739
 */
740
function get_interface_list($mode = "active", $keyby = "physical", $vfaces = "") {
741
        global $config;
742
	$upints = array();
743
        /* get a list of virtual interface types */
744
        if(!$vfaces) {
745
		$vfaces = array (
746
				'bridge',
747
				'ppp',
748
				'pppoe',
749
				'pptp',
750
				'l2tp',
751
				'sl',
752
				'gif',
753
				'gre',
754
				'faith',
755
				'lo',
756
				'ng',
757
				'_vlan',
758
				'_wlan',
759
				'pflog',
760
				'plip',
761
				'pfsync',
762
				'enc',
763
				'tun',
764
				'carp',
765
				'lagg',
766
				'vip',
767
				'ipfw'
768
		);
769
	}
770
	switch($mode) {
771
	case "active":
772
                $upints = explode(" ", trim(shell_exec("/sbin/ifconfig -lu")));
773
        	break;
774
	case "media":
775
                $intlist = explode(" ", trim(shell_exec("/sbin/ifconfig -l")));
776
                $ifconfig = "";
777
                exec("/sbin/ifconfig -a", $ifconfig);
778
                $regexp = '/(' . implode('|', $intlist) . '):\s/';
779
                $ifstatus = preg_grep('/status:/', $ifconfig);
780
		foreach($ifstatus as $status) {
781
			$int = array_shift($intlist);
782
                	if(stristr($status, "active")) $upints[] = $int;
783
		}
784
		break;
785
	default:
786
		$upints = explode(" ", trim(shell_exec("/sbin/ifconfig -l")));
787
		break;
788
	}
789
        /* build interface list with netstat */
790
        $linkinfo = "";
791
        exec("/usr/bin/netstat -inW -f link | awk '{ print $1, $4 }'", $linkinfo);
792
        array_shift($linkinfo);
793
	/* build ip address list with netstat */
794
	$ipinfo = "";
795
	exec("/usr/bin/netstat -inW -f inet | awk '{ print $1, $4 }'", $ipinfo);
796
	array_shift($ipinfo);
797
	foreach($linkinfo as $link) {
798
		$friendly = "";
799
                $alink = explode(" ", $link);
800
                $ifname = rtrim(trim($alink[0]), '*');
801
                /* trim out all numbers before checking for vfaces */
802
		if (!in_array(array_shift(preg_split('/\d/', $ifname)), $vfaces) &&
803
			!stristr($ifname, "_vlan") && !stristr($ifname, "_wlan")) {
804
			$toput = array(
805
					"mac" => trim($alink[1]),
806
					"up" => in_array($ifname, $upints)
807
				);
808
			foreach($ipinfo as $ip) {
809
				$aip = explode(" ", $ip);
810
				if($aip[0] == $ifname) {
811
					$toput['ipaddr'] = $aip[1];
812
				}
813
			}
814
			if (is_array($config['interfaces'])) {
815
				foreach($config['interfaces'] as $name => $int)
816
					if($int['if'] == $ifname) $friendly = $name;
817
			}
818
			switch($keyby) {
819
			case "physical":
820
				if($friendly != "") {
821
					$toput['friendly'] = $friendly;
822
				}
823
				$dmesg_arr = array();
824
				exec("/sbin/dmesg |grep $ifname | head -n1", $dmesg_arr);
825
				preg_match_all("/<(.*?)>/i", $dmesg_arr[0], $dmesg);
826
				$toput['dmesg'] = $dmesg[1][0];
827
				$iflist[$ifname] = $toput;
828
				break;
829
			case "ppp":
830
				
831
			case "friendly":
832
				if($friendly != "") {
833
					$toput['if'] = $ifname;
834
					$iflist[$friendly] = $toput;
835
				}
836
				break;
837
			}
838
                }
839
        }
840
        return $iflist;
841
}
842

    
843
/****f* util/log_error
844
* NAME
845
*   log_error  - Sends a string to syslog.
846
* INPUTS
847
*   $error     - string containing the syslog message.
848
* RESULT
849
*   null
850
******/
851
function log_error($error) {
852
        global $g;
853
        $page = $_SERVER['SCRIPT_NAME'];
854
        syslog(LOG_WARNING, "$page: $error");
855
        if ($g['debug'])
856
                syslog(LOG_WARNING, var_dump(debug_backtrace()));
857
        return;
858
}
859

    
860
/****f* util/log_auth
861
* NAME
862
*   log_error  - Sends a string to syslog as LOG_AUTH facility
863
* INPUTS
864
*   $error     - string containing the syslog message.
865
* RESULT
866
*   null
867
******/
868
function log_auth($error) {
869
        global $g;
870
        $page = $_SERVER['SCRIPT_NAME'];
871
        syslog(LOG_AUTH, "$page: $error");
872
        if ($g['debug'])
873
                syslog(LOG_WARNING, var_dump(debug_backtrace()));
874
        return;
875
}
876

    
877
/****f* util/exec_command
878
 * NAME
879
 *   exec_command - Execute a command and return a string of the result.
880
 * INPUTS
881
 *   $command   - String of the command to be executed.
882
 * RESULT
883
 *   String containing the command's result.
884
 * NOTES
885
 *   This function returns the command's stdout and stderr.
886
 ******/
887
function exec_command($command) {
888
        $output = array();
889
        exec($command . ' 2>&1 ', $output);
890
        return(implode("\n", $output));
891
}
892

    
893
/* wrapper for exec() */
894
function mwexec($command, $mute = false) {
895
	global $g;
896

    
897
	if ($g['debug']) {
898
		if (!$_SERVER['REMOTE_ADDR'])
899
			echo "mwexec(): $command\n";
900
	}
901
	$oarr = array();
902
	$retval = 0;
903
	$garbage = exec("$command 2>&1", $oarr, $retval);
904

    
905
	if(isset($config['system']['developerspew']))
906
                $mute = false;
907
	if(($retval <> 0) && ($mute === false)) {
908
		$output = implode(" ", $oarr);
909
		log_error("The command '$command' returned exit code '$retval', the output was '$output' ");
910
	}
911
	return $retval;
912
}
913

    
914
/* wrapper for exec() in background */
915
function mwexec_bg($command) {
916

    
917
	global $g;
918

    
919
	if ($g['debug']) {
920
		if (!$_SERVER['REMOTE_ADDR'])
921
			echo "mwexec(): $command\n";
922
	}
923

    
924
	exec("nohup $command > /dev/null 2>&1 &");
925
}
926

    
927
/* unlink a file, if it exists */
928
function unlink_if_exists($fn) {
929
	$to_do = glob($fn);
930
	if(is_array($to_do)) {
931
		foreach($to_do as $filename)
932
			@unlink($filename);
933
	} else {
934
		@unlink($fn);
935
	}
936
}
937
/* make a global alias table (for faster lookups) */
938
function alias_make_table($config) {
939

    
940
	global $aliastable;
941

    
942
	$aliastable = array();
943

    
944
	if (is_array($config['aliases']['alias'])) {
945
		foreach ($config['aliases']['alias'] as $alias) {
946
			if ($alias['name'])
947
				$aliastable[$alias['name']] = $alias['address'];
948
		}
949
	}
950
}
951
/* check if an alias exists */
952
function is_alias($name) {
953

    
954
	global $aliastable;
955

    
956
	return isset($aliastable[$name]);
957
}
958

    
959
/* expand a host or network alias, if necessary */
960
function alias_expand($name) {
961

    
962
	global $aliastable;
963

    
964
	if (isset($aliastable[$name]))
965
		return "\${$name}";
966
	else if (is_ipaddr($name) || is_subnet($name) || is_port($name))
967
		return "{$name}";
968
	else
969
		return null;
970
}
971

    
972
function alias_expand_urltable($name) {
973
	global $config;
974
	$urltable_prefix = "/var/db/aliastables/";
975
	$urltable_filename = $urltable_prefix . $name . ".txt";
976

    
977
	foreach ($config['aliases']['alias'] as $alias) {
978
		if (($alias['type'] == 'urltable') && ($alias['name'] == $name)) {
979
			if (is_URL($alias["url"]) && file_exists($urltable_filename) && filesize($urltable_filename))
980
				return $urltable_filename;
981
			else if (process_alias_urltable($name, $alias["url"], 0, true))
982
				return $urltable_filename;
983
		}
984
	}
985
	return null;
986
}
987

    
988
/* find out whether two subnets overlap */
989
function check_subnets_overlap($subnet1, $bits1, $subnet2, $bits2) {
990

    
991
	if (!is_numeric($bits1))
992
		$bits1 = 32;
993
	if (!is_numeric($bits2))
994
		$bits2 = 32;
995

    
996
	if ($bits1 < $bits2)
997
		$relbits = $bits1;
998
	else
999
		$relbits = $bits2;
1000

    
1001
	$sn1 = gen_subnet_mask_long($relbits) & ip2long($subnet1);
1002
	$sn2 = gen_subnet_mask_long($relbits) & ip2long($subnet2);
1003

    
1004
	if ($sn1 == $sn2)
1005
		return true;
1006
	else
1007
		return false;
1008
}
1009

    
1010
/* compare two IP addresses */
1011
function ipcmp($a, $b) {
1012
	if (ip_less_than($a, $b))
1013
		return -1;
1014
	else if (ip_greater_than($a, $b))
1015
		return 1;
1016
	else
1017
		return 0;
1018
}
1019

    
1020
/* return true if $addr is in $subnet, false if not */
1021
function ip_in_subnet($addr,$subnet) {
1022
	if(is_ipaddrv6($addr)) {
1023
		$result = Net_IPv6::IsInNetmask($addr, $subnet);
1024
		if($result)
1025
			return true;
1026
		else
1027
			return false;
1028
	}
1029
	list($ip, $mask) = explode('/', $subnet);
1030
	$mask = (0xffffffff << (32 - $mask)) & 0xffffffff;
1031
	return ((ip2long($addr) & $mask) == (ip2long($ip) & $mask));
1032
}
1033

    
1034
/* verify (and remove) the digital signature on a file - returns 0 if OK */
1035
function verify_digital_signature($fname) {
1036
	global $g;
1037

    
1038
	if(!file_exists("/usr/local/sbin/gzsig"))
1039
		return 4;
1040

    
1041
	return mwexec("/usr/local/sbin/gzsig verify {$g['etc_path']}/pubkey.pem < " . escapeshellarg($fname));
1042
}
1043

    
1044
/* obtain MAC address given an IP address by looking at the ARP table */
1045
function arp_get_mac_by_ip($ip) {
1046
	mwexec("/sbin/ping -c 1 -t 1 {$ip}", true);
1047
	$arpoutput = "";
1048
	exec("/usr/sbin/arp -n {$ip}", $arpoutput);
1049

    
1050
	if ($arpoutput[0]) {
1051
		$arpi = explode(" ", $arpoutput[0]);
1052
		$macaddr = $arpi[3];
1053
		if (is_macaddr($macaddr))
1054
			return $macaddr;
1055
		else
1056
			return false;
1057
	}
1058

    
1059
	return false;
1060
}
1061

    
1062
/* return a fieldname that is safe for xml usage */
1063
function xml_safe_fieldname($fieldname) {
1064
	$replace = array('/', '-', ' ', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
1065
			 '_', '+', '=', '{', '}', '[', ']', '|', '/', '<', '>', '?',
1066
			 ':', ',', '.', '\'', '\\'
1067
		);
1068
	return strtolower(str_replace($replace, "", $fieldname));
1069
}
1070

    
1071
function mac_format($clientmac) {
1072
    $mac =explode(":", $clientmac);
1073

    
1074
    global $config;
1075

    
1076
    $mac_format = $config['captiveportal']['radmac_format'] ? $config['captiveportal']['radmac_format'] : false;
1077

    
1078
    switch($mac_format) {
1079

    
1080
        case 'singledash':
1081
        return "$mac[0]$mac[1]$mac[2]-$mac[3]$mac[4]$mac[5]";
1082

    
1083
        case 'ietf':
1084
        return "$mac[0]-$mac[1]-$mac[2]-$mac[3]-$mac[4]-$mac[5]";
1085

    
1086
        case 'cisco':
1087
        return "$mac[0]$mac[1].$mac[2]$mac[3].$mac[4]$mac[5]";
1088

    
1089
        case 'unformatted':
1090
        return "$mac[0]$mac[1]$mac[2]$mac[3]$mac[4]$mac[5]";
1091

    
1092
        default:
1093
        return $clientmac;
1094
    }
1095
}
1096

    
1097
function resolve_retry($hostname, $retries = 5) {
1098

    
1099
       if (is_ipaddr($hostname))
1100
               return $hostname;
1101

    
1102
       for ($i = 0; $i < $retries; $i++) {
1103
               $ip = gethostbyname($hostname);
1104

    
1105
               if ($ip && $ip != $hostname) {
1106
                       /* success */
1107
                       return $ip;
1108
               }
1109

    
1110
               sleep(1);
1111
       }
1112

    
1113
       return false;
1114
}
1115

    
1116
function format_bytes($bytes) {
1117
	if ($bytes >= 1073741824) {
1118
		return sprintf("%.2f GB", $bytes/1073741824);
1119
	} else if ($bytes >= 1048576) {
1120
		return sprintf("%.2f MB", $bytes/1048576);
1121
	} else if ($bytes >= 1024) {
1122
		return sprintf("%.0f KB", $bytes/1024);
1123
	} else {
1124
		return sprintf("%d bytes", $bytes);
1125
	}
1126
}
1127

    
1128
function update_filter_reload_status($text) {
1129
        global $g;
1130

    
1131
        file_put_contents("{$g['varrun_path']}/filter_reload_status", $text);
1132
}
1133

    
1134
/****f* util/return_dir_as_array
1135
 * NAME
1136
 *   return_dir_as_array - Return a directory's contents as an array.
1137
 * INPUTS
1138
 *   $dir       - string containing the path to the desired directory.
1139
 * RESULT
1140
 *   $dir_array - array containing the directory's contents. This array will be empty if the path specified is invalid.
1141
 ******/
1142
function return_dir_as_array($dir) {
1143
        $dir_array = array();
1144
        if (is_dir($dir)) {
1145
                if ($dh = opendir($dir)) {
1146
                        while (($file = readdir($dh)) !== false) {
1147
                                $canadd = 0;
1148
                                if($file == ".") $canadd = 1;
1149
                                if($file == "..") $canadd = 1;
1150
                                if($canadd == 0)
1151
                                        array_push($dir_array, $file);
1152
                        }
1153
                        closedir($dh);
1154
                }
1155
        }
1156
        return $dir_array;
1157
}
1158

    
1159
function run_plugins($directory) {
1160
        global $config, $g;
1161

    
1162
		/* process packager manager custom rules */
1163
		$files = return_dir_as_array($directory);
1164
		if (is_array($files)) {
1165
			foreach ($files as $file) {
1166
				if (stristr($file, ".sh") == true)
1167
					mwexec($directory . $file . " start");
1168
				else if (!is_dir($directory . "/" . $file) && stristr($file,".inc")) 
1169
					require_once($directory . "/" . $file);
1170
			}
1171
		}
1172
}
1173

    
1174
/*
1175
 *    safe_mkdir($path, $mode = 0755)
1176
 *    create directory if it doesn't already exist and isn't a file!
1177
 */
1178
function safe_mkdir($path, $mode=0755) {
1179
        global $g;
1180

    
1181
        if (!is_file($path) && !is_dir($path)) {
1182
                return @mkdir($path, $mode, true);
1183
        } else {
1184
                return false;
1185
        }
1186
}
1187

    
1188
/*
1189
 * make_dirs($path, $mode = 0755)
1190
 * create directory tree recursively (mkdir -p)
1191
 */
1192
function make_dirs($path, $mode = 0755) {
1193
        $base = '';
1194
        foreach (explode('/', $path) as $dir) {
1195
                $base .= "/$dir";
1196
                if (!is_dir($base)) {
1197
                        if (!@mkdir($base, $mode))
1198
                                return false;
1199
                }
1200
        }
1201
        return true;
1202
}
1203

    
1204
/*
1205
 * get_sysctl($names)
1206
 * Get values of sysctl OID's listed in $names (accepts an array or a single
1207
 * name) and return an array of key/value pairs set for those that exist
1208
 */
1209
function get_sysctl($names) {
1210
	if (empty($names))
1211
		return array();
1212

    
1213
	if (is_array($names)) {
1214
		$name_list = array();
1215
		foreach ($names as $name) {
1216
			$name_list[] = escapeshellarg($name);
1217
		}
1218
	} else
1219
		$name_list = array(escapeshellarg($names));
1220

    
1221
	exec("/sbin/sysctl -i " . implode(" ", $name_list), $output);
1222
	$values = array();
1223
	foreach ($output as $line) {
1224
		$line = explode(": ", $line, 2);
1225
		if (count($line) == 2)
1226
			$values[$line[0]] = $line[1];
1227
	}
1228

    
1229
	return $values;
1230
}
1231

    
1232
/*
1233
 * set_sysctl($value_list)
1234
 * Set sysctl OID's listed as key/value pairs and return
1235
 * an array with keys set for those that succeeded
1236
 */
1237
function set_sysctl($values) {
1238
	if (empty($values))
1239
		return array();
1240

    
1241
	$value_list = array();
1242
	foreach ($values as $key => $value) {
1243
		$value_list[] = escapeshellarg($key) . "=" . escapeshellarg($value);
1244
	}
1245

    
1246
	exec("/sbin/sysctl -i " . implode(" ", $value_list), $output, $success);
1247

    
1248
	/* Retry individually if failed (one or more read-only) */
1249
	if ($success <> 0 && count($value_list) > 1) {
1250
		foreach ($value_list as $value) {
1251
			exec("/sbin/sysctl -i " . $value, $output);
1252
		}
1253
	}
1254

    
1255
	$ret = array();
1256
	foreach ($output as $line) {
1257
		$line = explode(": ", $line, 2);
1258
		if (count($line) == 2)
1259
			$ret[$line[0]] = true;
1260
	}
1261

    
1262
	return $ret;
1263
}
1264

    
1265
/*
1266
 *     get_memory()
1267
 *     returns an array listing the amount of
1268
 *     memory installed in the hardware
1269
 *     [0]real and [1]available
1270
 */
1271
function get_memory() {
1272
		$matches = "";
1273
        if(file_exists("/var/log/dmesg.boot"))
1274
			$mem = `cat /var/log/dmesg.boot | grep memory`;
1275
		else
1276
			$mem = `dmesg -a | grep memory`;			
1277
		if (preg_match_all("/avail memory.* \((.*)MB\)/", $mem, $matches)) 
1278
			return array($matches[1][0], $matches[1][0]);
1279
		if(!$real && !$avail) {
1280
			$real = trim(`sysctl hw.physmem | cut -d' ' -f2`);
1281
			$avail = trim(`sysctl hw.realmem | cut -d' ' -f2`);
1282
			/* convert from bytes to megabytes */
1283
			return array(($real/1048576),($avail/1048576));
1284
		}
1285
}
1286

    
1287
function mute_kernel_msgs() {
1288
		global $config;
1289
		// Do not mute serial console.  The kernel gets very very cranky
1290
		// and will start dishing you cannot control tty errors.
1291
		if(trim(file_get_contents("/etc/platform")) == "nanobsd") 
1292
			return;
1293
		if($config['system']['enableserial']) 
1294
			return;			
1295
		exec("/sbin/conscontrol mute on");
1296
}
1297

    
1298
function unmute_kernel_msgs() {
1299
		global $config;
1300
		// Do not mute serial console.  The kernel gets very very cranky
1301
		// and will start dishing you cannot control tty errors.
1302
		if(trim(file_get_contents("/etc/platform")) == "nanobsd") 
1303
			return;
1304
		exec("/sbin/conscontrol mute off");
1305
}
1306

    
1307
function start_devd() {
1308
	global $g;
1309

    
1310
        exec("/sbin/devd");
1311
        sleep(1);
1312
}
1313

    
1314
function is_interface_vlan_mismatch() {
1315
        global $config, $g;
1316

    
1317
        if (is_array($config['vlans']['vlan'])) {
1318
                foreach ($config['vlans']['vlan'] as $vlan) {
1319
                        if (does_interface_exist($vlan['if']) == false)
1320
				return true;
1321
                }
1322
        }
1323

    
1324
	return false;
1325
}
1326

    
1327
function is_interface_mismatch() {
1328
        global $config, $g;
1329

    
1330
        /* XXX: Should we process only enabled interfaces?! */
1331
        $do_assign = false;
1332
        $i = 0;
1333
	if (is_array($config['interfaces'])) {
1334
        	foreach ($config['interfaces'] as $ifname => $ifcfg) {
1335
                	if (preg_match("/^enc|^cua|^tun|^l2tp|^pptp|^ppp|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_wlan/i", $ifcfg['if'])) {
1336
                        	$i++;
1337
                	}
1338
                	else if (does_interface_exist($ifcfg['if']) == false) {
1339
				$do_assign = true;
1340
                	} else
1341
                        	$i++;
1342
        	}
1343
	}
1344

    
1345
        if ($g['minimum_nic_count'] > $i) {
1346
                $do_assign = true;
1347
        } else if (file_exists("{$g['tmp_path']}/assign_complete"))
1348
                $do_assign = false;
1349

    
1350
        return $do_assign;
1351
}
1352

    
1353
/* sync carp entries to other firewalls */
1354
function carp_sync_client() {
1355
	global $g;
1356
	send_event("filter sync");
1357
}
1358

    
1359
/****f* util/isAjax
1360
 * NAME
1361
 *   isAjax - reports if the request is driven from prototype
1362
 * INPUTS
1363
 *   none
1364
 * RESULT
1365
 *   true/false
1366
 ******/
1367
function isAjax() {
1368
        return isset ($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest';
1369
}
1370

    
1371
/****f* util/timeout
1372
 * NAME
1373
 *   timeout - console input with timeout countdown. Note: erases 2 char of screen for timer. Leave space.
1374
 * INPUTS
1375
 *   optional, seconds to wait before timeout. Default 9 seconds.
1376
 * RESULT
1377
 *   returns 1 char of user input or null if no input.
1378
 ******/
1379
function timeout($timer = 9) {
1380
	while(!isset($key)) {
1381
		if ($timer >= 9) { echo chr(8) . chr(8) . ($timer==9 ? chr(32) : null)  . "{$timer}";  }
1382
		else { echo chr(8). "{$timer}"; }
1383
		`/bin/stty -icanon min 0 time 25`;
1384
		$key = trim(`KEY=\`dd count=1 2>/dev/null\`; echo \$KEY`);
1385
		`/bin/stty icanon`;
1386
		if ($key == '')
1387
			unset($key);
1388
		$timer--;
1389
		if ($timer == 0)
1390
			break;
1391
	}
1392
	return $key;	
1393
}
1394

    
1395
/****f* util/msort
1396
 * NAME
1397
 *   msort - sort array
1398
 * INPUTS
1399
 *   $array to be sorted, field to sort by, direction of sort
1400
 * RESULT
1401
 *   returns newly sorted array
1402
 ******/
1403
function msort($array, $id="id", $sort_ascending=true) {
1404
	$temp_array = array();
1405
	while(count($array)>0) {
1406
		$lowest_id = 0;
1407
		$index=0;
1408
		foreach ($array as $item) {
1409
			if (isset($item[$id])) {
1410
				if ($array[$lowest_id][$id]) {
1411
					if (strtolower($item[$id]) < strtolower($array[$lowest_id][$id])) {
1412
						$lowest_id = $index;
1413
					}
1414
				}
1415
			}
1416
			$index++;
1417
		}
1418
		$temp_array[] = $array[$lowest_id];
1419
		$array = array_merge(array_slice($array, 0,$lowest_id), array_slice($array, $lowest_id+1));
1420
	}
1421
	if ($sort_ascending) {
1422
		return $temp_array;
1423
	} else {
1424
    	return array_reverse($temp_array);
1425
	}
1426
}
1427

    
1428
/****f* util/color
1429
 * NAME
1430
 *   color - outputs a color code to the ansi terminal if supported
1431
 * INPUTS
1432
 *   color code or color name
1433
 * RESULT
1434
 *   Outputs the ansi color sequence for the color specified.  Default resets terminal.
1435
 ******/
1436
function color($color = "0m") {
1437
	/*
1438
		Color codes available:
1439
		 0m reset; clears all colors and styles (to white on black)
1440
		 1m bold on (see below)
1441
		 3m italics on
1442
		 4m underline on
1443
		 7m inverse on; reverses foreground & background colors
1444
		 9m strikethrough on
1445
		 22m bold off (see below)
1446
		 23m italics off
1447
		 24m underline off
1448
		 27m inverse off
1449
		 29m strikethrough off
1450
		 30m set foreground color to black
1451
		 31m set foreground color to red
1452
		 32m set foreground color to green
1453
		 33m set foreground color to yellow
1454
		 34m set foreground color to blue
1455
		 35m set foreground color to magenta (purple)
1456
		 36m set foreground color to cyan
1457
		 37m set foreground color to white
1458
		 40m  set background color to black
1459
		 41m set background color to red
1460
		 42m set background color to green
1461
		 43m set background color to yellow
1462
		 44m set background color to blue
1463
		 45m set background color to magenta (purple)
1464
		 46m set background color to cyan
1465
		 47m set background color to white
1466
		 49m set background color to default (black)
1467
	*/	
1468
	// Allow caching of TERM to 
1469
	// speedup subequence requests.
1470
	global $TERM;
1471
	if(!$TERM) 
1472
		$TERM=`/usr/bin/env | grep color`;
1473
	if(!$TERM)
1474
		$TERM=`/usr/bin/env | grep cons25`;
1475
	if($TERM) {
1476
		$ESCAPE=chr(27);
1477
		switch ($color) {
1478
			case "black":
1479
				return "{$ESCAPE}[30m"; 
1480
			case "red":
1481
				return "{$ESCAPE}[31m"; 
1482
			case "green":
1483
				return "{$ESCAPE}[32m"; 
1484
			case "yellow":
1485
				return "{$ESCAPE}[33m"; 
1486
			case "blue":
1487
				return "{$ESCAPE}[34m"; 
1488
			case "magenta":
1489
				return "{$ESCAPE}[35m"; 
1490
			case "cyan":
1491
				return "{$ESCAPE}[36m"; 
1492
			case "white":
1493
				return "{$ESCAPE}[37m"; 
1494
			case "default":
1495
				return "{$ESCAPE}[39m"; 
1496
		}
1497
		return "{$ESCAPE}[{$color}";
1498
	}
1499
}
1500

    
1501
/****f* util/is_URL
1502
 * NAME
1503
 *   is_URL
1504
 * INPUTS
1505
 *   string to check
1506
 * RESULT
1507
 *   Returns true if item is a URL
1508
 ******/
1509
function is_URL($url) {
1510
	$match = preg_match("'\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))'", $url);
1511
	if($match)
1512
		return true;	
1513
	return false;
1514
}
1515

    
1516
function is_file_included($file = "") {
1517
	$files = get_included_files();
1518
	if (in_array($file, $files))
1519
		return true;
1520
	
1521
	return false;
1522
}
1523

    
1524
/*
1525
	This function was borrowed from a comment on PHP.net at the following URL:
1526
	http://www.php.net/manual/en/function.array-merge-recursive.php#73843
1527
 */
1528
function array_merge_recursive_unique($array0, $array1)
1529
{
1530
    $arrays = func_get_args();
1531
    $remains = $arrays;
1532

    
1533
    // We walk through each arrays and put value in the results (without
1534
    // considering previous value).
1535
    $result = array();
1536

    
1537
    // loop available array
1538
    foreach($arrays as $array) {
1539

    
1540
        // The first remaining array is $array. We are processing it. So
1541
        // we remove it from remaing arrays.
1542
        array_shift($remains);
1543

    
1544
        // We don't care non array param, like array_merge since PHP 5.0.
1545
        if(is_array($array)) {
1546
            // Loop values
1547
            foreach($array as $key => $value) {
1548
                if(is_array($value)) {
1549
                    // we gather all remaining arrays that have such key available
1550
                    $args = array();
1551
                    foreach($remains as $remain) {
1552
                        if(array_key_exists($key, $remain)) {
1553
                            array_push($args, $remain[$key]);
1554
                        }
1555
                    }
1556

    
1557
                    if(count($args) > 2) {
1558
                        // put the recursion
1559
                        $result[$key] = call_user_func_array(__FUNCTION__, $args);
1560
                    } else {
1561
                        foreach($value as $vkey => $vval) {
1562
                            $result[$key][$vkey] = $vval;
1563
                        }
1564
                    }
1565
                } else {
1566
                    // simply put the value
1567
                    $result[$key] = $value;
1568
                }
1569
            }
1570
        }
1571
    }
1572
    return $result;
1573
}
1574

    
1575
?>
(49-49/61)