Project

General

Profile

Download (56.9 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/****h* pfSense/pfsense-utils
3
 * NAME
4
 *   pfsense-utils.inc - Utilities specific to pfSense
5
 * DESCRIPTION
6
 *   This include contains various pfSense specific functions.
7
 * HISTORY
8
 *   $Id$
9
 ******
10
 *
11
 * Copyright (C) 2004-2007 Scott Ullrich (sullrich@gmail.com)
12
 * All rights reserved.
13
 * Redistribution and use in source and binary forms, with or without
14
 * modification, are permitted provided that the following conditions are met:
15
 *
16
 * 1. Redistributions of source code must retain the above copyright notice,
17
 * this list of conditions and the following disclaimer.
18
 *
19
 * 2. Redistributions in binary form must reproduce the above copyright
20
 * notice, this list of conditions and the following disclaimer in the
21
 * documentation and/or other materials provided with the distribution.
22
 *
23
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
25
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26
 * AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
27
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31
 * RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
 * POSSIBILITY OF SUCH DAMAGE.
33
 *
34
 */
35

    
36
/*
37
	pfSense_BUILDER_BINARIES:	/sbin/sysctl	/sbin/ifconfig	/sbin/pfctl	/usr/local/bin/php /usr/bin/netstat
38
	pfSense_BUILDER_BINARIES:	/bin/df	/usr/bin/grep	/usr/bin/awk	/bin/rm	/usr/sbin/pwd_mkdb	/usr/bin/host
39
	pfSense_BUILDER_BINARIES:	/sbin/kldload
40
	pfSense_MODULE:	utils
41
*/
42

    
43
/****f* pfsense-utils/have_natonetooneruleint_access
44
 * NAME
45
 *   have_natonetooneruleint_access
46
 * INPUTS
47
 *	 none
48
 * RESULT
49
 *   returns true if user has access to edit a specific firewall nat one to one interface
50
 ******/
51
function have_natonetooneruleint_access($if) {
52
	$security_url = "firewall_nat_1to1_edit.php?if=". strtolower($if);
53
	if(isAllowedPage($security_url, $_SESSION['Username'])) 
54
		return true;
55
	return false;
56
}
57

    
58
/****f* pfsense-utils/have_natpfruleint_access
59
 * NAME
60
 *   have_natpfruleint_access
61
 * INPUTS
62
 *	 none
63
 * RESULT
64
 *   returns true if user has access to edit a specific firewall nat port forward interface
65
 ******/
66
function have_natpfruleint_access($if) {
67
	$security_url = "firewall_nat_edit.php?if=". strtolower($if);
68
	if(isAllowedPage($security_url, $allowed)) 
69
		return true;
70
	return false;
71
}
72

    
73
/****f* pfsense-utils/have_ruleint_access
74
 * NAME
75
 *   have_ruleint_access
76
 * INPUTS
77
 *	 none
78
 * RESULT
79
 *   returns true if user has access to edit a specific firewall interface
80
 ******/
81
function have_ruleint_access($if) {
82
	$security_url = "firewall_rules.php?if=". strtolower($if);
83
	if(isAllowedPage($security_url)) 
84
		return true;
85
	return false;
86
}
87

    
88
/****f* pfsense-utils/does_url_exist
89
 * NAME
90
 *   does_url_exist
91
 * INPUTS
92
 *	 none
93
 * RESULT
94
 *   returns true if a url is available
95
 ******/
96
function does_url_exist($url) {
97
	$fd = fopen("$url","r");
98
	if($fd) {
99
		fclose($fd);
100
   		return true;    
101
	} else {
102
        return false;
103
	}
104
}
105

    
106
/****f* pfsense-utils/is_private_ip
107
 * NAME
108
 *   is_private_ip
109
 * INPUTS
110
 *	 none
111
 * RESULT
112
 *   returns true if an ip address is in a private range
113
 ******/
114
function is_private_ip($iptocheck) {
115
        $isprivate = false;
116
        $ip_private_list=array(
117
               "10.0.0.0/8",
118
               "172.16.0.0/12",
119
               "192.168.0.0/16",
120
               "99.0.0.0/8"
121
        );
122
        foreach($ip_private_list as $private) {
123
                if(ip_in_subnet($iptocheck,$private)==true)
124
                        $isprivate = true;
125
        }
126
        return $isprivate;
127
}
128

    
129
/****f* pfsense-utils/get_tmp_file
130
 * NAME
131
 *   get_tmp_file
132
 * INPUTS
133
 *	 none
134
 * RESULT
135
 *   returns a temporary filename
136
 ******/
137
function get_tmp_file() {
138
	global $g;
139
	return "{$g['tmp_path']}/tmp-" . time();
140
}
141

    
142
/****f* pfsense-utils/get_dns_servers
143
 * NAME
144
 *   get_dns_servres - get system dns servers
145
 * INPUTS
146
 *   $dns_servers - an array of the dns servers
147
 * RESULT
148
 *   null
149
 ******/
150
function get_dns_servers() {
151
	$dns_servers = array();
152
	$dns = `cat /etc/resolv.conf`;
153
	$dns_s = split("\n", $dns);
154
	foreach($dns_s as $dns) {
155
		$matches = "";
156
		if (preg_match("/nameserver (.*)/", $dns, $matches))
157
			$dns_servers[] = $matches[1];
158
	}
159
	$dns_server_master = array();
160
	$lastseen = "";
161
	foreach($dns_servers as $t) {
162
		if($t <> $lastseen)
163
			if($t <> "")
164
				$dns_server_master[] = $t;
165
		$lastseen = $t;
166
	}
167
	return $dns_server_master;
168
}
169

    
170
/****f* pfsense-utils/enable_hardware_offloading
171
 * NAME
172
 *   enable_hardware_offloading - Enable a NIC's supported hardware features.
173
 * INPUTS
174
 *   $interface	- string containing the physical interface to work on.
175
 * RESULT
176
 *   null
177
 * NOTES
178
 *   This function only supports the fxp driver's loadable microcode.
179
 ******/
180
function enable_hardware_offloading($interface) {
181
	global $g, $config;
182

    
183
	if(stristr($interface,"lnc"))
184
		return;
185

    
186
	/* translate wan, lan, opt -> real interface if needed */
187
	$int = get_real_interface($interface);
188
	if($int <> "") 
189
		$interface = $int;
190
	$int_family = preg_split("/[0-9]+/", $interface);
191
	$options = strtolower(`/sbin/ifconfig -m {$interface} | grep capabilities`);
192
	$supported_ints = array('fxp');
193
	if (in_array($int_family, $supported_ints)) {
194
		if(isset($config['system']['do_not_use_nic_microcode']))
195
			continue;
196
		if(does_interface_exist($interface)) 
197
			mwexec("/sbin/ifconfig {$interface} link0");
198
	}
199

    
200
	/* skip vlans for checksumming and polling */
201
	if(stristr($interface, "vlan")) 
202
		return;
203

    
204
	if($config['system']['disablechecksumoffloading']) {
205
		if(stristr($options, "txcsum") == true)
206
			mwexec("/sbin/ifconfig {$interface} -txcsum 2>/dev/null");
207
		if(stristr($options, "rxcsum") == true)
208
			mwexec("/sbin/ifconfig {$interface} -rxcsum 2>/dev/null");
209
	} else {
210
		if(stristr($options, "txcsum") == true)
211
			mwexec("/sbin/ifconfig {$interface} txcsum 2>/dev/null");
212
		if(stristr($options, "rxcsum") == true)
213
			mwexec("/sbin/ifconfig {$interface} rxcsum 2>/dev/null");
214
	}
215

    
216
	/* if the NIC supports polling *AND* it is enabled in the GUI */
217
	if(interface_supports_polling($interface)) {
218
		$polling = isset($config['system']['polling']);	
219
		if($polling) {
220
			mwexec("/sbin/ifconfig {$interface} polling 2>/dev/null");
221
		} else {
222
			mwexec("/sbin/ifconfig {$interface} -polling 2>/dev/null");
223
		}
224
	}
225
	return;
226
}
227

    
228
/****f* pfsense-utils/interface_supports_polling
229
 * NAME
230
 *   checks to see if an interface supports polling according to man polling
231
 * INPUTS
232
 *
233
 * RESULT
234
 *   true or false
235
 * NOTES
236
 *
237
 ******/
238
function interface_supports_polling($iface) {
239
	$pattern = '/([a-z].*)[0-9]/';
240
	preg_match($pattern, $iface, $iface2);
241
	$interface=$iface2[1];
242
	$supported_ints = array("bge",
243
		"dc",
244
		"em",
245
		"fwe",
246
		"fwip",
247
		"fxp",
248
		"ixgb",
249
		"nfe",
250
		"vge",
251
		"re",
252
		"rl",
253
		"sf",
254
		"sis",
255
		"ste",
256
		"stge",    
257
		"vge",
258
		"vr",
259
		"xl");
260
	if(in_array($interface, $supported_ints))
261
		return true;
262
	return false;
263
}
264

    
265
/****f* pfsense-utils/is_alias_inuse
266
 * NAME
267
 *   checks to see if an alias is currently in use by a rule
268
 * INPUTS
269
 *
270
 * RESULT
271
 *   true or false
272
 * NOTES
273
 *
274
 ******/
275
function is_alias_inuse($alias) {
276
	global $g, $config;
277

    
278
	if($alias == "") return false;
279
	/* loop through firewall rules looking for alias in use */
280
	if(is_array($config['filter']['rule']))
281
		foreach($config['filter']['rule'] as $rule) {
282
			if($rule['source']['address'])
283
				if($rule['source']['address'] == $alias)
284
					return true;
285
			if($rule['destination']['address'])
286
				if($rule['destination']['address'] == $alias)
287
					return true;
288
		}
289
	/* loop through nat rules looking for alias in use */
290
	if(is_array($config['nat']['rule']))
291
		foreach($config['nat']['rule'] as $rule) {
292
			if($rule['target'] == $alias)
293
				return true;
294
			if($rule['external-address'] == $alias)
295
				return true;
296
		}
297
	return false;
298
}
299

    
300
/****f* pfsense-utils/is_schedule_inuse
301
 * NAME
302
 *   checks to see if a schedule is currently in use by a rule
303
 * INPUTS
304
 *
305
 * RESULT
306
 *   true or false
307
 * NOTES
308
 *
309
 ******/
310
function is_schedule_inuse($schedule) {
311
	global $g, $config;
312

    
313
	if($schedule == "") return false;
314
	/* loop through firewall rules looking for schedule in use */
315
	if(is_array($config['filter']['rule']))
316
		foreach($config['filter']['rule'] as $rule) {
317
			if($rule['sched'] == $schedule)
318
				return true;
319
		}
320
	return false;
321
}
322

    
323
/****f* pfsense-utils/setup_polling_defaults
324
 * NAME
325
 *   sets up sysctls for polling
326
 * INPUTS
327
 *
328
 * RESULT
329
 *   null
330
 * NOTES
331
 *
332
 ******/
333
function setup_polling_defaults() {
334
	global $g, $config;
335
	if($config['system']['polling_each_burst'])
336
		mwexec("sysctl kern.polling.each_burst={$config['system']['polling_each_burst']}");
337
	if($config['system']['polling_burst_max'])
338
		mwexec("sysctl kern.polling.burst_max={$config['system']['polling_burst_max']}");
339
	if($config['system']['polling_user_frac'])
340
		mwexec("sysctl kern.polling.user_frac={$config['system']['polling_user_frac']}");
341
}
342

    
343
/****f* pfsense-utils/setup_polling
344
 * NAME
345
 *   sets up polling
346
 * INPUTS
347
 *
348
 * RESULT
349
 *   null
350
 * NOTES
351
 *
352
 ******/
353
function setup_polling() {
354
	global $g, $config;
355

    
356
	setup_polling_defaults();
357

    
358
	$supported_ints = array('bge', 'dc', 'em', 'fwe', 'fwip', 'fxp', 'ixgb', 'ste', 'nge', 're', 'rl', 'sf', 'sis', 'ste', 'vge', 'vr', 'xl');
359

    
360
	/* if list */
361
	$iflist = get_configured_interface_list();
362

    
363
	foreach ($iflist as $ifent => $ifname) {
364
		$real_interface = convert_friendly_interface_to_real_interface_name($ifname);
365
		$ifdevice = substr($real_interface, 0, -1);
366
		if(!in_array($ifdevice, $supported_ints)) {
367
			continue;
368
        }
369
		if(isset($config['system']['polling'])) {
370
			mwexec("/sbin/ifconfig {$real_interface} polling");
371
			mwexec("/sbin/sysctl kern.polling.idle_poll=1");
372
		} else {
373
			mwexec("/sbin/ifconfig {$real_interface} -polling");
374
		}
375
	}
376
}
377

    
378
/****f* pfsense-utils/setup_microcode
379
 * NAME
380
 *   enumerates all interfaces and calls enable_hardware_offloading which
381
 *   enables a NIC's supported hardware features.
382
 * INPUTS
383
 *
384
 * RESULT
385
 *   null
386
 * NOTES
387
 *   This function only supports the fxp driver's loadable microcode.
388
 ******/
389
function setup_microcode() {
390

    
391
	/* if list */
392
        $ifdescrs = get_configured_interface_list();
393

    
394
	foreach($ifdescrs as $if)
395
		enable_hardware_offloading($if);
396
}
397

    
398
/****f* pfsense-utils/get_carp_status
399
 * NAME
400
 *   get_carp_status - Return whether CARP is enabled or disabled.
401
 * RESULT
402
 *   boolean	- true if CARP is enabled, false if otherwise.
403
 ******/
404
function get_carp_status() {
405
    /* grab the current status of carp */
406
    $status = `/sbin/sysctl net.inet.carp.allow | cut -d" " -f2`;
407
    if(intval($status) == "0") return false;
408
    return true;
409
}
410

    
411
/*
412
 * convert_ip_to_network_format($ip, $subnet): converts an ip address to network form
413

    
414
 */
415
function convert_ip_to_network_format($ip, $subnet) {
416
	$ipsplit = split('[.]', $ip);
417
	$string = $ipsplit[0] . "." . $ipsplit[1] . "." . $ipsplit[2] . ".0/" . $subnet;
418
	return $string;
419
}
420

    
421
/*
422
 * get_carp_interface_status($carpinterface): returns the status of a carp ip
423
 */
424
function get_carp_interface_status($carpinterface) {
425
	/* basically cache the contents of ifconfig statement
426
	to speed up this routine */
427
	global $carp_query;
428
	if($carp_query == "")
429
		$carp_query = split("\n", `/sbin/ifconfig $carpinterface | grep carp`);
430
	foreach($carp_query as $int) {
431
		if(stristr($int, "MASTER")) 
432
			return "MASTER";
433
		if(stristr($int, "BACKUP")) 
434
			return "BACKUP";
435
		if(stristr($int, "INIT")) 
436
			return "INIT";
437
	}
438
	return;
439
}
440

    
441
/*
442
 * get_pfsync_interface_status($pfsyncinterface): returns the status of a pfsync
443
 */
444
function get_pfsync_interface_status($pfsyncinterface) {
445
    $result = does_interface_exist($pfsyncinterface);
446
    if($result <> true) return;
447
    $status = exec_command("/sbin/ifconfig {$pfsyncinterface} | /usr/bin/awk '/pfsync:/ {print \$5}'");
448
    return $status;
449
}
450

    
451
/*
452
 * add_rule_to_anchor($anchor, $rule): adds the specified rule to an anchor
453
 */
454
function add_rule_to_anchor($anchor, $rule, $label) {
455
	mwexec("echo " . $rule . " | /sbin/pfctl -a " . $anchor . ":" . $label . " -f -");
456
}
457

    
458
/*
459
 * remove_text_from_file
460
 * remove $text from file $file
461
 */
462
function remove_text_from_file($file, $text) {
463
	global $fd_log;
464
	if($fd_log)
465
		fwrite($fd_log, "Adding needed text items:\n");
466
	$filecontents = file_get_contents($file);
467
	$textTMP = str_replace($text, "", $filecontents);
468
	$text = $textTMP;
469
	if($fd_log)
470
		fwrite($fd_log, $text);
471
	$fd = fopen($file, "w");
472
	fwrite($fd, $text);
473
	fclose($fd);
474
}
475

    
476
/*
477
 * add_text_to_file($file, $text): adds $text to $file.
478
 * replaces the text if it already exists.
479
 */
480
function add_text_to_file($file, $text, $replace = false) {
481
	if(file_exists($file) and is_writable($file)) {
482
		$filecontents = file($file);
483
		$fout = fopen($file, "w");
484

    
485
		$filecontents = array_map('rtrim', $filecontents);
486
		array_push($filecontents, $text);
487
		if ($replace)
488
			$filecontents = array_unique($filecontents);
489

    
490
		$file_text = implode("\n", $filecontents);
491

    
492
		fwrite($fout, $file_text);
493
		fclose($fout);
494
		return true;
495
	} else {
496
		return false;
497
	}
498
}
499

    
500
/*
501
 *   after_sync_bump_adv_skew(): create skew values by 1S
502
 */
503
function after_sync_bump_adv_skew() {
504
	global $config, $g;
505
	$processed_skew = 1;
506
	$a_vip = &$config['virtualip']['vip'];
507
	foreach ($a_vip as $vipent) {
508
		if($vipent['advskew'] <> "") {
509
			$processed_skew = 1;
510
			$vipent['advskew'] = $vipent['advskew']+1;
511
		}
512
	}
513
	if($processed_skew == 1)
514
		write_config("After synch increase advertising skew");
515
}
516

    
517
/*
518
 * get_filename_from_url($url): converts a url to its filename.
519
 */
520
function get_filename_from_url($url) {
521
	return basename($url);
522
}
523

    
524
/*
525
 *   get_dir: return an array of $dir
526
 */
527
function get_dir($dir) {
528
	$dir_array = array();
529
	$d = dir($dir);
530
	while (false !== ($entry = $d->read())) {
531
		array_push($dir_array, $entry);
532
	}
533
	$d->close();
534
	return $dir_array;
535
}
536

    
537
/****f* pfsense-utils/WakeOnLan
538
 * NAME
539
 *   WakeOnLan - Wake a machine up using the wake on lan format/protocol
540
 * RESULT
541
 *   true/false - true if the operation was successful
542
 ******/
543
function WakeOnLan($addr, $mac)
544
{
545
	$addr_byte = explode(':', $mac);
546
	$hw_addr = '';
547

    
548
	for ($a=0; $a < 6; $a++)
549
		$hw_addr .= chr(hexdec($addr_byte[$a]));
550

    
551
	$msg = chr(255).chr(255).chr(255).chr(255).chr(255).chr(255);
552

    
553
	for ($a = 1; $a <= 16; $a++)
554
		$msg .= $hw_addr;
555

    
556
	// send it to the broadcast address using UDP
557
	$s = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
558
	if ($s == false) {
559
		log_error("Error creating socket!");
560
		log_error("Error code is '".socket_last_error($s)."' - " . socket_strerror(socket_last_error($s)));
561
	} else {
562
		// setting a broadcast option to socket:
563
		$opt_ret =  socket_set_option($s, 1, 6, TRUE);
564
		if($opt_ret < 0)
565
			log_error("setsockopt() failed, error: " . strerror($opt_ret));
566
		$e = socket_sendto($s, $msg, strlen($msg), 0, $addr, 2050);
567
		socket_close($s);
568
		log_error("Magic Packet sent ({$e}) to {$addr} MAC={$mac}");
569
		return true;
570
	}
571

    
572
	return false;
573
}
574

    
575
/*
576
 * gather_altq_queue_stats():  gather altq queue stats and return an array that
577
 *                             is queuename|qlength|measured_packets
578
 *                             NOTE: this command takes 5 seconds to run
579
 */
580
function gather_altq_queue_stats($dont_return_root_queues) {
581
	exec("/sbin/pfctl -vvsq", $stats_array);
582
	$queue_stats = array();
583
	foreach ($stats_array as $stats_line) {
584
		$match_array = "";
585
		if (preg_match_all("/queue\s+(\w+)\s+/",$stats_line,$match_array))
586
			$queue_name = $match_array[1][0];
587
		if (preg_match_all("/measured:\s+.*packets\/s\,\s(.*)\s+\]/",$stats_line,$match_array))
588
			$speed = $match_array[1][0];
589
		if (preg_match_all("/borrows:\s+(.*)/",$stats_line,$match_array))
590
			$borrows = $match_array[1][0];
591
		if (preg_match_all("/suspends:\s+(.*)/",$stats_line,$match_array))
592
			$suspends = $match_array[1][0];
593
		if (preg_match_all("/dropped pkts:\s+(.*)/",$stats_line,$match_array))
594
			$drops = $match_array[1][0];
595
		if (preg_match_all("/measured:\s+(.*)packets/",$stats_line,$match_array)) {
596
			$measured = $match_array[1][0];
597
			if($dont_return_root_queues == true)
598
				if(stristr($queue_name,"root_") == false)
599
					array_push($queue_stats, "{$queue_name}|{$speed}|{$measured}|{$borrows}|{$suspends}|{$drops}");
600
		}
601
	}
602
	return $queue_stats;
603
}
604

    
605
/*
606
 * reverse_strrchr($haystack, $needle):  Return everything in $haystack up to the *last* instance of $needle.
607
 *					 Useful for finding paths and stripping file extensions.
608
 */
609
function reverse_strrchr($haystack, $needle) {
610
	if (!is_string($haystack))
611
		return;
612
	return strrpos($haystack, $needle) ? substr($haystack, 0, strrpos($haystack, $needle) +1 ) : false;
613
}
614

    
615
/*
616
 *  backup_config_section($section): returns as an xml file string of
617
 *                                   the configuration section
618
 */
619
function backup_config_section($section) {
620
	global $config;
621
	$new_section = &$config[$section];
622
	/* generate configuration XML */
623
	$xmlconfig = dump_xml_config($new_section, $section);
624
	$xmlconfig = str_replace("<?xml version=\"1.0\"?>", "", $xmlconfig);
625
	return $xmlconfig;
626
}
627

    
628
/*
629
 *  restore_config_section($section, new_contents): restore a configuration section,
630
 *                                                  and write the configuration out
631
 *                                                  to disk/cf.
632
 */
633
function restore_config_section($section, $new_contents) {
634
	global $config, $g;
635
	conf_mount_rw();
636
	$fout = fopen("{$g['tmp_path']}/tmpxml","w");
637
	fwrite($fout, $new_contents);
638
	fclose($fout);
639
	$section_xml = parse_xml_config($g['tmp_path'] . "/tmpxml", $section);
640
	if ($section_xml != -1)
641
		$config[$section] = &$section_xml;
642
	@unlink($g['tmp_path'] . "/tmpxml");
643
	write_config("Restored {$section} of config file (maybe from CARP partner)");
644
	conf_mount_ro();
645
	return;
646
}
647

    
648
/*
649
 *  merge_config_section($section, new_contents):   restore a configuration section,
650
 *                                                  and write the configuration out
651
 *                                                  to disk/cf.  But preserve the prior
652
 * 													structure if needed
653
 */
654
function merge_config_section($section, $new_contents) {
655
	global $config;
656
	conf_mount_rw();
657
	$fname = get_tmp_filename();
658
	$fout = fopen($fname, "w");
659
	fwrite($fout, $new_contents);
660
	fclose($fout);
661
	$section_xml = parse_xml_config($fname, $section);
662
	$config[$section] = $section_xml;
663
	unlink($fname);
664
	write_config("Restored {$section} of config file (maybe from CARP partner)");
665
	conf_mount_ro();
666
	return;
667
}
668

    
669
/*
670
 * http_post($server, $port, $url, $vars): does an http post to a web server
671
 *                                         posting the vars array.
672
 * written by nf@bigpond.net.au
673
 */
674
function http_post($server, $port, $url, $vars) {
675
	$user_agent = "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98)";
676
	$urlencoded = "";
677
	while (list($key,$value) = each($vars))
678
		$urlencoded.= urlencode($key) . "=" . urlencode($value) . "&";
679
	$urlencoded = substr($urlencoded,0,-1);
680
	$content_length = strlen($urlencoded);
681
	$headers = "POST $url HTTP/1.1
682
Accept: */*
683
Accept-Language: en-au
684
Content-Type: application/x-www-form-urlencoded
685
User-Agent: $user_agent
686
Host: $server
687
Connection: Keep-Alive
688
Cache-Control: no-cache
689
Content-Length: $content_length
690

    
691
";
692

    
693
	$errno = "";
694
	$errstr = "";
695
	$fp = fsockopen($server, $port, $errno, $errstr);
696
	if (!$fp) {
697
		return false;
698
	}
699

    
700
	fputs($fp, $headers);
701
	fputs($fp, $urlencoded);
702

    
703
	$ret = "";
704
	while (!feof($fp))
705
		$ret.= fgets($fp, 1024);
706
	fclose($fp);
707

    
708
	return $ret;
709
}
710

    
711
/*
712
 *  php_check_syntax($code_tocheck, $errormessage): checks $code_to_check for errors
713
 */
714
if (!function_exists('php_check_syntax')){
715
	global $g;
716
	function php_check_syntax($code_to_check, &$errormessage){
717
		return false;
718
		$fout = fopen("{$g['tmp_path']}/codetocheck.php","w");
719
		$code = $_POST['content'];
720
		$code = str_replace("<?php", "", $code);
721
		$code = str_replace("?>", "", $code);
722
		fwrite($fout, "<?php\n\n");
723
		fwrite($fout, $code_to_check);
724
		fwrite($fout, "\n\n?>\n");
725
		fclose($fout);
726
		$command = "/usr/local/bin/php -l {$g['tmp_path']}/codetocheck.php";
727
		$output = exec_command($command);
728
		if (stristr($output, "Errors parsing") == false) {
729
			echo "false\n";
730
			$errormessage = '';
731
			return(false);
732
		} else {
733
			$errormessage = $output;
734
			return(true);
735
		}
736
	}
737
}
738

    
739
/*
740
 *  php_check_filename_syntax($filename, $errormessage): checks the file $filename for errors
741
 */
742
if (!function_exists('php_check_syntax')){
743
	function php_check_syntax($code_to_check, &$errormessage){
744
		return false;
745
		$command = "/usr/local/bin/php -l " . $code_to_check;
746
		$output = exec_command($command);
747
		if (stristr($output, "Errors parsing") == false) {
748
			echo "false\n";
749
			$errormessage = '';
750
			return(false);
751
		} else {
752
			$errormessage = $output;
753
			return(true);
754
		}
755
	}
756
}
757

    
758
/*
759
 * rmdir_recursive($path,$follow_links=false)
760
 * Recursively remove a directory tree (rm -rf path)
761
 * This is for directories _only_
762
 */
763
function rmdir_recursive($path,$follow_links=false) {
764
	$to_do = glob($path);
765
	if(!is_array($to_do)) $to_do = array($to_do);
766
	foreach($to_do as $workingdir) { // Handle wildcards by foreaching.
767
		if(file_exists($workingdir)) {
768
			if(is_dir($workingdir)) {
769
				$dir = opendir($workingdir);
770
				while ($entry = readdir($dir)) {
771
					if (is_file("$workingdir/$entry") || ((!$follow_links) && is_link("$workingdir/$entry")))
772
						unlink("$workingdir/$entry");
773
					elseif (is_dir("$workingdir/$entry") && $entry!='.' && $entry!='..')
774
						rmdir_recursive("$workingdir/$entry");
775
				}
776
				closedir($dir);
777
				rmdir($workingdir);
778
			} elseif (is_file($workingdir)) {
779
				unlink($workingdir);
780
			}
781
               	}
782
	}
783
	return;
784
}
785

    
786
/*
787
 * call_pfsense_method(): Call a method exposed by the pfsense.com XMLRPC server.
788
 */
789
function call_pfsense_method($method, $params, $timeout = 0) {
790
	global $g, $config;
791

    
792
	$ip = gethostbyname($g['product_website']);
793
	if($ip == $g['product_website'])
794
		return false;
795

    
796
	$xmlrpc_base_url = isset($config['system']['altpkgrepo']['enable']) ? $config['system']['altpkgrepo']['xmlrpcbaseurl'] : $g['xmlrpcbaseurl'];
797
	$xmlrpc_path = $g['xmlrpcpath'];
798
	$msg = new XML_RPC_Message($method, array(XML_RPC_Encode($params)));
799
	$cli = new XML_RPC_Client($xmlrpc_path, $xmlrpc_base_url);
800
	// If the ALT PKG Repo has a username/password set, use it.
801
	if($config['system']['altpkgrepo']['username'] && 
802
	   $config['system']['altpkgrepo']['password']) {
803
		$username = $config['system']['altpkgrepo']['username'];
804
		$password = $config['system']['altpkgrepo']['password'];
805
		$cli->setCredentials($username, $password);
806
	}
807
	$resp = $cli->send($msg, $timeout);
808
	if(!$resp) {
809
		log_error("XMLRPC communication error: " . $cli->errstr);
810
		return false;
811
	} elseif($resp->faultCode()) {
812
		log_error("XMLRPC request failed with error " . $resp->faultCode() . ": " . $resp->faultString());
813
		return false;
814
	} else {
815
		return XML_RPC_Decode($resp->value());
816
	}
817
}
818

    
819
/*
820
 * check_firmware_version(): Check whether the current firmware installed is the most recently released.
821
 */
822
function check_firmware_version($tocheck = "all", $return_php = true) {
823
	global $g, $config;
824
	$ip = gethostbyname($g['product_website']);
825
	if($ip == $g['product_website'])
826
		return false;
827
	$rawparams = array("firmware" => array("version" => trim(file_get_contents('/etc/version'))),
828
		"kernel"   => array("version" => trim(file_get_contents('/etc/version_kernel'))),
829
		"base"     => array("version" => trim(file_get_contents('/etc/version_base'))),
830
		"platform" => trim(file_get_contents('/etc/platform'))
831
		);
832
	if($tocheck == "all") {
833
		$params = $rawparams;
834
	} else {
835
		foreach($tocheck as $check) {
836
			$params['check'] = $rawparams['check'];
837
			$params['platform'] = $rawparams['platform'];
838
		}
839
	}
840
	if($config['system']['firmware']['branch']) {
841
		$params['branch'] = $config['system']['firmware']['branch'];
842
	}
843
	if(!$versions = call_pfsense_method('pfsense.get_firmware_version', $params)) {
844
		return false;
845
	} else {
846
		$versions["current"] = $params;
847
	}
848
	return $versions;
849
}
850

    
851
function get_disk_info() {
852
	$diskout = "";
853
	exec("/bin/df -h | /usr/bin/grep -w '/' | /usr/bin/awk '{ print $2, $3, $4, $5 }'", $diskout);
854
	return explode(' ', $diskout[0]);
855
	// $size, $used, $avail, $cap
856
}
857

    
858
/****f* pfsense-utils/strncpy
859
 * NAME
860
 *   strncpy - copy strings
861
 * INPUTS
862
 *   &$dst, $src, $length
863
 * RESULT
864
 *   none
865
 ******/
866
function strncpy(&$dst, $src, $length) {
867
	if (strlen($src) > $length) {
868
		$dst = substr($src, 0, $length);
869
	} else {
870
		$dst = $src;
871
	}
872
}
873

    
874
/****f* pfsense-utils/reload_interfaces_sync
875
 * NAME
876
 *   reload_interfaces - reload all interfaces
877
 * INPUTS
878
 *   none
879
 * RESULT
880
 *   none
881
 ******/
882
function reload_interfaces_sync() {
883
	global $config, $g;
884

    
885
	/* XXX: Use locks?! */
886
	if (file_exists("{$g['tmp_path']}/reloading_all")) {
887
		log_error("WARNING: Recursive call to interfaces sync!");
888
		return;
889
	}
890
	touch("{$g['tmp_path']}/reloading_all");
891

    
892
	if($g['debug'])
893
		log_error("reload_interfaces_sync() is starting.");
894

    
895
	/* parse config.xml again */
896
	$config = parse_config(true);
897

    
898
	/* enable routing */
899
	system_routing_enable();
900
	if($g['debug'])
901
		log_error("Enabling system routing");
902

    
903
	if($g['debug'])
904
		log_error("Cleaning up Interfaces");
905

    
906
	/* set up interfaces */
907
	interfaces_configure();
908

    
909
	/* remove reloading_all trigger */
910
	if($g['debug'])
911
		log_error("Removing {$g['tmp_path']}/reloading_all");
912

    
913
	/* start devd back up */
914
	mwexec("/bin/rm {$g['tmp_path']}/reload*");
915
}
916

    
917
/****f* pfsense-utils/reload_all
918
 * NAME
919
 *   reload_all - triggers a reload of all settings
920
 *   * INPUTS
921
 *   none
922
 * RESULT
923
 *   none
924
 ******/
925
function reload_all() {
926
	global $g;
927
	touch("{$g['tmp_path']}/reload_all");
928
}
929

    
930
/****f* pfsense-utils/reload_interfaces
931
 * NAME
932
 *   reload_interfaces - triggers a reload of all interfaces
933
 * INPUTS
934
 *   none
935
 * RESULT
936
 *   none
937
 ******/
938
function reload_interfaces() {
939
	global $g;
940
	touch("{$g['tmp_path']}/reload_interfaces");
941
}
942

    
943
/****f* pfsense-utils/reload_all_sync
944
 * NAME
945
 *   reload_all - reload all settings
946
 *   * INPUTS
947
 *   none
948
 * RESULT
949
 *   none
950
 ******/
951
function reload_all_sync() {
952
	global $config, $g;
953

    
954
	$g['booting'] = false;
955

    
956
	/* XXX: Use locks?! */
957
        if (file_exists("{$g['tmp_path']}/reloading_all")) {
958
                log_error("WARNING: Recursive call to reload all sync!");
959
                return;
960
        }
961
	touch("{$g['tmp_path']}/reloading_all");
962

    
963
	/* parse config.xml again */
964
	$config = parse_config(true);
965

    
966
	/* set up our timezone */
967
	system_timezone_configure();
968

    
969
	/* set up our hostname */
970
	system_hostname_configure();
971

    
972
	/* make hosts file */
973
	system_hosts_generate();
974

    
975
	/* generate resolv.conf */
976
	system_resolvconf_generate();
977

    
978
	/* enable routing */
979
	system_routing_enable();
980

    
981
	/* set up interfaces */
982
	interfaces_configure();
983

    
984
	/* start dyndns service */
985
	services_dyndns_configure();
986

    
987
	/* configure cron service */
988
	configure_cron();
989

    
990
	/* start the NTP client */
991
	system_ntp_configure();
992

    
993
	/* sync pw database */
994
	conf_mount_rw();
995
	unlink_if_exists("/etc/spwd.db.tmp");
996
	mwexec("/usr/sbin/pwd_mkdb -d /etc/ /etc/master.passwd");
997
	conf_mount_ro();
998

    
999
	/* restart sshd */
1000
	@touch("{$g['tmp_path']}/start_sshd");
1001

    
1002
	/* restart webConfigurator if needed */
1003
	touch("{$g['tmp_path']}/restart_webgui");
1004

    
1005
	mwexec("/bin/rm {$g['tmp_path']}/reload*");
1006
}
1007

    
1008
function auto_login() {
1009
	global $config;
1010

    
1011
	if(isset($config['system']['disableconsolemenu']))
1012
		$status = false;
1013
	else
1014
		$status = true;
1015

    
1016
	$gettytab = file_get_contents("/etc/gettytab");
1017
	$getty_split = split("\n", $gettytab);
1018
	conf_mount_rw();
1019
	$fd = false;
1020
	$tries = 0;
1021
	while (!$fd && $tries < 100) {
1022
		$fd = fopen("/etc/gettytab", "w");
1023
		$tries++;
1024
		
1025
	}
1026
	if (!$fd) {
1027
		conf_mount_ro();
1028
		log_error("Enabling auto login was not possible.");
1029
		return;
1030
	}
1031
	foreach($getty_split as $gs) {
1032
		if(stristr($gs, ":ht:np:sp#115200") ) {
1033
			if($status == true) {
1034
				fwrite($fd, "	:ht:np:sp#115200:al=root:\n");
1035
			} else {
1036
				fwrite($fd, "	:ht:np:sp#115200:\n");
1037
			}
1038
		} else {
1039
			fwrite($fd, "{$gs}\n");
1040
		}
1041
	}
1042
	fclose($fd);
1043
	conf_mount_ro();
1044
}
1045

    
1046
function setup_serial_port() {
1047
	global $g, $config;
1048
	conf_mount_rw();
1049
	/* serial console - write out /boot.config */
1050
	if(file_exists("/boot.config"))
1051
		$boot_config = file_get_contents("/boot.config");
1052
	else
1053
		$boot_config = "";
1054

    
1055
	if($g['platform'] <> "cdrom") {
1056
		$boot_config_split = split("\n", $boot_config);
1057
		$fd = fopen("/boot.config","w");
1058
		if($fd) {
1059
			foreach($boot_config_split as $bcs) {
1060
				if(stristr($bcs, "-D")) {
1061
					/* DONT WRITE OUT, WE'LL DO IT LATER */
1062
				} else {
1063
					if($bcs <> "")
1064
						fwrite($fd, "{$bcs}\n");
1065
				}
1066
			}
1067
			if(isset($config['system']['enableserial'])) {
1068
				fwrite($fd, "-D");
1069
			}
1070
			fclose($fd);
1071
		}
1072
		/* serial console - write out /boot/loader.conf */
1073
		$boot_config = file_get_contents("/boot/loader.conf");
1074
		$boot_config_split = split("\n", $boot_config);
1075
		$fd = fopen("/boot/loader.conf","w");
1076
		if($fd) {
1077
			foreach($boot_config_split as $bcs) {
1078
				if(stristr($bcs, "console")) {
1079
					/* DONT WRITE OUT, WE'LL DO IT LATER */
1080
				} else {
1081
					if($bcs <> "")
1082
						fwrite($fd, "{$bcs}\n");
1083
				}
1084
			}
1085
			if(isset($config['system']['enableserial'])) {
1086
				fwrite($fd, "console=\"comconsole\"\n");
1087
			}
1088
			fclose($fd);
1089
		}
1090
	}
1091
	$ttys = file_get_contents("/etc/ttys");
1092
	$ttys_split = split("\n", $ttys);
1093
	$fd = fopen("/etc/ttys", "w");
1094
	foreach($ttys_split as $tty) {
1095
		if(stristr($tty, "ttyd0") or stristr($tty, "ttyu0")) {
1096
			if(isset($config['system']['enableserial'])) {
1097
				fwrite($fd, "ttyu0	\"/usr/libexec/getty bootupcli\"	dialup	on	secure\n");
1098
			} else {
1099
				fwrite($fd, "ttyu0	\"/usr/libexec/getty bootupcli\"	dialup	off	secure\n");
1100
			}
1101
		} else {
1102
			fwrite($fd, $tty . "\n");
1103
		}
1104
	}
1105
	fclose($fd);
1106
	auto_login();
1107

    
1108
	conf_mount_ro();
1109
	return;
1110
}
1111

    
1112
function print_value_list($list, $count = 10, $separator = ",") {
1113
	$list = implode($separator, array_slice($list, 0, $count));
1114
	if(count($list) < $count) {
1115
		$list .= ".";
1116
	} else {
1117
		$list .= "...";
1118
	}
1119
	return $list;
1120
}
1121

    
1122
/* DHCP enabled on any interfaces? */
1123
function is_dhcp_server_enabled() 
1124
{
1125
	global $config;
1126

    
1127
	$dhcpdenable = false;
1128
	
1129
	if (!is_array($config['dhcpd']))
1130
		return false;
1131

    
1132
	$Iflist = get_configured_interface_list();
1133

    
1134
	foreach ($config['dhcpd'] as $dhcpif => $dhcpifconf) {
1135
		if (isset($dhcpifconf['enable']) && isset($Iflist[$dhcpif])) {
1136
			$dhcpdenable = true;
1137
			break;
1138
		}
1139
	}
1140

    
1141
	return $dhcpdenable;
1142
}
1143

    
1144
function convert_seconds_to_hms($sec){
1145
	$min=$hrs=0;
1146
	if ($sec != 0){
1147
		$min = floor($sec/60);
1148
		$sec %= 60;
1149
	}
1150
	if ($min != 0){
1151
		$hrs = floor($min/60);
1152
		$min %= 60;
1153
	}
1154
	if ($sec < 10)
1155
		$sec = "0".$sec;
1156
	if ($min < 10)
1157
		$min = "0".$min;
1158
	if ($hrs < 10)
1159
		$hrs = "0".$hrs;
1160
	$result = $hrs.":".$min.":".$sec;
1161
	return $result;
1162
}
1163

    
1164
/* Compute the total uptime from the ppp uptime log file in the conf directory */
1165
/* Written by: gnoahb@gmail.com */
1166

    
1167
function get_ppp_uptime($port){
1168
	if (file_exists("/conf/{$port}.log")){
1169
    	$saved_time = file_get_contents("/conf/{$port}.log");
1170
    	$uptime_data = explode("\n",$saved_time);
1171
		$sec=0;
1172
		foreach($uptime_data as $upt) {
1173
			$sec += substr($upt, 1 + strpos($upt, " "));
1174
 		}
1175
		return convert_seconds_to_hms($sec);
1176
	} else {
1177
		$total_time = "No session history data found!";
1178
		return $total_time;
1179
	}
1180
}
1181

    
1182
//returns interface information
1183
function get_interface_info($ifdescr) {
1184
	global $config, $linkinfo, $netstatrninfo, $g;
1185

    
1186
	$ifinfo = array();
1187
	/* if list */
1188
	$iflist = get_configured_interface_with_descr(false,true);
1189

    
1190
	$found = false;
1191
    	foreach ($iflist as $if => $ifname) {
1192
    		if ($ifdescr == $if || $ifdescr == $ifname) {
1193
			$ifinfo['hwif'] = $config['interfaces'][$if]['if'];
1194
			$ifinfo['if'] = get_real_interface($if);
1195
			$found = true;
1196
			break;
1197
		}
1198
	}
1199
	if ($found == false)
1200
		return;
1201

    
1202
	/* run netstat to determine link info */
1203

    
1204
	unset($linkinfo);
1205
	$chkif = $ifinfo['if'];
1206

    
1207
	exec("/usr/bin/netstat -I {$chkif} -nWb -f link", $linkinfo);
1208
	$linkinfo = preg_split("/\s+/", $linkinfo[1]);
1209

    
1210
	$ifinfotmp = pfSense_get_interface_addresses($chkif);
1211
	$ifinfo['status'] = $ifinfotmp['status'];
1212
	$ifinfo['macaddr'] = $ifinfotmp['macaddr'];
1213
	$ifinfo['ipaddr'] = $ifinfotmp['ipaddr'];
1214
	$ifinfo['subnet'] = $ifinfotmp['subnet'];
1215
	if (isset($ifinfotmp['link0']))
1216
		$link0 = "down";
1217

    
1218
	
1219
	if (preg_match("/^enc|^tun|^ppp|^pptp|^ovpn/i", $chkif)) {
1220
		$ifinfo['inpkts'] = $linkinfo[3];
1221
		$ifinfo['outpkts'] = $linkinfo[6];
1222
	} else {
1223
		$ifinfo['inerrs'] = $linkinfo[5];
1224
		$ifinfo['outerrs'] = $linkinfo[9];
1225
		$ifinfo['collisions'] = $linkinfo[11];
1226
	}
1227

    
1228
	/* Use pfctl for non wrapping 64 bit counters */
1229
	/* Pass */
1230
	exec("/sbin/pfctl -vvsI -i {$chkif}", $pfctlstats);
1231
	$pf_in4_pass = preg_split("/ +/ ", $pfctlstats[3]);
1232
	$pf_out4_pass = preg_split("/ +/", $pfctlstats[5]);
1233
	$in4_pass = $pf_in4_pass[5];
1234
	$out4_pass = $pf_out4_pass[5];
1235
	$in4_pass_packets = $pf_in4_pass[3];
1236
	$out4_pass_packets = $pf_out4_pass[3];
1237
	$ifinfo['inbytespass'] = $in4_pass;
1238
	$ifinfo['outbytespass'] = $out4_pass;
1239
	$ifinfo['inpktspass'] = $in4_pass_packets;
1240
	$ifinfo['outpktspass'] = $out4_pass_packets;
1241

    
1242
	/* Block */
1243
	$pf_in4_block = preg_split("/ +/", $pfctlstats[4]);
1244
	$pf_out4_block = preg_split("/ +/", $pfctlstats[6]);
1245
	$in4_block = $pf_in4_block[5];
1246
	$out4_block = $pf_out4_block[5];
1247
	$in4_block_packets = $pf_in4_block[3];
1248
	$out4_block_packets = $pf_out4_block[3];
1249
	$ifinfo['inbytesblock'] = $in4_block;
1250
	$ifinfo['outbytesblock'] = $out4_block;
1251
	$ifinfo['inpktsblock'] = $in4_block_packets;
1252
	$ifinfo['outpktsblock'] = $out4_block_packets;
1253

    
1254
	$ifinfo['inbytes'] = $in4_pass + $in4_block;
1255
	$ifinfo['outbytes'] = $out4_pass + $out4_block;
1256
	$ifinfo['inpkts'] = $in4_pass_packets + $in4_block_packets;
1257
	$ifinfo['outpkts'] = $in4_pass_packets + $out4_block_packets;
1258
		
1259
	$ifconfiginfo = "";
1260
	
1261
	unset($linkinfo);
1262
	exec("/usr/bin/netstat -I " . $ifinfo['if'] . " -nWb -f link", $linkinfo);
1263
	$linkinfo = preg_split("/\s+/", $linkinfo[1]);
1264
	
1265
	switch ($config['interfaces'][$ifdescr]['ipaddr']) {
1266
	 /* DHCP? -> see if dhclient is up */
1267
	case "dhcp":
1268
	case "carpdev-dhcp":
1269
		/* see if dhclient is up */
1270
		if (find_dhclient_process($ifinfo['if']) <> "")
1271
			$ifinfo['dhcplink'] = "up";
1272
		else
1273
			$ifinfo['dhcplink'] = "down";
1274

    
1275
		break;
1276
	/* PPPoE interface? -> get status from virtual interface */
1277
	case "pppoe":
1278
		if ("{$ifinfo['if']}*" == $linkinfo[0])
1279
			$ifinfo['pppoelink'] = "down";
1280
		else if ($ifinfo['if'] == $linkinfo[0] && !isset($link0))
1281
			/* get PPPoE link status for dial on demand */
1282
			$ifinfo['pppoelink'] = "up";
1283
		else
1284
			$ifinfo['pppoelink'] = "down";
1285

    
1286
		break;
1287
	/* PPTP interface? -> get status from virtual interface */
1288
	case "pptp":
1289
		if ("{$ifinfo['if']}*" == $linkinfo[0])
1290
			$ifinfo['pptplink'] = "down";
1291
		else if ($ifinfo['if'] == $linkinfo[0] && !isset($link0))
1292
			/* get PPTP link status for dial on demand */
1293
			$ifinfo['pptplink'] = "up";
1294
		else
1295
			$ifinfo['pptplink'] = "down";
1296
		break;
1297
	/* PPP interface? -> get uptime for this session and cumulative uptime from the persistant log file in conf */
1298
	case "ppp":
1299
		if ("{$ifinfo['if']}*" == $linkinfo[0])
1300
			$ifinfo['ppplink'] = "down";
1301
		else if ($ifinfo['if'] == $linkinfo[0])
1302
			$ifinfo['ppplink'] = "up";
1303
		else
1304
			$ifinfo['ppplink'] = "down" ;
1305
		if (empty($ifinfo['status']))
1306
			$ifinfo['status'] = "down";
1307

    
1308
		$dev = $config['interfaces'][$if]['if'];
1309
		if (empty($dev))
1310
			break;
1311
		if (file_exists("/dev/{$dev}")) {
1312
			if (file_exists("{$g['varrun_path']}/ppp_{$if}.pid")) {
1313
				$ifinfo['pppinfo'] = "{$ifinfo['if']}";
1314
				$sec = trim(`/usr/local/sbin/ppp-uptime.sh {$ifinfo['if']}`);
1315
        		$ifinfo['ppp_uptime'] = convert_seconds_to_hms($sec);
1316
			}
1317
		} else {
1318
			$ifinfo['nodevice'] = 1;
1319
			$ifinfo['pppinfo'] = $dev . " device not present! Is the modem attached to the system?";	
1320
		}
1321
		// Calculate cumulative uptime for PPP link. Useful for connections that have per minute/hour contracts so you don't go over!
1322
		$ifinfo['ppp_uptime_accumulated'] = get_ppp_uptime($ifinfo['if']);
1323

    
1324
		break;
1325
	default:
1326
		break;
1327
	}
1328

    
1329
	if ($ifinfo['status'] == "up") {
1330
		/* try to determine media with ifconfig */
1331
		unset($ifconfiginfo);
1332
		exec("/sbin/ifconfig " . $ifinfo['if'], $ifconfiginfo);
1333
		$wifconfiginfo = array();
1334
		if(is_interface_wireless($ifdescr)) {
1335
			exec("/sbin/ifconfig {$ifinfo['if']} list sta", $wifconfiginfo);
1336
			array_shift($wifconfiginfo);
1337
		}
1338
		$matches = "";
1339
		foreach ($ifconfiginfo as $ici) {
1340

    
1341
			/* don't list media/speed for wireless cards, as it always
1342
			   displays 2 Mbps even though clients can connect at 11 Mbps */
1343
			if (preg_match("/media: .*? \((.*?)\)/", $ici, $matches)) {
1344
				$ifinfo['media'] = $matches[1];
1345
			} else if (preg_match("/media: Ethernet (.*)/", $ici, $matches)) {
1346
				$ifinfo['media'] = $matches[1];
1347
			} else if (preg_match("/media: IEEE 802.11 Wireless Ethernet (.*)/", $ici, $matches)) {
1348
				$ifinfo['media'] = $matches[1];
1349
			}
1350

    
1351
			if (preg_match("/status: (.*)$/", $ici, $matches)) {
1352
				if ($matches[1] != "active")
1353
					$ifinfo['status'] = $matches[1];
1354
				if($ifinfo['status'] == "running")
1355
					$ifinfo['status'] = "up";
1356
			}
1357
			if (preg_match("/channel (\S*)/", $ici, $matches)) {
1358
				$ifinfo['channel'] = $matches[1];
1359
			}
1360
			if (preg_match("/ssid (\".*?\"|\S*)/", $ici, $matches)) {
1361
				if ($matches[1][0] == '"')
1362
					$ifinfo['ssid'] = substr($matches[1], 1, -1);
1363
				else
1364
					$ifinfo['ssid'] = $matches[1];
1365
			}
1366
		}
1367
		foreach($wifconfiginfo as $ici) {
1368
			$elements = preg_split("/[ ]+/i", $ici);
1369
			if ($elements[0] != "") {
1370
				$ifinfo['bssid'] = $elements[0];
1371
			}
1372
			if ($elements[3] != "") {
1373
				$ifinfo['rate'] = $elements[3];
1374
			}
1375
			if ($elements[4] != "") {
1376
				$ifinfo['rssi'] = $elements[4];
1377
			}
1378

    
1379
		}
1380
		/* lookup the gateway */
1381
		if (interface_has_gateway($if)) 
1382
			$ifinfo['gateway'] = get_interface_gateway($if);
1383
	}
1384

    
1385
	$bridge = "";
1386
	$bridge = link_interface_to_bridge($ifdescr);
1387
	if($bridge) {
1388
		$bridge_text = `/sbin/ifconfig {$bridge}`;
1389
		if(stristr($bridge_text, "blocking") <> false) {
1390
			$ifinfo['bridge'] = "<b><font color='red'>blocking</font></b> - check for ethernet loops";
1391
			$ifinfo['bridgeint'] = $bridge;
1392
		} else if(stristr($bridge_text, "learning") <> false) {
1393
			$ifinfo['bridge'] = "learning";
1394
			$ifinfo['bridgeint'] = $bridge;
1395
		} else if(stristr($bridge_text, "forwarding") <> false) {
1396
			$ifinfo['bridge'] = "forwarding";
1397
			$ifinfo['bridgeint'] = $bridge;
1398
		}
1399
	}
1400

    
1401
	return $ifinfo;
1402
}
1403

    
1404
//returns cpu speed of processor. Good for determining capabilities of machine
1405
function get_cpu_speed() {
1406
	 return exec("sysctl hw.clockrate | awk '{ print $2 }'");
1407
}
1408

    
1409
/* check if the wan interface is up
1410
 * Wait for a maximum of 10 seconds
1411
 * If the interface is up before then continue
1412
 */
1413
function is_wan_interface_up($interface) {
1414
	global $g;
1415
	global $config;
1416
	$i = 0;
1417
	while($i < 10) {
1418
		if(get_interface_gateway($interface)) {
1419
			return true;
1420
		} else {
1421
			sleep(1);
1422
		}
1423
		$i++;
1424
	}
1425
	return false;
1426
}
1427

    
1428
function add_hostname_to_watch($hostname) {
1429
	if(!is_dir("/var/db/dnscache")) {
1430
		mkdir("/var/db/dnscache");
1431
	}
1432
	if((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1433
		$domrecords = array();
1434
		$domips = array();
1435
		exec("host -t A $hostname", $domrecords, $rethost);
1436
		if($rethost == 0) {
1437
			foreach($domrecords as $domr) {
1438
				$doml = explode(" ", $domr);
1439
				$domip = $doml[3];
1440
				/* fill array with domain ip addresses */
1441
				if(is_ipaddr($domip)) {
1442
					$domips[] = $domip;
1443
				}
1444
			}
1445
		}
1446
		sort($domips);
1447
		$contents = "";
1448
		if(! empty($domips)) {
1449
			foreach($domips as $ip) {
1450
				$contents .= "$ip\n";
1451
			}
1452
		}
1453
		file_put_contents("/var/db/dnscache/$hostname", $contents);
1454
	}
1455
}
1456

    
1457
function is_fqdn($fqdn) {
1458
	$hostname = false;
1459
	if(preg_match("/[-A-Z0-9\.]+\.[-A-Z0-9\.]+/i", $fqdn)) {
1460
		$hostname = true;
1461
	}
1462
	if(preg_match("/\.\./", $fqdn)) {
1463
		$hostname = false;
1464
	}
1465
	if(preg_match("/^\./i", $fqdn)) { 
1466
		$hostname = false;
1467
	}
1468
	if(preg_match("/\//i", $fqdn)) {
1469
		$hostname = false;
1470
	}
1471
	return($hostname);
1472
}
1473

    
1474
function pfsense_default_state_size() {
1475
  /* get system memory amount */
1476
  $memory = get_memory();
1477
  $avail = $memory[0];
1478
  /* Be cautious and only allocate 10% of system memory to the state table */
1479
  $max_states = (int) ($avail/10)*1000;
1480
  return $max_states;
1481
}
1482

    
1483
/* Compare the current hostname DNS to the DNS cache we made
1484
 * if it has changed we return the old records
1485
 * if no change we return true */
1486
function compare_hostname_to_dnscache($hostname) {
1487
	if(!is_dir("/var/db/dnscache")) {
1488
		mkdir("/var/db/dnscache");
1489
	}
1490
	$hostname = trim($hostname);
1491
	if(is_readable("/var/db/dnscache/{$hostname}")) {
1492
		$oldcontents = file_get_contents("/var/db/dnscache/{$hostname}");
1493
	} else {
1494
		$oldcontents = "";
1495
	}
1496
	if((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1497
		$domrecords = array();
1498
		$domips = array();
1499
		exec("host -t A $hostname", $domrecords, $rethost);
1500
		if($rethost == 0) {
1501
			foreach($domrecords as $domr) {
1502
				$doml = explode(" ", $domr);
1503
				$domip = $doml[3];
1504
				/* fill array with domain ip addresses */
1505
				if(is_ipaddr($domip)) {
1506
					$domips[] = $domip;
1507
				}
1508
			}
1509
		}
1510
		sort($domips);
1511
		$contents = "";
1512
		if(! empty($domips)) {
1513
			foreach($domips as $ip) {
1514
				$contents .= "$ip\n";
1515
			}
1516
		}
1517
	}
1518

    
1519
	if(trim($oldcontents) != trim($contents)) {
1520
		if($g['debug']) {
1521
			log_error("DNSCACHE: Found old IP {$oldcontents} and new IP {$contents}");
1522
		}
1523
		return ($oldcontents);
1524
	} else {
1525
		return false;
1526
	}
1527
}
1528

    
1529
/*
1530
 * load_glxsb() - Load the glxsb crypto module if enabled in config.
1531
 */
1532
function load_glxsb() {
1533
	global $config, $g;
1534
	$is_loaded = `/sbin/kldstat | /usr/bin/grep -c glxsb`;
1535
	if (isset($config['system']['glxsb_enable']) && ($is_loaded == 0)) {
1536
		mwexec("/sbin/kldload glxsb");
1537
	}
1538
}
1539

    
1540
/****f* pfsense-utils/isvm
1541
 * NAME
1542
 *   isvm
1543
 * INPUTS
1544
 *	 none
1545
 * RESULT
1546
 *   returns true if machine is running under a virtual environment
1547
 ******/
1548
function isvm() {
1549
	$virtualenvs = array("vmware", "parallels", "qemu", "bochs", "plex86");
1550
	$bios_vendor = strtolower(`/bin/kenv | /usr/bin/awk -F= '/smbios.bios.vendor/ {print $2}'`);
1551
	if(in_array($bios_vendor, $virtualenvs)) 
1552
		return true;
1553
	else
1554
		return false;
1555
}
1556

    
1557
function get_freebsd_version() {
1558
	$version = trim(`/usr/bin/uname -r | /usr/bin/cut  -d'.' -f1`);
1559
	return $version;
1560
}
1561

    
1562
function download_file_with_progress_bar($url_file, $destination_file, $readbody = 'read_body') {
1563
        global $ch, $fout, $file_size, $downloaded;
1564
        $file_size  = 1;
1565
        $downloaded = 1;
1566
        /* open destination file */
1567
        $fout = fopen($destination_file, "wb");
1568

    
1569
        /*
1570
         *      Originally by Author: Keyvan Minoukadeh
1571
         *      Modified by Scott Ullrich to return Content-Length size
1572
         */
1573

    
1574
        $ch = curl_init();
1575
        curl_setopt($ch, CURLOPT_URL, $url_file);
1576
        curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'read_header');
1577
        curl_setopt($ch, CURLOPT_WRITEFUNCTION, $readbody);
1578
        curl_setopt($ch, CURLOPT_NOPROGRESS, '1');
1579
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, '5');
1580
        curl_setopt($ch, CURLOPT_TIMEOUT, 0);
1581

    
1582
        curl_exec($ch);
1583
        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1584
        if($fout)
1585
                fclose($fout);
1586
        curl_close($ch);
1587
        return ($http_code == 200) ? true : $http_code;
1588
}
1589

    
1590
function read_header($ch, $string) {
1591
        global $file_size, $fout;
1592
        $length = strlen($string);
1593
        $regs = "";
1594
        ereg("(Content-Length:) (.*)", $string, $regs);
1595
        if($regs[2] <> "") {
1596
                $file_size = intval($regs[2]);
1597
        }
1598
        ob_flush();
1599
        return $length;
1600
}
1601

    
1602
function read_body($ch, $string) {
1603
        global $fout, $file_size, $downloaded, $sendto, $static_status, $static_output, $lastseen;
1604
        $length = strlen($string);
1605
        $downloaded += intval($length);
1606
        $downloadProgress = round(100 * (1 - $downloaded / $file_size), 0);
1607
        $downloadProgress = 100 - $downloadProgress;
1608
        if($lastseen <> $downloadProgress and $downloadProgress < 101) {
1609
                if($sendto == "status") {
1610
                        $tostatus = $static_status . $downloadProgress . "%";
1611
                        update_status($tostatus);
1612
                } else {
1613
                        $tooutput = $static_output . $downloadProgress . "%";
1614
                        update_output_window($tooutput);
1615
                }
1616
                update_progress_bar($downloadProgress);
1617
                $lastseen = $downloadProgress;
1618
        }
1619
        if($fout)
1620
                fwrite($fout, $string);
1621
        ob_flush();
1622
        return $length;
1623
}
1624

    
1625
/*
1626
 *   update_output_window: update bottom textarea dynamically.
1627
 */
1628
function update_output_window($text) {
1629
        global $pkg_interface;
1630
        $log = ereg_replace("\n", "\\n", $text);
1631
        if($pkg_interface == "console") {
1632
                /* too chatty */
1633
        } else {
1634
                echo "\n<script language=\"JavaScript\">this.document.forms[0].output.value = \"" . $log . "\";</script>";
1635
        }
1636
        /* ensure that contents are written out */
1637
        ob_flush();
1638
}
1639

    
1640
/*
1641
 *   update_output_window: update top textarea dynamically.
1642
 */
1643
function update_status($status) {
1644
        global $pkg_interface;
1645
        if($pkg_interface == "console") {
1646
                echo $status . "\n";
1647
        } else {
1648
                echo "\n<script type=\"text/javascript\">this.document.forms[0].status.value=\"" . $status . "\";</script>";
1649
        }
1650
        /* ensure that contents are written out */
1651
        ob_flush();
1652
}
1653

    
1654
/*
1655
 * update_progress_bar($percent): updates the javascript driven progress bar.
1656
 */
1657
function update_progress_bar($percent) {
1658
        global $pkg_interface;
1659
        if($percent > 100) $percent = 1;
1660
        if($pkg_interface <> "console") {
1661
                echo "\n<script type=\"text/javascript\" language=\"javascript\">";
1662
                echo "\ndocument.progressbar.style.width='" . $percent . "%';";
1663
                echo "\n</script>";
1664
        } else {
1665
                echo " {$percent}%";
1666
        }
1667
}
1668

    
1669
/* Split() is being DEPRECATED as of PHP 5.3.0 and REMOVED as of PHP 6.0.0. Relying on this feature is highly discouraged. */
1670
if(!function_exists("split")) {
1671
	function split($seperator, $haystack, $limit = null) {
1672
		return preg_split($seperator, $haystack, $limit);
1673
	}
1674
}
1675

    
1676
function update_alias_names_upon_change($section, $subsection, $fielda, $fieldb, $new_alias_name, $origname) {
1677
	global $g, $config, $pconfig, $debug;
1678
	if(!$origname) 
1679
		return;
1680

    
1681
	if($debug) $fd = fopen("{$g['tmp_path']}/print_r", "a");
1682
	if($debug) fwrite($fd, print_r($pconfig, true));
1683

    
1684
	if($fieldb) {
1685
		if($debug) fwrite($fd, "fieldb exists\n");
1686
		for ($i = 0; isset($config["$section"]["$subsection"][$i]["$fielda"]); $i++) {
1687
			if($debug) fwrite($fd, "$i\n");
1688
			if($config["$section"]["$subsection"][$i]["$fielda"]["$fieldb"] == $origname) {
1689
				if($debug) fwrite($fd, "Setting old alias value $origname to $new_alias_name\n");
1690
				$config["$section"]["$subsection"][$i]["$fielda"]["$fieldb"] = $new_alias_name;
1691
			}
1692
		}	
1693
	} else {
1694
		if($debug) fwrite($fd, "fieldb does not exist\n");
1695
		for ($i = 0; isset($config["$section"]["$subsection"][$i]["$fielda"]); $i++) {
1696
			if($config["$section"]["$subsection"][$i]["$fielda"] == $origname) {
1697
				$config["$section"]["$subsection"][$i]["$fielda"] = $new_alias_name;
1698
				if($debug) fwrite($fd, "Setting old alias value $origname to $new_alias_name\n");
1699
			}
1700
		}
1701
	}
1702

    
1703
	if($debug) fclose($fd);
1704

    
1705
}
1706

    
1707
function update_alias_url_data() {
1708
	global $config, $g;
1709
	/* item is a url type */
1710
	$lockkey = lock('config');
1711
	for($x=0; $x<count($config['aliases']['alias']); $x++) {
1712
		if($config['aliases']['alias'][$x]['aliasurl']) {
1713
			/* fetch down and add in */
1714
			$isfirst = 0;
1715
			$temp_filename = tempnam("{$g['tmp_path']}/", "alias_import");
1716
			unlink($temp_filename);
1717
			$fda = fopen("{$g['tmp_path']}/tmpfetch","w");
1718
			fwrite($fda, "/usr/bin/fetch -q -o \"{$temp_filename}/aliases\" \"" . $config['aliases']['alias'][$x]['aliasurl'] . "\"");
1719
			fclose($fda);
1720
			mwexec("/bin/mkdir -p {$temp_filename}");
1721
			mwexec("/usr/bin/fetch -q -o \"{$temp_filename}/aliases\" \"" . $config['aliases']['alias'][$x]['aliasurl'] . "\"");
1722
			/* if the item is tar gzipped then extract */
1723
			if(stristr($config['aliases']['alias'][$x]['aliasurl'], ".tgz"))
1724
				process_alias_tgz($temp_filename);
1725
			if(stristr($config['aliases']['alias'][$x]['aliasurl'], ".zip"))
1726
				process_alias_unzip($temp_filename);
1727
			if(file_exists("{$temp_filename}/aliases")) {
1728
				$file_contents = file_get_contents("{$temp_filename}/aliases");
1729
				$file_contents = str_replace("#", "\n#", $file_contents);
1730
				$file_contents_split = split("\n", $file_contents);
1731
				foreach($file_contents_split as $fc) {
1732
					$tmp = trim($fc);
1733
					if(stristr($fc, "#")) {
1734
						$tmp_split = split("#", $tmp);
1735
						$tmp = trim($tmp_split[0]);
1736
					}
1737
					if(trim($tmp) <> "") {
1738
						if($isfirst == 1)
1739
							$address .= " ";
1740
						$address .= $tmp;
1741
						$isfirst = 1;
1742
					}
1743
				}
1744
				if($isfirst == 0) {
1745
					/* nothing was found */
1746
					$dont_update = true;
1747
					break;
1748
				}
1749
				if(!$dont_update) {
1750
					$config['aliases']['alias'][$x]['address'] = $address;
1751
					$updated = true;
1752
				}
1753
				mwexec("/bin/rm -rf {$temp_filename}");
1754
			}
1755
		}
1756
	}
1757
	if($updated)
1758
		write_config();
1759
	unlock($lockkey);
1760
}
1761

    
1762
function process_alias_unzip($temp_filename) {
1763
	if(!file_exists("/usr/local/bin/unzip"))
1764
		return;
1765
	mwexec("/bin/mv {$temp_filename}/aliases {$temp_filename}/aliases.zip");
1766
	mwexec("/usr/local/bin/unzip {$temp_filename}/aliases.tgz -d {$temp_filename}/aliases/");
1767
	unlink("{$temp_filename}/aliases.zip");
1768
	$files_to_process = return_dir_as_array("{$temp_filename}/");
1769
	/* foreach through all extracted files and build up aliases file */
1770
	$fd = fopen("{$temp_filename}/aliases", "w");
1771
	foreach($files_to_process as $f2p) {
1772
		$file_contents = file_get_contents($f2p);
1773
		fwrite($fd, $file_contents);
1774
		unlink($f2p);
1775
	}
1776
	fclose($fd);
1777
}
1778

    
1779
function process_alias_tgz($temp_filename) {
1780
	if(!file_exists("/usr/bin/tar"))
1781
		return;
1782
	mwexec("/bin/mv {$temp_filename}/aliases {$temp_filename}/aliases.tgz");
1783
	mwexec("/usr/bin/tar xzf {$temp_filename}/aliases.tgz -C {$temp_filename}/aliases/");
1784
	unlink("{$temp_filename}/aliases.tgz");
1785
	$files_to_process = return_dir_as_array("{$temp_filename}/");
1786
	/* foreach through all extracted files and build up aliases file */
1787
	$fd = fopen("{$temp_filename}/aliases", "w");
1788
	foreach($files_to_process as $f2p) {
1789
		$file_contents = file_get_contents($f2p);
1790
		fwrite($fd, $file_contents);
1791
		unlink($f2p);
1792
	}
1793
	fclose($fd);
1794
}
1795

    
1796
function version_compare_dates($a, $b) {
1797
	$a_time = strtotime($a);
1798
	$b_time = strtotime($b);
1799

    
1800
	if ((!$a_time) || (!$b_time)) {
1801
		return FALSE;
1802
	} else {
1803
		if ($a < $b)
1804
			return -1;
1805
		elseif ($a == $b)
1806
			return 0;
1807
		else
1808
			return 1;
1809
	}
1810
}
1811
function version_get_string_value($a) {
1812
	$strs = array(
1813
		0 => "ALPHA-ALPHA",
1814
		2 => "ALPHA",
1815
		3 => "BETA",
1816
		4 => "B",
1817
		5 => "RC",
1818
		6 => "RELEASE"
1819
	);
1820
	$major = 0;
1821
	$minor = 0;
1822
	foreach ($strs as $num => $str) {
1823
		if (substr($a, 0, strlen($str)) == $str) {
1824
			$major = $num;
1825
			$n = substr($a, strlen($str));
1826
			if (is_numeric($n))
1827
				$minor = $n;
1828
			break;
1829
		}
1830
	}
1831
	return "{$major}.{$minor}";
1832
}
1833
function version_compare_string($a, $b) {
1834
	return version_compare_numeric(version_get_string_value($a), version_get_string_value($b));
1835
}
1836
function version_compare_numeric($a, $b) {
1837
	$a_arr = explode('.', rtrim($a, '.0'));
1838
	$b_arr = explode('.', rtrim($b, '.0'));
1839

    
1840
	foreach ($a_arr as $n => $val) {
1841
		if (array_key_exists($n, $b_arr)) {
1842
			// So far so good, both have values at this minor version level. Compare.
1843
			if ($val > $b_arr[$n])
1844
				return 1;
1845
			elseif ($val < $b_arr[$n])
1846
				return -1;
1847
		} else {
1848
			// a is greater, since b doesn't have any minor version here.
1849
			return 1;
1850
		}
1851
	}
1852
	if (count($b_arr) > count($a_arr)) {
1853
		// b is longer than a, so it must be greater.
1854
		return -1;
1855
	} else {
1856
		// Both a and b are of equal length and value.
1857
		return 0;
1858
	}
1859
}
1860
function pfs_version_compare($cur_time, $cur_text, $remote) {
1861
	// First try date compare
1862
	$v = version_compare_dates($cur_time, $b);
1863
	if ($v === FALSE) {
1864
		// If that fails, try to compare by string
1865
		// Before anything else, simply test if the strings are equal
1866
		if ($cur_text == $remote)
1867
			return 0;
1868
		list($cur_num, $cur_str) = explode('-', $cur_text);
1869
		list($rem_num, $rem_str) = explode('-', $remote);
1870

    
1871
		// First try to compare the numeric parts of the version string.
1872
		$v = version_compare_numeric($cur_num, $rem_num);
1873

    
1874
		// If the numeric parts are the same, compare the string parts.
1875
		if ($v == 0)
1876
			return version_compare_string($cur_str, $rem_str);
1877
	}
1878
	return $v;
1879
}
1880
function process_alias_urltable($name, $url, $freq, $forceupdate=false) {
1881
	$urltable_prefix = "/var/db/aliastables/";
1882
	$urltable_filename = $urltable_prefix . $name . ".txt";
1883

    
1884
	// Make the aliases directory if it doesn't exist
1885
	if (!file_exists($urltable_prefix)) {
1886
		mkdir($urltable_prefix);
1887
	} elseif (!is_dir($urltable_prefix)) {
1888
		unlink($urltable_prefix);
1889
		mkdir($urltable_prefix);
1890
	}
1891

    
1892
	// If the file doesn't exist or is older than update_freq days, fetch a new copy.
1893
	if (!file_exists($urltable_filename)
1894
		|| ((time() - filemtime($urltable_filename)) > ($freq * 86400))
1895
		|| $forceupdate) {
1896

    
1897
		// Try to fetch the URL supplied
1898
		conf_mount_rw();
1899
		unlink_if_exists($urltable_filename . ".tmp");
1900
		// Use fetch to grab data since these may be large files, we don't want to process them through PHP if we can help it.
1901
		mwexec("/usr/bin/fetch -q -o " . escapeshellarg($urltable_filename . ".tmp") . " " . escapeshellarg($url));
1902
		// Remove comments. Might need some grep-fu to only allow lines that look like IPs/subnets
1903
		mwexec("/usr/bin/grep -v '^#' " . escapeshellarg($urltable_filename . ".tmp") . " > " . escapeshellarg($urltable_filename));
1904
		unlink_if_exists($urltable_filename . ".tmp");
1905
		conf_mount_ro();
1906
		if (filesize($urltable_filename)) {
1907
			return true;
1908
		} else {
1909
			// If it's unfetchable or an empty file, bail
1910
			return false;
1911
		}
1912
	} else {
1913
		// File exists, and it doesn't need updated.
1914
		return -1;
1915
	}
1916
}
1917
function get_real_slice_from_glabel($label) {
1918
	$label = escapeshellarg($label);
1919
	return trim(`/sbin/glabel list | /usr/bin/grep -B2 ufs/{$label} | /usr/bin/head -n 1 | /usr/bin/cut -f3 -d' '`);
1920
}
1921
function nanobsd_get_boot_slice() {
1922
	return trim(`/sbin/mount | /usr/bin/grep pfsense | /usr/bin/cut -d'/' -f4 | /usr/bin/cut -d' ' -f1`);
1923
}
1924
function nanobsd_get_boot_drive() {
1925
	return trim(`/sbin/glabel list | /usr/bin/grep -B2 ufs/pfsense | /usr/bin/head -n 1 | /usr/bin/cut -f3 -d' ' | /usr/bin/cut -d's' -f1`);
1926
}
1927
function nanobsd_get_active_slice() {
1928
	$boot_drive = nanobsd_get_boot_drive();
1929
	$active = trim(`gpart show $boot_drive | grep '\[active\]' | awk '{print $3;}'`);
1930

    
1931
	return "{$boot_drive}s{$active}";
1932
}
1933
function nanobsd_get_size() {
1934
	return strtoupper(file_get_contents("/etc/nanosize.txt"));
1935
}
1936
function nanobsd_switch_boot_slice() {
1937
	global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
1938
	global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
1939
	global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
1940
	nanobsd_detect_slice_info();
1941

    
1942
	if ($BOOTFLASH == $ACTIVE_SLICE) {
1943
		$slice = $TOFLASH;
1944
	} else {
1945
		$slice = $BOOTFLASH;
1946
	}
1947

    
1948
	for ($i = 0; $i < ob_get_level(); $i++) { ob_end_flush(); }
1949
	ob_implicit_flush(1);
1950
	if(strstr($slice, "s2")) {
1951
		$ASLICE="2";
1952
		$AOLDSLICE="1";
1953
		$AGLABEL_SLICE="pfsense1";
1954
		$AUFS_ID="1";
1955
		$AOLD_UFS_ID="0";
1956
	} else {
1957
		$ASLICE="1";
1958
		$AOLDSLICE="2";
1959
		$AGLABEL_SLICE="pfsense0";
1960
		$AUFS_ID="0";
1961
		$AOLD_UFS_ID="1";
1962
	}
1963
	$ATOFLASH="{$BOOT_DRIVE}s{$ASLICE}";
1964
	$ACOMPLETE_PATH="{$BOOT_DRIVE}s{$ASLICE}a";
1965
	$ABOOTFLASH="{$BOOT_DRIVE}s{$AOLDSLICE}";
1966
	conf_mount_rw();
1967
	exec("sysctl kern.geom.debugflags=16");
1968
	exec("gpart set -a active -i {$ASLICE} {$BOOT_DRIVE}");
1969
	exec("/usr/sbin/boot0cfg -s {$ASLICE} -v /dev/{$BOOT_DRIVE}");
1970
	// We can't update these if they are mounted now.
1971
	if ($BOOTFLASH != $slice) {
1972
		exec("/sbin/tunefs -L ${AGLABEL_SLICE} /dev/$ACOMPLETE_PATH");
1973
		nanobsd_update_fstab($AGLABEL_SLICE, $ACOMPLETE_PATH, $AOLD_UFS_ID, $AUFS_ID);
1974
	}
1975
	exec("/sbin/sysctl kern.geom.debugflags=0");
1976
	conf_mount_ro();
1977
}
1978
function nanobsd_clone_slice() {
1979
	global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
1980
	global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
1981
	global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
1982
	nanobsd_detect_slice_info();
1983

    
1984
	for ($i = 0; $i < ob_get_level(); $i++) { ob_end_flush(); }
1985
	ob_implicit_flush(1);
1986
	exec("/sbin/sysctl kern.geom.debugflags=16");
1987
	exec("/bin/dd if=/dev/zero of=/dev/{$TOFLASH} bs=1m count=1");
1988
	exec("/bin/dd if=/dev/{$BOOTFLASH} of=/dev/{$TOFLASH} bs=64k");
1989
	exec("/sbin/tunefs -L {$GLABEL_SLICE} /dev/{$COMPLETE_PATH}");
1990
	$status = nanobsd_update_fstab($GLABEL_SLICE, $COMPLETE_PATH, $OLD_UFS_ID, $UFS_ID);
1991
	exec("/sbin/sysctl kern.geom.debugflags=0");
1992
	if($status) {
1993
		return false;
1994
	} else {
1995
		return true;
1996
	}
1997
}
1998
function nanobsd_update_fstab($gslice, $complete_path, $oldufs, $newufs) {
1999
	$tmppath = "/tmp/{$gslice}";
2000
	$fstabpath = "/tmp/{$gslice}/etc/fstab";
2001

    
2002
	exec("/bin/mkdir {$tmppath}");
2003
	exec("/sbin/fsck_ufs -y /dev/{$complete_path}");
2004
	exec("/sbin/mount /dev/ufs/{$gslice} {$tmppath}");
2005
	exec("/bin/cp /etc/fstab {$fstabpath}");
2006

    
2007
	if (!file_exists($fstabpath)) {
2008
		$fstab = <<<EOF
2009
/dev/ufs/{$gslice} / ufs ro 1 1
2010
/dev/ufs/cf /cf ufs ro 1 1
2011
EOF;
2012
		if (file_put_contents($fstabpath, $fstab))
2013
			$status = true;
2014
		else
2015
			$status = false;
2016
	} else {
2017
		$status = exec("sed -i \"\" \"s/pfsense{$oldufs}/pfsense{$newufs}/g\" {$fstabpath}");
2018
	}
2019
	exec("/sbin/umount {$tmppath}");
2020
	exec("/bin/rmdir {$tmppath}");
2021

    
2022
	return $status;
2023
}
2024
function nanobsd_detect_slice_info() {
2025
	global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
2026
	global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
2027
	global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
2028

    
2029
	$BOOT_DEVICE=nanobsd_get_boot_slice();
2030
	$REAL_BOOT_DEVICE=get_real_slice_from_glabel($BOOT_DEVICE);
2031
	$BOOT_DRIVE=nanobsd_get_boot_drive();
2032
	$ACTIVE_SLICE=nanobsd_get_active_slice();
2033

    
2034
	// Detect which slice is active and set information.
2035
	if(strstr($REAL_BOOT_DEVICE, "s1")) {
2036
		$SLICE="2";
2037
		$OLDSLICE="1";
2038
		$GLABEL_SLICE="pfsense1";
2039
		$UFS_ID="1";
2040
		$OLD_UFS_ID="0";
2041

    
2042
	} else {
2043
		$SLICE="1";
2044
		$OLDSLICE="2";
2045
		$GLABEL_SLICE="pfsense0";
2046
		$UFS_ID="0";
2047
		$OLD_UFS_ID="1";
2048
	}
2049
	$TOFLASH="{$BOOT_DRIVE}s{$SLICE}";
2050
	$COMPLETE_PATH="{$BOOT_DRIVE}s{$SLICE}a";
2051
	$COMPLETE_BOOT_PATH="{$BOOT_DRIVE}s{$OLDSLICE}";
2052
	$BOOTFLASH="{$BOOT_DRIVE}s{$OLDSLICE}";
2053
}
2054
?>
(29-29/50)