Project

General

Profile

Download (54.8 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
$vardb = "/var/db/pkg";
82
safe_mkdir($vardb);
83
$g['platform'] = trim(file_get_contents("/etc/platform"));
84

    
85
if (!is_dir("/usr/local/pkg") or !is_dir("/usr/local/pkg/pf")) {
86
	conf_mount_rw();
87
	safe_mkdir("/usr/local/pkg");
88
	safe_mkdir("/usr/local/pkg/pf");
89
	conf_mount_ro();
90
}
91

    
92
/****f* pkg-utils/remove_package
93
 * NAME
94
 *   remove_package - Removes package from FreeBSD if it exists
95
 * INPUTS
96
 *   $packagestring	- name/string to check for
97
 * RESULT
98
 *   none
99
 * NOTES
100
 *
101
 ******/
102
function remove_freebsd_package($packagestring) {
103
	// The packagestring passed in must be the full PBI package name,
104
	// as displayed by the pbi_info utility. e.g. "package-1.2.3_4-i386"
105
	// It must NOT have ".pbi" on the end.
106
	$links = get_pbi_binaries(escapeshellarg($packagestring));
107
	foreach ($links as $link) {
108
		if (is_link("/usr/local/{$link['link_name']}")) {
109
			@unlink("/usr/local/{$link['link_name']}");
110
		}
111
	}
112
	exec("/usr/local/sbin/pbi_delete " . escapeshellarg($packagestring) . " 2>>/tmp/pbi_delete_errors.txt");
113
}
114

    
115
/****f* pkg-utils/is_package_installed
116
 * NAME
117
 *   is_package_installed - Check whether a package is installed.
118
 * INPUTS
119
 *   $packagename	- name of the package to check
120
 * RESULT
121
 *   boolean	- true if the package is installed, false otherwise
122
 * NOTES
123
 *   This function is deprecated - get_pkg_id() can already check for installation.
124
 ******/
125
function is_package_installed($packagename) {
126
	$pkg = get_pkg_id($packagename);
127
	if ($pkg == -1) {
128
		return false;
129
	}
130
	return true;
131
}
132

    
133
/****f* pkg-utils/get_pkg_id
134
 * NAME
135
 *   get_pkg_id - Find a package's numeric ID.
136
 * INPUTS
137
 *   $pkg_name	- name of the package to check
138
 * RESULT
139
 *   integer    - -1 if package is not found, >-1 otherwise
140
 ******/
141
function get_pkg_id($pkg_name) {
142
	global $config;
143

    
144
	if (is_array($config['installedpackages']['package'])) {
145
		foreach ($config['installedpackages']['package'] as $idx => $pkg) {
146
			if ($pkg['name'] == $pkg_name) {
147
				return $idx;
148
			}
149
		}
150
	}
151
	return -1;
152
}
153

    
154
/****f* pkg-utils/get_pkg_internal_name
155
 * NAME
156
 *   get_pkg_internal_name - Find a package's internal name (e.g. squid3 internal name is squid)
157
 * INPUTS
158
 *   $package - array of package data from config
159
 * RESULT
160
 *   string - internal name (if defined) or default to package name
161
 ******/
162
function get_pkg_internal_name($package) {
163
	if (isset($package['internal_name']) && ($package['internal_name'] != "")) {
164
		/* e.g. name is Ipguard-dev, internal name is ipguard */
165
		$pkg_internal_name = $package['internal_name'];
166
	} else {
167
		$pkg_internal_name = $package['name'];
168
	}
169
	return $pkg_internal_name;
170
}
171

    
172
/****f* pkg-utils/get_pkg_info
173
 * NAME
174
 *   get_pkg_info - Retrieve package information from package server.
175
 * INPUTS
176
 *   $pkgs - 'all' to retrieve all packages, an array containing package names otherwise
177
 *   $info - 'all' to retrieve all information, an array containing keys otherwise
178
 * RESULT
179
 *   $raw_versions - Array containing retrieved information, indexed by package name.
180
 ******/
181
function get_pkg_info($pkgs = 'all', $info = 'all') {
182
	global $g;
183

    
184
	$freebsd_machine = php_uname("m");
185
	$params = array(
186
		"pkg" => $pkgs,
187
		"info" => $info,
188
		"freebsd_version" => get_freebsd_version(),
189
		"freebsd_machine" => $freebsd_machine
190
	);
191
	$resp = call_pfsense_method('pfsense.get_pkgs', $params, 10);
192
	return $resp ? $resp : array();
193
}
194

    
195
function get_pkg_sizes($pkgs = 'all') {
196
	global $config, $g;
197

    
198
	$freebsd_machine = php_uname("m");
199
	$params = array(
200
		"pkg" => $pkgs,
201
		"freebsd_version" => get_freebsd_version(),
202
		"freebsd_machine" => $freebsd_machine
203
	);
204
	$msg = new XML_RPC_Message('pfsense.get_pkg_sizes', array(php_value_to_xmlrpc($params)));
205
	$xmlrpc_base_url = get_active_xml_rpc_base_url();
206
	$cli = new XML_RPC_Client($g['xmlrpcpath'], $xmlrpc_base_url);
207
	$resp = $cli->send($msg, 10);
208
	if (!is_object($resp)) {
209
		log_error("Could not get response from XMLRPC server!");
210
	} else if (!$resp->faultCode()) {
211
		$raw_versions = $resp->value();
212
		return xmlrpc_value_to_php($raw_versions);
213
	}
214

    
215
	return array();
216
}
217

    
218
/*
219
 * resync_all_package_configs() Force packages to setup their configuration and rc.d files.
220
 * This function may also print output to the terminal indicating progress.
221
 */
222
function resync_all_package_configs($show_message = false) {
223
	global $config, $pkg_interface, $g;
224

    
225
	log_error(gettext("Resyncing configuration for all packages."));
226

    
227
	if (!is_array($config['installedpackages']['package'])) {
228
		return;
229
	}
230

    
231
	if ($show_message == true) {
232
		echo "Syncing packages:";
233
	}
234

    
235
	conf_mount_rw();
236

    
237
	foreach ($config['installedpackages']['package'] as $idx => $package) {
238
		if (empty($package['name'])) {
239
			continue;
240
		}
241
		if ($show_message == true) {
242
			echo " " . $package['name'];
243
		}
244
		get_pkg_depends($package['name'], "all");
245
		if (platform_booting() != true) {
246
			stop_service(get_pkg_internal_name($package));
247
		}
248
		sync_package($idx, true, true);
249
		if ($pkg_interface == "console") {
250
			echo "\n" . gettext("Syncing packages:");
251
		}
252
	}
253

    
254
	if ($show_message == true) {
255
		echo " done.\n";
256
	}
257

    
258
	@unlink("/conf/needs_package_sync");
259
	conf_mount_ro();
260
}
261

    
262
/*
263
 * is_freebsd_pkg_installed() - Check /var/db/pkg to determine whether or not a FreeBSD
264
 *				package is installed.
265
 */
266
function is_freebsd_pkg_installed($pkg) {
267
	if (!$pkg) {
268
		return;
269
	}
270
	$output = "";
271
	$_gb = exec("/usr/local/sbin/pbi_info " . escapeshellarg($pkg) . ' 2>/dev/null', $output, $retval);
272

    
273
	return (intval($retval) == 0);
274
}
275

    
276
/*
277
 * get_pkg_depends($pkg_name, $filetype = ".xml", $format = "files", return_nosync = 1):  Return a package's dependencies.
278
 *
279
 * $filetype = "all" || ".xml", ".tgz", etc.
280
 * $format = "files" (full filenames) || "names" (stripped / parsed depend names)
281
 * $return_nosync = 1 (return depends that have nosync set) | 0 (ignore packages with nosync)
282
 *
283
 */
284
function get_pkg_depends($pkg_name, $filetype = ".xml", $format = "files", $return_nosync = 1) {
285
	global $config;
286

    
287
	$pkg_id = get_pkg_id($pkg_name);
288
	if ($pkg_id == -1) {
289
		return -1; // This package doesn't really exist - exit the function.
290
	} else if (!isset($config['installedpackages']['package'][$pkg_id])) {
291
		return; // No package belongs to the pkg_id passed to this function.
292
	}
293

    
294
	$package =& $config['installedpackages']['package'][$pkg_id];
295
	if (!file_exists("/usr/local/pkg/" . $package['configurationfile'])) {
296
		log_error(sprintf(gettext('The %1$s package is missing required dependencies and must be reinstalled. %2$s'), $package['name'], $package['configurationfile']));
297
		uninstall_package($package['name']);
298
		if (install_package($package['name']) < 0) {
299
			log_error("Failed reinstalling package {$package['name']}.");
300
			return false;
301
		}
302
	}
303
	$pkg_xml = parse_xml_config_pkg("/usr/local/pkg/" . $package['configurationfile'], "packagegui");
304
	if (!empty($pkg_xml['additional_files_needed'])) {
305
		foreach ($pkg_xml['additional_files_needed'] as $item) {
306
			if ($return_nosync == 0 && isset($item['nosync'])) {
307
				continue; // Do not return depends with nosync set if not required.
308
			}
309
			$depend_file = substr(strrchr($item['item']['0'], '/'),1); // Strip URLs down to filenames.
310
			$depend_name = substr(substr($depend_file,0,strpos($depend_file,".")+1),0,-1); // Strip filename down to dependency name.
311
			if (($filetype != "all") && (!preg_match("/{$filetype}/i", $depend_file))) {
312
				if (($filetype != "all") && (strtolower(substr($depend_file, -strlen($filetype))) != strtolower($filetype))) {
313
					continue;
314
				}
315
			}
316
			if ($item['prefix'] != "") {
317
				$prefix = $item['prefix'];
318
			} else {
319
				$prefix = "/usr/local/pkg/";
320
			}
321
			// Ensure that the prefix exists to avoid installation errors.
322
			if (!is_dir($prefix)) {
323
				exec("/bin/mkdir -p {$prefix}");
324
			}
325
			if (!file_exists($prefix . $depend_file)) {
326
				log_error(sprintf(gettext("The %s package is missing required dependencies and must be reinstalled."), $package['name']));
327
			}
328
			switch ($format) {
329
				case "files":
330
					$depends[] = $prefix . $depend_file;
331
					break;
332
				case "names":
333
					switch ($filetype) {
334
						case "all":
335
							if (preg_match("/\.xml/i", $depend_file)) {
336
								$depend_xml = parse_xml_config_pkg("/usr/local/pkg/{$depend_file}", "packagegui");
337
								if (!empty($depend_xml)) {
338
									$depends[] = $depend_xml['name'];
339
								}
340
							} else {
341
								$depends[] = $depend_name; // If this dependency isn't package XML, use the stripped filename.
342
							}
343
							break;
344
						case ".xml":
345
							$depend_xml = parse_xml_config_pkg("/usr/local/pkg/" . $depend_file, "packagegui");
346
							if (!empty($depend_xml)) {
347
								$depends[] = $depend_xml['name'];
348
							}
349
							break;
350
						default:
351
							$depends[] = $depend_name; // If we aren't looking for XML, use the stripped filename (it's all we have).
352
							break;
353
					}
354
			}
355
		}
356
		return $depends;
357
	}
358
}
359

    
360
function uninstall_package($pkg_name) {
361
	global $config, $static_output;
362
	global $builder_package_install;
363

    
364
	$id = get_pkg_id($pkg_name);
365
	if ($id >= 0) {
366
		stop_service(get_pkg_internal_name($config['installedpackages']['package'][$id]));
367
		$pkg_depends =& $config['installedpackages']['package'][$id]['depends_on_package_pbi'];
368
		$static_output .= "Removing package...\n";
369
		update_output_window($static_output);
370
		if (is_array($pkg_depends)) {
371
			foreach ($pkg_depends as $pkg_depend) {
372
				delete_package($pkg_depend);
373
			}
374
		} else {
375
			// The packages (1 or more) are all in one long string.
376
			// We need to pass them 1 at a time to delete_package.
377
			// Compress any multiple whitespace (sp, tab, cr, lf...) into a single space char.
378
			$pkg_dep_str = preg_replace("'\s+'", ' ', $pkg_depends);
379
			// Get rid of any leading or trailing space.
380
			$pkg_dep_str = trim($pkg_dep_str);
381
			// Now we have a space-separated string. Make it into an array and process it.
382
			$pkg_dep_array = explode(" ", $pkg_dep_str);
383
			foreach ($pkg_dep_array as $pkg_depend) {
384
				delete_package($pkg_depend);
385
			}
386
		}
387
	}
388
	delete_package_xml($pkg_name);
389

    
390
	$static_output .= gettext("done.") . "\n";
391
	update_output_window($static_output);
392
}
393

    
394
function force_remove_package($pkg_name) {
395
	delete_package_xml($pkg_name);
396
}
397

    
398
/*
399
 * sync_package($pkg_name, $sync_depends = true, $show_message = false) Force a package to setup its configuration and rc.d files.
400
 */
401
function sync_package($pkg_name, $sync_depends = true, $show_message = false) {
402
	global $config, $config_parsed;
403
	global $builder_package_install;
404

    
405
	// If this code is being called by pfspkg_installer
406
	// which the builder system uses then return (ignore).
407
	if ($builder_package_install) {
408
		return;
409
	}
410

    
411
	if (empty($config['installedpackages']['package'])) {
412
		return;
413
	}
414
	if (!is_numeric($pkg_name)) {
415
		$pkg_id = get_pkg_id($pkg_name);
416
		if ($pkg_id == -1) {
417
			return -1; // This package doesn't really exist - exit the function.
418
		}
419
	} else {
420
		$pkg_id = $pkg_name;
421
	}
422

    
423
	if (!is_array($config['installedpackages']['package'][$pkg_id])) {
424
		return;  // No package belongs to the pkg_id passed to this function.
425
	}
426

    
427
	$package =& $config['installedpackages']['package'][$pkg_id];
428
	if (!file_exists("/usr/local/pkg/" . $package['configurationfile'])) {
429
		log_error(sprintf(gettext("The %s package is missing its configuration file and must be reinstalled."), $package['name']));
430
		force_remove_package($package['name']);
431
		return -1;
432
	}
433
	$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $package['configurationfile'], "packagegui");
434
	if (isset($pkg_config['nosync'])) {
435
		return;
436
	}
437
	/* Bring in package include files */
438
	if (!empty($pkg_config['include_file'])) {
439
		$include_file = $pkg_config['include_file'];
440
		if (file_exists($include_file)) {
441
			require_once($include_file);
442
		} else {
443
			/* XXX: What the heck is this?! */
444
			log_error("Reinstalling package {$package['name']} because its include file({$include_file}) is missing!");
445
			uninstall_package($package['name']);
446
			if (install_package($package['name']) < 0) {
447
				log_error("Reinstalling package {$package['name']} failed. Take appropriate measures!!!");
448
				return -1;
449
			}
450
		}
451
	}
452

    
453
	if (!empty($pkg_config['custom_php_global_functions'])) {
454
		eval($pkg_config['custom_php_global_functions']);
455
	}
456
	if (!empty($pkg_config['custom_php_resync_config_command'])) {
457
		eval($pkg_config['custom_php_resync_config_command']);
458
	}
459
	if ($sync_depends == true) {
460
		$depends = get_pkg_depends($pkg_name, ".xml", "files", 1); // Call dependency handler and do a little more error checking.
461
		if (is_array($depends)) {
462
			foreach ($depends as $item) {
463
				if (!file_exists($item)) {
464
					require_once("notices.inc");
465
					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);
466
					log_error("Could not find {$item}. Reinstalling package.");
467
					uninstall_package($pkg_name);
468
					if (install_package($pkg_name) < 0) {
469
						log_error("Reinstalling package {$package['name']} failed. Take appropriate measures!!!");
470
						return -1;
471
					}
472
				} else {
473
					$item_config = parse_xml_config_pkg($item, "packagegui");
474
					if (empty($item_config)) {
475
						continue;
476
					}
477
					if (isset($item_config['nosync'])) {
478
						continue;
479
					}
480
					if (!empty($item_config['include_file'])) {
481
						if (file_exists($item_config['include_file'])) {
482
							require_once($item_config['include_file']);
483
						} else {
484
							log_error("Not calling package sync code for dependency {$item_config['name']} of {$package['name']} because some include files are missing.");
485
							continue;
486
						}
487
					}
488
					if ($item_config['custom_php_global_functions'] <> "") {
489
						eval($item_config['custom_php_global_functions']);
490
					}
491
					if ($item_config['custom_php_resync_config_command'] <> "") {
492
						eval($item_config['custom_php_resync_config_command']);
493
					}
494
					if ($show_message == true) {
495
						print " " . $item_config['name'];
496
					}
497
				}
498
			}
499
		}
500
	}
