Project

General

Profile

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

    
161
function send_multiple_events($cmds) {
162
	global $g;
163

    
164
	if(!isset($g['event_address']))
165
		$g['event_address'] = "unix:///var/run/check_reload_status";
166
			
167
	if (!is_array($cmds))
168
		return;
169
	$fd = fsockopen($g['event_address']);
170
	if ($fd) {
171
		foreach ($cmds as $cmd) {
172
			fwrite($fd, $cmd);
173
			$resp = fread($fd, 4096);
174
			if ($resp != "OK\n")
175
				log_error("send_event: sent {$cmd} got {$resp}");
176
		}
177
		fclose($fd);
178
	}
179
}
180

    
181
function refcount_init($reference) {
182
	$shmid = shmop_open($reference, "c", 0644, 10);
183
	shmop_write($shmid, 0, 0);
184
	shmop_close($shmid);
185
}
186

    
187
function refcount_reference($reference) {
188
	$shmid = @shmop_open($reference, "w", 0644, 10);
189
	if (!$shmid) {
190
		refcount_init($reference);
191
		$shmid = shmop_open($reference, "w", 0644, 10);
192
	}
193
	$shm_data = shmop_read($shmid, 0, 10);
194
	$shm_data = intval($shm_data) + 1;
195
	shmop_write($shmid, $shm_data, 0);
196
	shmop_close($shmid);
197
	
198
	return $shm_data;
199
}
200

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

    
216
function is_module_loaded($module_name) {
217
	$running = `/sbin/kldstat | grep {$module_name} | /usr/bin/grep -v grep | /usr/bin/wc -l`;
218
	if (intval($running) >= 1)
219
		return true;
220
	else
221
		return false;
222
}
223

    
224
/* return the subnet address given a host address and a subnet bit count */
225
function gen_subnet($ipaddr, $bits) {
226
	if (!is_ipaddr($ipaddr) || !is_numeric($bits))
227
		return "";
228

    
229
	return long2ip(ip2long($ipaddr) & gen_subnet_mask_long($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
/* returns a subnet mask (long given a bit count) */
241
function gen_subnet_mask_long($bits) {
242
	$sm = 0;
243
	for ($i = 0; $i < $bits; $i++) {
244
		$sm >>= 1;
245
		$sm |= 0x80000000;
246
	}
247
	return $sm;
248
}
249

    
250
/* same as above but returns a string */
251
function gen_subnet_mask($bits) {
252
	return long2ip(gen_subnet_mask_long($bits));
253
}
254

    
255
/* Convert long int to IP address, truncating to 32-bits. */
256
function long2ip32($ip) {
257
	return long2ip($ip & 0xFFFFFFFF);
258
}
259

    
260
/* Convert IP address to long int, truncated to 32-bits to avoid sign extension on 64-bit platforms. */
261
function ip2long32($ip) {
262
	return ( ip2long($ip) & 0xFFFFFFFF );
263
}
264

    
265
/* Convert IP address to unsigned long int. */
266
function ip2ulong($ip) {
267
	return sprintf("%u", ip2long32($ip));
268
}
269

    
270
/* Find out how many IPs are contained within a given IP range
271
 *  e.g. 192.168.0.0 to 192.168.0.255 returns 256
272
 */
273
function ip_range_size($startip, $endip) {
274
	if (is_ipaddr($startip) && is_ipaddr($endip)) {
275
		// Operate as unsigned long because otherwise it wouldn't work
276
		//   when crossing over from 127.255.255.255 / 128.0.0.0 barrier
277
		return abs(ip2ulong($startip) - ip2ulong($endip)) + 1;
278
	}
279
	return -1;
280
}
281

    
282
/* Find the smallest possible subnet mask which can contain a given number of IPs
283
 *  e.g. 512 IPs can fit in a /23, but 513 IPs need a /22
284
 */
285
function find_smallest_cidr($number) {
286
	$smallest = 1;
287
	for ($b=32; $b > 0; $b--) {
288
		$smallest = ($number <= pow(2,$b)) ? $b : $smallest;
289
	}
290
	return (32-$smallest);
291
}
292

    
293
/* Return the previous IP address before the given address */
294
function ip_before($ip) {
295
	return long2ip32(ip2long($ip)-1);
296
}
297

    
298
/* Return the next IP address after the given address */
299
function ip_after($ip) {
300
	return long2ip32(ip2long($ip)+1);
301
}
302

    
303
/* Return true if the first IP is 'before' the second */
304
function ip_less_than($ip1, $ip2) {
305
	// Compare as unsigned long because otherwise it wouldn't work when
306
	//   crossing over from 127.255.255.255 / 128.0.0.0 barrier
307
	return ip2ulong($ip1) < ip2ulong($ip2);
308
}
309

    
310
/* Return true if the first IP is 'after' the second */
311
function ip_greater_than($ip1, $ip2) {
312
	// Compare as unsigned long because otherwise it wouldn't work
313
	//   when crossing over from 127.255.255.255 / 128.0.0.0 barrier
314
	return ip2ulong($ip1) > ip2ulong($ip2);
315
}
316

    
317
/* Convert a range of IPs to an array of subnets which can contain the range. */
318
function ip_range_to_subnet_array($startip, $endip) {
319
	if (!is_ipaddr($startip) || !is_ipaddr($endip)) {
320
		return array();
321
	}
322

    
323
	// Container for subnets within this range.
324
	$rangesubnets = array();
325

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

    
329
	// Loop here to reduce subnet size and retest as needed. We need to make sure
330
	//   that the target subnet is wholly contained between $startip and $endip.
331
	for ($cidr; $cidr <= 32; $cidr++) {
332
		// Find the network and broadcast addresses for the subnet being tested.
333
		$targetsub_min = gen_subnet($startip, $cidr);
334
		$targetsub_max = gen_subnet_max($startip, $cidr);
335

    
336
		// Check best case where the range is exactly one subnet.
337
		if (($targetsub_min == $startip) && ($targetsub_max == $endip)) {
338
			// Hooray, the range is exactly this subnet!
339
			return array("{$startip}/{$cidr}");
340
		}
341

    
342
		// These remaining scenarios will find a subnet that uses the largest
343
		//  chunk possible of the range being tested, and leave the rest to be
344
		//  tested recursively after the loop.
345

    
346
		// Check if the subnet begins with $startip and ends before $endip
347
		if (($targetsub_min == $startip) && ip_less_than($targetsub_max, $endip)) {
348
			break;
349
		}
350

    
351
		// Check if the subnet ends at $endip and starts after $startip
352
		if (ip_greater_than($targetsub_min, $startip) && ($targetsub_max == $endip)) {
353
			break;
354
		}
355

    
356
		// Check if the subnet is between $startip and $endip
357
		if (ip_greater_than($targetsub_min, $startip) && ip_less_than($targetsub_max, $endip)) {
358
			break;
359
		}
360
	}
361

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

    
368
	// Add in the subnet we found before, to preserve ordering
369
	$rangesubnets[] = "{$targetsub_min}/{$cidr}";
370

    
371
	// And some more logic that will search after the subnet we found to fill in to the end of the range.
372
	if ($endip != $targetsub_max) {
373
		$rangesubnets = array_merge($rangesubnets, ip_range_to_subnet_array(ip_after($targetsub_max), $endip));
374
	}
375
	return $rangesubnets;
376
}
377

    
378
function is_iprange($range) {
379
	if (substr_count($range, '-') != 1) {
380
		return false;
381
	}
382
	list($ip1, $ip2) = explode ('-', $range);
383
	return (is_ipaddr($ip1) && is_ipaddr($ip2));
384
}
385

    
386
function is_numericint($arg) {
387
	return (preg_match("/[^0-9]/", $arg) ? false : true);
388
}
389

    
390
/* returns true if $ipaddr is a valid dotted IPv4 address */
391
function is_ipaddr($ipaddr) {
392
	if (!is_string($ipaddr))
393
		return false;
394

    
395
	$ip_long = ip2long($ipaddr);
396
	$ip_reverse = long2ip32($ip_long);
397

    
398
	if ($ipaddr == $ip_reverse)
399
		return true;
400
	else
401
		return false;
402
}
403

    
404
/* returns true if $ipaddr is a valid dotted IPv4 address or an alias thereof */
405
function is_ipaddroralias($ipaddr) {
406
	global $config;
407

    
408
	if (is_alias($ipaddr)) {
409
		if (is_array($config['aliases']['alias'])) {
410
			foreach ($config['aliases']['alias'] as $alias) {
411
				if ($alias['name'] == $ipaddr && $alias['type'] != "port")
412
					return true;
413
			}
414
		}
415
		return false;
416
	} else
417
		return is_ipaddr($ipaddr);
418

    
419
}
420

    
421
/* returns true if $subnet is a valid subnet in CIDR format */
422
function is_subnet($subnet) {
423
	if (!is_string($subnet))
424
		return false;
425

    
426
	list($hp,$np) = explode('/', $subnet);
427

    
428
	if (!is_ipaddr($hp))
429
		return false;
430

    
431
	if (!is_numeric($np) || ($np < 1) || ($np > 32))
432
		return false;
433

    
434
	return true;
435
}
436

    
437
/* returns true if $subnet is a valid subnet in CIDR format or an alias thereof */
438
function is_subnetoralias($subnet) {
439
	global $aliastable;
440

    
441
	if (isset($aliastable[$subnet]) && is_subnet($aliastable[$subnet]))
442
		return true;
443
	else
444
		return is_subnet($subnet);
445
}
446

    
447
/* returns true if $hostname is a valid hostname */
448
function is_hostname($hostname) {
449
	if (!is_string($hostname))
450
		return false;
451

    
452
	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))
453
		return true;
454
	else
455
		return false;
456
}
457

    
458
/* returns true if $domain is a valid domain name */
459
function is_domain($domain) {
460
	if (!is_string($domain))
461
		return false;
462

    
463
	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))
