Project

General

Profile

Download (48.2 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/****h* pfSense/pkg-utils
3
	NAME
4
		pkg-utils.inc - Package subsystem
5
	DESCRIPTION
6
		This file contains various functions used by the pfSense package system.
7
	HISTORY
8
		$Id$
9

    
10
	Copyright (C) 2010 Ermal Luci
11
	Copyright (C) 2005-2006 Colin Smith (ethethlay@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
	ARISING 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:	/usr/bin/cd	/usr/bin/tar	/usr/sbin/fifolog_create	/bin/chmod
38
	pfSense_BUILDER_BINARIES:	/usr/sbin/pkg_add	/usr/sbin/pkg_info	/usr/sbin/pkg_delete	/bin/rm
39
	pfSense_MODULE:	pkg
40
*/
41

    
42
require_once("globals.inc");
43
require_once("xmlrpc.inc");
44
require_once("service-utils.inc");
45
if (file_exists("/cf/conf/use_xmlreader")) {
46
	require_once("xmlreader.inc");
47
} else {
48
	require_once("xmlparse.inc");
49
}
50
require_once("pfsense-utils.inc");
51

    
52
if (!function_exists("update_status")) {
53
	function update_status($status) {
54
		echo $status . "\n";
55
	}
56
}
57
if (!function_exists("update_output_window")) {
58
	function update_output_window($status) {
59
		echo $status . "\n";
60
	}
61
}
62

    
63
if (!function_exists("pkg_debug")) {
64
	/* set up logging if needed */
65
	function pkg_debug($msg) {
66
		global $g, $debug, $fd_log;
67

    
68
		if (!$debug) {
69
			return;
70
		}
71

    
72
		if (!$fd_log) {
73
			if (!$fd_log = fopen("{$g['tmp_path']}/pkg_mgr_{$package}.log", "w")) {
74
				update_output_window("Warning, could not open log for writing.");
75
			}
76
		}
77
		@fwrite($fd_log, $msg);
78
	}
79
}
80

    
81
global $g;
82
if (!isset($g['platform'])) {
83
	$g['platform'] = trim(file_get_contents("/etc/platform"));
84
}
85

    
86
/* Remove pkg_prefix from package name if it's present */
87
function pkg_remove_prefix(&$pkg_name) {
88
	global $g;
89

    
90
	if (substr($pkg_name, 0, strlen($g['pkg_prefix'])) == $g['pkg_prefix']) {
91
		$pkg_name = substr($pkg_name, strlen($g['pkg_prefix']));
92
	}
93
}
94

    
95
/* Execute a pkg call */
96
function pkg_call($params) {
97
	if (empty($params)) {
98
		return false;
99
	}
100

    
101
	// XXX: Use proper call with fifo to collect statistics
102
	$_gc = exec("env ASSUME_ALWAYS_YES=1 /usr/sbin/pkg " . escapeshellarg($params), $output, $rc);
103

    
104
	return ($rc == 0);
105
}
106

    
107
/* Check if package is installed */
108
function is_pkg_installed($pkg_name) {
109
	global $g;
110

    
111
	pkg_remove_prefix($pkg_name);
112

    
113
	return pkg_call("info -e " . $g['pkg_prefix'] . $pkg_name);
114
}
115

    
116
/* Delete package from FreeBSD, $pkg_name should not contain prefix */
117
function pkg_delete($pkg_name) {
118
	global $g;
119

    
120
	pkg_remove_prefix($pkg_name);
121

    
122
	if (is_pkg_installed($pkg_name)) {
123
		pkg_call("delete -q -y " . $g['pkg_prefix'] . $pkg_name);
124
		/* Cleanup unecessary dependencies */
125
		pkg_call("autoremove -y -q");
126
	}
127
}
128

    
129
/* Check if package is present in config.xml */
130
function is_package_installed($package_name) {
131
	return (get_package_id($package_name) != -1);
132
}
133

    
134
/* Find package array index */
135
function get_package_id($package_name) {
136
	global $config;
137

    
138
	if (!is_array($config['installedpackages']['package'])) {
139
		return -1;
140
	}
141

    
142
	foreach ($config['installedpackages']['package'] as $idx => $pkg) {
143
		if ($pkg['name'] == $package_name) {
144
			return $idx;
145
		}
146
	}
147

    
148
	return -1;
149
}
150

    
151
/* Return internal_name when it's defined, otherwise, returns name */
152
function get_package_internal_name($package_data) {
153
	if (isset($package_data['internal_name']) && ($package_data['internal_name'] != "")) {
154
		/* e.g. name is Ipguard-dev, internal name is ipguard */
155
		return $package_data['internal_name'];
156
	} else {
157
		return $package_data['name'];
158
	}
159
}
160

    
161
/****f* pkg-utils/get_pkg_info
162
 * NAME
163
 *   get_pkg_info - Retrieve package information from package server.
164
 * INPUTS
165
 *   $pkgs - 'all' to retrieve all packages, an array containing package names otherwise
166
 *   $info - 'all' to retrieve all information, an array containing keys otherwise
167
 * RESULT
168
 *   $raw_versions - Array containing retrieved information, indexed by package name.
169
 ******/
170
function get_pkg_info($pkgs = 'all', $info = 'all') {
171
	global $g;
172

    
173
	$freebsd_machine = php_uname("m");
174
	$params = array(
175
		"pkg" => $pkgs,
176
		"info" => $info,
177
		"freebsd_version" => get_freebsd_version(),
178
		"freebsd_machine" => $freebsd_machine
179
	);
180
	$resp = call_pfsense_method('pfsense.get_pkgs', $params, 10);
181
	return $resp ? $resp : array();
182
}
183

    
184
/*
185
 * resync_all_package_configs() Force packages to setup their configuration and rc.d files.
186
 * This function may also print output to the terminal indicating progress.
187
 */
188
function resync_all_package_configs($show_message = false) {
189
	global $config, $pkg_interface, $g;
190

    
191
	log_error(gettext("Resyncing configuration for all packages."));
192

    
193
	if (!is_array($config['installedpackages']['package'])) {
194
		return;
195
	}
196

    
197
	if ($show_message == true) {
198
		echo "Syncing packages:";
199
	}
200

    
201
	conf_mount_rw();
202

    
203
	foreach ($config['installedpackages']['package'] as $idx => $package) {
204
		if (empty($package['name'])) {
205
			continue;
206
		}
207
		if ($show_message == true) {
208
			echo " " . $package['name'];
209
		}
210
		get_pkg_depends($package['name'], "all");
211
		if (platform_booting() != true) {
212
			stop_service(get_package_internal_name($package));
213
		}
214
		sync_package($idx, true, true);
215
		if ($pkg_interface == "console") {
216
			echo "\n" . gettext("Syncing packages:");
217
		}
218
	}
219

    
220
	if ($show_message == true) {
221
		echo " done.\n";
222
	}
223

    
224
	@unlink("/conf/needs_package_sync");
225
	conf_mount_ro();
226
}
227

    
228
/*
229
 * get_pkg_depends($pkg_name, $filetype = ".xml", $format = "files", return_nosync = 1):  Return a package's dependencies.
230
 *
231
 * $filetype = "all" || ".xml", ".tgz", etc.
232
 * $format = "files" (full filenames) || "names" (stripped / parsed depend names)
233
 * $return_nosync = 1 (return depends that have nosync set) | 0 (ignore packages with nosync)
234
 *
235
 */
236
function get_pkg_depends($pkg_name, $filetype = ".xml", $format = "files", $return_nosync = 1) {
237
	global $config;
238

    
239
	$pkg_id = get_package_id($pkg_name);
240
	if ($pkg_id == -1) {
241
		return -1; // This package doesn't really exist - exit the function.
242
	} else if (!isset($config['installedpackages']['package'][$pkg_id])) {
243
		return; // No package belongs to the pkg_id passed to this function.
244
	}
245

    
246
	$package =& $config['installedpackages']['package'][$pkg_id];
247
	if (!file_exists("/usr/local/pkg/" . $package['configurationfile'])) {
248
		log_error(sprintf(gettext('The %1$s package is missing required dependencies and must be reinstalled. %2$s'), $package['name'], $package['configurationfile']));
249
		uninstall_package($package['name']);
250
		if (install_package($package['name']) < 0) {
251
			log_error("Failed reinstalling package {$package['name']}.");
252
			return false;
253
		}
254
	}
255
	$pkg_xml = parse_xml_config_pkg("/usr/local/pkg/" . $package['configurationfile'], "packagegui");
256
	if (!empty($pkg_xml['additional_files_needed'])) {
257
		foreach ($pkg_xml['additional_files_needed'] as $item) {
258
			if ($return_nosync == 0 && isset($item['nosync'])) {
259
				continue; // Do not return depends with nosync set if not required.
260
			}
261
			$depend_file = substr(strrchr($item['item']['0'], '/'),1); // Strip URLs down to filenames.
262
			$depend_name = substr(substr($depend_file,0,strpos($depend_file,".")+1),0,-1); // Strip filename down to dependency name.
263
			if (($filetype != "all") && (!preg_match("/{$filetype}/i", $depend_file))) {
264
				if (($filetype != "all") && (strtolower(substr($depend_file, -strlen($filetype))) != strtolower($filetype))) {
265
					continue;
266
				}
267
			}
268
			if ($item['prefix'] != "") {
269
				$prefix = $item['prefix'];
270
			} else {
271
				$prefix = "/usr/local/pkg/";
272
			}
273
			// Ensure that the prefix exists to avoid installation errors.
274
			if (!is_dir($prefix)) {
275
				exec("/bin/mkdir -p {$prefix}");
276
			}
277
			if (!file_exists($prefix . $depend_file)) {
278
				log_error(sprintf(gettext("The %s package is missing required dependencies and must be reinstalled."), $package['name']));
279
			}
280
			switch ($format) {
281
				case "files":
282
					$depends[] = $prefix . $depend_file;
283
					break;
284
				case "names":
285
					switch ($filetype) {
286
						case "all":
287
							if (preg_match("/\.xml/i", $depend_file)) {
288
								$depend_xml = parse_xml_config_pkg("/usr/local/pkg/{$depend_file}", "packagegui");
289
								if (!empty($depend_xml)) {
290
									$depends[] = $depend_xml['name'];
291
								}
292
							} else {
293
								$depends[] = $depend_name; // If this dependency isn't package XML, use the stripped filename.
294
							}
295
							break;
296
						case ".xml":
297
							$depend_xml = parse_xml_config_pkg("/usr/local/pkg/" . $depend_file, "packagegui");
298
							if (!empty($depend_xml)) {
299
								$depends[] = $depend_xml['name'];
300
							}
301
							break;
302
						default:
303
							$depends[] = $depend_name; // If we aren't looking for XML, use the stripped filename (it's all we have).
304
							break;
305
					}
306
			}
307
		}
308
		return $depends;
309
	}
310
}
311

    
312
function uninstall_package($pkg_name) {
313
	global $config, $static_output;
314
	global $builder_package_install;
315

    
316
	$id = get_package_id($pkg_name);
317
	if ($id >= 0) {
318
		stop_service(get_package_internal_name($config['installedpackages']['package'][$id]));
319
		$pkg_depends =& $config['installedpackages']['package'][$id]['depends_on_package_pbi'];
320
		$static_output .= "Removing package...\n";
321
		update_output_window($static_output);
322
		if (is_array($pkg_depends)) {
323
			foreach ($pkg_depends as $pkg_depend) {
324
				delete_package($pkg_depend);
325
			}
326
		} else {
327
			// The packages (1 or more) are all in one long string.
328
			// We need to pass them 1 at a time to delete_package.
329
			// Compress any multiple whitespace (sp, tab, cr, lf...) into a single space char.
330
			$pkg_dep_str = preg_replace("'\s+'", ' ', $pkg_depends);
331
			// Get rid of any leading or trailing space.
332
			$pkg_dep_str = trim($pkg_dep_str);
333
			// Now we have a space-separated string. Make it into an array and process it.
334
			$pkg_dep_array = explode(" ", $pkg_dep_str);
335
			foreach ($pkg_dep_array as $pkg_depend) {
336
				delete_package($pkg_depend);
337
			}
338
		}
339
	}
340
	delete_package_xml($pkg_name);
341

    
342
	$static_output .= gettext("done.") . "\n";
343
	update_output_window($static_output);
344
}
345

    
346
/*
347
 * sync_package($pkg_name, $sync_depends = true, $show_message = false) Force a package to setup its configuration and rc.d files.
348
 */
349
function sync_package($pkg_name, $sync_depends = true, $show_message = false) {
350
	global $config, $config_parsed;
351
	global $builder_package_install;
352

    
353
	// If this code is being called by pfspkg_installer
354
	// which the builder system uses then return (ignore).
355
	if ($builder_package_install) {
356
		return;
357
	}
358

    
359
	if (empty($config['installedpackages']['package'])) {
360
		return;
361
	}
362
	if (!is_numeric($pkg_name)) {
363
		$pkg_id = get_package_id($pkg_name);
364
		if ($pkg_id == -1) {
365
			return -1; // This package doesn't really exist - exit the function.
366
		}
367
	} else {
368
		$pkg_id = $pkg_name;
369
	}
370

    
371
	if (!is_array($config['installedpackages']['package'][$pkg_id])) {
372
		return;  // No package belongs to the pkg_id passed to this function.
373
	}
374

    
375
	$package =& $config['installedpackages']['package'][$pkg_id];
376
	if (!file_exists("/usr/local/pkg/" . $package['configurationfile'])) {
377
		log_error(sprintf(gettext("The %s package is missing its configuration file and must be reinstalled."), $package['name']));
378
		delete_package_xml($package['name']);
379
		return -1;
380
	}
381
	$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $package['configurationfile'], "packagegui");
382
	if (isset($pkg_config['nosync'])) {
383
		return;
384
	}
385
	/* Bring in package include files */
386
	if (!empty($pkg_config['include_file'])) {
387
		$include_file = $pkg_config['include_file'];
388
		if (file_exists($include_file)) {
389
			require_once($include_file);
390
		} else {
391
			/* XXX: What the heck is this?! */
392
			log_error("Reinstalling package {$package['name']} because its include file({$include_file}) is missing!");
393
			uninstall_package($package['name']);
394
			if (install_package($package['name']) < 0) {
395
				log_error("Reinstalling package {$package['name']} failed. Take appropriate measures!!!");
396
				return -1;
397
			}
398
		}
399
	}
400

    
401
	if (!empty($pkg_config['custom_php_global_functions'])) {
402
		eval($pkg_config['custom_php_global_functions']);
403
	}
404
	if (!empty($pkg_config['custom_php_resync_config_command'])) {
405
		eval($pkg_config['custom_php_resync_config_command']);
406
	}
407
	if ($sync_depends == true) {
408
		$depends = get_pkg_depends($pkg_name, ".xml", "files", 1); // Call dependency handler and do a little more error checking.
409
		if (is_array($depends)) {
410
			foreach ($depends as $item) {
411
				if (!file_exists($item)) {
412
					require_once("notices.inc");
413
					file_notice($package['name'], sprintf(gettext("The %s package is missing required dependencies and must be reinstalled."), $package['name']), "Packages", "/pkg_mgr_install.php?mode=reinstallpkg&pkg={$package['name']}", 1);
414
					log_error("Could not find {$item}. Reinstalling package.");
415
					uninstall_package($pkg_name);
416
					if (install_package($pkg_name) < 0) {
417
						log_error("Reinstalling package {$package['name']} failed. Take appropriate measures!!!");
418
						return -1;
419
					}
420
				} else {
421
					$item_config = parse_xml_config_pkg($item, "packagegui");
422
					if (empty($item_config)) {
423
						continue;
424
					}
425
					if (isset($item_config['nosync'])) {
426
						continue;
427
					}
428
					if (!empty($item_config['include_file'])) {
429
						if (file_exists($item_config['include_file'])) {
430
							require_once($item_config['include_file']);
431
						} else {
432
							log_error("Not calling package sync code for dependency {$item_config['name']} of {$package['name']} because some include files are missing.");
433
							continue;
434
						}
435
					}
436
					if ($item_config['custom_php_global_functions'] <> "") {
437
						eval($item_config['custom_php_global_functions']);
438
					}
439
					if ($item_config['custom_php_resync_config_command'] <> "") {
440
						eval($item_config['custom_php_resync_config_command']);
441
					}
442
					if ($show_message == true) {
443
						print " " . $item_config['name'];
444
					}
445
				}
446
			}
447
		}
448
	}
449
}
450

    
451
/*
452
 * pkg_fetch_recursive: Download and install a FreeBSD PBI package. This function provides output to
453
 * 			a progress bar and output window.
454
 */
