Project

General

Profile

Download (40.2 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(sprintf(gettext("WARNING: Could not mark subsystem: %s dirty"), $subsystem));
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(gettext("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
	try {
189
		$shmid = @shmop_open($reference, "w", 0644, 10);
190
		if (!$shmid) {
191
			refcount_init($reference);
192
			$shmid = @shmop_open($reference, "w", 0, 0);
193
		}
194
		$shm_data = @shmop_read($shmid, 0, 10);
195
		$shm_data = intval($shm_data) + 1;
196
		@shmop_write($shmid, $shm_data, 0);
197
		@shmop_close($shmid);
198
	} catch (Exception $e) {
199
		log_error($e->getMessage());
200
	}
201

    
202
	return $shm_data;
203
}
204

    
205
function refcount_unreference($reference) {
206
	try {
207
		/* We assume that the shared memory exists. */
208
		$shmid = @shmop_open($reference, "w", 0, 0);
209
		$shm_data = @shmop_read($shmid, 0, 10);
210
		$shm_data = intval($shm_data) - 1;
211
		if ($shm_data < 0) {
212
			//debug_backtrace();
213
			log_error(sprintf(gettext("Reference %s is going negative, not doing unreference."), $reference));
214
		} else
215
			@shmop_write($shmid, $shm_data, 0);
216
		@shmop_close($shmid);
217
	} catch (Exception $e) {
218
		log_error($e->getMessage());
219
	}
220

    
221
	return $shm_data;
222
}
223

    
224
function is_module_loaded($module_name) {
225
	$running = `/sbin/kldstat | grep {$module_name} | /usr/bin/grep -v grep | /usr/bin/wc -l`;
226
	if (intval($running) >= 1)
227
		return true;
228
	else
229
		return false;
230
}
231

    
232
/* return the subnet address given a host address and a subnet bit count */
233
function gen_subnet($ipaddr, $bits) {
234
	if (!is_ipaddr($ipaddr) || !is_numeric($bits))
235
		return "";
236
	return long2ip(ip2long($ipaddr) & gen_subnet_mask_long($bits));
237
}
238

    
239
/* return the subnet address given a host address and a subnet bit count */
240
function gen_subnetv6($ipaddr, $bits) {
241
	if (!is_ipaddrv6($ipaddr) || !is_numeric($bits))
242
		return "";
243

    
244
	$address = Net_IPv6::getNetmask($ipaddr, $bits);
245
	return $address;
246
}
247

    
248
/* return the highest (broadcast) address in the subnet given a host address and a subnet bit count */
249
function gen_subnet_max($ipaddr, $bits) {
250
	if (!is_ipaddr($ipaddr) || !is_numeric($bits))
251
		return "";
252

    
253
	return long2ip32(ip2long($ipaddr) | ~gen_subnet_mask_long($bits));
254
}
255

    
256
/* Generate end number for a given ipv6 subnet mask
257
 * no, it does not perform math */
258
function gen_subnetv6_max($ipaddr, $bits) {
259
	if(!is_ipaddrv6($ipaddr))
260
		return false;
261
	
262
	$subnetstart = gen_subnetv6($ipaddr, $bits);
263
	/* we should have a expanded full ipv6 subnet starting at 0.
264
	 * Now split those by the semicolon so we can do 16 bit math */
265
	$parts = explode(":", $subnetstart);
266
	if(count($parts) <> 8)
267
		return false;
268

    
269
	/* reverse the array, we start with the lsb */
270
	$parts = array_reverse($parts);
271
	/* set the itteration count properly */
272
	$bitsleft = 128 - $bits;
273
	$i = 0;
274
	foreach($parts as $part) {
275
		/* foreach 16 bits we go to the next part */
276
		/* no this isn't proper hex math, neither does it overflow properly */
277
		while($bitsleft > 0) {
278
			if($part == "0") {
279
				$part = "f";
280
			} else {
281
				$part = $part . "f";
282
			}
283
			$bitsleft = $bitsleft - 4;
284
			$j++;
285
			if($j == 4) {
286
				$parts[$i] = $part;
287
				$j = 0;
288
				$i++;
289
				continue 2;
290
			}
291
		}
292
		$i++;
293
	}
294
	$parts = array_reverse($parts);
295
	$subnet_end = implode(":", $parts);
296
	return $subnet_end;
297
}
298

    
299
/* returns a subnet mask (long given a bit count) */
300
function gen_subnet_mask_long($bits) {
301
	$sm = 0;
302
	for ($i = 0; $i < $bits; $i++) {
303
		$sm >>= 1;
304
		$sm |= 0x80000000;
305
	}
306
	return $sm;
307
}
308

    
309
/* same as above but returns a string */
310
function gen_subnet_mask($bits) {
311
	return long2ip(gen_subnet_mask_long($bits));
312
}
313

    
314
/* Convert long int to IP address, truncating to 32-bits. */
315
function long2ip32($ip) {
316
	return long2ip($ip & 0xFFFFFFFF);
317
}
318

    
319
/* Convert IP address to long int, truncated to 32-bits to avoid sign extension on 64-bit platforms. */
320
function ip2long32($ip) {
321
	return ( ip2long($ip) & 0xFFFFFFFF );
322
}
323

    
324
/* Convert IP address to unsigned long int. */
325
function ip2ulong($ip) {
326
	return sprintf("%u", ip2long32($ip));
327
}
328

    
329
/* Find out how many IPs are contained within a given IP range
330
 *  e.g. 192.168.0.0 to 192.168.0.255 returns 256
331
 */
332
function ip_range_size($startip, $endip) {
333
	if (is_ipaddr($startip) && is_ipaddr($endip)) {
334
		// Operate as unsigned long because otherwise it wouldn't work
335
		//   when crossing over from 127.255.255.255 / 128.0.0.0 barrier
336
		return abs(ip2ulong($startip) - ip2ulong($endip)) + 1;
337
	}
338
	return -1;
339
}
340

    
341
/* Find the smallest possible subnet mask which can contain a given number of IPs
342
 *  e.g. 512 IPs can fit in a /23, but 513 IPs need a /22
343
 */
344
function find_smallest_cidr($number) {
345
	$smallest = 1;
346
	for ($b=32; $b > 0; $b--) {
347
		$smallest = ($number <= pow(2,$b)) ? $b : $smallest;
348
	}
349
	return (32-$smallest);
350
}
351

    
352
/* Return the previous IP address before the given address */
353
function ip_before($ip) {
354
	return long2ip32(ip2long($ip)-1);
355
}
356

    
357
/* Return the next IP address after the given address */
358
function ip_after($ip) {
359
	return long2ip32(ip2long($ip)+1);
360
}
361

    
362
/* Return true if the first IP is 'before' the second */
363
function ip_less_than($ip1, $ip2) {
364
	// Compare as unsigned long because otherwise it wouldn't work when
365
	//   crossing over from 127.255.255.255 / 128.0.0.0 barrier
366
	return ip2ulong($ip1) < ip2ulong($ip2);
367
}
368

    
369
/* Return true if the first IP is 'after' the second */
370
function ip_greater_than($ip1, $ip2) {
371
	// Compare as unsigned long because otherwise it wouldn't work
372
	//   when crossing over from 127.255.255.255 / 128.0.0.0 barrier
373
	return ip2ulong($ip1) > ip2ulong($ip2);
374
}
375

    
376
/* Convert a range of IPs to an array of subnets which can contain the range. */
377
function ip_range_to_subnet_array($startip, $endip) {
378
	if (!is_ipaddr($startip) || !is_ipaddr($endip)) {
379
		return array();
380
	}
381

    
382
	// Container for subnets within this range.
383
	$rangesubnets = array();
384

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

    
388
	// Loop here to reduce subnet size and retest as needed. We need to make sure
389
	//   that the target subnet is wholly contained between $startip and $endip.
390
	for ($cidr; $cidr <= 32; $cidr++) {
391
		// Find the network and broadcast addresses for the subnet being tested.
392
		$targetsub_min = gen_subnet($startip, $cidr);
393
		$targetsub_max = gen_subnet_max($startip, $cidr);
394

    
395
		// Check best case where the range is exactly one subnet.
396
		if (($targetsub_min == $startip) && ($targetsub_max == $endip)) {
397
			// Hooray, the range is exactly this subnet!
398
			return array("{$startip}/{$cidr}");
399
		}
400

    
401
		// These remaining scenarios will find a subnet that uses the largest
402
		//  chunk possible of the range being tested, and leave the rest to be
403
		//  tested recursively after the loop.
404

    
405
		// Check if the subnet begins with $startip and ends before $endip
406
		if (($targetsub_min == $startip) && ip_less_than($targetsub_max, $endip)) {
407
			break;
408
		}
409

    
410
		// Check if the subnet ends at $endip and starts after $startip
411
		if (ip_greater_than($targetsub_min, $startip) && ($targetsub_max == $endip)) {
412
			break;
413
		}
414

    
415
		// Check if the subnet is between $startip and $endip
416
		if (ip_greater_than($targetsub_min, $startip) && ip_less_than($targetsub_max, $endip)) {
417
			break;
418
		}
419
	}
420

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

    
427
	// Add in the subnet we found before, to preserve ordering
428
	$rangesubnets[] = "{$targetsub_min}/{$cidr}";
429

    
430
	// And some more logic that will search after the subnet we found to fill in to the end of the range.
431
	if ($endip != $targetsub_max) {
432
		$rangesubnets = array_merge($rangesubnets, ip_range_to_subnet_array(ip_after($targetsub_max), $endip));
433
	}
434
	return $rangesubnets;
435
}
436

    
437
function is_iprange($range) {
438
	if (substr_count($range, '-') != 1) {
439
		return false;
440
	}
441
	list($ip1, $ip2) = explode ('-', $range);
442
	return (is_ipaddr($ip1) && is_ipaddr($ip2));
443
}
444

    
445
function is_numericint($arg) {
446
	return (preg_match("/[^0-9]/", $arg) ? false : true);
447
}
448

    
449

    
450
/* returns true if $ipaddr is a valid dotted IPv4 address or a IPv6 */
451
function is_ipaddr($ipaddr) {
452
	if(is_ipaddrv4($ipaddr)) {
453
		return true;
454
	}
455
	if(is_ipaddrv6($ipaddr)) {
456
		return true;
457
	}
458
	return false;
459
}
460

    
461
/* returns true if $ipaddr is a valid IPv6 address */
462
function is_ipaddrv6($ipaddr) {
463
	$result = Net_IPv6::checkIPv6($ipaddr);
464
	return $result;
465
}
466

    
467
/* returns true if $ipaddr is a valid dotted IPv4 address */
468
function is_ipaddrv4($ipaddr) {
469
	if (!is_string($ipaddr))
470
		return false;
471

    
472
	$ip_long = ip2long($ipaddr);
473
	$ip_reverse = long2ip32($ip_long);
474

    
475
	if ($ipaddr == $ip_reverse)
476
		return true;
477
	else
478
		return false;
479
}
480

    
481
/* returns true if $ipaddr is a valid dotted IPv4 address or an alias thereof */
482
function is_ipaddroralias($ipaddr) {
483
	global $config;
484

    
485
	if (is_alias($ipaddr)) {
486
		if (is_array($config['aliases']['alias'])) {
487
			foreach ($config['aliases']['alias'] as $alias) {
488
				if ($alias['name'] == $ipaddr && $alias['type'] != "port")
489
					return true;
490
			}
491
		}
492
		return false;
493
	} else
494
		return is_ipaddr($ipaddr);
495

    
496
}
497

    
498
/* returns true if $subnet is a valid subnet in CIDR format */
499
function is_subnet($subnet) {
500
	if (!is_string($subnet))
501
		return false;
502

    
503
	list($hp,$np) = explode('/', $subnet);
504

    
505
	if (!is_ipaddr($hp))
506
		return false;
507

    
508
	if (!is_numeric($np) || ($np < 1) || ($np > 32))
509
		return false;
510

    
511
	return true;
512
}
513

    
514
/* returns true if $subnet is a valid subnet in CIDR format or an alias thereof */
515
function is_subnetoralias($subnet) {
516
	global $aliastable;
517

    
518
	if (isset($aliastable[$subnet]) && is_subnet($aliastable[$subnet]))
519
		return true;
520
	else
521
		return is_subnet($subnet);
522
}
523

    
524
/* returns true if $hostname is a valid hostname */
525
function is_hostname($hostname) {
526
	if (!is_string($hostname))
527
		return false;
528

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

    
535
/* returns true if $domain is a valid domain name */
536
function is_domain($domain) {
537
	if (!is_string($domain))
538
		return false;
539

    
540
	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))
541
		return true;
542
	else
543
		return false;
544
}
545

    
546
/* returns true if $macaddr is a valid MAC address */
547
function is_macaddr($macaddr) {
548
	return preg_match('/^[0-9A-F]{2}(?:[:][0-9A-F]{2}){5}$/i', $macaddr) == 1 ? true : false;
549
}
550

    
551
/* returns true if $name is a valid name for an alias */
552
/* returns NULL if a reserved word is used */
553
function is_validaliasname($name) {
554
	/* Array of reserved words */
555
	$reserved = array("port", "pass");
556
	if (in_array($name, $reserved, true))
557
		return; /* return NULL */
558
	if (!preg_match("/[^a-zA-Z0-9_]/", $name) && (strlen($name) < 32))
559
		return true;
560
	else
561
		return false;
562
}
563

    
564
/* returns true if $port is a valid TCP/UDP port */
565
function is_port($port) {
566
	$tmpports = explode(":", $port);
567
	foreach($tmpports as $tmpport) {
568
		if (getservbyname($tmpport, "tcp") || getservbyname($tmpport, "udp"))
569
			continue;
570
		if (!ctype_digit($tmpport))
571
			return false;
572
		else if ((intval($tmpport) < 1) || (intval($tmpport) > 65535))
573
			return false;
574
	}
575
	return true;
576
}
577

    
578
/* returns true if $portrange is a valid TCP/UDP portrange ("<port>:<port>") */
579
function is_portrange($portrange) {
580
	$ports = explode(":", $portrange);
581

    
582
	if(count($ports) == 2 && is_port($ports[0]) && is_port($ports[1]))
583
		return true;
584
	else
585
		return false;
586
}
587

    
588
/* returns true if $port is a valid port number or an alias thereof */
589
function is_portoralias($port) {
590
	global $config;
591

    
592
	if (is_alias($port)) {
593
		if (is_array($config['aliases']['alias'])) {
594
			foreach ($config['aliases']['alias'] as $alias) {
595
				if ($alias['name'] == $port && $alias['type'] == "port")
596
					return true;
597
				}
598
			}
599
			return false;
600
	} else
601
		return is_port($port);
602
}
603

    
604
/* returns true if $val is a valid shaper bandwidth value */
605
function is_valid_shaperbw($val) {
606
	return (preg_match("/^(\d+(?:\.\d+)?)([MKG]?b|%)$/", $val));
607
}
608

    
609
/* return the configured carp interface list */
610
function get_configured_carp_interface_list() {
611
	global $config;
612

    
613
	$iflist = array();
614

    
615
	if(is_array($config['virtualip']['vip'])) {
616
		$viparr = &$config['virtualip']['vip'];
617
		foreach ($viparr as $vip) {
618
			switch ($vip['mode']) {
619
				case "carp":
620
				case "carpdev-dhcp":
621
					$vipif = "vip" . $vip['vhid'];
622
					$iflist[$vipif] = $vip['subnet'];
623
					break;
624
			}
625
		}
626
	}
627

    
628
	return $iflist;
629
}
630

    
631
/* return the configured IP aliases list */
632
function get_configured_ip_aliases_list() {
633
	global $config;
634

    
635
	$alias_list=array();
636

    
637
	if(is_array($config['virtualip']['vip'])) {
638
		$viparr = &$config['virtualip']['vip'];
639
		foreach ($viparr as $vip) {
640
			if ($vip['mode']=="ipalias") {
641
				$alias_list[$vip['subnet']] = $vip['interface'];
642
			}
643
		}
644
	}
645

    
646
	return $alias_list;
647
}
648

    
649

    
650
/* comparison function for sorting by the order in which interfaces are normally created */
651
function compare_interface_friendly_names($a, $b) {
652
	if ($a == $b)
653
		return 0;
654
	else if ($a == 'wan')
655
		return -1;
656
	else if ($b == 'wan')
657
		return 1;
658
	else if ($a == 'lan')
659
		return -1;
660
	else if ($b == 'lan')
661
		return 1;
662

    
663
	return strnatcmp($a, $b);
664
}
665

    
666
/* return the configured interfaces list. */
667
function get_configured_interface_list($only_opt = false, $withdisabled = false) {
668
	global $config;
669

    
670
	$iflist = array();
671

    
672
	/* if list */
673
	foreach($config['interfaces'] as $if => $ifdetail) {
674
		if ($only_opt && ($if == "wan" || $if == "lan"))
675
			continue;
676
		if (isset($ifdetail['enable']) || $withdisabled == true)
677
			$iflist[$if] = $if;
678
	}
679

    
680
	return $iflist;
681
}
682

    
683
/* return the configured interfaces list. */
684
function get_configured_interface_list_by_realif($only_opt = false, $withdisabled = false) {
685
	global $config;
686

    
687
	$iflist = array();
688

    
689
	/* if list */
690
	foreach($config['interfaces'] as $if => $ifdetail) {
691
		if ($only_opt && ($if == "wan" || $if == "lan"))
692
			continue;
693
		if (isset($ifdetail['enable']) || $withdisabled == true) {
694
			$tmpif = get_real_interface($if);
695
			if (!empty($tmpif))
696
				$iflist[$tmpif] = $if;
697
		}
698
	}
699

    
700
	return $iflist;
701
}
702

    
703
/* return the configured interfaces list with their description. */
704
function get_configured_interface_with_descr($only_opt = false, $withdisabled = false) {
705
	global $config;
706

    
707
	$iflist = array();
708

    
709
	/* if list */
710
	foreach($config['interfaces'] as $if => $ifdetail) {
711
		if ($only_opt && ($if == "wan" || $if == "lan"))
712
			continue;
713
		if (isset($ifdetail['enable']) || $withdisabled == true) {
714
			if(empty($ifdetail['descr']))
715
				$iflist[$if] = strtoupper($if);
716
			else
717
				$iflist[$if] = strtoupper($ifdetail['descr']);
718
		}
719
	}
720

    
721
	return $iflist;
722
}
723

    
724
/*
725
 *   get_configured_ip_addresses() - Return a list of all configured
726
 *   interfaces IP Addresses
727
 *
728
 */
729
function get_configured_ip_addresses() {
730
	require_once("interfaces.inc");
731
	$ip_array = array();
732
	$interfaces = get_configured_interface_list();
733
	if(is_array($interfaces)) {
734
		foreach($interfaces as $int) {
735
			$ipaddr = get_interface_ip($int);
736
			$ip_array[$int] = $ipaddr;
737
		}
738
	}
739
	$interfaces = get_configured_carp_interface_list();
740
	if(is_array($interfaces)) 
741
		foreach($interfaces as $int => $ipaddr) 
742
			$ip_array[$int] = $ipaddr;
743
	return $ip_array;
744
}
745

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

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

    
874
/****f* util/log_auth
875
* NAME
876
*   log_error  - Sends a string to syslog as LOG_AUTH facility
877
* INPUTS
878
*   $error     - string containing the syslog message.
879
* RESULT
880
*   null
881
******/
882
function log_auth($error) {
883
	global $g;
884
	$page = $_SERVER['SCRIPT_NAME'];
885
	syslog(LOG_AUTH, "$page: $error");
886
	if ($g['debug'])
887
		syslog(LOG_WARNING, var_dump(debug_backtrace()));
888
	return;
889
}
890

    
891
/****f* util/exec_command
892
 * NAME
893
 *   exec_command - Execute a command and return a string of the result.
894
 * INPUTS
895
 *   $command   - String of the command to be executed.
896
 * RESULT
897
 *   String containing the command's result.
898
 * NOTES
899
 *   This function returns the command's stdout and stderr.
900
 ******/
901
function exec_command($command) {
902
	$output = array();
903
	exec($command . ' 2>&1 ', $output);
904
	return(implode("\n", $output));
905
}
906

    
907
/* wrapper for exec() */
908
function mwexec($command, $mute = false) {
909
	global $g;
910

    
911
	if ($g['debug']) {
912
		if (!$_SERVER['REMOTE_ADDR'])
913
			echo "mwexec(): $command\n";
914
	}
915
	$oarr = array();
916
	$retval = 0;
917
	$garbage = exec("$command 2>&1", $oarr, $retval);
918

    
919
	if(isset($config['system']['developerspew']))
920
		$mute = false;
921
	if(($retval <> 0) && ($mute === false)) {
922
		$output = implode(" ", $oarr);
923
		log_error(sprintf(gettext("The command '%1\$s' returned exit code '%2\$d', the output was '%3\$s' "), $command, $retval, $output));
924
	}
925
	return $retval;
926
}
927

    
928
/* wrapper for exec() in background */
929
function mwexec_bg($command) {
930
	global $g;
931

    
932
	if ($g['debug']) {
933
		if (!$_SERVER['REMOTE_ADDR'])
934
			echo "mwexec(): $command\n";
935
	}
936

    
937
	exec("nohup $command > /dev/null 2>&1 &");
938
}
939

    
940
/* unlink a file, if it exists */
941
function unlink_if_exists($fn) {
942
	$to_do = glob($fn);
943
	if(is_array($to_do)) {
944
		foreach($to_do as $filename)
945
			@unlink($filename);
946
	} else {
947
		@unlink($fn);
948
	}
949
}
950
/* make a global alias table (for faster lookups) */
951
function alias_make_table($config) {
952
	global $aliastable;
953

    
954
	$aliastable = array();
955

    
956
	if (is_array($config['aliases']['alias'])) {
957
		foreach ($config['aliases']['alias'] as $alias) {
958
			if ($alias['name'])
959
				$aliastable[$alias['name']] = $alias['address'];
960
		}
961
	}
962
}
963

    
964
/* check if an alias exists */
965
function is_alias($name) {
966
	global $aliastable;
967

    
968
	return isset($aliastable[$name]);
969
}
970

    
971
function alias_get_type($name) {
972
        global $config;
973
        
974
	if (is_array($config['aliases']['alias'])) {
975
		foreach ($config['aliases']['alias'] as $alias) {
976
			if ($name == $alias['name'])
977
				return $alias['type'];
978
		}
979
	}
980

    
981
        return "";
982
}
983

    
984
/* expand a host or network alias, if necessary */
985
function alias_expand($name) {
986
	global $aliastable;
987

    
988
	if (isset($aliastable[$name]))
989
		return "\${$name}";
990
	else if (is_ipaddr($name) || is_subnet($name) || is_port($name))
991
		return "{$name}";
992
	else
993
		return null;
994
}
995

    
996
function alias_expand_urltable($name) {
997
	global $config;
998
	$urltable_prefix = "/var/db/aliastables/";
999
	$urltable_filename = $urltable_prefix . $name . ".txt";
1000

    
1001
	if (is_array($config['aliases']['alias'])) {
1002
		foreach ($config['aliases']['alias'] as $alias) {
1003
			if (($alias['type'] == 'urltable') && ($alias['name'] == $name)) {
1004
				if (is_URL($alias["url"]) && file_exists($urltable_filename) && filesize($urltable_filename))
1005
					return $urltable_filename;
1006
				else if (process_alias_urltable($name, $alias["url"], 0, true))
1007
					return $urltable_filename;
1008
			}
1009
		}
1010
	}
1011
	return null;
1012
}
1013

    
1014
/* find out whether two subnets overlap */
1015
function check_subnets_overlap($subnet1, $bits1, $subnet2, $bits2) {
1016

    
1017
	if (!is_numeric($bits1))
1018
		$bits1 = 32;
1019
	if (!is_numeric($bits2))
1020
		$bits2 = 32;
1021

    
1022
	if ($bits1 < $bits2)
1023
		$relbits = $bits1;
1024
	else
1025
		$relbits = $bits2;
1026

    
1027
	$sn1 = gen_subnet_mask_long($relbits) & ip2long($subnet1);
1028
	$sn2 = gen_subnet_mask_long($relbits) & ip2long($subnet2);
1029

    
1030
	if ($sn1 == $sn2)
1031
		return true;
1032
	else
1033
		return false;
1034
}
1035

    
1036
/* compare two IP addresses */
1037
function ipcmp($a, $b) {
1038
	if (ip_less_than($a, $b))
1039
		return -1;
1040
	else if (ip_greater_than($a, $b))
1041
		return 1;
1042
	else
1043
		return 0;
1044
}
1045

    
1046
/* return true if $addr is in $subnet, false if not */
1047
function ip_in_subnet($addr,$subnet) {
1048
	if(is_ipaddrv6($addr)) {
1049
		$result = Net_IPv6::IsInNetmask($addr, $subnet);
1050
		if($result)
1051
			return true;
1052
		else
1053
			return false;
1054
	}
1055
	list($ip, $mask) = explode('/', $subnet);
1056
	$mask = (0xffffffff << (32 - $mask)) & 0xffffffff;
1057
	return ((ip2long($addr) & $mask) == (ip2long($ip) & $mask));
1058
}
1059

    
1060
/* verify (and remove) the digital signature on a file - returns 0 if OK */
1061
function verify_digital_signature($fname) {
1062
	global $g;
1063

    
1064
	if(!file_exists("/usr/local/sbin/gzsig"))
1065
		return 4;
1066

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

    
1070
/* obtain MAC address given an IP address by looking at the ARP table */
1071
function arp_get_mac_by_ip($ip) {
1072
	mwexec("/sbin/ping -c 1 -t 1 {$ip}", true);
1073
	$arpoutput = "";
1074
	exec("/usr/sbin/arp -n {$ip}", $arpoutput);
1075

    
1076
	if ($arpoutput[0]) {
1077
		$arpi = explode(" ", $arpoutput[0]);
1078
		$macaddr = $arpi[3];
1079
		if (is_macaddr($macaddr))
1080
			return $macaddr;
1081
		else
1082
			return false;
1083
	}
1084

    
1085
	return false;
1086
}
1087

    
1088
/* return a fieldname that is safe for xml usage */
1089
function xml_safe_fieldname($fieldname) {
1090
	$replace = array('/', '-', ' ', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
1091
			 '_', '+', '=', '{', '}', '[', ']', '|', '/', '<', '>', '?',
1092
			 ':', ',', '.', '\'', '\\'
1093
		);
1094
	return strtolower(str_replace($replace, "", $fieldname));
1095
}
1096

    
1097
function mac_format($clientmac) {
1098
    $mac =explode(":", $clientmac);
1099

    
1100
    global $config;
1101

    
1102
    $mac_format = $config['captiveportal']['radmac_format'] ? $config['captiveportal']['radmac_format'] : false;
1103

    
1104
    switch($mac_format) {
1105

    
1106
        case 'singledash':
1107
        return "$mac[0]$mac[1]$mac[2]-$mac[3]$mac[4]$mac[5]";
1108

    
1109
        case 'ietf':
1110
        return "$mac[0]-$mac[1]-$mac[2]-$mac[3]-$mac[4]-$mac[5]";
1111

    
1112
        case 'cisco':
1113
        return "$mac[0]$mac[1].$mac[2]$mac[3].$mac[4]$mac[5]";
1114

    
1115
        case 'unformatted':
1116
        return "$mac[0]$mac[1]$mac[2]$mac[3]$mac[4]$mac[5]";
1117

    
1118
        default:
1119
        return $clientmac;
1120
    }
1121
}
1122

    
1123
function resolve_retry($hostname, $retries = 5) {
1124

    
1125
	if (is_ipaddr($hostname))
1126
		return $hostname;
1127

    
1128
       for ($i = 0; $i < $retries; $i++) {
1129
		// FIXME: gethostbyname does not work for AAAA hostnames, boo, hiss
1130
               $ip = gethostbyname($hostname);
1131

    
1132
		if ($ip && $ip != $hostname) {
1133
			/* success */
1134
			return $ip;
1135
		}
1136

    
1137
		sleep(1);
1138
	}
1139

    
1140
	return false;
1141
}
1142

    
1143
function format_bytes($bytes) {
1144
	if ($bytes >= 1073741824) {
1145
		return sprintf("%.2f GB", $bytes/1073741824);
1146
	} else if ($bytes >= 1048576) {
1147
		return sprintf("%.2f MB", $bytes/1048576);
1148
	} else if ($bytes >= 1024) {
1149
		return sprintf("%.0f KB", $bytes/1024);
1150
	} else {
1151
		return sprintf("%d bytes", $bytes);
1152
	}
1153
}
1154

    
1155
function update_filter_reload_status($text) {
1156
	global $g;
1157

    
1158
	file_put_contents("{$g['varrun_path']}/filter_reload_status", $text);
1159
}
1160

    
1161
/****f* util/return_dir_as_array
1162
 * NAME
1163
 *   return_dir_as_array - Return a directory's contents as an array.
1164
 * INPUTS
1165
 *   $dir       - string containing the path to the desired directory.
1166
 * RESULT
1167
 *   $dir_array - array containing the directory's contents. This array will be empty if the path specified is invalid.
1168
 ******/
1169
function return_dir_as_array($dir) {
1170
	$dir_array = array();
1171
	if (is_dir($dir)) {
1172
		if ($dh = opendir($dir)) {
1173
			while (($file = readdir($dh)) !== false) {
1174
				$canadd = 0;
1175
				if($file == ".") $canadd = 1;
1176
				if($file == "..") $canadd = 1;
1177
				if($canadd == 0)
1178
					array_push($dir_array, $file);
1179
			}
1180
			closedir($dh);
1181
		}
1182
	}
1183
	return $dir_array;
1184
}
1185

    
1186
function run_plugins($directory) {
1187
	global $config, $g;
1188

    
1189
	/* process packager manager custom rules */
1190
	$files = return_dir_as_array($directory);
1191
	if (is_array($files)) {
1192
		foreach ($files as $file) {
1193
			if (stristr($file, ".sh") == true)
1194
				mwexec($directory . $file . " start");
1195
			else if (!is_dir($directory . "/" . $file) && stristr($file,".inc")) 
1196
				require_once($directory . "/" . $file);
1197
		}
1198
	}
1199
}
1200

    
1201
/*
1202
 *    safe_mkdir($path, $mode = 0755)
1203
 *    create directory if it doesn't already exist and isn't a file!
1204
 */
1205
function safe_mkdir($path, $mode=0755) {
1206
	global $g;
1207

    
1208
	if (!is_file($path) && !is_dir($path)) {
1209
		return @mkdir($path, $mode, true);
1210
	} else {
1211
		return false;
1212
	}
1213
}
1214

    
1215
/*
1216
 * make_dirs($path, $mode = 0755)
1217
 * create directory tree recursively (mkdir -p)
1218
 */
1219
function make_dirs($path, $mode = 0755) {
1220
	$base = '';
1221
	foreach (explode('/', $path) as $dir) {
1222
		$base .= "/$dir";
1223
		if (!is_dir($base)) {
1224
			if (!@mkdir($base, $mode))
1225
				return false;
1226
		}
1227
	}
1228
	return true;
1229
}
1230

    
1231
/*
1232
 * get_sysctl($names)
1233
 * Get values of sysctl OID's listed in $names (accepts an array or a single
1234
 * name) and return an array of key/value pairs set for those that exist
1235
 */
1236
function get_sysctl($names) {
1237
	if (empty($names))
1238
		return array();
1239

    
1240
	if (is_array($names)) {
1241
		$name_list = array();
1242
		foreach ($names as $name) {
1243
			$name_list[] = escapeshellarg($name);
1244
		}
1245
	} else
1246
		$name_list = array(escapeshellarg($names));
1247

    
1248
	exec("/sbin/sysctl -i " . implode(" ", $name_list), $output);
1249
	$values = array();
1250
	foreach ($output as $line) {
1251
		$line = explode(": ", $line, 2);
1252
		if (count($line) == 2)
1253
			$values[$line[0]] = $line[1];
1254
	}
1255

    
1256
	return $values;
1257
}
1258

    
1259
/*
1260
 * set_sysctl($value_list)
1261
 * Set sysctl OID's listed as key/value pairs and return
1262
 * an array with keys set for those that succeeded
1263
 */
1264
function set_sysctl($values) {
1265
	if (empty($values))
1266
		return array();
1267

    
1268
	$value_list = array();
1269
	foreach ($values as $key => $value) {
1270
		$value_list[] = escapeshellarg($key) . "=" . escapeshellarg($value);
1271
	}
1272

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

    
1275
	/* Retry individually if failed (one or more read-only) */
1276
	if ($success <> 0 && count($value_list) > 1) {
1277
		foreach ($value_list as $value) {
1278
			exec("/sbin/sysctl -i " . $value, $output);
1279
		}
1280
	}
1281

    
1282
	$ret = array();
1283
	foreach ($output as $line) {
1284
		$line = explode(": ", $line, 2);
1285
		if (count($line) == 2)
1286
			$ret[$line[0]] = true;
1287
	}
1288

    
1289
	return $ret;
1290
}
1291

    
1292
/*
1293
 *     get_memory()
1294
 *     returns an array listing the amount of
1295
 *     memory installed in the hardware
1296
 *     [0]real and [1]available
1297
 */
1298
function get_memory() {
1299
	$matches = "";
1300
	if(file_exists("/var/log/dmesg.boot"))
1301
		$mem = `cat /var/log/dmesg.boot | grep memory`;
1302
	else
1303
		$mem = `dmesg -a | grep memory`;			
1304
	if (preg_match_all("/avail memory.* \((.*)MB\)/", $mem, $matches)) 
1305
		return array($matches[1][0], $matches[1][0]);
1306
	if(!$real && !$avail) {
1307
		$real = trim(`sysctl hw.physmem | cut -d' ' -f2`);
1308
		$avail = trim(`sysctl hw.realmem | cut -d' ' -f2`);
1309
		/* convert from bytes to megabytes */
1310
		return array(($real/1048576),($avail/1048576));
1311
	}
1312
}
1313

    
1314
function mute_kernel_msgs() {
1315
	global $config;
1316
	// Do not mute serial console.  The kernel gets very very cranky
1317
	// and will start dishing you cannot control tty errors.
1318
	switch (trim(file_get_contents("/etc/platform"))) {
1319
		case "nanobsd":
1320
		case "jail":
1321
			return;
1322
	}
1323
	if($config['system']['enableserial']) 
1324
		return;			
1325
	exec("/sbin/conscontrol mute on");
1326
}
1327

    
1328
function unmute_kernel_msgs() {
1329
	global $config;
1330
	// Do not mute serial console.  The kernel gets very very cranky
1331
	// and will start dishing you cannot control tty errors.
1332
	switch (trim(file_get_contents("/etc/platform"))) {
1333
		case "nanobsd":
1334
		case "jail":
1335
			return;
1336
	}
1337
	exec("/sbin/conscontrol mute off");
1338
}
1339

    
1340
function start_devd() {
1341
	global $g;
1342

    
1343
	if ($g['platform'] == 'jail')
1344
		return;
1345
	exec("/sbin/devd");
1346
	sleep(1);
1347
}
1348

    
1349
function is_interface_vlan_mismatch() {
1350
	global $config, $g;
1351

    
1352
	if (is_array($config['vlans']['vlan'])) {
1353
		foreach ($config['vlans']['vlan'] as $vlan) {
1354
			if (does_interface_exist($vlan['if']) == false)
1355
				return true;
1356
		}
1357
	}
1358

    
1359
	return false;
1360
}
1361

    
1362
function is_interface_mismatch() {
1363
	global $config, $g;
1364

    
1365
	$do_assign = false;
1366
	$i = 0;
1367
	if (is_array($config['interfaces'])) {
1368
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
1369
			if (preg_match("/^enc|^cua|^tun|^l2tp|^pptp|^ppp|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_wlan/i", $ifcfg['if'])) {
1370
				// Do not check these interfaces.
1371
				$i++;
1372
				continue;
1373
			}
1374
			else if (does_interface_exist($ifcfg['if']) == false) {
1375
				$do_assign = true;
1376
			} else
1377
				$i++;
1378
		}
1379
	}
1380

    
1381
	if ($g['minimum_nic_count'] > $i) {
1382
		$do_assign = true;
1383
	} else if (file_exists("{$g['tmp_path']}/assign_complete"))
1384
	$do_assign = false;
1385

    
1386
	return $do_assign;
1387
}
1388

    
1389
/* sync carp entries to other firewalls */
1390
function carp_sync_client() {
1391
	global $g;
1392
	send_event("filter sync");
1393
}
1394

    
1395
/****f* util/isAjax
1396
 * NAME
1397
 *   isAjax - reports if the request is driven from prototype
1398
 * INPUTS
1399
 *   none
1400
 * RESULT
1401
 *   true/false
1402
 ******/
1403
function isAjax() {
1404
	return isset ($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest';
1405
}
1406

    
1407
/****f* util/timeout
1408
 * NAME
1409
 *   timeout - console input with timeout countdown. Note: erases 2 char of screen for timer. Leave space.
1410
 * INPUTS
1411
 *   optional, seconds to wait before timeout. Default 9 seconds.
1412
 * RESULT
1413
 *   returns 1 char of user input or null if no input.
1414
 ******/
1415
function timeout($timer = 9) {
1416
	while(!isset($key)) {
1417
		if ($timer >= 9) { echo chr(8) . chr(8) . ($timer==9 ? chr(32) : null)  . "{$timer}";  }
1418
		else { echo chr(8). "{$timer}"; }
1419
		`/bin/stty -icanon min 0 time 25`;
1420
		$key = trim(`KEY=\`dd count=1 2>/dev/null\`; echo \$KEY`);
1421
		`/bin/stty icanon`;
1422
		if ($key == '')
1423
			unset($key);
1424
		$timer--;
1425
		if ($timer == 0)
1426
			break;
1427
	}
1428
	return $key;	
1429
}
1430

    
1431
/****f* util/msort
1432
 * NAME
1433
 *   msort - sort array
1434
 * INPUTS
1435
 *   $array to be sorted, field to sort by, direction of sort
1436
 * RESULT
1437
 *   returns newly sorted array
1438
 ******/
1439
function msort($array, $id="id", $sort_ascending=true) {
1440
	$temp_array = array();
1441
	while(count($array)>0) {
1442
		$lowest_id = 0;
1443
		$index=0;
1444
		foreach ($array as $item) {
1445
			if (isset($item[$id])) {
1446
				if ($array[$lowest_id][$id]) {
1447
					if (strtolower($item[$id]) < strtolower($array[$lowest_id][$id])) {
1448
						$lowest_id = $index;
1449
					}
1450
				}
1451
			}
1452
			$index++;
1453
		}
1454
		$temp_array[] = $array[$lowest_id];
1455
		$array = array_merge(array_slice($array, 0,$lowest_id), array_slice($array, $lowest_id+1));
1456
	}
1457
	if ($sort_ascending) {
1458
		return $temp_array;
1459
	} else {
1460
    	return array_reverse($temp_array);
1461
	}
1462
}
1463

    
1464
/****f* util/color
1465
 * NAME
1466
 *   color - outputs a color code to the ansi terminal if supported
1467
 * INPUTS
1468
 *   color code or color name
1469
 * RESULT
1470
 *   Outputs the ansi color sequence for the color specified.  Default resets terminal.
1471
 ******/
1472
function color($color = "0m") {
1473
	/*
1474
		Color codes available:
1475
		 0m reset; clears all colors and styles (to white on black)
1476
		 1m bold on (see below)
1477
		 3m italics on
1478
		 4m underline on
1479
		 7m inverse on; reverses foreground & background colors
1480
		 9m strikethrough on
1481
		 22m bold off (see below)
1482
		 23m italics off
1483
		 24m underline off
1484
		 27m inverse off
1485
		 29m strikethrough off
1486
		 30m set foreground color to black
1487
		 31m set foreground color to red
1488
		 32m set foreground color to green
1489
		 33m set foreground color to yellow
1490
		 34m set foreground color to blue
1491
		 35m set foreground color to magenta (purple)
1492
		 36m set foreground color to cyan
1493
		 37m set foreground color to white
1494
		 40m  set background color to black
1495
		 41m set background color to red
1496
		 42m set background color to green
1497
		 43m set background color to yellow
1498
		 44m set background color to blue
1499
		 45m set background color to magenta (purple)
1500
		 46m set background color to cyan
1501
		 47m set background color to white
1502
		 49m set background color to default (black)
1503
	*/	
1504
	// Allow caching of TERM to 
1505
	// speedup subequence requests.
1506
	global $TERM;
1507
	if(!$TERM) 
1508
		$TERM=`/usr/bin/env | grep color`;
1509
	if(!$TERM)
1510
		$TERM=`/usr/bin/env | grep cons25`;
1511
	if($TERM) {
1512
		$ESCAPE=chr(27);
1513
		switch ($color) {
1514
			case "black":
1515
				return "{$ESCAPE}[30m"; 
1516
			case "red":
1517
				return "{$ESCAPE}[31m"; 
1518
			case "green":
1519
				return "{$ESCAPE}[32m"; 
1520
			case "yellow":
1521
				return "{$ESCAPE}[33m"; 
1522
			case "blue":
1523
				return "{$ESCAPE}[34m"; 
1524
			case "magenta":
1525
				return "{$ESCAPE}[35m"; 
1526
			case "cyan":
1527
				return "{$ESCAPE}[36m"; 
1528
			case "white":
1529
				return "{$ESCAPE}[37m"; 
1530
			case "default":
1531
				return "{$ESCAPE}[39m"; 
1532
		}
1533
		return "{$ESCAPE}[{$color}";
1534
	}
1535
}
1536

    
1537
/****f* util/is_URL
1538
 * NAME
1539
 *   is_URL
1540
 * INPUTS
1541
 *   string to check
1542
 * RESULT
1543
 *   Returns true if item is a URL
1544
 ******/
1545
function is_URL($url) {
1546
	$match = preg_match("'\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))'", $url);
1547
	if($match)
1548
		return true;	
1549
	return false;
1550
}
1551

    
1552
function is_file_included($file = "") {
1553
	$files = get_included_files();
1554
	if (in_array($file, $files))
1555
		return true;
1556
	
1557
	return false;
1558
}
1559

    
1560
/*
1561
	This function was borrowed from a comment on PHP.net at the following URL:
1562
	http://www.php.net/manual/en/function.array-merge-recursive.php#73843
1563
 */
1564
function array_merge_recursive_unique($array0, $array1) {
1565

    
1566
	$arrays = func_get_args();
1567
	$remains = $arrays;
1568

    
1569
	// We walk through each arrays and put value in the results (without
1570
	// considering previous value).
1571
	$result = array();
1572

    
1573
	// loop available array
1574
	foreach($arrays as $array) {
1575

    
1576
		// The first remaining array is $array. We are processing it. So
1577
		// we remove it from remaing arrays.
1578
        array_shift($remains);
1579

    
1580
		// We don't care non array param, like array_merge since PHP 5.0.
1581
		if(is_array($array)) {
1582
			// Loop values
1583
			foreach($array as $key => $value) {
1584
				if(is_array($value)) {
1585
					// we gather all remaining arrays that have such key available
1586
					$args = array();
1587
					foreach($remains as $remain) {
1588
						if(array_key_exists($key, $remain)) {
1589
							array_push($args, $remain[$key]);
1590
						}
1591
					}
1592

    
1593
					if(count($args) > 2) {
1594
						// put the recursion
1595
						$result[$key] = call_user_func_array(__FUNCTION__, $args);
1596
					} else {
1597
						foreach($value as $vkey => $vval) {
1598
							$result[$key][$vkey] = $vval;
1599
						}
1600
					}
1601
				} else {
1602
					// simply put the value
1603
					$result[$key] = $value;
1604
				}
1605
			}
1606
		}
1607
	}
1608
	return $result;
1609
}
1610

    
1611
?>
(49-49/61)