464
		return true;
465
	else
466
		return false;
467
}
468

    
469
/* returns true if $macaddr is a valid MAC address */
470
function is_macaddr($macaddr) {
471
	return preg_match('/^[0-9A-F]{2}(?:[:][0-9A-F]{2}){5}$/i', $macaddr) == 1 ? true : false;
472
}
473

    
474
/* returns true if $name is a valid name for an alias */
475
/* returns NULL if a reserved word is used */
476
function is_validaliasname($name) {
477
	/* Array of reserved words */
478
	$reserved = array("port", "pass");
479
	if (in_array($name, $reserved, true))
480
		return; /* return NULL */
481
	if (!preg_match("/[^a-zA-Z0-9_]/", $name) && (strlen($name) < 32))
482
		return true;
483
	else
484
		return false;
485
}
486

    
487
/* returns true if $port is a valid TCP/UDP port */
488
function is_port($port) {
489
	$tmpports = explode(":", $port);
490
	foreach($tmpports as $tmpport) {
491
		if (getservbyname($tmpport, "tcp") || getservbyname($tmpport, "udp"))
492
			continue;
493
		if (!ctype_digit($tmpport))
494
			return false;
495
		else if ((intval($tmpport) < 1) || (intval($tmpport) > 65535))
496
			return false;
497
	}
498
	return true;
499
}
500

    
501
/* returns true if $portrange is a valid TCP/UDP portrange ("<port>:<port>") */
502
function is_portrange($portrange) {
503
	$ports = explode(":", $portrange);
504

    
505
	if(count($ports) == 2 && is_port($ports[0]) && is_port($ports[1]))
506
		return true;
507
	else
508
		return false;
509
}
510

    
511
/* returns true if $port is a valid port number or an alias thereof */
512
function is_portoralias($port) {
513
	global $config;
514

    
515
	if (is_alias($port)) {
516
		if (is_array($config['aliases']['alias'])) {
517
			foreach ($config['aliases']['alias'] as $alias) {
518
				if ($alias['name'] == $port && $alias['type'] == "port")
519
					return true;
520
				}
521
			}
522
			return false;
523
	} else
524
		return is_port($port);
525
}
526

    
527
/* returns true if $val is a valid shaper bandwidth value */
528
function is_valid_shaperbw($val) {
529
	return (preg_match("/^(\d+(?:\.\d+)?)([MKG]?b|%)$/", $val));
530
}
531

    
532
/* return the configured carp interface list */
533
function get_configured_carp_interface_list() {
534
	global $config;
535

    
536
	$iflist = array();
537

    
538
	if(is_array($config['virtualip']['vip'])) {
539
		$viparr = &$config['virtualip']['vip'];
540
		foreach ($viparr as $vip) {
541
			switch ($vip['mode']) {
542
				case "carp":
543
				case "carpdev-dhcp":
544
					$vipif = "vip" . $vip['vhid'];
545
					$iflist[$vipif] = $vip['subnet'];
546
					break;
547
			}
548
		}
549
	}
550

    
551
	return $iflist;
552
}
553

    
554
/* return the configured IP aliases list */
555
function get_configured_ip_aliases_list() {
556
	global $config;
557

    
558
	$alias_list=array();
559

    
560
	if(is_array($config['virtualip']['vip'])) {
561
		$viparr = &$config['virtualip']['vip'];
562
		foreach ($viparr as $vip) {
563
			if ($vip['mode']=="ipalias") {
564
				$alias_list[$vip['subnet']] = $vip['interface'];
565
			}
566
		}
567
	}
568

    
569
	return $alias_list;
570
}
571

    
572

    
573
/* comparison function for sorting by the order in which interfaces are normally created */
574
function compare_interface_friendly_names($a, $b) {
575
	if ($a == $b)
576
		return 0;
577
	else if ($a == 'wan')
578
		return -1;
579
	else if ($b == 'wan')
580
		return 1;
581
	else if ($a == 'lan')
582
		return -1;
583
	else if ($b == 'lan')
584
		return 1;
585

    
586
	return strnatcmp($a, $b);
587
}
588

    
589
/* return the configured interfaces list. */
590
function get_configured_interface_list($only_opt = false, $withdisabled = false) {
591
	global $config;
592

    
593
	$iflist = array();
594

    
595
	/* if list */
596
	foreach($config['interfaces'] as $if => $ifdetail) {
597
		if ($only_opt && ($if == "wan" || $if == "lan"))
598
			continue;
599
		if (isset($ifdetail['enable']) || $withdisabled == true)
600
			$iflist[$if] = $if;
601
	}
602

    
603
	return $iflist;
604
}
605

    
606
/* return the configured interfaces list. */
607
function get_configured_interface_list_by_realif($only_opt = false, $withdisabled = false) {
608
	global $config;
609

    
610
	$iflist = array();
611

    
612
	/* if list */
613
	foreach($config['interfaces'] as $if => $ifdetail) {
614
		if ($only_opt && ($if == "wan" || $if == "lan"))
615
			continue;
616
		if (isset($ifdetail['enable']) || $withdisabled == true) {
617
			$tmpif = get_real_interface($if);
618
			if (!empty($tmpif))
619
				$iflist[$tmpif] = $if;
620
		}
621
	}
622

    
623
	return $iflist;
624
}
625

    
626
/* return the configured interfaces list with their description. */
627
function get_configured_interface_with_descr($only_opt = false, $withdisabled = false) {
628
	global $config;
629

    
630
	$iflist = array();
631

    
632
	/* if list */
633
	foreach($config['interfaces'] as $if => $ifdetail) {
634
		if ($only_opt && ($if == "wan" || $if == "lan"))
635
			continue;
636
		if (isset($ifdetail['enable']) || $withdisabled == true) {
637
			if(empty($ifdetail['descr']))
638
				$iflist[$if] = strtoupper($if);
639
			else
640
				$iflist[$if] = strtoupper($ifdetail['descr']);
641
		}
642
	}
643

    
644
	return $iflist;
645
}
646

    
647
/*
648
 *   get_configured_ip_addresses() - Return a list of all configured
649
 *   interfaces IP Addresses
650
 *
651
 */