455
function pkg_fetch_recursive($pkgname, $filename, $dependlevel = 0, $base_url = "") {
456
	global $static_output, $g, $config;
457

    
458
	// Clean up incoming filenames
459
	$filename = str_replace("  ", " ", $filename);
460
	$filename = str_replace("\n", " ", $filename);
461
	$filename = str_replace("  ", " ", $filename);
462

    
463
	$pkgs = explode(" ", $filename);
464
	foreach ($pkgs as $filename) {
465
		$filename = trim($filename);
466
		if ($g['platform'] == "nanobsd") {
467
			$pkgtmpdir = "/usr/bin/env PKG_TMPDIR=/root/ ";
468
			$pkgstagingdir = "/root/tmp";
469
			if (!is_dir($pkgstagingdir)) {
470
				mkdir($pkgstagingdir);
471
			}
472
			$pkgstaging = "-o {$pkgstagingdir}/instmp.XXXXXX";
473
			$fetchdir = $pkgstagingdir;
474
		} else {
475
			$fetchdir = $g['tmp_path'];
476
		}
477

    
478
		/* FreeBSD has no PBI's hosted, so fall back to our own URL for now. (Maybe fail to PC-BSD?) */
479
		$rel = get_freebsd_version();
480
		$priv_url = "https://files.pfsense.org/packages/{$rel}/All/";
481
		if (empty($base_url)) {
482
			$base_url = $priv_url;
483
		}
484
		if (substr($base_url, -1) == "/") {
485
			$base_url = substr($base_url, 0, -1);
486
		}
487
		$fetchto = "{$fetchdir}/apkg_{$filename}";
488
		$static_output .= "\n" . str_repeat(" ", $dependlevel * 2 + 1) . "Downloading {$base_url}/{$filename} ... ";
489
		if (download_file_with_progress_bar("{$base_url}/{$filename}", $fetchto) !== true) {
490
			if ($base_url != $priv_url && download_file_with_progress_bar("{$priv_url}/{$filename}", $fetchto) !== true) {
491
				$static_output .= " could not download from there or {$priv_url}/{$filename}.\n";
492
				update_output_window($static_output);
493
				return false;
494
			} else if ($base_url == $priv_url) {
495
				$static_output .= " failed to download.\n";
496
				update_output_window($static_output);
497
				return false;
498
			} else {
499
				$static_output .= " [{$osname} repository]\n";
500
				update_output_window($static_output);
501
			}
502
		}
503
		$static_output .= " (extracting)\n";
504
		update_output_window($static_output);
505

    
506
		$pkgaddout = "";
507

    
508
		$no_checksig = "";
509
		if (isset($config['system']['pkg_nochecksig'])) {
510
			$no_checksig = "--no-checksig";
511
		}
512

    
513
		$result = exec("/usr/local/sbin/pbi_add " . $pkgstaging . " -f -v {$no_checksig} " . escapeshellarg($fetchto) . " 2>&1", $pkgaddout, $rc);
514
		pkg_debug($pkgname . " " . print_r($pkgaddout, true) . "\n");
515
		if ($rc == 0) {
516
			$pbi_name = preg_replace('/\.pbi$/','',$filename);
517

    
518
			$gb = exec("/usr/local/sbin/pbi_info {$pbi_name} | /usr/bin/awk '/Prefix/ {print $2}'", $pbi_prefix);
519
			$pbi_prefix = $pbi_prefix[0];
520

    
521
			$links = get_pbi_binaries(escapeshellarg($pbi_name));
522
			foreach ($links as $link) {
523
				@unlink("/usr/local/{$link['link_name']}");
524
				@symlink("{$link['target']}","/usr/local/{$link['link_name']}");
525
			}
526

    
527
			$extra_links = array(
528
				array("target" => "bin", "link_name" => "sbin"),
529
				array("target" => "local/lib", "link_name" => "lib"),
530
				array("target" => "local/libexec", "link_name" => "libexec"),
531
				array("target" => "local/share", "link_name" => "share"),
532
				array("target" => "local/www", "link_name" => "www"),
533
				array("target" => "local/etc", "link_name" => "etc")
534
			);
535

    
536
			foreach ($extra_links as $link) {
537
				if (!file_exists($pbi_prefix . "/" . $link['target'])) {
538
					continue;
539
				}
540
				@rmdir("{$pbi_prefix}/{$link['link_name']}");
541
				unlink_if_exists("{$pbi_prefix}/{$link['link_name']}");
542
				@symlink("{$pbi_prefix}/{$link['target']}", "{$pbi_prefix}/{$link['link_name']}");
543
			}
544
			pkg_debug("pbi_add successfully completed.\n");
545
		} else {
546
			if (is_array($pkgaddout)) {
547
				foreach ($pkgaddout as $line) {
548
					$static_output .= " " . $line .= "\n";
549
				}
550
			}
551

    
552
			update_output_window($static_output);
553
			pkg_debug("pbi_add failed.\n");
554
			return false;
555
		}
556
	}
557
	return true;
558
}
559

    
560
function get_pbi_binaries($pbi) {
561
	$result = array();
562

    
563
	if (empty($pbi)) {
564
		return $result;
565
	}
566

    
567
	$gb = exec("/usr/local/sbin/pbi_info {$pbi} | /usr/bin/awk '/Prefix/ {print $2}'", $pbi_prefix);
568
	$pbi_prefix = $pbi_prefix[0];
569

    
570
	if (empty($pbi_prefix)) {
571
		return $result;
572
	}
573

    
574
	foreach (array('bin', 'sbin') as $dir) {
575
		if (!is_dir("{$pbi_prefix}/{$dir}")) {
576
			continue;
577
		}
578

    
579
		$files = glob("{$pbi_prefix}/{$dir}/*.pbiopt");
580
		foreach ($files as $f) {
581
			$pbiopts = file($f, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
582
			foreach ($pbiopts as $pbiopt) {
583
				if (!preg_match('/^TARGET:\s+(.*)$/', $pbiopt, $matches)) {
584
					continue;
585
				}
586

    
587
				$result[] = array(
588
					'target' => preg_replace('/\.pbiopt$/', '', $f),
589
					'link_name' => $matches[1]);
590
			}
591
		}
592
	}
593

    
594
	return $result;
595
}
596

    
597

    
598
function install_package($package, $pkg_info = "", $force_install = false) {
599
	global $g, $config, $static_output, $pkg_interface;
600

    
601
	/* safe side. Write config below will send to ro again. */
602
	conf_mount_rw();
603

    
604
	if ($pkg_interface == "console") {
605
		echo "\n";
606
	}
607
	/* fetch package information if needed */
608
	if (empty($pkg_info) or !is_array($pkg_info[$package])) {
609
		$pkg_info = get_pkg_info(array($package));
610
		$pkg_info = $pkg_info[$package]; // We're only dealing with one package, so we can strip away the extra array.
611
		if (empty($pkg_info)) {
612
			conf_mount_ro();
613
			return -1;
614
		}
615
	}
616
	if (!$force_install) {
617
		$compatible = true;
618
		$version = rtrim(file_get_contents("/etc/version"));
619

    
620
		if (isset($pkg_info['required_version'])) {
621
			$compatible = (pfs_version_compare("", $version, $pkg_info['required_version']) >= 0);
622
		}
623
		if (isset($pkg_info['maximum_version'])) {
624
			$compatible = $compatible && (pfs_version_compare("", $version, $pkg_info['maximum_version']) <= 0);
625
		}
626

    
627
		if (!$compatible) {
628
			log_error(sprintf(gettext('Package %s is not supported on this version.'), $pkg_info['name']));
629
			$static_output .= sprintf(gettext("Package %s is not supported on this version."), $pkg_info['name']);
630
			update_status($static_output);
631

    
632
			conf_mount_ro();
633
			return -1;
634
		}
635
	}
636
	pkg_debug(gettext("Beginning package installation.") . "\n");
637
	log_error(sprintf(gettext('Beginning package installation for %s .'), $pkg_info['name']));
638
	$static_output .= sprintf(gettext("Beginning package installation for %s ."), $pkg_info['name']);
639
	update_status($static_output);
640

    
641
	/* fetch the package's configuration file */
642
	pkg_fetch_config_file($package, $pkg_info);
643

    
644
	/* add package information to config.xml */
645
	$pkgid = get_package_id($pkg_info['name']);
646
	$static_output .= gettext("Saving updated package information...") . " ";
647
	update_output_window($static_output);
648
	if ($pkgid == -1) {
649
		$config['installedpackages']['package'][] = $pkg_info;
650
		$changedesc = sprintf(gettext("Installed %s package."),$pkg_info['name']);
651
		$to_output = gettext("done.") . "\n";
652
	} else {
653
		$config['installedpackages']['package'][$pkgid] = $pkg_info;
654
		$changedesc = sprintf(gettext("Overwrote previous installation of %s."), $pkg_info['name']);
655
		$to_output = gettext("overwrite!") . "\n";
656
	}
657
	if (file_exists('/conf/needs_package_sync')) {
658
		@unlink('/conf/needs_package_sync');
659
	}
660
	conf_mount_ro();
661
	write_config("Intermediate config write during package install for {$pkg_info['name']}.");
662
	$static_output .= $to_output;
663
	update_output_window($static_output);
664
	/* install other package components */
665
	if (!install_package_xml($package)) {
666
		uninstall_package($package);
667
		write_config($changedesc);
668
		log_error(sprintf(gettext("Failed to install package: %s."), $pkg_info['name']));
669
		$static_output .= gettext("Failed to install package.") . "\n";
670
		update_output_window($static_output);
671
		return -1;
672
	} else {
673
		$static_output .= gettext("Writing configuration... ");
674
		update_output_window($static_output);
675
		write_config($changedesc);
676
		log_error(sprintf(gettext("Successfully installed package: %s."), $pkg_info['name']));
677
		$static_output .= gettext("done.") . "\n";
678
		update_output_window($static_output);
679
		if ($pkg_info['after_install_info']) {
680
			update_output_window($pkg_info['after_install_info']);
681
		}
682
	}
683
}
684

    
685
function get_after_install_info($package) {
686
	global $pkg_info;
687
	/* fetch package information if needed */
688
	if (!$pkg_info or !is_array($pkg_info[$package])) {
689
		$pkg_info = get_pkg_info(array($package));
690
		$pkg_info = $pkg_info[$package]; // We're only dealing with one package, so we can strip away the extra array.
691
	}
692
	if ($pkg_info['after_install_info']) {
693
		return $pkg_info['after_install_info'];
694
	}
695
}
696

    
697
function eval_once($toeval) {
698
	global $evaled;
699
	if (!$evaled) {
700
		$evaled = array();
701
	}
702
	$evalmd5 = md5($toeval);
703
	if (!in_array($evalmd5, $evaled)) {
704
		@eval($toeval);
705
		$evaled[] = $evalmd5;
706
	}
707
	return;
708
}
709

    
710
function install_package_xml($pkg) {
711
	global $g, $config, $static_output, $pkg_interface, $config_parsed;
712

    
713
	if (($pkgid = get_package_id($pkg)) == -1) {
714
		$static_output .= sprintf(gettext("The %s package is not installed.%sInstallation aborted."), $pkg, "\n\n");
715
		update_output_window($static_output);
716
		if ($pkg_interface <> "console") {
717
			echo "\n<script type=\"text/javascript\">document.progressbar.style.visibility='hidden';</script>";
718
			echo "\n<script type=\"text/javascript\">document.progholder.style.visibility='hidden';</script>";
719
		}
720
		sleep(1);
721
		return false;
722
	} else {
723
		$pkg_info = $config['installedpackages']['package'][$pkgid];
724
	}
725

    
726
	/* pkg_add the package and its dependencies */
727
	if ($pkg_info['depends_on_package_base_url'] != "") {
728
		if ($pkg_interface == "console") {
729
			echo "\n";
730
		}
731
		update_status(gettext("Installing") . " " . $pkg_info['name'] . " " . gettext("and its dependencies."));
732
		$static_output .= gettext("Downloading") . " " . $pkg_info['name'] . " " . gettext("and its dependencies... ");
733
		$static_orig = $static_output;
734
		$static_output .= "\n";
735
		update_output_window($static_output);
736
		foreach ((array) $pkg_info['depends_on_package_pbi'] as $pkgdep) {
737
			$pkg_name = substr(reverse_strrchr($pkgdep, "."), 0, -1);
738
			$static_output = $static_orig . "\nChecking for package installation... ";
739
			update_output_window($static_output);
740
			if (!is_pkg_installed($pkg_name)) {
741
				if (!pkg_fetch_recursive($pkg_name, $pkgdep, 0, $pkg_info['depends_on_package_base_url'])) {
742
					$static_output .= "of {$pkg_name} failed!\n\nInstallation aborted.";
743
					update_output_window($static_output);
744
					pkg_debug(gettext("Package WAS NOT installed properly.") . "\n");
745
					if ($pkg_interface <> "console") {
746
						echo "\n<script type=\"text/javascript\">document.progressbar.style.visibility='hidden';</script>";
747
						echo "\n<script type=\"text/javascript\">document.progholder.style.visibility='hidden';</script>";
748
					}
749
					sleep(1);
750
					return false;
751
				}
752
			}
753
		}
754
	}
755

    
756
	$configfile = substr(strrchr($pkg_info['config_file'], '/'), 1);
757
	if (file_exists("/usr/local/pkg/" . $configfile)) {
758
		$static_output .= gettext("Loading package configuration... ");
759
		update_output_window($static_output);
760
		$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $configfile, "packagegui");
761
		$static_output .= gettext("done.") . "\n";
762
		update_output_window($static_output);
763
		$static_output .= gettext("Configuring package components...\n");
764
		if (!empty($pkg_config['filter_rules_needed'])) {
765
			$config['installedpackages']['package'][$pkgid]['filter_rule_function'] = $pkg_config['filter_rules_needed'];
766
		}
767
		update_output_window($static_output);
768

    
769
		pkg_fetch_additional_files($pkg, $pkg_info);
770

    
771
		/*   if a require exists, include it.  this will
772
		 *   show us where an error exists in a package
773
		 *   instead of making us blindly guess
774
		 */
775
		$missing_include = false;
776
		if ($pkg_config['include_file'] <> "") {
777
			$static_output .= gettext("Loading package instructions...") . "\n";
778
			update_output_window($static_output);
779
			pkg_debug("require_once('{$pkg_config['include_file']}')\n");
780
			if (file_exists($pkg_config['include_file'])) {
781
				require_once($pkg_config['include_file']);
782
			} else {
783
				$missing_include = true;
784
				$static_output .= "Include " . basename($pkg_config['include_file']) . " is missing!\n";
785
				update_output_window($static_output);
786
				/* XXX: Should undo the steps before this?! */
787
				return false;
788
			}
789
		}
790

    
791
		/* custom commands */
792
		$static_output .= gettext("Custom commands...") . "\n";
793
		update_output_window($static_output);
794
		if ($missing_include == false) {
795
			if ($pkg_config['custom_php_global_functions'] <> "") {
796
				$static_output .= gettext("Executing custom_php_global_functions()...");
797
				update_output_window($static_output);
798
				eval_once($pkg_config['custom_php_global_functions']);
799
				$static_output .= gettext("done.") . "\n";
800
				update_output_window($static_output);
801
			}
802
			if ($pkg_config['custom_php_install_command']) {
803
				$static_output .= gettext("Executing custom_php_install_command()...");
804
				update_output_window($static_output);
805
				/* XXX: create symlinks for conf files into the PBI directories.
806
				 *	change packages to store configs at /usr/pbi/pkg/etc and remove this
807
				 */
808
				eval_once($pkg_config['custom_php_install_command']);
809
				// Note: pkg may be mixed-case, e.g. "squidGuard" but the PBI names are lowercase.
810
				// e.g. "squidguard-1.4_4-i386" so feed lowercase to pbi_info below.
811
				// Also add the "-" so that examples like "squid-" do not match "squidguard-".
812
				$pkg_name_for_pbi_match = strtolower($pkg) . "-";
813
				exec("/usr/local/sbin/pbi_info | grep '^{$pkg_name_for_pbi_match}' | xargs /usr/local/sbin/pbi_info | awk '/Prefix/ {print $2}'",$pbidirarray);
814
				$pbidir0 = $pbidirarray[0];
815
				exec("find /usr/local/etc/ -name *.conf | grep " . escapeshellarg($pkg),$files);
816
				foreach ($files as $f) {
817
					$pbiconf = str_replace('/usr/local',$pbidir0,$f);
818
					if (is_file($pbiconf) || is_link($pbiconf)) {
819
						unlink($pbiconf);
820
					}
821
					if (is_dir(dirname($pbiconf))) {
822
						symlink($f,$pbiconf);
823
					} else {
824
						log_error("The dir for {$pbiconf} does not exist. Cannot add symlink to {$f}.");
825
					}
826
				}
827
				eval_once($pkg_config['custom_php_install_command']);
828
				$static_output .= gettext("done.") . "\n";
829
				update_output_window($static_output);
830
			}
831
			if ($pkg_config['custom_php_resync_config_command'] <> "") {
832
				$static_output .= gettext("Executing custom_php_resync_config_command()...");
833
				update_output_window($static_output);
834
				eval_once($pkg_config['custom_php_resync_config_command']);
835
				$static_output .= gettext("done.") . "\n";
836
				update_output_window($static_output);
837
			}
838
		}
839
		/* sidebar items */
840
		if (is_array($pkg_config['menu'])) {
841
			$static_output .= gettext("Menu items... ");
842
			update_output_window($static_output);
843
			foreach ($pkg_config['menu'] as $menu) {
844
				if (is_array($config['installedpackages']['menu'])) {
845
					foreach ($config['installedpackages']['menu'] as $amenu) {
846
						if ($amenu['name'] == $menu['name']) {
847
							continue 2;
848
						}
849
					}
850
				} else {
851
					$config['installedpackages']['menu'] = array();
852
				}
853
				$config['installedpackages']['menu'][] = $menu;
854
			}
855
			$static_output .= gettext("done.") . "\n";
856
			update_output_window($static_output);
857
		}
858
		/* services */
859
		if (is_array($pkg_config['service'])) {
860
			$static_output .= gettext("Services... ");
861
			update_output_window($static_output);
862
			foreach ($pkg_config['service'] as $service) {
863
				if (is_array($config['installedpackages']['service'])) {
864
					foreach ($config['installedpackages']['service'] as $aservice) {
865
						if ($aservice['name'] == $service['name']) {
866
							continue 2;
867
						}
868
					}
869
				} else {
870
					$config['installedpackages']['service'] = array();
871
				}
872
				$config['installedpackages']['service'][] = $service;
873
			}
874
			$static_output .= gettext("done.") . "\n";
875
			update_output_window($static_output);
876
		}
877
	} else {
878
		$static_output .= gettext("Loading package configuration... failed!") . "\n\n" . gettext("Installation aborted.");
879
		update_output_window($static_output);
880
		pkg_debug(gettext("Unable to load package configuration. Installation aborted.") ."\n");
881
		if ($pkg_interface <> "console") {
882
			echo "\n<script type=\"text/javascript\">document.progressbar.style.visibility='hidden';</script>";
883
			echo "\n<script type=\"text/javascript\">document.progholder.style.visibility='hidden';</script>";
884
		}
885
		sleep(1);
886
		return false;
887
	}
888

    
889
	/* set up package logging streams */
890
	if ($pkg_info['logging']) {
891
		system_syslogd_start();
892
	}
893

    
894
	return true;
895
}
896

    
897
function delete_package($pkg) {
898
	global $config, $g, $static_output, $vardb;
899

    
900
	if (!$pkg) {
901
		return;
902
	}
903

    
904
	// Note: $pkg has the full PBI package name followed by ".pbi". Strip off ".pbi".
905
	$pkg = substr(reverse_strrchr($pkg, "."), 0, -1);
906

    
907
	if ($pkg) {
908
		$static_output .= sprintf(gettext("Starting package deletion for %s..."),$pkg);
909
	}
910
	update_output_window($static_output);
911

    
912
	pkg_delete($pkg);
913
	$static_output .= "done.\n";
914
	update_output_window($static_output);
915

    
916
	/* Rescan directories for what has been left and avoid fooling other programs. */
917
	mwexec("/sbin/ldconfig");
918

    
919
	return;
920
}
921

    
922
function delete_package_xml($pkg) {
923
	global $g, $config, $static_output, $pkg_interface;
924

    
925
	conf_mount_rw();
926

    
927
	$pkgid = get_package_id($pkg);
928
	if ($pkgid == -1) {
929
		$static_output .= sprintf(gettext("The %s package is not installed.%sDeletion aborted."), $pkg, "\n\n");
930
		update_output_window($static_output);
931
		if ($pkg_interface <> "console") {
932
			echo "\n<script type=\"text/javascript\">document.progressbar.style.visibility='hidden';</script>";
933
			echo "\n<script type=\"text/javascript\">document.progholder.style.visibility='hidden';</script>";
934
		}
935
		ob_flush();
936
		sleep(1);
937
		conf_mount_ro();
938
		return;
939
	}
940
	pkg_debug(sprintf(gettext("Removing %s package... "),$pkg));
941
	$static_output .= sprintf(gettext("Removing %s components..."),$pkg) . "\n";
942
	update_output_window($static_output);
943
	/* parse package configuration */
944
	$packages = &$config['installedpackages']['package'];
945
	$menus =& $config['installedpackages']['menu'];
946
	$services = &$config['installedpackages']['service'];
947
	$pkg_info =& $packages[$pkgid];
948
	if (file_exists("/usr/local/pkg/" . $pkg_info['configurationfile'])) {
949
		$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $packages[$pkgid]['configurationfile'], "packagegui");
950
		/* remove menu items */
951
		if (is_array($pkg_config['menu'])) {
952
			$static_output .= gettext("Menu items... ");
953
			update_output_window($static_output);
954
			if (is_array($pkg_config['menu']) && is_array($menus)) {
955
				foreach ($pkg_config['menu'] as $menu) {
956
					foreach ($menus as $key => $instmenu) {
957
						if ($instmenu['name'] == $menu['name']) {
958
							unset($menus[$key]);
959
							break;
960
						}
961
					}
962
				}
963
			}
964
			$static_output .= gettext("done.") . "\n";
965
			update_output_window($static_output);
966
		}
967
		/* remove services */
968
		if (is_array($pkg_config['service'])) {
969
			$static_output .= gettext("Services... ");
970
			update_output_window($static_output);
971
			if (is_array($pkg_config['service']) && is_array($services)) {
972
				foreach ($pkg_config['service'] as $service) {
973
					foreach ($services as $key => $instservice) {
974
						if ($instservice['name'] == $service['name']) {
975
							if (platform_booting() != true) {
976
								stop_service($service['name']);
977
							}
978
							if ($service['rcfile']) {
979
								$prefix = RCFILEPREFIX;
980
								if (!empty($service['prefix'])) {
981
									$prefix = $service['prefix'];
982
								}
983
								if (file_exists("{$prefix}{$service['rcfile']}")) {
984
									@unlink("{$prefix}{$service['rcfile']}");
985
								}
986
							}
987
							unset($services[$key]);
988
						}
989
					}
990
				}
991
			}
992
			$static_output .= gettext("done.") . "\n";
993
			update_output_window($static_output);
994
		}
995
		/*
996
		 * XXX: Otherwise inclusion of config.inc again invalidates actions taken.
997
		 * 	Same is done during installation.
998
		 */
999
		write_config("Intermediate config write during package removal for {$pkg}.");
1000

    
1001
		/*
1002
		 * If a require exists, include it.  this will
1003
		 * show us where an error exists in a package
1004
		 * instead of making us blindly guess
1005
		 */
1006
		$missing_include = false;
1007
		if ($pkg_config['include_file'] <> "") {
1008
			$static_output .= gettext("Loading package instructions...") . "\n";
1009
			update_output_window($static_output);
1010
			pkg_debug("require_once(\"{$pkg_config['include_file']}\")\n");
1011
			if (file_exists($pkg_config['include_file'])) {
1012
				require_once($pkg_config['include_file']);
1013
			} else {
1014
				$missing_include = true;
1015
				update_output_window($static_output);
1016
				$static_output .= "Include file " . basename($pkg_config['include_file']) . " could not be found for inclusion.\n";
1017
			}
1018
		}
1019
		/* ermal
1020
		 * NOTE: It is not possible to handle parse errors on eval.
1021
		 * So we prevent it from being run at all to not interrupt all the other code.
1022
		 */
1023
		if ($missing_include == false) {
1024
			/* evaluate this package's global functions and pre deinstall commands */
1025
			if ($pkg_config['custom_php_global_functions'] <> "") {
1026
				eval_once($pkg_config['custom_php_global_functions']);
1027
			}
1028
			if ($pkg_config['custom_php_pre_deinstall_command'] <> "") {
1029
				eval_once($pkg_config['custom_php_pre_deinstall_command']);
1030
			}
1031
		}
1032
		/* deinstall commands */
1033
		if ($pkg_config['custom_php_deinstall_command'] <> "") {
1034
			$static_output .= gettext("Deinstall commands... ");
1035
			update_output_window($static_output);
1036
			if ($missing_include == false) {
1037
				eval_once($pkg_config['custom_php_deinstall_command']);
1038
				$static_output .= gettext("done.") . "\n";
1039
			} else {
1040
				$static_output .= "\nNot executing custom deinstall hook because an include is missing.\n";
1041
			}
1042
			update_output_window($static_output);
1043
		}
1044
		if ($pkg_config['include_file'] <> "") {
1045
			$static_output .= gettext("Removing package instructions...");
1046
			update_output_window($static_output);
1047
			pkg_debug(sprintf(gettext("Remove '%s'"), $pkg_config['include_file']) . "\n");
1048
			unlink_if_exists("/usr/local/pkg/" . $pkg_config['include_file']);
1049
			$static_output .= gettext("done.") . "\n";
1050
			update_output_window($static_output);
1051
		}
1052
		/* remove all additional files */
1053
		if (is_array($pkg_config['additional_files_needed'])) {
1054
			$static_output .= gettext("Auxiliary files... ");
1055
			update_output_window($static_output);
1056
			foreach ($pkg_config['additional_files_needed'] as $afn) {
1057
				$filename = get_filename_from_url($afn['item'][0]);
1058
				if ($afn['prefix'] <> "") {
1059
					$prefix = $afn['prefix'];
1060
				} else {
1061
					$prefix = "/usr/local/pkg/";
1062
				}
1063
				unlink_if_exists($prefix . $filename);
1064
			}
1065
			$static_output .= gettext("done.") . "\n";
1066
			update_output_window($static_output);
1067
		}
1068
		/* package XML file */
1069
		$static_output .= gettext("Package XML... ");
1070
		update_output_window($static_output);
1071
		unlink_if_exists("/usr/local/pkg/" . $packages[$pkgid]['configurationfile']);
1072
		$static_output .= gettext("done.") . "\n";
1073
		update_output_window($static_output);
1074
	}
