Project

General

Profile

Download (41.5 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 -ax {$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

    
230
	$address = Net_IPv6::getNetmask($ipaddr, $bits);
231
	return $address;
232
}
233

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

    
239
	return long2ip32(ip2long($ipaddr) | ~gen_subnet_mask_long($bits));
240
}
241

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
435

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

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

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

    
458
	$ip_long = ip2long($ipaddr);
459
	$ip_reverse = long2ip32($ip_long);
460

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

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

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

    
482
}
483

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

    
489
	list($hp,$np) = explode('/', $subnet);
490

    
491
	if (!is_ipaddr($hp))
492
		return false;
493

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

    
497
	return true;
498
}
499

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

    
503
	global $aliastable;
504

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

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

    
516
	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))
517
		return true;
518
	else
519
		return false;
520
}
521

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

    
527
	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))
528
		return true;
529
	else
530
		return false;
531
}
532

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

    
538
/* returns true if $name is a valid name for an alias */
539
/* returns NULL if a reserved word is used */
540
function is_validaliasname($name) {
541
	/* Array of reserved words */
542
	$reserved = array("port", "pass");
543
	if (in_array($name, $reserved, true))
544
		return; /* return NULL */
545
	if (!preg_match("/[^a-zA-Z0-9_]/", $name) && (strlen($name) < 32))
546
		return true;
547
	else
548
		return false;
549
}
550

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

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

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

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

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

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

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

    
600
	$iflist = array();
601

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

    
615
	return $iflist;
616
}
617

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

    
622
        $alias_list=array();
623

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

    
633
        return $alias_list;
634
}
635

    
636

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

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

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

    
657
	$iflist = array();
658

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

    
667
	return $iflist;
668
}
669

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

    
674
	$iflist = array();
675

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

    
687
	return $iflist;
688
}
689

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

    
694
	$iflist = array();
695

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

    
708
	return $iflist;
709
}
710

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

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

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

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

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

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

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

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

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

    
918
	global $g;
919

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

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

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

    
941
	global $aliastable;
942

    
943
	$aliastable = array();
944

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

    
955
	global $aliastable;
956

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

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

    
963
	global $aliastable;
964

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1060
	return false;
1061
}
1062

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

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

    
1075
    global $config;
1076

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

    
1079
    switch($mac_format) {
1080

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

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

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

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

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

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

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

    
1103
       for ($i = 0; $i < $retries; $i++) {
1104
		// FIXME: gethostbyname does not work for AAAA hostnames, boo, hiss
1105
               $ip = gethostbyname($hostname);
1106

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

    
1112
               sleep(1);
1113
       }
1114

    
1115
       return false;
1116
}
1117

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

    
1130
function update_filter_reload_status($text) {
1131
        global $g;
1132

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

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

    
1161
function run_plugins($directory) {
1162
        global $config, $g;
1163

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

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

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

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

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

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

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

    
1231
	return $values;
1232
}
1233

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

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

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

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

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

    
1264
	return $ret;
1265
}
1266

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

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

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

    
1309
function start_devd() {
1310
	global $g;
1311

    
1312
        exec("/sbin/devd");
1313
        sleep(1);
1314
}
1315

    
1316
function is_interface_vlan_mismatch() {
1317
        global $config, $g;
1318

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

    
1326
	return false;
1327
}
1328

    
1329
function is_interface_mismatch() {
1330
        global $config, $g;
1331

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

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

    
1352
        return $do_assign;
1353
}
1354

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

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

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

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

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

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

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

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

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

    
1539
    // loop available array
1540
    foreach($arrays as $array) {
1541

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

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

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

    
1577
?>
(49-49/61)