Project

General

Profile

Download (37.9 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
 *
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
 * RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
 * POSSIBILITY OF SUCH DAMAGE.
33
 *
34
 */
35

    
36
/*
37
	pfSense_BUILDER_BINARIES:	/usr/bin/cd	/usr/bin/tar	/bin/cat	/usr/sbin/fifolog_create	/bin/chmod
38
	pfSense_BUILDER_BINARIES:	/usr/bin/killall	/usr/sbin/pkg_info	/usr/sbin/pkg_delete	/bin/rm	/bin/ls
39
	pfSense_BUILDER_BINARIES:	/sbin/pfctl
40
	pfSense_MODULE:	pkg
41
*/
42

    
43
require_once("xmlrpc.inc");
44
if(file_exists("/cf/conf/use_xmlreader"))
45
	require_once("xmlreader.inc");
46
else
47
	require_once("xmlparse.inc");
48
require_once("service-utils.inc");
49
require_once("pfsense-utils.inc");
50
require_once("globals.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
		if (!$fd_log) {
72
			if (!$fd_log = fopen("{$g['tmp_path']}/pkg_mgr_{$package}.log", "w"))
73
				update_output_window("Warning, could not open log for writing.");
74
		}
75
		@fwrite($fd_log, $msg);
76
	}
77
}
78

    
79
$vardb = "/var/db/pkg";
80
safe_mkdir($vardb);
81
$g['platform'] = trim(file_get_contents("/etc/platform"));
82

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

    
90
/****f* pkg-utils/remove_package
91
 * NAME
92
 *   remove_package - Removes package from FreeBSD if it exists
93
 * INPUTS
94
 *   $packagestring	- name/string to check for
95
 * RESULT
96
 *   none
97
 * NOTES
98
 *   
99
 ******/
100
function remove_freebsd_package($packagestring) {
101
	$todel = substr(reverse_strrchr($packagestring, "."), 0, -1);
102
	exec("/usr/sbin/pkg_delete -x {$todel}");
103
}
104

    
105
/****f* pkg-utils/is_package_installed
106
 * NAME
107
 *   is_package_installed - Check whether a package is installed.
108
 * INPUTS
109
 *   $packagename	- name of the package to check
110
 * RESULT
111
 *   boolean	- true if the package is installed, false otherwise
112
 * NOTES
113
 *   This function is deprecated - get_pkg_id() can already check for installation.
114
 ******/
115
function is_package_installed($packagename) {
116
	$pkg = get_pkg_id($packagename);
117
	if($pkg == -1)
118
		return false;
119
	return true;
120
}
121

    
122
/****f* pkg-utils/get_pkg_id
123
 * NAME
124
 *   get_pkg_id - Find a package's numeric ID.
125
 * INPUTS
126
 *   $pkg_name	- name of the package to check
127
 * RESULT
128
 *   integer    - -1 if package is not found, >-1 otherwise
129
 ******/
130
function get_pkg_id($pkg_name) {
131
	global $config;
132

    
133
	if(is_array($config['installedpackages']['package'])) {
134
		$i = 0;
135
		foreach($config['installedpackages']['package'] as $pkg) {
136
			if($pkg['name'] == $pkg_name)
137
				return $i;
138
			$i++;
139
		}
140
	}
141
	return -1;
142
}
143

    
144
/****f* pkg-utils/get_pkg_info
145
 * NAME
146
 *   get_pkg_info - Retrive package information from pfsense.com.
147
 * INPUTS
148
 *   $pkgs - 'all' to retrive all packages, an array containing package names otherwise
149
 *   $info - 'all' to retrive all information, an array containing keys otherwise
150
 * RESULT
151
 *   $raw_versions - Array containing retrieved information, indexed by package name.
152
 ******/
153
function get_pkg_info($pkgs = 'all', $info = 'all') {
154
	global $g;
155

    
156
	$freebsd_version = str_replace("\n", "", `uname -r | cut -d'-' -f1 | cut -d'.' -f1`);
157
	$freebsd_machine = str_replace("\n", "", `uname -m`);
158
	$params = array(
159
		"pkg" => $pkgs, 
160
		"info" => $info, 
161
		"freebsd_version" => $freebsd_version,
162
		"freebsd_machine" => $freebsd_machine
163
	);
164
	$resp = call_pfsense_method('pfsense.get_pkgs', $params, 10);
165
	return $resp ? $resp : array();
166
}
167

    
168
function get_pkg_sizes($pkgs = 'all') {
169
	global $g;
170

    
171
	$params = array("pkg" => $pkgs);
172
	$msg = new XML_RPC_Message('pfsense.get_pkg_sizes', array(php_value_to_xmlrpc($params)));
173
	$xmlrpc_base_url = isset($config['system']['altpkgrepo']['enable']) ? $config['system']['altpkgrepo']['xmlrpcbaseurl'] : $g['xmlrpcbaseurl'];
174
	$cli = new XML_RPC_Client($g['xmlrpcpath'], $xmlrpc_base_url);
175
	$resp = $cli->send($msg, 10);
176
	if($resp and !$resp->faultCode()) {
177
		$raw_versions = $resp->value();
178
		return xmlrpc_value_to_php($raw_versions);
179
	}
180

    
181
	return 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, $restart_sync, $pkg_interface;
190

    
191
	$i = 0;
192
	log_error("Resyncing configuration for all packages.");
193
	if(!$config['installedpackages']['package'])
194
		return;
195
	if($show_message == true)
196
		echo "Syncing packages:";
197

    
198
	if (is_array($config['installedpackages']['package'])) {
199
		foreach($config['installedpackages']['package'] as $package) {
200
			if (empty($package['name']))
201
				continue;
202
			if($show_message == true)
203
				echo " " . $package['name'];
204
			get_pkg_depends($package['name'], "all");
205
			stop_service($package['name']);
206
			sync_package($i, true, true);
207
			if($restart_sync == true) {
208
				$restart_sync = false;
209
				if($pkg_interface == "console") 
210
					echo "\nSyncing packages:";
211
			}
212
			$i++;
213
		}
214
	}
215
	if($show_message == true)
216
		echo " done.\n";
217
	@unlink("/conf/needs_package_sync");
218
}
219

    
220
/*
221
 * is_freebsd_pkg_installed() - Check /var/db/pkg to determine whether or not a FreeBSD
222
 *				package is installed.
223
 */