652
function get_configured_ip_addresses() {
653
	require_once("interfaces.inc");
654
	$ip_array = array();
655
	$interfaces = get_configured_interface_list();
656
	if(is_array($interfaces)) {
657
		foreach($interfaces as $int) {
658
			$ipaddr = get_interface_ip($int);
659
			$ip_array[$int] = $ipaddr;
660
		}
661
	}
662
	$interfaces = get_configured_carp_interface_list();
663
	if(is_array($interfaces)) 
664
		foreach($interfaces as $int => $ipaddr) 
665
			$ip_array[$int] = $ipaddr;
666
	return $ip_array;
667
}
668

    
669
/*
670
 *   get_interface_list() - Return a list of all physical interfaces
671
 *   along with MAC and status.
672
 *
673
 *   $mode = "active" - use ifconfig -lu
674
 *           "media"  - use ifconfig to check physical connection
675
 *			status (much slower)
676
 */
677
function get_interface_list($mode = "active", $keyby = "physical", $vfaces = "") {
678
        global $config;
679
	$upints = array();
680
        /* get a list of virtual interface types */
681
        if(!$vfaces) {
682
		$vfaces = array (
683
				'bridge',
684
				'ppp',
685
				'pppoe',
686
				'pptp',
687
				'l2tp',
688
				'sl',
689
				'gif',
690
				'gre',
691
				'faith',
692
				'lo',
693
				'ng',
694
				'_vlan',
695
				'_wlan',
696
				'pflog',
697
				'plip',
698
				'pfsync',
699
				'enc',
700
				'tun',
701
				'carp',
702
				'lagg',
703
				'vip',
704
				'ipfw'
705
		);
706
	}
707
	switch($mode) {
708
	case "active":
709
                $upints = explode(" ", trim(shell_exec("/sbin/ifconfig -lu")));
710
        	break;
711
	case "media":
712
                $intlist = explode(" ", trim(shell_exec("/sbin/ifconfig -l")));
713
                $ifconfig = "";
714
                exec("/sbin/ifconfig -a", $ifconfig);
715
                $regexp = '/(' . implode('|', $intlist) . '):\s/';
716
                $ifstatus = preg_grep('/status:/', $ifconfig);
717
		foreach($ifstatus as $status) {
718
			$int = array_shift($intlist);
719
			if(stristr($status, "active")) $upints[] = $int;
720
		}
721
		break;
722
	default:
723
		$upints = explode(" ", trim(shell_exec("/sbin/ifconfig -l")));
724
		break;
725
	}
726
        /* build interface list with netstat */
727
        $linkinfo = "";
728
        exec("/usr/bin/netstat -inW -f link | awk '{ print $1, $4 }'", $linkinfo);
729
        array_shift($linkinfo);
730
	/* build ip address list with netstat */
731
	$ipinfo = "";
732
	exec("/usr/bin/netstat -inW -f inet | awk '{ print $1, $4 }'", $ipinfo);
733
	array_shift($ipinfo);
734
	foreach($linkinfo as $link) {
735
		$friendly = "";
736
		$alink = explode(" ", $link);
737
		$ifname = rtrim(trim($alink[0]), '*');
738
		/* trim out all numbers before checking for vfaces */
739
		if (!in_array(array_shift(preg_split('/\d/', $ifname)), $vfaces) &&
740
			!stristr($ifname, "_vlan") && !stristr($ifname, "_wlan")) {
741
			$toput = array(
742
					"mac" => trim($alink[1]),
743
					"up" => in_array($ifname, $upints)
744
				);
745
			foreach($ipinfo as $ip) {
746
				$aip = explode(" ", $ip);
747
				if($aip[0] == $ifname) {
748
					$toput['ipaddr'] = $aip[1];
749
				}
750
			}
751
			if (is_array($config['interfaces'])) {
752
				foreach($config['interfaces'] as $name => $int)
753
					if($int['if'] == $ifname) $friendly = $name;
754
			}
755
			switch($keyby) {
756
			case "physical":
757
				if($friendly != "") {
758
					$toput['friendly'] = $friendly;
759
				}
760
				$dmesg_arr = array();
761
				exec("/sbin/dmesg |grep $ifname | head -n1", $dmesg_arr);
762
				preg_match_all("/<(.*?)>/i", $dmesg_arr[0], $dmesg);
763
				$toput['dmesg'] = $dmesg[1][0];
764
				$iflist[$ifname] = $toput;
765
				break;
766
			case "ppp":
767
				
768
			case "friendly":
769
				if($friendly != "") {
770
					$toput['if'] = $ifname;
771
					$iflist[$friendly] = $toput;
772
				}
773
				break;
774
			}
775
		}
776
	}
777
	return $iflist;
778
}
779

    
780
/****f* util/log_error
781
* NAME
782
*   log_error  - Sends a string to syslog.
783
* INPUTS
784
*   $error     - string containing the syslog message.
785
* RESULT
786
*   null
787
******/
788
function log_error($error) {
789
	global $g;
790
	$page = $_SERVER['SCRIPT_NAME'];
791
	syslog(LOG_WARNING, "$page: $error");
792
	if ($g['debug'])
793
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
794
	return;
795
}
796

    
797
/****f* util/log_auth
798
* NAME
799
*   log_error  - Sends a string to syslog as LOG_AUTH facility
800
* INPUTS
801
*   $error     - string containing the syslog message.
802
* RESULT
803
*   null
804
******/
805
function log_auth($error) {
806
	global $g;
807
	$page = $_SERVER['SCRIPT_NAME'];
808
	syslog(LOG_AUTH, "$page: $error");
809
	if ($g['debug'])
810
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
811
	return;
812
}
813

    
814
/****f* util/exec_command
815
 * NAME
816
 *   exec_command - Execute a command and return a string of the result.
817
 * INPUTS
818
 *   $command   - String of the command to be executed.
819
 * RESULT
820
 *   String containing the command's result.
821
 * NOTES
822
 *   This function returns the command's stdout and stderr.
823
 ******/