501
}
502

    
503
/*
504
 * pkg_fetch_recursive: Download and install a FreeBSD PBI package. This function provides output to
505
 * 			a progress bar and output window.
506
 */
507
function pkg_fetch_recursive($pkgname, $filename, $dependlevel = 0, $base_url = "") {
508
	global $static_output, $g, $config;
509

    
510
	// Clean up incoming filenames
511
	$filename = str_replace("  ", " ", $filename);
512
	$filename = str_replace("\n", " ", $filename);
513
	$filename = str_replace("  ", " ", $filename);
514

    
515
	$pkgs = explode(" ", $filename);
516
	foreach ($pkgs as $filename) {
517
		$filename = trim($filename);
518
		if ($g['platform'] == "nanobsd") {
519
			$pkgtmpdir = "/usr/bin/env PKG_TMPDIR=/root/ ";
520
			$pkgstagingdir = "/root/tmp";
521
			if (!is_dir($pkgstagingdir)) {
522
				mkdir($pkgstagingdir);
523
			}
524
			$pkgstaging = "-o {$pkgstagingdir}/instmp.XXXXXX";
525
			$fetchdir = $pkgstagingdir;
526
		} else {
527
			$fetchdir = $g['tmp_path'];
528
		}
529

    
530
		/* FreeBSD has no PBI's hosted, so fall back to our own URL for now. (Maybe fail to PC-BSD?) */
531
		$rel = get_freebsd_version();
532
		$priv_url = "https://files.pfsense.org/packages/{$rel}/All/";
533
		if (empty($base_url)) {
534
			$base_url = $priv_url;
535
		}
536
		if (substr($base_url, -1) == "/") {
537
			$base_url = substr($base_url, 0, -1);
538
		}
539
		$fetchto = "{$fetchdir}/apkg_{$filename}";
540
		$static_output .= "\n" . str_repeat(" ", $dependlevel * 2 + 1) . "Downloading {$base_url}/{$filename} ... ";
541
		if (download_file_with_progress_bar("{$base_url}/{$filename}", $fetchto) !== true) {
542
			if ($base_url != $priv_url && download_file_with_progress_bar("{$priv_url}/{$filename}", $fetchto) !== true) {
543
				$static_output .= " could not download from there or {$priv_url}/{$filename}.\n";
544
				update_output_window($static_output);
545
				return false;
546
			} else if ($base_url == $priv_url) {
547
				$static_output .= " failed to download.\n";
548
				update_output_window($static_output);
549
				return false;
550
			} else {
551
				$static_output .= " [{$osname} repository]\n";
552
				update_output_window($static_output);
553
			}
554
		}
555
		$static_output .= " (extracting)\n";
556
		update_output_window($static_output);
557

    
558
		$pkgaddout = "";
559

    
560
		$no_checksig = "";
561
		if (isset($config['system']['pkg_nochecksig'])) {
562
			$no_checksig = "--no-checksig";
563
		}
564

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

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

    
573
			$links = get_pbi_binaries(escapeshellarg($pbi_name));
574
			foreach ($links as $link) {
575
				@unlink("/usr/local/{$link['link_name']}");
576
				@symlink("{$link['target']}","/usr/local/{$link['link_name']}");
577
			}
578

    
579
			$extra_links = array(
580
				array("target" => "bin", "link_name" => "sbin"),
581
				array("target" => "local/lib", "link_name" => "lib"),
582
				array("target" => "local/libexec", "link_name" => "libexec"),
583
				array("target" => "local/share", "link_name" => "share"),
584
				array("target" => "local/www", "link_name" => "www"),
585
				array("target" => "local/etc", "link_name" => "etc")
586
			);
587

    
588
			foreach ($extra_links as $link) {
589
				if (!file_exists($pbi_prefix . "/" . $link['target'])) {
590
					continue;
591
				}
592
				@rmdir("{$pbi_prefix}/{$link['link_name']}");
593
				unlink_if_exists("{$pbi_prefix}/{$link['link_name']}");
594
				@symlink("{$pbi_prefix}/{$link['target']}", "{$pbi_prefix}/{$link['link_name']}");
595
			}
596
			pkg_debug("pbi_add successfully completed.\n");
597
		} else {
598
			if (is_array($pkgaddout)) {
599
				foreach ($pkgaddout as $line) {
600
					$static_output .= " " . $line .= "\n";
601
				}
602
			}
603

    
604
			update_output_window($static_output);
605
			pkg_debug("pbi_add failed.\n");
606
			return false;
607
		}
608
	}