224
function is_freebsd_pkg_installed($pkg) {
225
	$output = "";
226
	exec("/usr/sbin/pkg_info -E \"{$pkg}*\"", $output, $retval);
227

    
228
	return (intval($retval) == 0);
229
}
230

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

    
243
	$pkg_id = get_pkg_id($pkg_name);
244
	if($pkg_id == -1)
245
		return -1; // This package doesn't really exist - exit the function.
246
	else if (!isset($config['installedpackages']['package'][$pkg_id]))
247
		return; // No package belongs to the pkg_id passed to this function.
248

    
249
	$package =& $config['installedpackages']['package'][$pkg_id];
250
	if(!file_exists("/usr/local/pkg/" . $package['configurationfile'])) {
251
		log_error("The {$package['name']} package is missing required dependencies and is being reinstalled." . $package['configurationfile']);
252
		uninstall_package($package['name']);
253
		if (install_package($package['name']) < 0)
254
			return false;
255
	}
256
	$pkg_xml = parse_xml_config_pkg("/usr/local/pkg/" . $package['configurationfile'], "packagegui");
257
	if (!empty($pkg_xml['additional_files_needed'])) {
258
		foreach($pkg_xml['additional_files_needed'] as $item) {
259
			if ($return_nosync == 0 && isset($item['nosync']))
260
				continue; // Do not return depends with nosync set if not required.
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
					continue;
265
			if ($item['prefix'] != "")
266
				$prefix = $item['prefix'];
267
			else
268
				$prefix = "/usr/local/pkg/";
269
			// Ensure that the prefix exists to avoid installation errors.
270
			if(!is_dir($prefix)) 
271
				exec("/bin/mkdir -p {$prefix}");
272
			if(!file_exists($prefix . $depend_file))
273
				log_error("The {$package['name']} package is missing required dependencies and must be reinstalled.");
274
			switch ($format) {
275
			case "files":
276
				$depends[] = $prefix . $depend_file;
277
				break;
278
			case "names":
279
				switch ($filetype) {
280
				case "all":
281
					if(preg_match("/\.xml/i", $depend_file)) {
282
						$depend_xml = parse_xml_config_pkg("/usr/local/pkg/{$depend_file}", "packagegui");
283
						if (!empty($depend_xml))
284
							$depends[] = $depend_xml['name'];
285
					} else
286
						$depends[] = $depend_name; // If this dependency isn't package XML, use the stripped filename.
287
					break;
288
				case ".xml":
289
					$depend_xml = parse_xml_config_pkg("/usr/local/pkg/" . $depend_file, "packagegui");
290
					if (!empty($depend_xml))
291
						$depends[] = $depend_xml['name'];
292
					break;
293
				default:
294
					$depends[] = $depend_name; // If we aren't looking for XML, use the stripped filename (it's all we have).
295
					break;
296
				}
297
			}
298
		}
299
		return $depends;
300
	}
301
}
302

    
303
function uninstall_package($pkg_name) {
304
	global $config, $static_output;
305

    
306
	$id = get_pkg_id($pkg_name);
307
	if ($id >= 0) {
308
		$pkg_depends =& $config['installedpackages']['package'][$id]['depends_on_package'];
309
		$static_output .= "Removing package...\n";
310
		update_output_window($static_output);
311
		if (is_array($pkg_depends)) {
312
			foreach ($pkg_depends as $pkg_depend)
313
				delete_package($pkg_depend);
314
		}
315
	}
316
	delete_package_xml($pkg_name);
317
}
318

    
319
function force_remove_package($pkg_name) {
320
	global $config;
321
	delete_package_xml($pkg_name);
322
}
323

    
324
/*
325
 * sync_package($pkg_name, $sync_depends = true, $show_message = false) Force a package to setup its configuration and rc.d files.
326
 */
327
function sync_package($pkg_name, $sync_depends = true, $show_message = false) {
328
	global $config;
329
	require_once("notices.inc");
330
	
331
	if(empty($config['installedpackages']['package']))
332
		return;
333
	if(!is_numeric($pkg_name)) {
334
		$pkg_id = get_pkg_id($pkg_name);
335
		if($pkg_id == -1)
336
			return -1; // This package doesn't really exist - exit the function.
337
	} else {
338
		$pkg_id = $pkg_name;
339
		if(empty($config['installedpackages']['package'][$pkg_id]))
340
			return;  // No package belongs to the pkg_id passed to this function.
341
	}
342
        if (is_array($config['installedpackages']['package'][$pkg_id]))
343
		$package =& $config['installedpackages']['package'][$pkg_id];
344
        else
345
		return; /* empty package tag */
346
	if(!file_exists("/usr/local/pkg/" . $package['configurationfile'])) {
347
		log_error("The {$package['name']} package is missing its configuration file and must be reinstalled.");
348
		force_remove_package($package['name']);
349
		return -1;
350
	}
351
	$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $package['configurationfile'], "packagegui");