824
function exec_command($command) {
825
	$output = array();
826
	exec($command . ' 2>&1 ', $output);
827
	return(implode("\n", $output));
828
}
829

    
830
/* wrapper for exec() */
831
function mwexec($command, $mute = false) {
832
	global $g;
833

    
834
	if ($g['debug']) {
835
		if (!$_SERVER['REMOTE_ADDR'])
836
			echo "mwexec(): $command\n";
837
	}
838
	$oarr = array();
839
	$retval = 0;
840
	$garbage = exec("$command 2>&1", $oarr, $retval);
841

    
842
	if(isset($config['system']['developerspew']))
843
		$mute = false;
844
	if(($retval <> 0) && ($mute === false)) {
845
		$output = implode(" ", $oarr);
846
		log_error("The command '$command' returned exit code '$retval', the output was '$output' ");
847
	}
848
	return $retval;
849
}
850

    
851
/* wrapper for exec() in background */
852
function mwexec_bg($command) {
853
	global $g;
854

    
855
	if ($g['debug']) {
856
		if (!$_SERVER['REMOTE_ADDR'])
857
			echo "mwexec(): $command\n";
858
	}
859

    
860
	exec("nohup $command > /dev/null 2>&1 &");
861
}
862

    
863
/* unlink a file, if it exists */
864
function unlink_if_exists($fn) {
865
	$to_do = glob($fn);
866
	if(is_array($to_do)) {
867
		foreach($to_do as $filename)
868
			@unlink($filename);
869
	} else {
870
		@unlink($fn);
871
	}
872
}
873
/* make a global alias table (for faster lookups) */
874
function alias_make_table($config) {
875
	global $aliastable;
876

    
877
	$aliastable = array();
878

    
879
	if (is_array($config['aliases']['alias'])) {
880
		foreach ($config['aliases']['alias'] as $alias) {
881
			if ($alias['name'])
882
				$aliastable[$alias['name']] = $alias['address'];
883
		}
884
	}
885
}
886

    
887
/* check if an alias exists */
888
function is_alias($name) {
889
	global $aliastable;
890

    
891
	return isset($aliastable[$name]);
892
}
893

    
894
function alias_get_type($name) {
895
        global $config;
896
        
897
	if (is_array($config['aliases']['alias'])) {
898
		foreach ($config['aliases']['alias'] as $alias) {
899
			if ($name == $alias['name'])
900
				return $alias['type'];
901
		}
902
	}
903

    
904
        return "";
905
}
906

    
907
/* expand a host or network alias, if necessary */
908
function alias_expand($name) {
909
	global $aliastable;
910

    
911
	if (isset($aliastable[$name]))
912
		return "\${$name}";
913
	else if (is_ipaddr($name) || is_subnet($name) || is_port($name))
914
		return "{$name}";
915
	else
916
		return null;
917
}
918

    
919
function alias_expand_urltable($name) {
920
	global $config;
921
	$urltable_prefix = "/var/db/aliastables/";
922
	$urltable_filename = $urltable_prefix . $name . ".txt";
923

    
924
	if (is_array($config['aliases']['alias'])) {
925
		foreach ($config['aliases']['alias'] as $alias) {
926
			if (($alias['type'] == 'urltable') && ($alias['name'] == $name)) {
927
				if (is_URL($alias["url"]) && file_exists($urltable_filename) && filesize($urltable_filename))
928
					return $urltable_filename;
929
				else if (process_alias_urltable($name, $alias["url"], 0, true))
930
					return $urltable_filename;
931
			}
932
		}
933
	}
934
	return null;
935
}
936

    
937
/* find out whether two subnets overlap */
938
function check_subnets_overlap($subnet1, $bits1, $subnet2, $bits2) {
939

    
940
	if (!is_numeric($bits1))
941
		$bits1 = 32;
942
	if (!is_numeric($bits2))
943
		$bits2 = 32;
944

    
945
	if ($bits1 < $bits2)
946
		$relbits = $bits1;
947
	else
948
		$relbits = $bits2;
949

    
950
	$sn1 = gen_subnet_mask_long($relbits) & ip2long($subnet1);
951
	$sn2 = gen_subnet_mask_long($relbits) & ip2long($subnet2);
952

    
953
	if ($sn1 == $sn2)
954
		return true;
955
	else
956
		return false;
957
}
958

    
959
/* compare two IP addresses */
960
function ipcmp($a, $b) {
961
	if (ip_less_than($a, $b))
962
		return -1;
963
	else if (ip_greater_than($a, $b))
964
		return 1;
965
	else
966
		return 0;
967
}
968

    
969
/* return true if $addr is in $subnet, false if not */
970
function ip_in_subnet($addr,$subnet) {
971
	list($ip, $mask) = explode('/', $subnet);
972
	$mask = (0xffffffff << (32 - $mask)) & 0xffffffff;
973
	return ((ip2long($addr) & $mask) == (ip2long($ip) & $mask));
974
}
975

    
976
/* verify (and remove) the digital signature on a file - returns 0 if OK */
977
function verify_digital_signature($fname) {
978
	global $g;
979

    
980
	if(!file_exists("/usr/local/sbin/gzsig"))
981
		return 4;
982

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

    
986
/* obtain MAC address given an IP address by looking at the ARP table */
987
function arp_get_mac_by_ip($ip) {
988
	mwexec("/sbin/ping -c 1 -t 1 {$ip}", true);
989
	$arpoutput = "";
990
	exec("/usr/sbin/arp -n {$ip}", $arpoutput);
991

    
992
	if ($arpoutput[0]) {
993
		$arpi = explode(" ", $arpoutput[0]);
994
		$macaddr = $arpi[3];
995
		if (is_macaddr($macaddr))
996
			return $macaddr;
997
		else
998
			return false;
999
	}
1000

    
1001
	return false;
1002
}
1003

    
1004
/* return a fieldname that is safe for xml usage */
1005
function xml_safe_fieldname($fieldname) {
1006
	$replace = array('/', '-', ' ', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
1007
			 '_', '+', '=', '{', '}', '[', ']', '|', '/', '<', '>', '?',
1008
			 ':', ',', '.', '\'', '\\'
1009
		);
1010
	return strtolower(str_replace($replace, "", $fieldname));
1011
}
1012

    
1013
function mac_format($clientmac) {
1014
    $mac =explode(":", $clientmac);
1015

    
1016
    global $config;
1017

    
1018
    $mac_format = $config['captiveportal']['radmac_format'] ? $config['captiveportal']['radmac_format'] : false;
1019

    
1020
    switch($mac_format) {
1021

    
1022
        case 'singledash':
1023
        return "$mac[0]$mac[1]$mac[2]-$mac[3]$mac[4]$mac[5]";
1024

    
1025
        case 'ietf':
1026
        return "$mac[0]-$mac[1]-$mac[2]-$mac[3]-$mac[4]-$mac[5]";
1027

    
1028
        case 'cisco':
1029
        return "$mac[0]$mac[1].$mac[2]$mac[3].$mac[4]$mac[5]";
1030

    
1031
        case 'unformatted':
1032
        return "$mac[0]$mac[1]$mac[2]$mac[3]$mac[4]$mac[5]";
1033

    
1034
        default:
1035
        return $clientmac;
1036
    }
1037
}
1038

    
1039
function resolve_retry($hostname, $retries = 5) {
1040

    
1041
	if (is_ipaddr($hostname))
1042
		return $hostname;
1043

    
1044
	for ($i = 0; $i < $retries; $i++) {
1045
		$ip = gethostbyname($hostname);
1046

    
1047
		if ($ip && $ip != $hostname) {
1048
			/* success */
1049
			return $ip;
1050
		}
1051

    
1052
		sleep(1);
1053
	}
1054

    
1055
	return false;
1056
}
1057

    
1058
function format_bytes($bytes) {
1059
	if ($bytes >= 1073741824) {
1060
		return sprintf("%.2f GB", $bytes/1073741824);
1061
	} else if ($bytes >= 1048576) {
1062
		return sprintf("%.2f MB", $bytes/1048576);
1063
	} else if ($bytes >= 1024) {
1064
		return sprintf("%.0f KB", $bytes/1024);
1065
	} else {
1066
		return sprintf("%d bytes", $bytes);
1067
	}
1068
}
1069

    
1070
function update_filter_reload_status($text) {
1071
	global $g;
1072

    
1073
	file_put_contents("{$g['varrun_path']}/filter_reload_status", $text);
1074
}
1075

    
1076
/****f* util/return_dir_as_array
1077
 * NAME
1078
 *   return_dir_as_array - Return a directory's contents as an array.
1079
 * INPUTS
1080
 *   $dir       - string containing the path to the desired directory.
1081
 * RESULT
1082
 *   $dir_array - array containing the directory's contents. This array will be empty if the path specified is invalid.
1083
 ******/
1084
function return_dir_as_array($dir) {
1085
	$dir_array = array();
1086
	if (is_dir($dir)) {
1087
		if ($dh = opendir($dir)) {
1088
			while (($file = readdir($dh)) !== false) {
1089
				$canadd = 0;
1090
				if($file == ".") $canadd = 1;
1091
				if($file == "..") $canadd = 1;
1092
				if($canadd == 0)
1093
					array_push($dir_array, $file);
1094
			}
1095
			closedir($dh);
1096
		}
1097
	}
1098
	return $dir_array;
1099
}
1100

    
1101
function run_plugins($directory) {
1102
	global $config, $g;
1103

    
1104
	/* process packager manager custom rules */
1105
	$files = return_dir_as_array($directory);
1106
	if (is_array($files)) {
1107
		foreach ($files as $file) {
1108
			if (stristr($file, ".sh") == true)
1109
				mwexec($directory . $file . " start");
1110
			else if (!is_dir($directory . "/" . $file) && stristr($file,".inc")) 
1111
				require_once($directory . "/" . $file);
1112
		}
1113
	}
1114
}
1115

    
1116
/*
1117
 *    safe_mkdir($path, $mode = 0755)
1118
 *    create directory if it doesn't already exist and isn't a file!
1119
 */
1120
function safe_mkdir($path, $mode=0755) {
1121
	global $g;
1122

    
1123
	if (!is_file($path) && !is_dir($path)) {
1124
		return @mkdir($path, $mode, true);
1125
	} else {
1126
		return false;
1127
	}
1128
}
1129

    
1130
/*
1131
 * make_dirs($path, $mode = 0755)
1132
 * create directory tree recursively (mkdir -p)
1133
 */
1134
function make_dirs($path, $mode = 0755) {
1135
	$base = '';
1136
	foreach (explode('/', $path) as $dir) {
1137
		$base .= "/$dir";
1138
		if (!is_dir($base)) {
1139
			if (!@mkdir($base, $mode))
1140
				return false;
1141
		}
1142
	}
1143
	return true;
1144
}
1145

    
1146
/*
1147
 * get_sysctl($names)
1148
 * Get values of sysctl OID's listed in $names (accepts an array or a single
1149
 * name) and return an array of key/value pairs set for those that exist
1150
 */
1151
function get_sysctl($names) {
1152
	if (empty($names))
1153
		return array();
1154

    
1155
	if (is_array($names)) {
1156
		$name_list = array();
1157
		foreach ($names as $name) {
1158
			$name_list[] = escapeshellarg($name);
1159
		}
1160
	} else
1161
		$name_list = array(escapeshellarg($names));
1162

    
1163
	exec("/sbin/sysctl -i " . implode(" ", $name_list), $output);
1164
	$values = array();
1165
	foreach ($output as $line) {
1166
		$line = explode(": ", $line, 2);
1167
		if (count($line) == 2)
1168
			$values[$line[0]] = $line[1];
1169
	}
1170

    
1171
	return $values;
1172
}
1173

    
1174
/*
1175
 * set_sysctl($value_list)
1176
 * Set sysctl OID's listed as key/value pairs and return
1177
 * an array with keys set for those that succeeded
1178
 */
1179
function set_sysctl($values) {
1180
	if (empty($values))
1181
		return array();
1182

    
1183
	$value_list = array();
1184
	foreach ($values as $key => $value) {
1185
		$value_list[] = escapeshellarg($key) . "=" . escapeshellarg($value);
1186
	}
1187

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

    
1190
	/* Retry individually if failed (one or more read-only) */
1191
	if ($success <> 0 && count($value_list) > 1) {
1192
		foreach ($value_list as $value) {
1193
			exec("/sbin/sysctl -i " . $value, $output);
1194
		}
1195
	}
1196

    
1197
	$ret = array();
1198
	foreach ($output as $line) {
1199
		$line = explode(": ", $line, 2);
1200
		if (count($line) == 2)
1201
			$ret[$line[0]] = true;
1202
	}
1203

    
1204
	return $ret;
1205
}
1206

    
1207
/*
1208
 *     get_memory()
1209
 *     returns an array listing the amount of
1210
 *     memory installed in the hardware
1211
 *     [0]real and [1]available
1212
 */
1213
function get_memory() {
1214
	$matches = "";
1215
	if(file_exists("/var/log/dmesg.boot"))
1216
		$mem = `cat /var/log/dmesg.boot | grep memory`;
1217
	else
1218
		$mem = `dmesg -a | grep memory`;			
1219
	if (preg_match_all("/avail memory.* \((.*)MB\)/", $mem, $matches)) 
1220
		return array($matches[1][0], $matches[1][0]);
1221
	if(!$real && !$avail) {
1222
		$real = trim(`sysctl hw.physmem | cut -d' ' -f2`);
1223
		$avail = trim(`sysctl hw.realmem | cut -d' ' -f2`);
1224
		/* convert from bytes to megabytes */
1225
		return array(($real/1048576),($avail/1048576));
1226
	}
1227
}
1228

    
1229
function mute_kernel_msgs() {
1230
	global $config;
1231
	// Do not mute serial console.  The kernel gets very very cranky
1232
	// and will start dishing you cannot control tty errors.
1233
	if(trim(file_get_contents("/etc/platform")) == "nanobsd") 
1234
		return;
1235
	if($config['system']['enableserial']) 
1236
		return;			
1237
	exec("/sbin/conscontrol mute on");
1238
}
1239

    
1240
function unmute_kernel_msgs() {
1241
	global $config;
1242
	// Do not mute serial console.  The kernel gets very very cranky
1243
	// and will start dishing you cannot control tty errors.
1244
	if(trim(file_get_contents("/etc/platform")) == "nanobsd") 
1245
		return;
1246
	exec("/sbin/conscontrol mute off");
1247
}
1248

    
1249
function start_devd() {
1250
	global $g;
1251

    
1252
	exec("/sbin/devd");
1253
	sleep(1);
1254
}
1255

    
1256
function is_interface_vlan_mismatch() {
1257
	global $config, $g;
1258

    
1259
	if (is_array($config['vlans']['vlan'])) {
1260
		foreach ($config['vlans']['vlan'] as $vlan) {
1261
			if (does_interface_exist($vlan['if']) == false)
1262
				return true;
1263
		}
1264
	}
1265

    
1266
	return false;
1267
}
1268

    
1269
function is_interface_mismatch() {
1270
	global $config, $g;
1271

    
1272
	$do_assign = false;
1273
	$i = 0;
1274
	if (is_array($config['interfaces'])) {
1275
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
1276
			if (preg_match("/^enc|^cua|^tun|^l2tp|^pptp|^ppp|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_wlan/i", $ifcfg['if'])) {
1277
				// Do not check these interfaces.
1278
				$i++;
1279
				continue;
1280
			}
1281
			else if (does_interface_exist($ifcfg['if']) == false) {
1282
				$do_assign = true;
1283
			} else
1284
				$i++;
1285
		}
1286
	}
1287

    
1288
	if ($g['minimum_nic_count'] > $i) {
1289
		$do_assign = true;
1290
	} else if (file_exists("{$g['tmp_path']}/assign_complete"))
1291
	$do_assign = false;
1292

    
1293
	return $do_assign;
1294
}
1295

    
1296
/* sync carp entries to other firewalls */
1297
function carp_sync_client() {
1298
	global $g;
1299
	send_event("filter sync");
1300
}
1301

    
1302
/****f* util/isAjax
1303
 * NAME
1304
 *   isAjax - reports if the request is driven from prototype
1305
 * INPUTS
1306
 *   none
1307
 * RESULT
1308
 *   true/false
1309
 ******/