1075
	/* syslog */
1076
	if (is_array($pkg_info['logging']) && $pkg_info['logging']['logfile_name'] <> "") {
1077
		$static_output .= "Syslog entries... ";
1078
		update_output_window($static_output);
1079
		remove_text_from_file("/etc/syslog.conf", $pkg_info['logging']['facilityname'] . "\t\t\t\t" . $pkg_info['logging']['logfilename']);
1080
		system_syslogd_start();
1081
		@unlink("{$g['varlog_path']}/{$pkg_info['logging']['logfilename']}");
1082
		$static_output .= "done.\n";
1083
		update_output_window($static_output);
1084
	}
1085

    
1086
	conf_mount_ro();
1087
	/* remove config.xml entries */
1088
	$static_output .= gettext("Configuration... ");
1089
	update_output_window($static_output);
1090
	unset($config['installedpackages']['package'][$pkgid]);
1091
	$static_output .= gettext("done.") . "\n";
1092
	update_output_window($static_output);
1093
	write_config("Removed {$pkg} package.\n");
1094
}
1095

    
1096
function pkg_reinstall_all() {
1097
	global $g, $config;
1098

    
1099
	@unlink('/conf/needs_package_sync');
1100
	if (is_array($config['installedpackages']['package'])) {
1101
		echo gettext("One moment please, reinstalling packages...\n");
1102
		echo gettext(" >>> Trying to fetch package info...");
1103
		log_error(gettext("Attempting to reinstall all packages"));
1104
		$pkg_info = get_pkg_info();
1105
		if ($pkg_info) {
1106
			echo " Done.\n";
1107
		} else {
1108
			$xmlrpc_base_url = get_active_xml_rpc_base_url();
1109
			$error = sprintf(gettext(' >>> Unable to communicate with %1$s. Please verify DNS and interface configuration, and that %2$s has functional Internet connectivity.'), $xmlrpc_base_url, $g['product_name']);
1110
			echo "\n{$error}\n";
1111
			log_error(gettext("Cannot reinstall packages: ") . $error);
1112
			return;
1113
		}
1114
		$todo = array();
1115
		$all_names = array();
1116
		foreach ($config['installedpackages']['package'] as $package) {
1117
			$todo[] = array('name' => $package['name'], 'version' => $package['version']);
1118
			$all_names[] = $package['name'];
1119
		}
1120
		$package_name_list = gettext("List of packages to reinstall: ") . implode(", ", $all_names);
1121
		echo " >>> {$package_name_list}\n";
1122
		log_error($package_name_list);
1123

    
1124
		foreach ($todo as $pkgtodo) {
1125
			$static_output = "";
1126
			if ($pkgtodo['name']) {
1127
				log_error(gettext("Uninstalling package") . " {$pkgtodo['name']}");
1128
				uninstall_package($pkgtodo['name']);
1129
				log_error(gettext("Finished uninstalling package") . " {$pkgtodo['name']}");
1130
				log_error(gettext("Reinstalling package") . " {$pkgtodo['name']}");
1131
				install_package($pkgtodo['name'], '', true);
1132
				log_error(gettext("Finished installing package") . " {$pkgtodo['name']}");
1133
			}
1134
		}
1135
		log_error(gettext("Finished reinstalling all packages."));
1136
	} else {
1137
		echo "No packages are installed.";
1138
	}
1139
}
1140

    
1141
function stop_packages() {
1142
	require_once("config.inc");
1143
	require_once("functions.inc");
1144
	require_once("filter.inc");
1145
	require_once("shaper.inc");
1146
	require_once("captiveportal.inc");
1147
	require_once("pkg-utils.inc");
1148
	require_once("pfsense-utils.inc");
1149
	require_once("service-utils.inc");
1150

    
1151
	global $config, $g;
1152

    
1153
	log_error("Stopping all packages.");
1154

    
1155
	$rcfiles = glob(RCFILEPREFIX . "*.sh");
1156
	if (!$rcfiles) {
1157
		$rcfiles = array();
1158
	} else {
1159
		$rcfiles = array_flip($rcfiles);
1160
		if (!$rcfiles) {
1161
			$rcfiles = array();
1162
		}
1163
	}
1164

    
1165
	if (is_array($config['installedpackages']['package'])) {
1166
		foreach ($config['installedpackages']['package'] as $package) {
1167
			echo " Stopping package {$package['name']}...";
1168
			$internal_name = get_package_internal_name($package);
1169
			stop_service($internal_name);
1170
			unset($rcfiles[RCFILEPREFIX . strtolower($internal_name) . ".sh"]);
1171
			echo "done.\n";
1172
		}
1173
	}
1174

    
1175
	foreach ($rcfiles as $rcfile => $number) {
1176
		$shell = @popen("/bin/sh", "w");
1177
		if ($shell) {
1178
			echo " Stopping {$rcfile}...";
1179
			if (!@fwrite($shell, "{$rcfile} stop >>/tmp/bootup_messages 2>&1")) {
1180
				if ($shell) {
1181
					pclose($shell);
1182
				}
1183
				$shell = @popen("/bin/sh", "w");
1184
			}
1185
			echo "done.\n";
1186
			pclose($shell);
1187
		}
1188
	}
1189
}
1190

    
1191
function package_skip_tests($index,$requested_version) {
1192
	global $config, $g;
1193

    
1194
	/* Get pfsense version*/
1195
	$version = rtrim(file_get_contents("/etc/version"));
1196

    
1197
	if ($g['platform'] == "nanobsd") {
1198
		if ($index['noembedded']) {
1199
			return true;
1200
		}
1201
	}
1202

    
1203
	/* If we are on not on HEAD, and the package wants it, skip */
1204
	if ($version <> "HEAD" && $index['required_version'] == "HEAD" && $requested_version <> "other") {
1205
		return true;
1206
	}
1207

    
1208
	/* If there is no required version, and the requested package version is not 'none', then skip */
1209
	if (empty($index['required_version']) && $requested_version <> "none") {
1210
		return true;
1211
	}
1212

    
1213
	/* If the requested version is not 'other', and the required version is newer than what we have, skip. */
1214
	if ($requested_version <> "other" && (pfs_version_compare("", $version, $index['required_version']) < 0)) {
1215
		return true;
1216
	}
1217

    
1218
	/* If the requested version is 'other' and we are on the version requested, skip. */
1219
	if ($requested_version == "other" && (pfs_version_compare("", $version, $index['required_version']) == 0)) {
1220
		return true;
1221
	}
1222

    
1223
	/* Package is only for an older version, lets skip */
1224
	if ($index['maximum_version'] && (pfs_version_compare("", $version, $index['maximum_version']) > 0)) {
1225
		return true;
1226
	}
1227

    
1228
	/* Do not skip package list */
1229
	return false;
1230
}
1231

    
1232
function verify_all_package_servers() {
1233
	return verify_package_server(get_active_xml_rpc_base_url());
1234
}
1235

    
1236
/* Check if the active package server is a valid default or if it has been
1237
	altered. */