352

    
353
	/* Bring in package include files */
354
	if (!empty($pkg_config['include_file'])) {
355
		$include_file = $pkg_config['include_file'];
356
		if (file_exists($include_file))
357
			require_once($include_file);
358
		else {
359
			/* XXX: What the heck is this?! */
360
			log_error("Reinstalling package {$package['name']} because its include file({$include_file}) is missing!");
361
			uninstall_package($package['name']);
362
			if (install_package($package['name']) < 0) {
363
				log_error("Reinstalling package {$package['name']} failed. Take appropriate measures!!!");
364
				return -1;
365
			}
366
		}
367
	}
368

    
369
	/* XXX: Zend complains about the next line "Wrong break depth"
370
	 * The code is obviously wrong, but I'm not sure what it's supposed to do?
371
	 */
372
	if(isset($pkg_config['nosync']))
373
		continue;
374
	if(!empty($pkg_config['custom_php_global_functions']))
375
		eval($pkg_config['custom_php_global_functions']);
376
	if(!empty($pkg_config['custom_php_resync_config_command']))
377
		eval($pkg_config['custom_php_resync_config_command']);
378
	if($sync_depends == true) {
379
		$depends = get_pkg_depends($pkg_name, ".xml", "files", 1); // Call dependency handler and do a little more error checking.
380
		if(is_array($depends)) {
381
			foreach($depends as $item) {
382
				if(!file_exists($item)) {
383
					file_notice($package['name'], "The {$package['name']} package is missing required dependencies and must be reinstalled.", "Packages", "/pkg_mgr_install.php?mode=reinstallpkg&pkg={$package['name']}", 1);
384
					log_error("Could not find {$item}. Reinstalling package.");
385
					uninstall_package($pkg_name);
386
					install_package($pkg_name);
387
				} else {
388
					$item_config = parse_xml_config_pkg($item, "packagegui");
389
					if (empty($item_config))
390
						continue;
391
					if(isset($item_config['nosync']))
392
						continue;
393
					if($item_config['custom_php_command_before_form'] <> "")
394
						eval($item_config['custom_php_command_before_form']);
395
					if($item_config['custom_php_resync_config_command'] <> "")
396
						eval($item_config['custom_php_resync_config_command']);
397
					if($show_message == true)
398
						print " " . $item_config['name'];
399
				}
400
			}
401
		}
402
	}
403
}
404

    
405
/*
406
 * pkg_fetch_recursive: Download and install a FreeBSD package and its dependencies. This function provides output to
407
 * 			a progress bar and output window.
408
 *
409
 * XXX: This function needs to return where a pkg_add fails. Our current error messages aren't very descriptive.
410
 */