609
	return true;
610
}
611

    
612
function get_pbi_binaries($pbi) {
613
	$result = array();
614

    
615
	if (empty($pbi)) {
616
		return $result;
617
	}
618

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

    
622
	if (empty($pbi_prefix)) {
623
		return $result;
624
	}
625

    
626
	foreach (array('bin', 'sbin') as $dir) {
627
		if (!is_dir("{$pbi_prefix}/{$dir}")) {
628
			continue;
629
		}
630

    
631
		$files = glob("{$pbi_prefix}/{$dir}/*.pbiopt");
632
		foreach ($files as $f) {
633
			$pbiopts = file($f, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
634
			foreach ($pbiopts as $pbiopt) {
635
				if (!preg_match('/^TARGET:\s+(.*)$/', $pbiopt, $matches)) {
636
					continue;
637
				}
638

    
639
				$result[] = array(
640
					'target' => preg_replace('/\.pbiopt$/', '', $f),
641
					'link_name' => $matches[1]);
642
			}
643
		}
644
	}
645

    
646
	return $result;
647
}
648

    
649

    
650
function install_package($package, $pkg_info = "", $force_install = false) {
651
	global $g, $config, $static_output, $pkg_interface;
652

    
653
	/* safe side. Write config below will send to ro again. */
654
	conf_mount_rw();
655

    
656
	if ($pkg_interface == "console") {
657
		echo "\n";
658
	}
659
	/* fetch package information if needed */
660
	if (empty($pkg_info) or !is_array($pkg_info[$package])) {
661
		$pkg_info = get_pkg_info(array($package));
662
		$pkg_info = $pkg_info[$package]; // We're only dealing with one package, so we can strip away the extra array.
663
		if (empty($pkg_info)) {
664
			conf_mount_ro();
665
			return -1;
666
		}
667
	}
668
	if (!$force_install) {
669
		$compatible = true;
670
		$version = rtrim(file_get_contents("/etc/version"));
671

    
672
		if (isset($pkg_info['required_version'])) {
673
			$compatible = (pfs_version_compare("", $version, $pkg_info['required_version']) >= 0);
674
		}
675
		if (isset($pkg_info['maximum_version'])) {
676
			$compatible = $compatible && (pfs_version_compare("", $version, $pkg_info['maximum_version']) <= 0);
677
		}
678

    
679
		if (!$compatible) {
680
			log_error(sprintf(gettext('Package %s is not supported on this version.'), $pkg_info['name']));
681
			$static_output .= sprintf(gettext("Package %s is not supported on this version."), $pkg_info['name']);
682
			update_status($static_output);
683

    
684
			conf_mount_ro();
685
			return -1;
686
		}
687
	}
688
	pkg_debug(gettext("Beginning package installation.") . "\n");
689
	log_error(sprintf(gettext('Beginning package installation for %s .'), $pkg_info['name']));
690
	$static_output .= sprintf(gettext("Beginning package installation for %s ."), $pkg_info['name']);
691
	update_status($static_output);
692

    
693
	/* fetch the package's configuration file */
694
	pkg_fetch_config_file($package, $pkg_info);
695

    
696
	/* add package information to config.xml */
697
	$pkgid = get_pkg_id($pkg_info['name']);
698
	$static_output .= gettext("Saving updated package information...") . " ";
699
	update_output_window($static_output);
700
	if ($pkgid == -1) {
701
		$config['installedpackages']['package'][] = $pkg_info;
702
		$changedesc = sprintf(gettext("Installed %s package."),$pkg_info['name']);
703
		$to_output = gettext("done.") . "\n";
704
	} else {
705
		$config['installedpackages']['package'][$pkgid] = $pkg_info;
706
		$changedesc = sprintf(gettext("Overwrote previous installation of %s."), $pkg_info['name']);
707
		$to_output = gettext("overwrite!") . "\n";
708
	}
709
	if (file_exists('/conf/needs_package_sync')) {
710
		@unlink('/conf/needs_package_sync');
711
	}
712
	conf_mount_ro();
713
	write_config("Intermediate config write during package install for {$pkg_info['name']}.");
714
	$static_output .= $to_output;
715
	update_output_window($static_output);
716
	/* install other package components */
717
	if (!install_package_xml($package)) {
718
		uninstall_package($package);
719
		write_config($changedesc);
720
		log_error(sprintf(gettext("Failed to install package: %s."), $pkg_info['name']));
721
		$static_output .= gettext("Failed to install package.") . "\n";
722
		update_output_window($static_output);
723
		return -1;
724
	} else {
725
		$static_output .= gettext("Writing configuration... ");
726
		update_output_window($static_output);
727
		write_config($changedesc);
728
		log_error(sprintf(gettext("Successfully installed package: %s."), $pkg_info['name']));
729
		$static_output .= gettext("done.") . "\n";
730
		update_output_window($static_output);
731
		if ($pkg_info['after_install_info']) {
732
			update_output_window($pkg_info['after_install_info']);
733
		}
734
	}
735
}
736

    
737
function get_after_install_info($package) {
738
	global $pkg_info;
739
	/* fetch package information if needed */
740
	if (!$pkg_info or !is_array($pkg_info[$package])) {
741
		$pkg_info = get_pkg_info(array($package));
742
		$pkg_info = $pkg_info[$package]; // We're only dealing with one package, so we can strip away the extra array.
743
	}
744
	if ($pkg_info['after_install_info']) {
745
		return $pkg_info['after_install_info'];
746
	}
747
}
748

    
749
function eval_once($toeval) {
750
	global $evaled;
751
	if (!$evaled) {
752
		$evaled = array();
753
	}
754
	$evalmd5 = md5($toeval);
755
	if (!in_array($evalmd5, $evaled)) {
756
		@eval($toeval);
757
		$evaled[] = $evalmd5;
758
	}
759
	return;
760
}
761

    
762
function install_package_xml($pkg) {
763
	global $g, $config, $static_output, $pkg_interface, $config_parsed;
764

    
765
	if (($pkgid = get_pkg_id($pkg)) == -1) {
766
		$static_output .= sprintf(gettext("The %s package is not installed.%sInstallation aborted."), $pkg, "\n\n");
767
		update_output_window($static_output);
768
		if ($pkg_interface <> "console") {
769
			echo "\n<script type=\"text/javascript\">document.progressbar.style.visibility='hidden';</script>";
770
			echo "\n<script type=\"text/javascript\">document.progholder.style.visibility='hidden';</script>";
771
		}
772
		sleep(1);
773
		return false;
774
	} else {
775
		$pkg_info = $config['installedpackages']['package'][$pkgid];
776
	}
777

    
778
	/* pkg_add the package and its dependencies */
779
	if ($pkg_info['depends_on_package_base_url'] != "") {
780
		if ($pkg_interface == "console") {
781
			echo "\n";
782
		}
783
		update_status(gettext("Installing") . " " . $pkg_info['name'] . " " . gettext("and its dependencies."));
784
		$static_output .= gettext("Downloading") . " " . $pkg_info['name'] . " " . gettext("and its dependencies... ");
785
		$static_orig = $static_output;
786
		$static_output .= "\n";
787
		update_output_window($static_output);
788
		foreach ((array) $pkg_info['depends_on_package_pbi'] as $pkgdep) {
789
			$pkg_name = substr(reverse_strrchr($pkgdep, "."), 0, -1);
790
			$static_output = $static_orig . "\nChecking for package installation... ";
791
			update_output_window($static_output);
792
			if (!is_freebsd_pkg_installed($pkg_name)) {
793
				if (!pkg_fetch_recursive($pkg_name, $pkgdep, 0, $pkg_info['depends_on_package_base_url'])) {
794
					$static_output .= "of {$pkg_name} failed!\n\nInstallation aborted.";
795
					update_output_window($static_output);
796
					pkg_debug(gettext("Package WAS NOT installed properly.") . "\n");
797
					if ($pkg_interface <> "console") {
798
						echo "\n<script type=\"text/javascript\">document.progressbar.style.visibility='hidden';</script>";
799
						echo "\n<script type=\"text/javascript\">document.progholder.style.visibility='hidden';</script>";
800
					}
801
					sleep(1);
802
					return false;
803
				}
804
			}
805
		}
806
	}
807

    
808
	$configfile = substr(strrchr($pkg_info['config_file'], '/'), 1);
809
	if (file_exists("/usr/local/pkg/" . $configfile)) {
810
		$static_output .= gettext("Loading package configuration... ");
811
		update_output_window($static_output);
812
		$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $configfile, "packagegui");
813
		$static_output .= gettext("done.") . "\n";
814
		update_output_window($static_output);
815
		$static_output .= gettext("Configuring package components...\n");
816
		if (!empty($pkg_config['filter_rules_needed'])) {
817
			$config['installedpackages']['package'][$pkgid]['filter_rule_function'] = $pkg_config['filter_rules_needed'];
818
		}
819
		update_output_window($static_output);
820
		/* modify system files */
821
		if (is_array($pkg_config['modify_system']) && is_array($pkg_config['modify_system']['item'])) {
822
			$static_output .= gettext("System files... ");
823
			update_output_window($static_output);
824
			foreach ($pkg_config['modify_system']['item'] as $ms) {
825
				if ($ms['textneeded']) {
826
					add_text_to_file($ms['modifyfilename'], $ms['textneeded']);
827
				}
828
			}
829
			$static_output .= gettext("done.") . "\n";
830
			update_output_window($static_output);
831
		}
832

    
833
		pkg_fetch_additional_files($pkg, $pkg_info);
834

    
835
		/*   if a require exists, include it.  this will
836
		 *   show us where an error exists in a package
837
		 *   instead of making us blindly guess
838
		 */
839
		$missing_include = false;
840
		if ($pkg_config['include_file'] <> "") {
841
			$static_output .= gettext("Loading package instructions...") . "\n";
842
			update_output_window($static_output);
843
			pkg_debug("require_once('{$pkg_config['include_file']}')\n");
844
			if (file_exists($pkg_config['include_file'])) {
845
				require_once($pkg_config['include_file']);
846
			} else {
847
				$missing_include = true;
848
				$static_output .= "Include " . basename($pkg_config['include_file']) . " is missing!\n";
849
				update_output_window($static_output);
850
				/* XXX: Should undo the steps before this?! */
851
				return false;
852
			}
853
		}
854

    
855
		/* custom commands */
856
		$static_output .= gettext("Custom commands...") . "\n";
857
		update_output_window($static_output);
858
		if ($missing_include == false) {
859
			if ($pkg_config['custom_php_global_functions'] <> "") {
860
				$static_output .= gettext("Executing custom_php_global_functions()...");
861
				update_output_window($static_output);
862
				eval_once($pkg_config['custom_php_global_functions']);
863
				$static_output .= gettext("done.") . "\n";
864
				update_output_window($static_output);
865
			}
866
			if ($pkg_config['custom_php_install_command']) {
867
				$static_output .= gettext("Executing custom_php_install_command()...");
868
				update_output_window($static_output);
869
				/* XXX: create symlinks for conf files into the PBI directories.
870
				 *	change packages to store configs at /usr/pbi/pkg/etc and remove this
871
				 */
872
				eval_once($pkg_config['custom_php_install_command']);
873
				// Note: pkg may be mixed-case, e.g. "squidGuard" but the PBI names are lowercase.
874
				// e.g. "squidguard-1.4_4-i386" so feed lowercase to pbi_info below.
875
				// Also add the "-" so that examples like "squid-" do not match "squidguard-".
876
				$pkg_name_for_pbi_match = strtolower($pkg) . "-";
877
				exec("/usr/local/sbin/pbi_info | grep '^{$pkg_name_for_pbi_match}' | xargs /usr/local/sbin/pbi_info | awk '/Prefix/ {print $2}'",$pbidirarray);
878
				$pbidir0 = $pbidirarray[0];
879
				exec("find /usr/local/etc/ -name *.conf | grep " . escapeshellarg($pkg),$files);
880
				foreach ($files as $f) {
881
					$pbiconf = str_replace('/usr/local',$pbidir0,$f);
882
					if (is_file($pbiconf) || is_link($pbiconf)) {
883
						unlink($pbiconf);
884
					}
885
					if (is_dir(dirname($pbiconf))) {
886
						symlink($f,$pbiconf);
887
					} else {
888
						log_error("The dir for {$pbiconf} does not exist. Cannot add symlink to {$f}.");
889
					}
890
				}
891
				eval_once($pkg_config['custom_php_install_command']);
892
				$static_output .= gettext("done.") . "\n";
893
				update_output_window($static_output);
894
			}
895
			if ($pkg_config['custom_php_resync_config_command'] <> "") {
896
				$static_output .= gettext("Executing custom_php_resync_config_command()...");
897
				update_output_window($static_output);
898
				eval_once($pkg_config['custom_php_resync_config_command']);
899
				$static_output .= gettext("done.") . "\n";
900
				update_output_window($static_output);
901
			}
902
		}
903
		/* sidebar items */
904
		if (is_array($pkg_config['menu'])) {
905
			$static_output .= gettext("Menu items... ");
906
			update_output_window($static_output);
907
			foreach ($pkg_config['menu'] as $menu) {
908
				if (is_array($config['installedpackages']['menu'])) {
909
					foreach ($config['installedpackages']['menu'] as $amenu) {
910
						if ($amenu['name'] == $menu['name']) {
911
							continue 2;
912
						}
913
					}
914
				} else {
915
					$config['installedpackages']['menu'] = array();
916
				}
917
				$config['installedpackages']['menu'][] = $menu;
918
			}
919
			$static_output .= gettext("done.") . "\n";
920
			update_output_window($static_output);
921
		}
922
		/* integrated tab items */
923
		if (is_array($pkg_config['tabs']['tab'])) {
924
			$static_output .= gettext("Integrated Tab items... ");
925
			update_output_window($static_output);
926
			foreach ($pkg_config['tabs']['tab'] as $tab) {
927
				if (is_array($config['installedpackages']['tab'])) {
928
					foreach ($config['installedpackages']['tab'] as $atab) {
929
						if ($atab['name'] == $tab['name']) {
930
							continue 2;
931
						}
932
					}
933
				} else {
934
					$config['installedpackages']['tab'] = array();
935
				}
936
				$config['installedpackages']['tab'][] = $tab;
937
			}
938
			$static_output .= gettext("done.") . "\n";
939
			update_output_window($static_output);
940
		}
941
		/* services */
942
		if (is_array($pkg_config['service'])) {
943
			$static_output .= gettext("Services... ");
944
			update_output_window($static_output);
945
			foreach ($pkg_config['service'] as $service) {
946
				if (is_array($config['installedpackages']['service'])) {
947
					foreach ($config['installedpackages']['service'] as $aservice) {
948
						if ($aservice['name'] == $service['name']) {
949
							continue 2;
950
						}
951
					}
952
				} else {
953
					$config['installedpackages']['service'] = array();
954
				}
955
				$config['installedpackages']['service'][] = $service;
956
			}
957
			$static_output .= gettext("done.") . "\n";
958
			update_output_window($static_output);
959
		}
960
	} else {
961
		$static_output .= gettext("Loading package configuration... failed!") . "\n\n" . gettext("Installation aborted.");
962
		update_output_window($static_output);
963
		pkg_debug(gettext("Unable to load package configuration. Installation aborted.") ."\n");
964
		if ($pkg_interface <> "console") {
965
			echo "\n<script type=\"text/javascript\">document.progressbar.style.visibility='hidden';</script>";
966
			echo "\n<script type=\"text/javascript\">document.progholder.style.visibility='hidden';</script>";
967
		}
968
		sleep(1);
969
		return false;
970
	}
971

    
972
	/* set up package logging streams */
973
	if ($pkg_info['logging']) {
974
		mwexec("/usr/sbin/fifolog_create -s 32768 {$g['varlog_path']}/{$pkg_info['logging']['logfilename']}");
975
		@chmod($g['varlog_path'] . '/' . $pkg_info['logging']['logfilename'], 0600);
976
		add_text_to_file("/etc/syslog.conf", $pkg_info['logging']['facilityname'] . "\t\t\t\t" . $pkg_info['logging']['logfilename']);
977
		pkg_debug("Adding text to file /etc/syslog.conf\n");
978
		system_syslogd_start();
979
	}
980

    
981
	return true;
982
}
983

    
984
function does_package_depend($pkg) {
985
	// Should not happen, but just in case.
986
	if (!$pkg) {
987
		return;
988
	}
989
	$pkg_var_db_dir = glob("/var/db/pkg/{$pkg}*");
990
	// If this package has dependency then return true
991
	foreach ($pkg_var_db_dir as $pvdd) {
992
		if (file_exists("{$vardb}/{$pvdd}/+REQUIRED_BY") && count(file("{$vardb}/{$pvdd}/+REQUIRED_BY")) > 0) {
993
			return true;
994
		}
995
	}
996
	// Did not find a record of dependencies, so return false.
997
	return false;
998
}
999

    
1000
function delete_package($pkg) {
1001
	global $config, $g, $static_output, $vardb;
1002

    
1003
	if (!$pkg) {
1004
		return;
1005
	}
1006

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

    
1010
	if ($pkg) {
1011
		$static_output .= sprintf(gettext("Starting package deletion for %s..."),$pkg);
1012
	}
1013
	update_output_window($static_output);
1014

    
1015
	remove_freebsd_package($pkg);
1016
	$static_output .= "done.\n";
1017
	update_output_window($static_output);
1018

    
1019
	/* Rescan directories for what has been left and avoid fooling other programs. */
1020
	mwexec("/sbin/ldconfig");
1021

    
1022
	return;
1023
}
1024

    
1025
function delete_package_xml($pkg) {
1026
	global $g, $config, $static_output, $pkg_interface;
1027

    
1028
	conf_mount_rw();
1029

    
1030
	$pkgid = get_pkg_id($pkg);
1031
	if ($pkgid == -1) {
1032
		$static_output .= sprintf(gettext("The %s package is not installed.%sDeletion aborted."), $pkg, "\n\n");
1033
		update_output_window($static_output);
1034
		if ($pkg_interface <> "console") {
1035
			echo "\n<script type=\"text/javascript\">document.progressbar.style.visibility='hidden';</script>";
1036
			echo "\n<script type=\"text/javascript\">document.progholder.style.visibility='hidden';</script>";
1037
		}
1038
		ob_flush();
1039
		sleep(1);
1040
		conf_mount_ro();
1041
		return;
1042
	}
1043
	pkg_debug(sprintf(gettext("Removing %s package... "),$pkg));
1044
	$static_output .= sprintf(gettext("Removing %s components..."),$pkg) . "\n";
1045
	update_output_window($static_output);
1046
	/* parse package configuration */
1047
	$packages = &$config['installedpackages']['package'];
1048
	$tabs =& $config['installedpackages']['tab'];
1049
	$menus =& $config['installedpackages']['menu'];
1050
	$services = &$config['installedpackages']['service'];
1051
	$pkg_info =& $packages[$pkgid];
1052
	if (file_exists("/usr/local/pkg/" . $pkg_info['configurationfile'])) {
1053
		$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $packages[$pkgid]['configurationfile'], "packagegui");
1054
		/* remove tab items */
1055
		if (is_array($pkg_config['tabs'])) {
1056
			$static_output .= gettext("Tabs items... ");
1057
			update_output_window($static_output);
1058
			if (is_array($pkg_config['tabs']['tab']) && is_array($tabs)) {
1059
				foreach ($pkg_config['tabs']['tab'] as $tab) {
1060
					foreach ($tabs as $key => $insttab) {
1061
						if ($insttab['name'] == $tab['name']) {
1062
							unset($tabs[$key]);
1063
							break;
1064
						}
1065
					}
1066
				}
1067
			}
1068
			$static_output .= gettext("done.") . "\n";
1069
			update_output_window($static_output);
1070
		}
1071
		/* remove menu items */
1072
		if (is_array($pkg_config['menu'])) {
1073
			$static_output .= gettext("Menu items... ");
1074
			update_output_window($static_output);
1075
			if (is_array($pkg_config['menu']) && is_array($menus)) {
1076
				foreach ($pkg_config['menu'] as $menu) {
1077
					foreach ($menus as $key => $instmenu) {
1078
						if ($instmenu['name'] == $menu['name']) {
1079
							unset($menus[$key]);
1080
							break;
1081
						}
1082
					}
1083
				}
1084
			}
1085
			$static_output .= gettext("done.") . "\n";
1086
			update_output_window($static_output);
1087
		}
1088
		/* remove services */
1089
		if (is_array($pkg_config['service'])) {
1090
			$static_output .= gettext("Services... ");
1091
			update_output_window($static_output);
1092
			if (is_array($pkg_config['service']) && is_array($services)) {
1093
				foreach ($pkg_config['service'] as $service) {
1094
					foreach ($services as $key => $instservice) {
1095
						if ($instservice['name'] == $service['name']) {
1096
							if (platform_booting() != true) {
1097
								stop_service($service['name']);
1098
							}
1099
							if ($service['rcfile']) {
1100
								$prefix = RCFILEPREFIX;
1101
								if (!empty($service['prefix'])) {
1102
									$prefix = $service['prefix'];
1103
								}
1104
								if (file_exists("{$prefix}{$service['rcfile']}")) {
1105
									@unlink("{$prefix}{$service['rcfile']}");
1106
								}
1107
							}
1108
							unset($services[$key]);
1109
						}
1110
					}
1111
				}
1112
			}
1113
			$static_output .= gettext("done.") . "\n";
1114
			update_output_window($static_output);
1115
		}
1116
		/*
1117
		 * XXX: Otherwise inclusion of config.inc again invalidates actions taken.
1118
		 * 	Same is done during installation.
1119
		 */
1120
		write_config("Intermediate config write during package removal for {$pkg}.");
1121

    
1122
		/*
1123
		 * If a require exists, include it.  this will
1124
		 * show us where an error exists in a package
1125
		 * instead of making us blindly guess
1126
		 */
1127
		$missing_include = false;
1128
		if ($pkg_config['include_file'] <> "") {
1129
			$static_output .= gettext("Loading package instructions...") . "\n";
1130
			update_output_window($static_output);
1131
			pkg_debug("require_once(\"{$pkg_config['include_file']}\")\n");
1132
			if (file_exists($pkg_config['include_file'])) {
1133
				require_once($pkg_config['include_file']);
1134
			} else {
1135
				$missing_include = true;
1136
				update_output_window($static_output);
1137
				$static_output .= "Include file " . basename($pkg_config['include_file']) . " could not be found for inclusion.\n";
1138
			}
1139
		}
1140
		/* ermal
1141
		 * NOTE: It is not possible to handle parse errors on eval.
1142
		 * So we prevent it from being run at all to not interrupt all the other code.
1143
		 */
1144
		if ($missing_include == false) {
1145
			/* evaluate this package's global functions and pre deinstall commands */
1146
			if ($pkg_config['custom_php_global_functions'] <> "") {
1147
				eval_once($pkg_config['custom_php_global_functions']);
1148
			}
1149
			if ($pkg_config['custom_php_pre_deinstall_command'] <> "") {
1150
				eval_once($pkg_config['custom_php_pre_deinstall_command']);
1151
			}
1152
		}
1153
		/* system files */
1154
		if (is_array($pkg_config['modify_system']) && is_array($pkg_config['modify_system']['item'])) {
1155
			$static_output .= gettext("System files... ");
1156
			update_output_window($static_output);
1157
			foreach ($pkg_config['modify_system']['item'] as $ms) {
1158
				if ($ms['textneeded']) {
1159
					remove_text_from_file($ms['modifyfilename'], $ms['textneeded']);
1160
				}
1161
			}
1162

    
1163
			$static_output .= gettext("done.") . "\n";
1164
			update_output_window($static_output);
1165
		}
1166
		/* deinstall commands */
1167
		if ($pkg_config['custom_php_deinstall_command'] <> "") {
1168
			$static_output .= gettext("Deinstall commands... ");
1169
			update_output_window($static_output);
1170
			if ($missing_include == false) {
1171
				eval_once($pkg_config['custom_php_deinstall_command']);
1172
				$static_output .= gettext("done.") . "\n";
1173
			} else {
1174
				$static_output .= "\nNot executing custom deinstall hook because an include is missing.\n";
1175
			}
1176
			update_output_window($static_output);
1177
		}
1178
		if ($pkg_config['include_file'] <> "") {
1179
			$static_output .= gettext("Removing package instructions...");
1180
			update_output_window($static_output);
1181
			pkg_debug(sprintf(gettext("Remove '%s'"), $pkg_config['include_file']) . "\n");
1182
			unlink_if_exists("/usr/local/pkg/" . $pkg_config['include_file']);
1183
			$static_output .= gettext("done.") . "\n";
1184
			update_output_window($static_output);
1185
		}
1186
		/* remove all additional files */
1187
		if (is_array($pkg_config['additional_files_needed'])) {
1188
			$static_output .= gettext("Auxiliary files... ");
1189
			update_output_window($static_output);
1190
			foreach ($pkg_config['additional_files_needed'] as $afn) {
1191
				$filename = get_filename_from_url($afn['item'][0]);
1192
				if ($afn['prefix'] <> "") {
1193
					$prefix = $afn['prefix'];
1194
				} else {
1195
					$prefix = "/usr/local/pkg/";
1196
				}
1197
				unlink_if_exists($prefix . $filename);
1198
			}
1199
			$static_output .= gettext("done.") . "\n";
1200
			update_output_window($static_output);
1201
		}
1202
		/* package XML file */
1203
		$static_output .= gettext("Package XML... ");
1204
		update_output_window($static_output);
1205
		unlink_if_exists("/usr/local/pkg/" . $packages[$pkgid]['configurationfile']);
1206
		$static_output .= gettext("done.") . "\n";
1207
		update_output_window($static_output);
1208
	}