1238
function verify_package_server($server) {
1239
	/* Define the expected default package server domains. Include
1240
		preceding "." to prevent matching from being too liberal. */
1241
	$default_package_domains = array('.pfsense.org', '.pfsense.com', '.netgate.com');
1242

    
1243
	/* For this test we only need to check the hostname. */
1244
	$xmlrpcbase = parse_url($server, PHP_URL_HOST);
1245

    
1246
	foreach ($default_package_domains as $dom) {
1247
		if (substr($xmlrpcbase, -(strlen($dom))) == $dom) {
1248
			return true;
1249
		}
1250
	}
1251
	return false;
1252
}
1253

    
1254
/* Test the package server certificate to ensure that it validates properly */
1255
function check_package_server_ssl() {
1256
	global $g;
1257
	$xmlrpcurl = get_active_xml_rpc_base_url() . $g['xmlrpcpath'];
1258

    
1259
	/* If the package server is using HTTP, we can't verify SSL */
1260
	if (substr($xmlrpcurl, 0, 5) == "http:") {
1261
		return "http";
1262
	}
1263

    
1264
	/* Setup a basic cURL connection. We do not care about the content of
1265
		the result, only the SSL verification. */
1266
	$ch = curl_init($xmlrpcurl);
1267
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
1268
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
1269
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, '30');
1270
	curl_setopt($ch, CURLOPT_TIMEOUT, 60);