411
function pkg_fetch_recursive($pkgname, $filename, $dependlevel = 0, $base_url = '') {
412
	global $pkgent, $static_output, $g, $fd_log;
413

    
414
	$osname = php_uname("s");
415
	$arch =  php_uname("m");
416
	$rel = php_uname("r");
417
	$rel = substr($rel, 0, strrpos($rel, "-"));
418
	$priv_url = "http://ftp2.{$osname}.org/pub/{$osname}/ports/{$arch}/packages-{$rel}/Latest";
419
	if (empty($base_url))
420
		$base_url = $priv_url;
421
	$pkg_extension = ".tgz";
422
	if (substr($filename, -4) != ".tbz")
423
		$filename .= $pkg_extension;
424
	$static_output .= "\n" . str_repeat(" ", $dependlevel * 2) . $pkgname . " ";
425
	$fetchto = "{$g['tmp_path']}/apkg_{$filename}";
426
	if (download_file_with_progress_bar("{$base_url}/{$filename}", $fetchto) !== true) {
427
		if ($base_url != $priv_url && download_file_with_progress_bar("{$priv_url}/{$filename}", $fetchto) !== true) {
428
			$static_output .= " could not download.\n";
429
			update_output_window($static_output);
430
			return false;
431
		} else if ($base_url == $priv_url) {
432
			$static_output .= " failed to download.\n";
433
			update_output_window($static_output);
434
			return false;
435
		} else {
436
			$static_output .= " downloaded from {$osname} repository instead of provided one.\n";
437
			update_output_window($static_output);
438
		}
439
	}
440
	$static_output .= " (extracting)";
441
	update_output_window($static_output);
442
	$slaveout = "";
443
	exec("/usr/bin/tar --fast-read -O -f {$fetchto} -x +CONTENTS 2>&1", $slaveout);
444
	$workingdir = preg_grep("/instmp/", $slaveout);
445
	$workingdir = $workingdir[0];
446
	$raw_depends_list = array_values(preg_grep("/\@pkgdep/", $slaveout));
447
	if($raw_depends_list != "") {
448
		if($pkgent['exclude_dependency'] != "")
449
			$raw_depends_list = array_values(preg_grep($pkgent['exclude_dependency'], PREG_GREP_INVERT));
450
		foreach($raw_depends_list as $adepend) {
451
			$working_depend = explode(" ", $adepend);
452
			if (substr($working_depend[1], -4) != ".tbz")
453
				$depend_filename = $working_depend[1] . $pkg_extension;
454
			else
455
				$depend_filename = $working_depend[1];
456
			if(is_freebsd_pkg_installed($working_depend[1]) === false) {
457
				pkg_fetch_recursive($working_depend[1], $depend_filename, $dependlevel + 1, $base_url);
458
			} else {
459
				//$dependlevel++;
460
				$static_output .= "\n" . str_repeat(" ", $dependlevel * 2) . $working_depend[1] . " ";
461
				pkg_debug($working_depend[1] . "\n");
462
			}
463
		}
464
	}
465
	$pkgaddout = "";
466
	exec("/usr/sbin/pkg_add -fv {$fetchto} 2>&1", $pkgaddout);
467
	pkg_debug($pkgname . " " . print_r($pkgaddout, true) . "\n");
468

    
469
	return true;
470
}
471

    
472
function install_package($package, $pkg_info = "") {
473
	global $g, $config, $pkg_interface, $fd_log, $static_output, $pkg_interface, $restart_sync;
474

    
475
	/* safe side. Write config below will send to ro again. */
476
	conf_mount_rw();
477

    
478
	if($pkg_interface == "console") 	
479
		echo "\n";
480
	/* fetch package information if needed */
481
	if(empty($pkg_info) or !is_array($pkg_info[$package])) {
482
		$pkg_info = get_pkg_info(array($package));
483
		$pkg_info = $pkg_info[$package]; // We're only dealing with one package, so we can strip away the extra array.
484
		if (empty($pkg_info)) {
485
			conf_mount_ro();
486
			return -1;
487
		}
488
	}
489
	pkg_debug("Beginning package installation.\n");
490
	log_error('Beginning package installation for ' . $pkg_info['name'] . '.');
491
	$static_output .= "Beginning package installation for " . $pkg_info['name'] . "...";
492
	update_status($static_output);
493
	/* fetch the package's configuration file */
494
	if($pkg_info['config_file'] != "") {
495
		$static_output .= "Downloading package configuration file... ";
496
		update_output_window($static_output);
497
		pkg_debug("Downloading package configuration file...\n");
498
		$fetchto = substr(strrchr($pkg_info['config_file'], '/'), 1);
499
		download_file_with_progress_bar($pkg_info['config_file'], '/usr/local/pkg/' . $fetchto);
500
		if(!file_exists('/usr/local/pkg/' . $fetchto)) {
501
			pkg_debug("ERROR! Unable to fetch package configuration file. Aborting installation.\n");
502
			if($pkg_interface == "console")
503
				print "\nERROR! Unable to fetch package configuration file. Aborting package installation.\n";
504
			else {
505
				$static_output .= "failed!\n\nInstallation aborted.";
506
				update_output_window($static_output);
507
				echo "<br>Show <a href=\"pkg_mgr_install.php?showlog=true\">install log</a></center>";
508
			}
509
			conf_mount_ro();
510
			return -1;
511
		}
512
		$static_output .= "done.\n";
513
		update_output_window($static_output);
514
	}
515
	/* add package information to config.xml */
516
	$pkgid = get_pkg_id($pkg_info['name']);
517
	$static_output .= "Saving updated package information... ";
518
	update_output_window($static_output);
519
	if($pkgid == -1) {
520
		$config['installedpackages']['package'][] = $pkg_info;
521
		$changedesc = "Installed {$pkg_info['name']} package.";
522
		$to_output = "done.\n";
523
	} else {
524
		$config['installedpackages']['package'][$pkgid] = $pkg_info;
525
		$changedesc = "Overwrote previous installation of {$pkg_info['name']}.";
526
		$to_output = "overwrite!\n";
527
	}
528
	/* XXX: Fix inclusion of config.inc that causes data loss! */
529
	conf_mount_ro();
530
	write_config();
531
	$static_output .= $to_output;
532
	update_output_window($static_output);
533
	/* install other package components */
534
	if (!install_package_xml($package)) {
535
		uninstall_package($package);
536
		write_config($changedesc);
537
		$static_output .= "Failed to install package.\n";
538
		update_output_window($static_output);
539
		return -1;
540
	} else {
541
		$static_output .= "Writing configuration... ";
542
		update_output_window($static_output);
543
		write_config($changedesc);
544
		$static_output .= "done.\n";
545
		update_output_window($static_output);
546
		$static_output .= "Starting service.\n";
547
		update_output_window($static_output);
548
		if($pkg_info['after_install_info']) 
549
			update_output_window($pkg_info['after_install_info']);	
550
		start_service($pkg_info['name']);
551
		$restart_sync = true;
552
	}
553
}
554

    
555
function get_after_install_info($package) {
556
	global $pkg_info;
557
	/* fetch package information if needed */
558
	if(!$pkg_info or !is_array($pkg_info[$package])) {
559
		$pkg_info = get_pkg_info(array($package));
560
		$pkg_info = $pkg_info[$package]; // We're only dealing with one package, so we can strip away the extra array.
561
	}
562
	if($pkg_info['after_install_info'])
563
		return $pkg_info['after_install_info'];
564
}
565

    
566
function eval_once($toeval) {
567
	global $evaled;
568
	if(!$evaled) $evaled = array();
569
	$evalmd5 = md5($toeval);
570
	if(!in_array($evalmd5, $evaled)) {
571
		@eval($toeval);
572
		$evaled[] = $evalmd5;
573
	}
574
	return;
575
}
576

    
577
function install_package_xml($pkg) {
578
	global $g, $config, $fd_log, $static_output, $pkg_interface;
579

    
580
	if(($pkgid = get_pkg_id($pkg)) == -1) {
581
		$static_output .= "The {$pkg} package is not installed.\n\nInstallation aborted.";
582
		update_output_window($static_output);
583
		if($pkg_interface <> "console") {
584
			echo "\n<script language=\"JavaScript\">document.progressbar.style.visibility='hidden';</script>";
585
			echo "\n<script language=\"JavaScript\">document.progholder.style.visibility='hidden';</script>";
586
		}
587
		sleep(1);
588
		return false;
589
	} else
590
		$pkg_info = $config['installedpackages']['package'][$pkgid];
591

    
592
	/* pkg_add the package and its dependencies */
593
	if($pkg_info['depends_on_package_base_url'] != "") {
594
		if($pkg_interface == "console") 
595
			echo "\n";
596
		update_status("Installing " . $pkg_info['name'] . " and its dependencies.");
597
		$static_output .= "Downloading " . $pkg_info['name'] . " and its dependencies... ";
598
		$static_orig = $static_output;
599
		$static_output .= "\n";
600
		update_output_window($static_output);
601
		foreach((array) $pkg_info['depends_on_package'] as $pkgdep) {
602
			$pkg_name = substr(reverse_strrchr($pkgdep, "."), 0, -1);
603
			$static_output = $static_orig . "done.\nChecking for successful package installation... ";
604
			update_output_window($static_output);
605
			$pkg_installed = true;
606
			if (!isset($pkg_info['skip_install_checks']))
607
				$pkg_installed = is_freebsd_pkg_installed($pkg_name);
608

    
609
			if($pkg_installed == false)
610
				pkg_fetch_recursive($pkg_name, $pkgdep, 0, $pkg_info['depends_on_package_base_url']);
611
			/* make sure our package was successfully installed */
612
			if($pkg_installed == false)
613
				$pkg_installed = is_freebsd_pkg_installed($pkg_name);
614
			if($pkg_installed == true) {
615
				$static_output .= "done.\n";
616
				update_output_window($static_output);
617
				pkg_debug("pkg_add successfully completed.\n");
618
			} else {
619
				$static_output .= "of {$pkg_name} failed!\n\nInstallation aborted.";
620
				update_output_window($static_output);
621
				pkg_debug("Package WAS NOT installed properly.\n");
622
				if($pkg_interface <> "console") {
623
					echo "\n<script language=\"JavaScript\">document.progressbar.style.visibility='hidden';</script>";
624
					echo "\n<script language=\"JavaScript\">document.progholder.style.visibility='hidden';</script>";
625
				}
626
				sleep(1);
627
				return false;
628
			}
629
		}
630
	}
631
	$configfile = substr(strrchr($pkg_info['config_file'], '/'), 1);
632
	if(file_exists("/usr/local/pkg/" . $configfile)) {
633
		$static_output .= "Loading package configuration... ";
634
		update_output_window($static_output);
635
		$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $configfile, "packagegui");
636
		$static_output .= "done.\n";
637
		update_output_window($static_output);
638
		$static_output .= "\tConfiguring package components...\n";
639
		if (!empty($pkg_config['filter_rules_needed']))
640
			$config['installedpackages']['package'][$pkgid]['filter_rule_function'] = $pkg_config['filter_rules_needed'];
641
		update_output_window($static_output);
642
		/* modify system files */
643
		if(is_array($pkg_config['modify_system']) && is_array($pkg_config['modify_system']['item'])) {
644
			$static_output .= "\tSystem files... ";
645
			update_output_window($static_output);
646
			foreach($pkg_config['modify_system']['item'] as $ms) {
647
				if($ms['textneeded']) {
648
					add_text_to_file($ms['modifyfilename'], $ms['textneeded']);
649
				}
650
			}
651
			$static_output .= "done.\n";
652
			update_output_window($static_output);
653
		}
654
		/* download additional files */
655
		if(is_array($pkg_config['additional_files_needed'])) {
656
			$static_output .= "\tAdditional files... ";
657
			$static_orig = $static_output;
658
			update_output_window($static_output);
659
			foreach($pkg_config['additional_files_needed'] as $afn) {
660
				$filename = get_filename_from_url($afn['item'][0]);
661
				if($afn['chmod'] <> "")
662
					$pkg_chmod = $afn['chmod'];
663
				else
664
					$pkg_chmod = "";
665

    
666
				if($afn['prefix'] <> "")
667
					$prefix = $afn['prefix'];
668
				else
669
					$prefix = "/usr/local/pkg/";
670

    
671
				if(!is_dir($prefix)) 
672
					safe_mkdir($prefix);
673
 				$static_output .= $filename . " ";
674
                                update_output_window($static_output);
675
				if (download_file_with_progress_bar($afn['item'][0], $prefix . $filename) !== true) {
676
					$static_output .= "failed.\n";
677
					update_output_window($static_output);
678
					return false;
679
				}
680
				if(stristr($filename, ".tgz") <> "") {
681
					pkg_debug("Extracting tarball to -C for " . $filename . "...\n");
682
					$tarout = "";
683
					exec("/usr/bin/tar xvzf " . $prefix . $filename . " -C / 2>&1", $tarout);
684
					pkg_debug(print_r($tarout, true) . "\n");
685
				}
686
				if($pkg_chmod <> "") {
687
					pkg_debug("Changing file mode to {$pkg_chmod} for {$prefix}{$filename}\n");
688
					@chmod($prefix . $filename, $pkg_chmod);
689
					system("/bin/chmod {$pkg_chmod} {$prefix}{$filename}");
690
				}
691
				$static_output = $static_orig;
692
                                update_output_window($static_output);
693
			}
694
			$static_output .= "done.\n";
695
			update_output_window($static_output);
696
		}
697
		/*   if a require exists, include it.  this will
698
		 *   show us where an error exists in a package
699
		 *   instead of making us blindly guess
700
		 */
701
		$missing_include = false;
702
		if($pkg_config['include_file'] <> "") {
703
			$static_output .= "Loading package instructions...\n";
704
			update_output_window($static_output);
705
			pkg_debug("require_once('{$pkg_config['include_file']}')\n");
706
			if (file_exists($pkg_config['include_file']))
707
				require_once($pkg_config['include_file']);
708
			else {
709
				$missing_include = true;
710
				$static_output .= "\tInclude " . basename($pkg_config['include_file']) . " is missing!\n";
711
				update_output_window($static_output);
712
				/* XXX: Should undo the steps before this?! */
713
				return false;
714
			}
715
		}
716
		/* sidebar items */
717
		if(is_array($pkg_config['menu'])) {
718
			$static_output .= "\tMenu items... ";
719
			update_output_window($static_output);
720
			foreach($pkg_config['menu'] as $menu) {
721
				if(is_array($config['installedpackages']['menu']))
722
					foreach($config['installedpackages']['menu'] as $amenu)
723
						if($amenu['name'] == $menu['name'])
724
							continue 2;
725
				$config['installedpackages']['menu'][] = $menu;
726
			}
727
			$static_output .= "done.\n";
728
			update_output_window($static_output);
729
		}
730
		/* integrated tab items */
731
		if(is_array($pkg_config['tabs']['tab'])) {
732
			$static_output .= "\tIntegrated Tab items... ";
733
			update_output_window($static_output);
734
			foreach($pkg_config['tabs']['tab'] as $tab) {
735
				if(is_array($config['installedpackages']['tab']))
736
					foreach($config['installedpackages']['tab'] as $atab)
737
						if($atab['name'] == $tab['name'])
738
							continue 2;
739
				$config['installedpackages']['tab'][] = $tab;
740
			}
741
			$static_output .= "done.\n";
742
			update_output_window($static_output);
743
		}
744
		/* services */
745
		if(is_array($pkg_config['service'])) {
746
			$static_output .= "\tServices... ";
747
			update_output_window($static_output);
748
			foreach($pkg_config['service'] as $service) {
749
				if(is_array($config['installedpackages']['service']))
750
					foreach($config['installedpackages']['service'] as $aservice)
751
						if($aservice['name'] == $service['name'])
752
							continue 2;
753
				$config['installedpackages']['service'][] = $service;
754
			}
755
			$static_output .= "done.\n";
756
			update_output_window($static_output);
757
		}
758
		/* custom commands */
759
		$static_output .= "Custom commands...\n";
760
		update_output_window($static_output);
761
		if ($missing_include == false) {
762
			if($pkg_config['custom_php_global_functions'] <> "") {
763
				$static_output .= "\tExecuting custom_php_global_functions()...";
764
				update_output_window($static_output);
765
				eval_once($pkg_config['custom_php_global_functions']);
766
				$static_output .= "done.\n";
767
				update_output_window($static_output);
768
			}
769
			if($pkg_config['custom_php_install_command']) {
770
				$static_output .= "\tExecuting custom_php_install_command()...";
771
				update_output_window($static_output);
772
				eval_once($pkg_config['custom_php_install_command']);
773
				$static_output .= "done.\n";
774
				update_output_window($static_output);
775
			}
776
			if($pkg_config['custom_php_resync_config_command'] <> "") {
777
				$static_output .= "\tExecuting custom_php_resync_config_command()...";
778
				update_output_window($static_output);
779
				eval_once($pkg_config['custom_php_resync_config_command']);
780
				$static_output .= "done.\n";
781
				update_output_window($static_output);
782
			}
783
		}
784
	} else {
785
		$static_output .= "Loading package configuration... failed!\n\nInstallation aborted.";
786
		update_output_window($static_output);
787
		pkg_debug("Unable to load package configuration. Installation aborted.\n");
788
		if($pkg_interface <> "console") {
789
			echo "\n<script language=\"JavaScript\">document.progressbar.style.visibility='hidden';</script>";
790
			echo "\n<script language=\"JavaScript\">document.progholder.style.visibility='hidden';</script>";
791
		}
792
		sleep(1);
793
		return false;
794
	}