1209
	/* syslog */
1210
	if (is_array($pkg_info['logging']) && $pkg_info['logging']['logfile_name'] <> "") {
1211
		$static_output .= "Syslog entries... ";
1212
		update_output_window($static_output);
1213
		remove_text_from_file("/etc/syslog.conf", $pkg_info['logging']['facilityname'] . "\t\t\t\t" . $pkg_info['logging']['logfilename']);
1214
		system_syslogd_start();
1215
		@unlink("{$g['varlog_path']}/{$pkg_info['logging']['logfilename']}");
1216
		$static_output .= "done.\n";
1217
		update_output_window($static_output);
1218
	}
1219

    
1220
	conf_mount_ro();
1221
	/* remove config.xml entries */
1222
	$static_output .= gettext("Configuration... ");
1223
	update_output_window($static_output);
1224
	unset($config['installedpackages']['package'][$pkgid]);
1225
	$static_output .= gettext("done.") . "\n";
1226
	update_output_window($static_output);
1227
	write_config("Removed {$pkg} package.\n");
1228
}
1229

    
1230
function expand_to_bytes($size) {
1231
	$conv = array(
1232
			"G" =>	"3",
1233
			"M" =>  "2",
1234
			"K" =>  "1",
1235
			"B" =>  "0"
1236
		);
1237
	$suffix = substr($size, -1);
1238
	if (!in_array($suffix, array_keys($conv))) {
1239
		return $size;
1240
	}
1241
	$size = substr($size, 0, -1);
1242
	for ($i = 0; $i < $conv[$suffix]; $i++) {
1243
		$size *= 1024;
1244
	}
1245
	return $size;
1246
}
1247

    
1248
function get_pkg_db() {
1249
	global $g;
1250
	return return_dir_as_array($g['vardb_path'] . '/pkg');
1251
}
1252

    
1253
function walk_depend($depend, $pkgdb = "", $alreadyseen = "") {
1254
	if (!$pkgdb) {
1255
		$pkgdb = get_pkg_db();
1256
	}
1257
	if (!is_array($alreadyseen)) {
1258
		$alreadyseen = array();
1259
	}
1260
	if (!is_array($depend)) {
1261
		$depend = array();
1262
	}
1263
	foreach ($depend as $adepend) {
1264
		$pkgname = reverse_strrchr($adepend['name'], '.');
1265
		if (in_array($pkgname, $alreadyseen)) {
1266
			continue;
1267
		} elseif (!in_array($pkgname, $pkgdb)) {
1268
			$size += expand_to_bytes($adepend['size']);
1269
			$alreadyseen[] = $pkgname;
1270
			if (is_array($adepend['depend'])) {
1271
				$size += walk_depend($adepend['depend'], $pkgdb, $alreadyseen);
1272
			}
1273
		}
1274
	}
1275
	return $size;
1276
}
1277

    
1278
function get_package_install_size($pkg = 'all', $pkg_info = "") {
1279
	global $config, $g;
1280
	if ((!is_array($pkg)) and ($pkg != 'all')) {
1281
		$pkg = array($pkg);
1282
	}
1283
	$pkgdb = get_pkg_db();
1284
	if (!$pkg_info) {
1285
		$pkg_info = get_pkg_sizes($pkg);
1286
	}
1287
	foreach ($pkg as $apkg) {
1288
		if (!$pkg_info[$apkg]) {
1289
			continue;
1290
		}
1291
		$toreturn[$apkg] = expand_to_bytes(walk_depend(array($pkg_info[$apkg]), $pkgdb));
1292
	}
1293
	return $toreturn;
1294
}
1295

    
1296
function squash_from_bytes($size, $round = "") {
1297
	$conv = array(1 => "B", "K", "M", "G");
1298
	foreach ($conv as $div => $suffix) {
1299
		$sizeorig = $size;
1300
		if (($size /= 1024) < 1) {
1301
			if ($round) {
1302
				$sizeorig = round($sizeorig, $round);
1303
			}
1304
			return $sizeorig . $suffix;
1305
		}
1306
	}
1307
	return;
1308
}
1309

    
1310
function pkg_reinstall_all() {
1311
	global $g, $config;
1312

    
1313
	@unlink('/conf/needs_package_sync');
1314
	if (is_array($config['installedpackages']['package'])) {
1315
		echo gettext("One moment please, reinstalling packages...\n");
1316
		echo gettext(" >>> Trying to fetch package info...");
1317
		log_error(gettext("Attempting to reinstall all packages"));
1318
		$pkg_info = get_pkg_info();
1319
		if ($pkg_info) {
1320
			echo " Done.\n";
1321
		} else {
1322
			$xmlrpc_base_url = get_active_xml_rpc_base_url();
1323
			$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']);
1324
			echo "\n{$error}\n";
1325
			log_error(gettext("Cannot reinstall packages: ") . $error);
1326
			return;
1327
		}
1328
		$todo = array();
1329
		$all_names = array();
1330
		foreach ($config['installedpackages']['package'] as $package) {
1331
			$todo[] = array('name' => $package['name'], 'version' => $package['version']);
1332
			$all_names[] = $package['name'];
1333
		}
1334
		$package_name_list = gettext("List of packages to reinstall: ") . implode(", ", $all_names);
1335
		echo " >>> {$package_name_list}\n";
1336
		log_error($package_name_list);
1337

    
1338
		foreach ($todo as $pkgtodo) {
1339
			$static_output = "";
1340
			if ($pkgtodo['name']) {
1341
				log_error(gettext("Uninstalling package") . " {$pkgtodo['name']}");
1342
				uninstall_package($pkgtodo['name']);
1343
				log_error(gettext("Finished uninstalling package") . " {$pkgtodo['name']}");
1344
				log_error(gettext("Reinstalling package") . " {$pkgtodo['name']}");
1345
				install_package($pkgtodo['name'], '', true);
1346
				log_error(gettext("Finished installing package") . " {$pkgtodo['name']}");
1347
			}
1348
		}
1349
		log_error(gettext("Finished reinstalling all packages."));
1350
	} else {
1351
		echo "No packages are installed.";
1352
	}
1353
}
1354

    
1355
function stop_packages() {
1356
	require_once("config.inc");
1357
	require_once("functions.inc");
1358
	require_once("filter.inc");
1359
	require_once("shaper.inc");
1360
	require_once("captiveportal.inc");
1361
	require_once("pkg-utils.inc");
1362
	require_once("pfsense-utils.inc");
1363
	require_once("service-utils.inc");
1364

    
1365
	global $config, $g;
1366

    
1367
	log_error("Stopping all packages.");
1368

    
1369
	$rcfiles = glob(RCFILEPREFIX . "*.sh");
1370
	if (!$rcfiles) {
1371
		$rcfiles = array();
1372
	} else {
1373
		$rcfiles = array_flip($rcfiles);
1374
		if (!$rcfiles) {
1375
			$rcfiles = array();
1376
		}
1377
	}
1378

    
1379
	if (is_array($config['installedpackages']['package'])) {
1380
		foreach ($config['installedpackages']['package'] as $package) {
1381
			echo " Stopping package {$package['name']}...";
1382
			$internal_name = get_pkg_internal_name($package);
1383
			stop_service($internal_name);
1384
			unset($rcfiles[RCFILEPREFIX . strtolower($internal_name) . ".sh"]);
1385
			echo "done.\n";
1386
		}
1387
	}
1388

    
1389
	foreach ($rcfiles as $rcfile => $number) {
1390
		$shell = @popen("/bin/sh", "w");
1391
		if ($shell) {
1392
			echo " Stopping {$rcfile}...";
1393
			if (!@fwrite($shell, "{$rcfile} stop >>/tmp/bootup_messages 2>&1")) {
1394
				if ($shell) {
1395
					pclose($shell);
1396
				}
1397
				$shell = @popen("/bin/sh", "w");
1398
			}
1399
			echo "done.\n";
1400
			pclose($shell);
1401
		}
1402
	}
1403
}
1404

    
1405
function package_skip_tests($index,$requested_version) {
1406
	global $config, $g;
1407

    
1408
	/* Get pfsense version*/
1409
	$version = rtrim(file_get_contents("/etc/version"));
1410

    
1411
	if ($g['platform'] == "nanobsd") {
1412
		if ($index['noembedded']) {
1413
			return true;
1414
		}
1415
	}
1416

    
1417
	/* If we are on not on HEAD, and the package wants it, skip */
1418
	if ($version <> "HEAD" && $index['required_version'] == "HEAD" && $requested_version <> "other") {
1419
		return true;
1420
	}
1421

    
1422
	/* If there is no required version, and the requested package version is not 'none', then skip */
1423
	if (empty($index['required_version']) && $requested_version <> "none") {
1424
		return true;
1425
	}
1426

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

    
1432
	/* If the requested version is 'other' and we are on the version requested, skip. */
1433
	if ($requested_version == "other" && (pfs_version_compare("", $version, $index['required_version']) == 0)) {
1434
		return true;
1435
	}
1436

    
1437
	/* Package is only for an older version, lets skip */
1438
	if ($index['maximum_version'] && (pfs_version_compare("", $version, $index['maximum_version']) > 0)) {
1439
		return true;
1440
	}
1441

    
1442
	/* Do not skip package list */
1443
	return false;
1444
}
1445

    
1446
function get_pkg_interfaces_select_source($include_localhost=false) {
1447
	$interfaces = get_configured_interface_with_descr();
1448
	$ssifs = array();
1449
	foreach ($interfaces as $iface => $ifacename) {
1450
		$tmp["name"]  = $ifacename;
1451
		$tmp["value"] = $iface;
1452
		$ssifs[] = $tmp;
1453
	}
1454
	if ($include_localhost) {
1455
		$tmp["name"]  = "Localhost";
1456
		$tmp["value"] = "lo0";
1457
		$ssifs[] = $tmp;
1458
	}
1459
	return $ssifs;
1460
}
1461

    
1462
function verify_all_package_servers() {
1463
	return verify_package_server(get_active_xml_rpc_base_url());
1464
}
1465

    
1466
/* Check if the active package server is a valid default or if it has been
1467
	altered. */