1271
	curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . rtrim(file_get_contents("/etc/version")));
1272
	$result_page = curl_exec($ch);
1273
	$verifyfail = curl_getinfo($ch, CURLINFO_SSL_VERIFYRESULT);
1274
	curl_close($ch);
1275

    
1276
	/* The result from curl is 1 on failure, 0 on success. */
1277
	if ($verifyfail == 0) {
1278
		return true;
1279
	} else {
1280
		return false;
1281
	}
1282
}
1283

    
1284
/* Keep this message centrally since it will be used several times on pages
1285
	in the GUI. */
1286
function package_server_ssl_failure_message() {
1287
	$msg = "The package server's SSL certificate could not be verified. "
1288
	. "The SSL certificate itself may be invalid, its chain of trust may "
1289
	. "have failed validation, or the server may have been impersonated. "
1290
	. "Downloaded packages may come from an untrusted source. "
1291
	. "Proceed with caution.";
1292

    
1293
	return sprintf(gettext($msg), htmlspecialchars(get_active_xml_rpc_base_url()));
1294
}
1295

    
1296
/* Keep this message centrally since it will be used several times on pages
1297
	in the GUI. */
1298
function package_server_mismatch_message() {
1299
	$msg = "The package server currently configured on "
1300
	. "this firewall (%s) is NOT an official package server. The contents "
1301
	. "of such servers cannot be verified and may contain malicious files. "
1302
	. "Return the package server settings to their default values to "
1303
	. "ensure that verifiable and trusted packages are received.";
1304

    
1305
	return sprintf(gettext($msg), htmlspecialchars(get_active_xml_rpc_base_url())) . '<br/><br/>'
1306
	. '<a href="/pkg_mgr_settings.php">' . gettext("Package Manager Settings") . '</a>';
1307
}
1308

    
1309

    
1310
function pkg_fetch_config_file($package, $pkg_info = "") {
1311
	global $g, $config, $static_output, $pkg_interface;
1312
	conf_mount_rw();
1313

    
1314
	if (empty($pkg_info) or !is_array($pkg_info[$package])) {
1315
		$pkg_info = get_pkg_info(array($package));
1316
		$pkg_info = $pkg_info[$package]; // We're only dealing with one package, so we can strip away the extra array.
1317
		if (empty($pkg_info)) {
1318
			conf_mount_ro();
1319
			return -1;
1320
		}
1321
	}
1322

    
1323
	/* fetch the package's configuration file */
1324
	if ($pkg_info['config_file'] != "") {
1325
		$static_output .= "\n" . gettext("Downloading package configuration file... ");
1326
		update_output_window($static_output);
1327
		pkg_debug(gettext("Downloading package configuration file...") . "\n");
1328
		$fetchto = substr(strrchr($pkg_info['config_file'], '/'), 1);
1329
		download_file_with_progress_bar($pkg_info['config_file'], '/usr/local/pkg/' . $fetchto);
1330
		if (!file_exists('/usr/local/pkg/' . $fetchto)) {
1331
			pkg_debug(gettext("ERROR! Unable to fetch package configuration file. Aborting installation.") . "\n");
1332
			if ($pkg_interface == "console") {
1333
				print "\n" . gettext("ERROR! Unable to fetch package configuration file. Aborting package installation.") . "\n";
1334
			} else {
1335
				$static_output .= gettext("failed!\n\nInstallation aborted.\n");
1336
				update_output_window($static_output);
1337
				echo "<br />Show <a href=\"pkg_mgr_install.php?showlog=true\">install log</a></center>";
1338
			}
1339
			conf_mount_ro();
1340
			return -1;
1341
		}
1342
		$static_output .= gettext("done.") . "\n";
1343
		update_output_window($static_output);
1344
	}
1345
	conf_mount_ro();
1346
	return true;
1347
}
1348

    
1349

    
1350
function pkg_fetch_additional_files($package, $pkg_info = "") {
1351
	global $g, $config, $static_output, $pkg_interface;
1352
	conf_mount_rw();
1353

    
1354
	if (empty($pkg_info) or !is_array($pkg_info[$package])) {
1355
		$pkg_info = get_pkg_info(array($package));
1356
		$pkg_info = $pkg_info[$package]; // We're only dealing with one package, so we can strip away the extra array.
1357
		if (empty($pkg_info)) {
1358
			conf_mount_ro();
1359
			return -1;
1360
		}
1361
	}
1362

    
1363
	$configfile = substr(strrchr($pkg_info['config_file'], '/'), 1);
1364
	if (file_exists("/usr/local/pkg/" . $configfile)) {
1365
		$static_output .= gettext("Loading package configuration... ");
1366
		update_output_window($static_output);
1367
		$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $configfile, "packagegui");
1368
		$static_output .= gettext("done.") . "\n";
1369
		update_output_window($static_output);
1370
		/* download additional files */
1371
		if (is_array($pkg_config['additional_files_needed'])) {
1372
			$static_output .= gettext("Additional files... ");
1373
			$static_orig = $static_output;
1374
			update_output_window($static_output);
1375
			foreach ($pkg_config['additional_files_needed'] as $afn) {
1376
				$filename = get_filename_from_url($afn['item'][0]);
1377
				if ($afn['chmod'] <> "") {
1378
					$pkg_chmod = $afn['chmod'];
1379
				} else {
1380
					$pkg_chmod = "";
1381
				}
1382

    
1383
				if ($afn['prefix'] <> "") {
1384
					$prefix = $afn['prefix'];
1385
				} else {
1386
					$prefix = "/usr/local/pkg/";
1387
				}
1388

    
1389
				if (!is_dir($prefix)) {
1390
					safe_mkdir($prefix);
1391
				}
1392
				$static_output .= $filename . " ";
1393
				update_output_window($static_output);
1394
				if (download_file_with_progress_bar($afn['item'][0], $prefix . $filename) !== true) {
1395
					$static_output .= "failed.\n";
1396
					@unlink($prefix . $filename);
1397
					update_output_window($static_output);
1398
					return false;
1399
				}
1400
				if (stristr($filename, ".tgz") <> "") {
1401
					pkg_debug(gettext("Extracting tarball to -C for ") . $filename . "...\n");
1402
					$tarout = "";
1403
					exec("/usr/bin/tar xvzf " . escapeshellarg($prefix . $filename) . " -C / 2>&1", $tarout);
1404
					pkg_debug(print_r($tarout, true) . "\n");
1405
				}
1406
				if ($pkg_chmod <> "") {
1407
					pkg_debug(sprintf(gettext('Changing file mode to %1$s for %2$s%3$s%4$s'), $pkg_chmod, $prefix, $filename, "\n"));
1408
					@chmod($prefix . $filename, $pkg_chmod);
1409
					system("/bin/chmod {$pkg_chmod} {$prefix}{$filename}");
1410
				}
1411
				$static_output = $static_orig;
1412
				update_output_window($static_output);
1413
			}
1414
			$static_output .= gettext("done.") . "\n";
1415
			update_output_window($static_output);
1416
		}
1417
		conf_mount_ro();
1418
		return true;
1419
	}
1420
}
1421

    
1422
?>
(40-40/67)