795

    
796
	/* set up package logging streams */
797
	if($pkg_info['logging']) {
798
		mwexec("/usr/sbin/fifolog_create -s 32768 {$g['varlog_path']}/{$pkg_info['logging']['logfilename']}");
799
		@chmod($g['varlog_path'] . '/' . $pkg_info['logging']['logfilename'], 0600);
800
		pkg_debug("Adding text to file /etc/syslog.conf\n");
801
		if(is_process_running("syslogd"))
802
			mwexec("killall syslogd");
803
		system_syslogd_start();
804
	}
805

    
806
	return true;
807
}
808

    
809
function delete_package($pkg) {
810
	global $config, $g, $static_output, $vardb;
811

    
812
	$pkg = substr(reverse_strrchr($pkg, "."), 0, -1);
813

    
814

    
815
	if (file_exists("{$vardb}/{$pkg}/+REQUIRED_BY") && count(file("{$vardb}/{$pkg}/+REQUIRED_BY")) > 0) {
816
		$static_output .= "\tSkipping package deletion for {$pkg} because it is required by other packages.\n";
817
		update_output_window($static_output);
818
		return;
819
	} else {
820
		$static_output .= "\tStarting package deletion for {$pkg}...";
821
		update_output_window($static_output);
822
	}
823
	$info = "";
824
	exec("/usr/sbin/pkg_info -qrx {$pkg}", $info);
825
	remove_freebsd_package($pkg);
826
	foreach($info as $line) {
827
		$depend = trim(str_replace("@pkgdep", "", $line));
828
		delete_package($depend);
829
	}
830
	$static_output .= "done.\n";
831
	update_output_window($static_output);
832

    
833
	return;
834
}
835

    
836
function delete_package_xml($pkg) {
837
	global $g, $config, $fd_log, $static_output, $pkg_interface;
838

    
839
	conf_mount_rw();
840

    
841
	$pkgid = get_pkg_id($pkg);
842
	if ($pkgid == -1) {
843
		$static_output .= "The {$pkg} package is not installed.\n\nDeletion aborted.";
844
		update_output_window($static_output);
845
		if($pkg_interface <> "console") {
846
			echo "\n<script language=\"JavaScript\">document.progressbar.style.visibility='hidden';</script>";
847
			echo "\n<script language=\"JavaScript\">document.progholder.style.visibility='hidden';</script>";
848
		}
849
		ob_flush();
850
		sleep(1);
851
		conf_mount_ro();
852
		return;
853
	}
854
	pkg_debug("Removing {$pkg} package... ");
855
	$static_output .= "Removing {$pkg} components...\n";
856
	update_output_window($static_output);
857
	/* parse package configuration */
858
	$packages = &$config['installedpackages']['package'];
859
	$tabs =& $config['installedpackages']['tab'];
860
	$menus =& $config['installedpackages']['menu'];
861
	$services = &$config['installedpackages']['service'];
862
	if(file_exists("/usr/local/pkg/" . $packages[$pkgid]['configurationfile'])) {
863
		$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $packages[$pkgid]['configurationfile'], "packagegui");
864
		/* remove tab items */
865
		if(is_array($pkg_config['tabs'])) {
866
			$static_output .= "\tTabs items... ";
867
			update_output_window($static_output);
868
			if(is_array($pkg_config['tabs']['tab']) && is_array($tabs)) {
869
				foreach($pkg_config['tabs']['tab'] as $tab) {
870
					foreach($tabs as $key => $insttab) {
871
						if($insttab['name'] == $tab['name']) {
872
							unset($tabs[$key]);
873
							break;
874
						}
875
					}
876
				}
877
			}
878
			$static_output .= "done.\n";
879
			update_output_window($static_output);
880
		}
881
		/* remove menu items */
882
		if(is_array($pkg_config['menu'])) {
883
			$static_output .= "\tMenu items... ";
884
			update_output_window($static_output);
885
			if (is_array($pkg_config['menu']) && is_array($menus)) {
886
				foreach($pkg_config['menu'] as $menu) {
887
					foreach($menus as $key => $instmenu) {
888
						if($instmenu['name'] == $menu['name']) {
889
							unset($menus[$key]);
890
							break;
891
						}
892
					}
893
				}
894
			}
895
			$static_output .= "done.\n";
896
			update_output_window($static_output);
897
		}
898
		/* remove services */
899
		if(is_array($pkg_config['service'])) {
900
			$static_output .= "\tServices... ";
901
			update_output_window($static_output);
902
			if (is_array($pkg_config['service']) && is_array($services)) {
903
				foreach($pkg_config['service'] as $service) {
904
					foreach($services as $key => $instservice) {
905
						if($instservice['name'] == $service['name']) {
906
							stop_service($service['name']);
907
							unset($services[$key]);
908
						}
909
					}
910
				}
911
			}
912
			$static_output .= "done.\n";
913
			update_output_window($static_output);
914
		}
915
		/*
916
		 * XXX: Otherwise inclusion of config.inc again invalidates actions taken.
917
		 * 	Same is done during installation.
918
		 */
919
		write_config();
920

    
921
		/*
922
		 * If a require exists, include it.  this will
923
		 * show us where an error exists in a package
924
		 * instead of making us blindly guess
925
		 */
926
		$missing_include = false;
927
		if($pkg_config['include_file'] <> "") {
928
			$static_output .= "Loading package instructions...\n";
929
			update_output_window($static_output);
930
			pkg_debug("require_once(\"{$pkg_config['include_file']}\")\n");
931
			if (file_exists($pkg_config['include_file']))
932
				require_once($pkg_config['include_file']);
933
			else {
934
				$missing_include = true;
935
				update_output_window($static_output);
936
				$static_output .= "\tInclude file " . basename($pkg_config['include_file']) . " could not be found for inclusion.\n";
937
			}
938
		}
939
		/* ermal
940
		 * NOTE: It is not possible to handle parse errors on eval.
941
		 * So we prevent it from being run at all to not interrupt all the other code.
942
		 */
943
		if ($missing_include == false) {
944
			/* evalate this package's global functions and pre deinstall commands */
945
			if($pkg_config['custom_php_global_functions'] <> "")
946
				eval_once($pkg_config['custom_php_global_functions']);
947
			if($pkg_config['custom_php_pre_deinstall_command'] <> "")
948
				eval_once($pkg_config['custom_php_pre_deinstall_command']);
949
		}
950
		/* system files */
951
		if(is_array($pkg_config['modify_system']) && is_array($pkg_config['modify_system']['item'])) {
952
			$static_output .= "\tSystem files... ";
953
			update_output_window($static_output);
954
			foreach($pkg_config['modify_system']['item'] as $ms)
955
				if($ms['textneeded']) remove_text_from_file($ms['modifyfilename'], $ms['textneeded']);
956

    
957
			$static_output .= "done.\n";
958
			update_output_window($static_output);
959
		}
960
		/* syslog */
961
		if(is_array($pkg_config['logging']) && $pkg_config['logging']['logfile_name'] <> "") {
962
			$static_output .= "\tSyslog entries... ";
963
			update_output_window($static_output);
964
			remove_text_from_file("/etc/syslog.conf", $pkg_config['logging']['facilityname'] . "\t\t\t\t" . $pkg_config['logging']['logfilename']);
965
			$static_output .= "done.\n";
966
			update_output_window($static_output);
967
		}
968
		/* deinstall commands */
969
		if($pkg_config['custom_php_deinstall_command'] <> "") {
970
			$static_output .= "\tDeinstall commands... ";
971
			update_output_window($static_output);
972
			if ($missing_include == false) {
973
				eval_once($pkg_config['custom_php_deinstall_command']);
974
				$static_output .= "done.\n";
975
			} else
976
				$static_output .= "\n\tNot executing custom deinstall hook because an include is missing.\n";
977
			update_output_window($static_output);
978
		}
979
		if($pkg_config['include_file'] <> "") {
980
                        $static_output .= "\tRemoving package instructions...";
981
                        update_output_window($static_output);
982
                        pkg_debug("Remove '{$pkg_config['include_file']}'\n");
983
                        unlink_if_exists("/usr/local/pkg/" . $pkg_config['include_file']);
984
			$static_output .= "done.\n";
985
                        update_output_window($static_output);
986
			
987
                }
988
		/* remove all additional files */
989
		if(is_array($pkg_config['additional_files_needed'])) {
990
			$static_output .= "\tAuxiliary files... ";
991
			update_output_window($static_output);
992
			foreach($pkg_config['additional_files_needed'] as $afn) {
993
				$filename = get_filename_from_url($afn['item'][0]);
994
				if($afn['prefix'] <> "")
995
					$prefix = $afn['prefix'];
996
				else
997
					$prefix = "/usr/local/pkg/";
998

    
999
				unlink_if_exists($prefix . $filename);
1000
			}
1001
			$static_output .= "done.\n";
1002
			update_output_window($static_output);
1003
		}
1004
		/* package XML file */
1005
		$static_output .= "\tPackage XML... ";
1006
		update_output_window($static_output);
1007
		unlink_if_exists("/usr/local/pkg/" . $packages[$pkgid]['configurationfile']);
1008
		$static_output .= "done.\n";
1009
		update_output_window($static_output);
1010
	}