1468
function verify_package_server($server) {
1469
	/* Define the expected default package server domains. Include
1470
		preceding "." to prevent matching from being too liberal. */
1471
	$default_package_domains = array('.pfsense.org', '.pfsense.com', '.netgate.com');
1472

    
1473
	/* For this test we only need to check the hostname. */
1474
	$xmlrpcbase = parse_url($server, PHP_URL_HOST);
1475

    
1476
	foreach ($default_package_domains as $dom) {
1477
		if (substr($xmlrpcbase, -(strlen($dom))) == $dom) {
1478
			return true;
1479
		}
1480
	}
1481
	return false;
1482
}
1483

    
1484
/* Test the package server certificate to ensure that it validates properly */
1485
function check_package_server_ssl() {
1486
	global $g;
1487
	$xmlrpcurl = get_active_xml_rpc_base_url() . $g['xmlrpcpath'];
1488

    
1489
	/* If the package server is using HTTP, we can't verify SSL */
1490
	if (substr($xmlrpcurl, 0, 5) == "http:") {
1491
		return "http";
1492
	}
1493

    
1494
	/* Setup a basic cURL connection. We do not care about the content of
1495
		the result, only the SSL verification. */
1496
	$ch = curl_init($xmlrpcurl);
1497
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
1498
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
1499
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, '30');
1500
	curl_setopt($ch, CURLOPT_TIMEOUT, 60);