1310
function isAjax() {
1311
	return isset ($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest';
1312
}
1313

    
1314
/****f* util/timeout
1315
 * NAME
1316
 *   timeout - console input with timeout countdown. Note: erases 2 char of screen for timer. Leave space.
1317
 * INPUTS
1318
 *   optional, seconds to wait before timeout. Default 9 seconds.
1319
 * RESULT
1320
 *   returns 1 char of user input or null if no input.
1321
 ******/
1322
function timeout($timer = 9) {
1323
	while(!isset($key)) {
1324
		if ($timer >= 9) { echo chr(8) . chr(8) . ($timer==9 ? chr(32) : null)  . "{$timer}";  }
1325
		else { echo chr(8). "{$timer}"; }
1326
		`/bin/stty -icanon min 0 time 25`;
1327
		$key = trim(`KEY=\`dd count=1 2>/dev/null\`; echo \$KEY`);
1328
		`/bin/stty icanon`;
1329
		if ($key == '')
1330
			unset($key);
1331
		$timer--;
1332
		if ($timer == 0)
1333
			break;
1334
	}
1335
	return $key;	
1336
}
1337

    
1338
/****f* util/msort
1339
 * NAME
1340
 *   msort - sort array
1341
 * INPUTS
1342
 *   $array to be sorted, field to sort by, direction of sort
1343
 * RESULT
1344
 *   returns newly sorted array
1345
 ******/
1346
function msort($array, $id="id", $sort_ascending=true) {
1347
	$temp_array = array();
1348
	while(count($array)>0) {
1349
		$lowest_id = 0;
1350
		$index=0;
1351
		foreach ($array as $item) {
1352
			if (isset($item[$id])) {
1353
				if ($array[$lowest_id][$id]) {
1354
					if (strtolower($item[$id]) < strtolower($array[$lowest_id][$id])) {
1355
						$lowest_id = $index;
1356
					}
1357
				}
1358
			}
1359
			$index++;
1360
		}
1361
		$temp_array[] = $array[$lowest_id];
1362
		$array = array_merge(array_slice($array, 0,$lowest_id), array_slice($array, $lowest_id+1));
1363
	}
1364
	if ($sort_ascending) {
1365
		return $temp_array;
1366
	} else {
1367
    	return array_reverse($temp_array);
1368
	}
1369
}
1370

    
1371
/****f* util/color
1372
 * NAME
1373
 *   color - outputs a color code to the ansi terminal if supported
1374
 * INPUTS
1375
 *   color code or color name
1376
 * RESULT
1377
 *   Outputs the ansi color sequence for the color specified.  Default resets terminal.
1378
 ******/
1379
function color($color = "0m") {
1380
	/*
1381
		Color codes available:
1382
		 0m reset; clears all colors and styles (to white on black)
1383
		 1m bold on (see below)
1384
		 3m italics on
1385
		 4m underline on
1386
		 7m inverse on; reverses foreground & background colors
1387
		 9m strikethrough on
1388
		 22m bold off (see below)
1389
		 23m italics off
1390
		 24m underline off
1391
		 27m inverse off
1392
		 29m strikethrough off
1393
		 30m set foreground color to black
1394
		 31m set foreground color to red
1395
		 32m set foreground color to green
1396
		 33m set foreground color to yellow
1397
		 34m set foreground color to blue
1398
		 35m set foreground color to magenta (purple)
1399
		 36m set foreground color to cyan
1400
		 37m set foreground color to white
1401
		 40m  set background color to black
1402
		 41m set background color to red
1403
		 42m set background color to green
1404
		 43m set background color to yellow
1405
		 44m set background color to blue
1406
		 45m set background color to magenta (purple)
1407
		 46m set background color to cyan
1408
		 47m set background color to white
1409
		 49m set background color to default (black)
1410
	*/	
1411
	// Allow caching of TERM to 
1412
	// speedup subequence requests.
1413
	global $TERM;
1414
	if(!$TERM) 
1415
		$TERM=`/usr/bin/env | grep color`;
1416
	if(!$TERM)
1417
		$TERM=`/usr/bin/env | grep cons25`;
1418
	if($TERM) {
1419
		$ESCAPE=chr(27);
1420
		switch ($color) {
1421
			case "black":
1422
				return "{$ESCAPE}[30m"; 
1423
			case "red":
1424
				return "{$ESCAPE}[31m"; 
1425
			case "green":
1426
				return "{$ESCAPE}[32m"; 
1427
			case "yellow":
1428
				return "{$ESCAPE}[33m"; 
1429
			case "blue":
1430
				return "{$ESCAPE}[34m"; 
1431
			case "magenta":
1432
				return "{$ESCAPE}[35m"; 
1433
			case "cyan":
1434
				return "{$ESCAPE}[36m"; 
1435
			case "white":
1436
				return "{$ESCAPE}[37m"; 
1437
			case "default":
1438
				return "{$ESCAPE}[39m"; 
1439
		}
1440
		return "{$ESCAPE}[{$color}";
1441
	}
1442
}
1443

    
1444
/****f* util/is_URL
1445
 * NAME
1446
 *   is_URL
1447
 * INPUTS
1448
 *   string to check
1449
 * RESULT
1450
 *   Returns true if item is a URL
1451
 ******/
1452
function is_URL($url) {
1453
	$match = preg_match("'\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))'", $url);
1454
	if($match)
1455
		return true;	
1456
	return false;
1457
}
1458

    
1459
function is_file_included($file = "") {
1460
	$files = get_included_files();
1461
	if (in_array($file, $files))
1462
		return true;
1463
	
1464
	return false;
1465
}
1466

    
1467
/*
1468
	This function was borrowed from a comment on PHP.net at the following URL:
1469
	http://www.php.net/manual/en/function.array-merge-recursive.php#73843
1470
 */
1471
function array_merge_recursive_unique($array0, $array1) {
1472

    
1473
	$arrays = func_get_args();
1474
	$remains = $arrays;
1475

    
1476
	// We walk through each arrays and put value in the results (without
1477
	// considering previous value).
1478
	$result = array();
1479

    
1480
	// loop available array
1481
	foreach($arrays as $array) {
1482

    
1483
		// The first remaining array is $array. We are processing it. So
1484
		// we remove it from remaing arrays.
1485
        array_shift($remains);
1486

    
1487
		// We don't care non array param, like array_merge since PHP 5.0.
1488
		if(is_array($array)) {
1489
			// Loop values
1490
			foreach($array as $key => $value) {
1491
				if(is_array($value)) {
1492
					// we gather all remaining arrays that have such key available
1493
					$args = array();
1494
					foreach($remains as $remain) {
1495
						if(array_key_exists($key, $remain)) {
1496
							array_push($args, $remain[$key]);
1497
						}
1498
					}
1499

    
1500
					if(count($args) > 2) {
1501
						// put the recursion
1502
						$result[$key] = call_user_func_array(__FUNCTION__, $args);
1503
					} else {
1504
						foreach($value as $vkey => $vval) {
1505
							$result[$key][$vkey] = $vval;
1506
						}
1507
					}
1508
				} else {
1509
					// simply put the value
1510
					$result[$key] = $value;
1511
				}
1512
			}
1513
		}
1514
	}
1515
	return $result;
1516
}
1517

    
1518
?>
(49-49/61)