1011
	/* remove config.xml entries */
1012
	conf_mount_ro();
1013
	$static_output .= "\tConfiguration... ";
1014
	update_output_window($static_output);
1015
	unset($config['installedpackages']['package'][$pkgid]);
1016
	$static_output .= "done.\n";
1017
	update_output_window($static_output);
1018
	write_config("Removed {$pkg} package.\n");
1019
}
1020

    
1021
function expand_to_bytes($size) {
1022
	$conv = array(
1023
			"G" =>	"3",
1024
			"M" =>  "2",
1025
			"K" =>  "1",
1026
			"B" =>  "0"
1027
		);
1028
	$suffix = substr($size, -1);
1029
	if(!in_array($suffix, array_keys($conv))) return $size;
1030
	$size = substr($size, 0, -1);
1031
	for($i = 0; $i < $conv[$suffix]; $i++) {
1032
		$size *= 1024;
1033
	}
1034
	return $size;
1035
}
1036

    
1037
function get_pkg_db() {
1038
	global $g;
1039
	return return_dir_as_array($g['vardb_path'] . '/pkg');
1040
}
1041

    
1042
function walk_depend($depend, $pkgdb = "", $alreadyseen = "") {
1043
	if(!$pkgdb)
1044
		$pkgdb = get_pkg_db();
1045
	if(!is_array($alreadyseen))
1046
		$alreadyseen = array();
1047
	if (!is_array($depend))
1048
		$depend = array();
1049
	foreach($depend as $adepend) {
1050
		$pkgname = reverse_strrchr($adepend['name'], '.');
1051
		if(in_array($pkgname, $alreadyseen)) {
1052
			continue;
1053
		} elseif(!in_array($pkgname, $pkgdb)) {
1054
			$size += expand_to_bytes($adepend['size']);
1055
			$alreadyseen[] = $pkgname;
1056
			if(is_array($adepend['depend'])) $size += walk_depend($adepend['depend'], $pkgdb, $alreadyseen);
1057
		}
1058
	}
1059
	return $size;
1060
}
1061

    
1062
function get_package_install_size($pkg = 'all', $pkg_info = "") {
1063
	global $config, $g;
1064
	if((!is_array($pkg)) and ($pkg != 'all'))
1065
		$pkg = array($pkg);
1066
	$pkgdb = get_pkg_db();
1067
	if(!$pkg_info)
1068
		$pkg_info = get_pkg_sizes($pkg);
1069
	foreach($pkg as $apkg) {
1070
		if(!$pkg_info[$apkg]) continue;
1071
		$toreturn[$apkg] = expand_to_bytes(walk_depend(array($pkg_info[$apkg]), $pkgdb));
1072
	}
1073
	return $toreturn;
1074
}
1075

    
1076
function squash_from_bytes($size, $round = "") {
1077
	$conv = array(1 => "B", "K", "M", "G");
1078
	foreach($conv as $div => $suffix) {
1079
		$sizeorig = $size;
1080
		if(($size /= 1024) < 1) {
1081
			if($round) {
1082
				$sizeorig = round($sizeorig, $round);
1083
			}
1084
			return $sizeorig . $suffix;
1085
		}
1086
	}
1087
	return;
1088
}
1089

    
1090
?>
(31-31/54)