1501
	curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . rtrim(file_get_contents("/etc/version")));
1502
	$result_page = curl_exec($ch);
1503
	$verifyfail = curl_getinfo($ch, CURLINFO_SSL_VERIFYRESULT);
1504
	curl_close($ch);
1505

    
1506
	/* The result from curl is 1 on failure, 0 on success. */
1507
	if ($verifyfail == 0) {
1508
		return true;
1509
	} else {
1510
		return false;
1511
	}
1512
}
1513

    
1514
/* Keep this message centrally since it will be used several times on pages
1515
	in the GUI. */
1516
function package_server_ssl_failure_message() {
1517
	$msg = "The package server's SSL certificate could not be verified. "
1518
	. "The SSL certificate itself may be invalid, its chain of trust may "
1519
	. "have failed validation, or the server may have been impersonated. "
1520
	. "Downloaded packages may come from an untrusted source. "
1521
	. "Proceed with caution.";
1522

    
1523
	return sprintf(gettext($msg), htmlspecialchars(get_active_xml_rpc_base_url()));
1524
}
1525

    
1526
/* Keep this message centrally since it will be used several times on pages
1527
	in the GUI. */
1528
function package_server_mismatch_message() {
1529
	$msg = "The package server currently configured on "
1530
	. "this firewall (%s) is NOT an official package server. The contents "
1531
	. "of such servers cannot be verified and may contain malicious files. "
1532
	. "Return the package server settings to their default values to "
1533
	. "ensure that verifiable and trusted packages are received.";
1534

    
1535
	return sprintf(gettext($msg), htmlspecialchars(get_active_xml_rpc_base_url())) . '<br/><br/>'
1536
	. '<a href="/pkg_mgr_settings.php">' . gettext("Package Manager Settings") . '</a>';
1537
}
1538

    
1539

    
1540
function pkg_fetch_config_file($package, $pkg_info = "") {
1541
	global $g, $config, $static_output, $pkg_interface;
1542
	conf_mount_rw();
1543

    
1544
	if (empty($pkg_info) or !is_array($pkg_info[$package])) {
1545
		$pkg_info = get_pkg_info(array($package));
1546
		$pkg_info = $pkg_info[$package]; // We're only dealing with one package, so we can strip away the extra array.
1547
		if (empty($pkg_info)) {
1548
			conf_mount_ro();
1549
			return -1;
1550
		}
1551
	}
1552

    
1553
	/* fetch the package's configuration file */
1554
	if ($pkg_info['config_file'] != "") {
1555
		$static_output .= "\n" . gettext("Downloading package configuration file... ");
1556
		update_output_window($static_output);
1557
		pkg_debug(gettext("Downloading package configuration file...") . "\n");
1558
		$fetchto = substr(strrchr($pkg_info['config_file'], '/'), 1);
1559
		download_file_with_progress_bar($pkg_info['config_file'], '/usr/local/pkg/' . $fetchto);
1560
		if (!file_exists('/usr/local/pkg/' . $fetchto)) {
1561
			pkg_debug(gettext("ERROR! Unable to fetch package configuration file. Aborting installation.") . "\n");
1562
			if ($pkg_interface == "console") {
1563
				print "\n" . gettext("ERROR! Unable to fetch package configuration file. Aborting package installation.") . "\n";
1564
			} else {
1565
				$static_output .= gettext("failed!\n\nInstallation aborted.\n");
1566
				update_output_window($static_output);
1567
				echo "<br />Show <a href=\"pkg_mgr_install.php?showlog=true\">install log</a></center>";
1568
			}
1569
			conf_mount_ro();
1570
			return -1;
1571
		}
1572
		$static_output .= gettext("done.") . "\n";
1573
		update_output_window($static_output);
1574
	}
1575
	conf_mount_ro();
1576
	return true;
1577
}
1578

    
1579

    
1580
function pkg_fetch_additional_files($package, $pkg_info = "") {
1581
	global $g, $config, $static_output, $pkg_interface;
1582
	conf_mount_rw();
1583

    
1584
	if (empty($pkg_info) or !is_array($pkg_info[$package])) {
1585
		$pkg_info = get_pkg_info(array($package));
1586
		$pkg_info = $pkg_info[$package]; // We're only dealing with one package, so we can strip away the extra array.
1587
		if (empty($pkg_info)) {
1588
			conf_mount_ro();
1589
			return -1;
1590
		}
1591
	}
1592

    
1593
	$configfile = substr(strrchr($pkg_info['config_file'], '/'), 1);
1594
	if (file_exists("/usr/local/pkg/" . $configfile)) {
1595
		$static_output .= gettext("Loading package configuration... ");
1596
		update_output_window($static_output);
1597
		$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $configfile, "packagegui");
1598
		$static_output .= gettext("done.") . "\n";
1599
		update_output_window($static_output);
1600
		/* download additional files */
1601
		if (is_array($pkg_config['additional_files_needed'])) {
1602
			$static_output .= gettext("Additional files... ");
1603
			$static_orig = $static_output;
1604
			update_output_window($static_output);
1605
			foreach ($pkg_config['additional_files_needed'] as $afn) {
1606
				$filename = get_filename_from_url($afn['item'][0]);
1607
				if ($afn['chmod'] <> "") {
1608
					$pkg_chmod = $afn['chmod'];
1609
				} else {
1610
					$pkg_chmod = "";
1611
				}
1612

    
1613
				if ($afn['prefix'] <> "") {
1614
					$prefix = $afn['prefix'];
1615
				} else {
1616
					$prefix = "/usr/local/pkg/";
1617
				}
1618

    
1619
				if (!is_dir($prefix)) {
1620
					safe_mkdir($prefix);
1621
				}
1622
				$static_output .= $filename . " ";
1623
				update_output_window($static_output);
1624
				if (download_file_with_progress_bar($afn['item'][0], $prefix . $filename) !== true) {
1625
					$static_output .= "failed.\n";
1626
					@unlink($prefix . $filename);
1627
					update_output_window($static_output);
1628
					return false;
1629
				}
1630
				if (stristr($filename, ".tgz") <> "") {
1631
					pkg_debug(gettext("Extracting tarball to -C for ") . $filename . "...\n");
1632
					$tarout = "";
1633
					exec("/usr/bin/tar xvzf " . escapeshellarg($prefix . $filename) . " -C / 2>&1", $tarout);
1634
					pkg_debug(print_r($tarout, true) . "\n");
1635
				}
1636
				if ($pkg_chmod <> "") {
1637
					pkg_debug(sprintf(gettext('Changing file mode to %1$s for %2$s%3$s%4$s'), $pkg_chmod, $prefix, $filename, "\n"));
1638
					@chmod($prefix . $filename, $pkg_chmod);
1639
					system("/bin/chmod {$pkg_chmod} {$prefix}{$filename}");
1640
				}
1641
				$static_output = $static_orig;
1642
				update_output_window($static_output);
1643
			}
1644
			$static_output .= gettext("done.") . "\n";
1645
			update_output_window($static_output);
1646
		}
1647
		conf_mount_ro();
1648
		return true;
1649
	}
1650
}
1651

    
1652
?>
(41-41/68)