Project

General

Profile

Download (35.1 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
require_once("xmlrpc.inc");
36
require_once("xmlparse.inc");
37
require_once("service-utils.inc");
38
require_once("pfsense-utils.inc");
39
require_once("globals.inc");
40

    
41
safe_mkdir("/var/db/pkg");
42
$g['platform'] = trim(file_get_contents("/etc/platform"));
43
if($g['platform'] == "pfSense") {
44
	safe_mkdir("/usr/local/pkg");
45
	safe_mkdir("/usr/local/pkg/pf");
46
}
47

    
48
/****f* pkg-utils/remove_package
49
 * NAME
50
 *   remove_package - Removes package from FreeBSD if it exists
51
 * INPUTS
52
 *   $packagestring	- name/string to check for
53
 * RESULT
54
 *   none
55
 * NOTES
56
 *   
57
 ******/
58
function remove_freebsd_package($packagestring) {
59
	
60
	exec("cd /var/db/pkg && pkg_delete `ls | grep $packagestring`");
61
	log_error("cd /var/db/pkg && pkg_delete ls | grep $packagestring");
62
}
63

    
64
/****f* pkg-utils/is_package_installed
65
 * NAME
66
 *   is_package_installed - Check whether a package is installed.
67
 * INPUTS
68
 *   $packagename	- name of the package to check
69
 * RESULT
70
 *   boolean	- true if the package is installed, false otherwise
71
 * NOTES
72
 *   This function is deprecated - get_pkg_id() can already check for installation.
73
 ******/
74
function is_package_installed($packagename) {
75
	$pkg = get_pkg_id($packagename);
76
	if($pkg == -1) return false;
77
	return true;
78
}
79

    
80
/****f* pkg-utils/get_pkg_id
81
 * NAME
82
 *   get_pkg_id - Find a package's numeric ID.
83
 * INPUTS
84
 *   $pkg_name	- name of the package to check
85
 * RESULT
86
 *   integer    - -1 if package is not found, >-1 otherwise
87
 ******/
88
function get_pkg_id($pkg_name) {
89
	global $config;
90

    
91
	if(is_array($config['installedpackages']['package'])) {
92
		$i = 0;
93
		foreach($config['installedpackages']['package'] as $pkg) {
94
			if($pkg['name'] == $pkg_name) return $i;
95
			$i++;
96
		}
97
	}
98
	return -1;
99
}
100

    
101
/****f* pkg-utils/get_pkg_info
102
 * NAME
103
 *   get_pkg_info - Retrive package information from pfsense.com.
104
 * INPUTS
105
 *   $pkgs - 'all' to retrive all packages, an array containing package names otherwise
106
 *   $info - 'all' to retrive all information, an array containing keys otherwise
107
 * RESULT
108
 *   $raw_versions - Array containing retrieved information, indexed by package name.
109
 ******/
110
function get_pkg_info($pkgs = 'all', $info = 'all') {
111
	global $g;
112
	$params = array("pkg" => $pkgs, "info" => $info);
113
	$resp = call_pfsense_method('pfsense.get_pkgs', $params, 10);
114
	return $resp ? $resp : array();
115
}
116

    
117
function get_pkg_sizes($pkgs = 'all') {
118
	global $g;
119
	$params = array("pkg" => $pkgs);
120
	$msg = new XML_RPC_Message('pfsense.get_pkg_sizes', array(php_value_to_xmlrpc($params)));
121
	$cli = new XML_RPC_Client($g['xmlrpcpath'], $g['xmlrpcbaseurl']);
122
	$resp = $cli->send($msg, 10);
123
	if($resp and !$resp->faultCode()) {
124
		$raw_versions = $resp->value();
125
		return xmlrpc_value_to_php($raw_versions);
126
	} else {
127
		return array();
128
	}
129
}
130

    
131
/*
132
 * resync_all_package_configs() Force packages to setup their configuration and rc.d files.
133
 * This function may also print output to the terminal indicating progress.
134
 */
135
function resync_all_package_configs($show_message = false) {
136
	global $config, $restart_sync, $pkg_interface;
137
	$i = 0;
138
	log_error("Resyncing configuration for all packages.");
139
	if(!$config['installedpackages']['package']) return;
140
	if($show_message == true) print "Syncing packages:";
141
	foreach($config['installedpackages']['package'] as $package) {
142
		if($show_message == true) print " " . $package['name'];
143
		get_pkg_depends($package['name'], "all");
144
		stop_service($package['name']);
145
		sync_package($i, true, true);
146
		if($restart_sync == true) {
147
			$restart_sync = false;
148
			if($pkg_interface == "console") 
149
				echo "\nSyncing packages:";
150
		}
151
		$i++;
152
	}
153
	if($show_message == true) print ".\n";
154
}
155

    
156
/*
157
 * is_freebsd_pkg_installed() - Check /var/db/pkg to determine whether or not a FreeBSD
158
 *				package is installed.
159
 */
160
function is_freebsd_pkg_installed($pkg) {
161
	global $g;
162
	if(in_array($pkg, return_dir_as_array("{$g['vardb_path']}/pkg"))) return true;
163
	return false;
164
}
165

    
166
/*
167
 * get_pkg_depends($pkg_name, $filetype = ".xml", $format = "files", return_nosync = 1):  Return a package's dependencies.
168
 *
169
 * $filetype = "all" || ".xml", ".tgz", etc.
170
 * $format = "files" (full filenames) || "names" (stripped / parsed depend names)
171
 * $return_nosync = 1 (return depends that have nosync set) | 0 (ignore packages with nosync)
172
 *
173
 */
174
function get_pkg_depends($pkg_name, $filetype = ".xml", $format = "files", $return_nosync = 1) {
175
	global $config;
176
	require_once("notices.inc");
177
	$pkg_id = get_pkg_id($pkg_name);
178
	if(!is_numeric($pkg_name)) {
179
		if($pkg_id == -1) return -1; // This package doesn't really exist - exit the function.
180
	} else {
181
		if(!isset($config['installedpackages']['package'][$pkg_id])) return; // No package belongs to the pkg_id passed to this function.
182
	}
183
	$package = $config['installedpackages']['package'][$pkg_id];
184
	if(!file_exists("/usr/local/pkg/" . $package['configurationfile'])) {
185
		log_error("The {$package['name']} package is missing required dependencies and must be reinstalled. " . $package['configurationfile']);
186
		install_package($package['name']);
187
		uninstall_package_from_name($package['name']);
188
		remove_freebsd_package($package['name']);
189
		install_package($package['name']);
190
		return;
191
	}
192
	$pkg_xml = parse_xml_config_pkg("/usr/local/pkg/" . $package['configurationfile'], "packagegui");
193
	if($pkg_xml['additional_files_needed'] != "") {
194
		foreach($pkg_xml['additional_files_needed'] as $item) {
195
			if (($return_nosync == 0) && (isset($item['nosync']))) continue; // Do not return depends with nosync set if not required.
196
			$depend_file = substr(strrchr($item['item']['0'], '/'),1); // Strip URLs down to filenames.
197
			$depend_name = substr(substr($depend_file,0,strpos($depend_file,".")+1),0,-1); // Strip filename down to dependency name.
198
			if (($filetype != "all") && (!preg_match("/{$filetype}/i", $depend_file))) continue;
199
			if ($item['prefix'] != "") {
200
				$prefix = $item['prefix'];
201
			} else {
202
				$prefix = "/usr/local/pkg/";
203
			}
204
			if(!file_exists($prefix . $depend_file))
205
				log_error("The {$package['name']} package is missing required dependencies and must be reinstalled.");
206
			switch ($format) {
207
				case "files":
208
				$depends[] = $depend_file;
209
			break;
210
            			case "names":
211
                		switch ($filetype) {
212

    
213
				case "all":
214
				if(preg_match("/\.xml/i", $depend_file)) {
215
					$depend_xml = parse_xml_config_pkg("/usr/local/pkg/" . $depend_file, "packagegui");
216
					$depends[] = $depend_xml['name'];
217
					break;
218
				} else {
219
					$depends[] = $depend_name; // If this dependency isn't package XML, use the stripped filename.
220
				break;
221
				}
222
				case ".xml":
223
				$depend_xml = parse_xml_config_pkg("/usr/local/pkg/" . $depend_file, "packagegui");
224
				$depends[] = $depend_xml['name'];
225
				break;
226
				default:
227
				$depends[] = $depend_name; // If we aren't looking for XML, use the stripped filename (it's all we have).
228
				break;
229
				}
230
			}
231
		}
232
		return $depends;
233
	}
234
}
235

    
236
function uninstall_package_from_name($pkg_name) {
237
	global $config;
238
	$id = get_pkg_id($pkg_name);
239
	$todel = substr(reverse_strrchr($config['installedpackages']['package'][$id]['depends_on_package'], "."), 0, -1);
240
	delete_package($todel, $pkg_name);
241
	delete_package_xml($pkg_name);
242
	remove_freebsd_package($pkg_name);
243
}
244

    
245
function force_remove_package($pkg_name) {
246
	global $config;
247
	delete_package_xml($pkg_name);
248
	remove_freebsd_package($pkg_name);
249
}
250

    
251
/*
252
 * sync_package($pkg_name, $sync_depends = true, $show_message = false) Force a package to setup its configuration and rc.d files.
253
 */
254
function sync_package($pkg_name, $sync_depends = true, $show_message = false) {
255
	global $config;
256
	require_once("notices.inc");
257
	if(!$config['installedpackages']['package']) return;
258
	if(!is_numeric($pkg_name)) {
259
		$pkg_id = get_pkg_id($pkg_name);
260
		if($pkg_id == -1) return -1; // This package doesn't really exist - exit the function.
261
	} else {
262
		$pkg_id = $pkg_name;
263
		if(!isset($config['installedpackages']['package'][$pkg_id]))
264
		return;  // No package belongs to the pkg_id passed to this function.
265
	}
266
        if (is_array($config['installedpackages']['package'][$pkg_id]))
267
			$package = $config['installedpackages']['package'][$pkg_id];
268
        else
269
			return; /* empty package tag */
270
	if(!file_exists("/usr/local/pkg/" . $package['configurationfile'])) {
271
		log_error("The {$package['name']} package is missing its configuration file and must be reinstalled.");
272
		force_remove_package($package['name']);
273
	} else {
274
		$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $package['configurationfile'], "packagegui");
275

    
276
		/* Bring in package include files */
277
		if (isset($pkg_config['include_file']) && $pkg_config['include_file'] != "") {
278
			$include_file = $pkg_config['include_file'];
279
			if (file_exists($include_file))
280
				require_once($include_file);
281
			else
282
				if (file_exists($include_file)) {
283
					require_once($include_file);
284
				} else {
285
					log_error("Could not locate {$include_file}.");
286
					install_package($package['name']);
287
					uninstall_package_from_name($package['name']);
288
					install_package($package['name']);
289
				}
290
		}
291

    
292
		/* XXX: Zend complains about the next line "Wrong break depth"
293
		 * The code is obviously wrong, but I'm not sure what it's supposed to do?
294
		 */
295
		if(isset($pkg_config['nosync'])) continue;
296
		if($pkg_config['custom_php_global_functions'] <> "")
297
		eval($pkg_config['custom_php_global_functions']);
298
		if($pkg_config['custom_php_resync_config_command'] <> "")
299
		eval($pkg_config['custom_php_resync_config_command']);
300
		if($sync_depends == true) {
301
			$depends = get_pkg_depends($pkg_name, ".xml", "files", 1); // Call dependency handler and do a little more error checking.
302
			if(is_array($depends)) {
303
				foreach($depends as $item) {
304
					if(!file_exists("/usr/local/pkg/" . $item)) {
305
						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);
306
						log_error("Could not find {$item} ... Reinstalling package.");
307
						install_package($pkg_name);
308
						uninstall_package_from_name($pkg_name);
309
						install_package($pkg_name);
310
					} else {
311
						$item_config = parse_xml_config_pkg("/usr/local/pkg/" . $item, "packagegui");
312
						if(isset($item_config['nosync'])) continue;
313
						if($item_config['custom_php_command_before_form'] <> "") {
314
							eval($item_config['custom_php_command_before_form']);
315
						}
316
						if($item_config['custom_php_resync_config_command'] <> "") {
317
							eval($item_config['custom_php_resync_config_command']);
318
						}
319
						if($show_message == true) print " " . $item_config['name'];
320
					}
321
				}
322
			}
323
		}
324
	}
325
}
326

    
327
/*
328
 * pkg_fetch_recursive: Download and install a FreeBSD package and its dependencies. This function provides output to
329
 * 			a progress bar and output window.
330
 *
331
 * XXX: This function needs to return where a pkg_add fails. Our current error messages aren't very descriptive.
332
 */
333
function pkg_fetch_recursive($pkgname, $filename, $dependlevel = 0, $base_url = 'http://ftp2.freebsd.org/pub/FreeBSD/ports/i386/packages-5.4-release/Latest') {
334
	global $pkgent, $static_output, $g, $fd_log;
335
	$pkg_extension = strrchr($filename, '.');
336
	$static_output .= "\n" . str_repeat(" ", $dependlevel * 2) . $pkgname . " ";
337
	$fetchto = "/tmp/apkg_" . $pkgname . $pkg_extension;
338
	download_file_with_progress_bar($base_url . '/' . $filename, $fetchto);
339
	$static_output .= " (extracting)";
340
	update_output_window($static_output);
341
		$slaveout = "";
342
	exec("/usr/bin/tar --fast-read -O -f {$fetchto} -x +CONTENTS 2>&1", $slaveout);
343
	$workingdir = preg_grep("/instmp/", $slaveout);
344
	$workingdir = $workingdir[0];
345
	$raw_depends_list = array_values(preg_grep("/\@pkgdep/", $slaveout));
346
	if($raw_depends_list != "") {
347
		if($pkgent['exclude_dependency'] != "")
348
			$raw_depends_list = array_values(preg_grep($pkgent['exclude_dependency'], PREG_GREP_INVERT));
349
		foreach($raw_depends_list as $adepend) {
350
			$working_depend = explode(" ", $adepend);
351
			//$working_depend = explode("-", $working_depend[1]);
352
			$depend_filename = $working_depend[1] . $pkg_extension;
353
			if(is_freebsd_pkg_installed($working_depend[1]) === false) {
354
				pkg_fetch_recursive($working_depend[1], $depend_filename, $dependlevel + 1, $base_url);
355
			} else {
356
//				$dependlevel++;
357
				$static_output .= "\n" . str_repeat(" ", $dependlevel * 2) . $working_depend[1] . " ";
358
				@fwrite($fd_log, $working_depend[1] . "\n");
359
			}
360
		}
361
	}
362
	$pkgaddout = "";
363
	exec("cat {$g['tmp_path']}/y | /usr/sbin/pkg_add -fv {$fetchto} 2>&1", $pkgaddout);
364
	@fwrite($fd_log, $pkgname . " " . print_r($pkgaddout, true) . "\n");
365
	return true;
366
}
367

    
368
function download_file_with_progress_bar($url_file, $destination_file) {
369
	global $ch, $fout, $file_size, $downloaded, $pkg_interface;
370
	$file_size  = 1;
371
	$downloaded = 1;
372
	/* open destination file */
373
	$fout = fopen($destination_file, "wb");
374

    
375
	/*
376
	 *	Originally by Author: Keyvan Minoukadeh
377
	 *	Modified by Scott Ullrich to return Content-Length size
378
         */
379

    
380
	$ch = curl_init();
381
	curl_setopt($ch, CURLOPT_URL, $url_file);
382
	curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'read_header');
383
	curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'read_body');
384
	curl_setopt($ch, CURLOPT_NOPROGRESS, '1');
385

    
386
	curl_exec($ch);
387
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
388
	if($fout)
389
		fclose($fout);
390
	curl_close($ch);
391
	return ($http_code == 200) ? true : $http_code;
392
}
393

    
394
function read_header($ch, $string) {
395
	global $file_size, $fout;
396
	$length = strlen($string);
397
	$regs = "";
398
	ereg("(Content-Length:) (.*)", $string, $regs);
399
	if($regs[2] <> "") {
400
	$file_size = intval($regs[2]);
401
	}
402
	ob_flush();
403
	return $length;
404
}
405

    
406
function read_body($ch, $string) {
407
	global $fout, $file_size, $downloaded, $sendto, $static_status, $static_output, $lastseen, $pkg_interface;
408
	$length = strlen($string);
409
	$downloaded += intval($length);
410
	$downloadProgress = round(100 * (1 - $downloaded / $file_size), 0);
411
	$downloadProgress = 100 - $downloadProgress;
412
	if($lastseen <> $downloadProgress and $downloadProgress < 101) {
413
		if($sendto == "status") {
414
			$tostatus = $static_status . $downloadProgress . "%";
415
			update_status($tostatus);
416
		} else {
417
			$tooutput = $static_output . $downloadProgress . "%";
418
			update_output_window($tooutput);
419
		}
420
		update_progress_bar($downloadProgress);
421
		$lastseen = $downloadProgress;
422
	}
423
	if($fout)
424
		fwrite($fout, $string);
425
	ob_flush();
426
	return $length;
427
}
428

    
429
function install_package($package, $pkg_info = "") {
430
	global $g, $config, $pkg_interface, $fd_log, $static_output, $pkg_interface, $restart_sync;
431
	if($pkg_interface == "console") 	
432
		echo "\n";
433
	/* open logfiles and begin installation */
434
	if(!$fd_log) {
435
		if(!$fd_log = fopen("{$g['tmp_path']}/pkg_mgr_{$package}.log", "w")) {
436
			update_output_window("Warning, could not open log for writing.");
437
		}
438
	}
439
	/* fetch package information if needed */
440
	if(!$pkg_info or !is_array($pkg_info[$package])) {
441
		$pkg_info = get_pkg_info(array($package));
442
		$pkg_info = $pkg_info[$package]; // We're only dealing with one package, so we can strip away the extra array.
443
	}
444
	@fwrite($fd_log, "Beginning package installation.\n");
445
	log_error('Beginning package installation for ' . $pkg_info['name'] . '.');
446
	update_status("Beginning package installation for " . $pkg_info['name'] . "...");
447
	/* fetch the package's configuration file */
448
	if($pkg_info['config_file'] != "") {
449
		$static_output .= "Downloading package configuration file... ";
450
		update_output_window($static_output);
451
		@fwrite($fd_log, "Downloading package configuration file...\n");
452
		$fetchto = substr(strrchr($pkg_info['config_file'], '/'), 1);
453
		download_file_with_progress_bar($pkg_info['config_file'], '/usr/local/pkg/' . $fetchto);
454
		if(!file_exists('/usr/local/pkg/' . $fetchto)) {
455
			@fwrite($fd_log, "ERROR! Unable to fetch package configuration file. Aborting installation.\n");
456
			if($pkg_interface == "console") {
457
				print "\nERROR! Unable to fetch package configuration file. Aborting package installation.\n";
458
				return;
459
			} else {
460
				$static_output .= "failed!\n\nInstallation aborted.";
461
				update_output_window($static_output);
462
				echo "<br>Show <a href=\"pkg_mgr_install.php?showlog=true\">install log</a></center>";
463
			 	return -1;
464
			}
465
		}
466
		$static_output .= "done.\n";
467
		update_output_window($static_output);
468
	}
469
	/* add package information to config.xml */
470
	$pkgid = get_pkg_id($pkg_info['name']);
471
	$static_output .= "Saving updated package information... ";
472
	update_output_window($static_output);
473
	if($pkgid == -1) {
474
		$config['installedpackages']['package'][] = $pkg_info;
475
		$changedesc = "Installed {$pkg_info['name']} package.";
476
		$to_output = "done.\n";
477
	} else {
478
		$config['installedpackages']['package'][$pkgid] = $pkg_info;
479
		$changedesc = "Overwrote previous installation of {$pkg_info['name']}.";
480
		$to_output = "overwrite!\n";
481
	}
482
	$static_output .= $to_output;
483
	update_output_window($static_output);
484
	/* install other package components */
485
	install_package_xml($package);
486
	$static_output .= "Writing configuration... ";
487
	update_output_window($static_output);
488
	write_config($changedesc);
489
	$static_output .= "done.\n";
490
	update_output_window($static_output);
491
	$static_output .= "Starting service.\n";
492
	update_output_window($static_output);
493
	start_service($pkg_info['config_file']);
494
	$restart_sync = true;
495
}
496

    
497
function eval_once($toeval) {
498
	global $evaled;
499
	if(!$evaled) $evaled = array();
500
	$evalmd5 = md5($toeval);
501
	if(!in_array($evalmd5, $evaled)) {
502
		eval($toeval);
503
		$evaled[] = $evalmd5;
504
	}
505
	return;
506
}
507

    
508
function install_package_xml($pkg) {
509
	global $g, $config, $fd_log, $static_output, $pkg_interface;
510
	if(($pkgid = get_pkg_id($pkg)) == -1) {
511
		$static_output .= "The {$pkg} package is not installed.\n\nInstallation aborted.";
512
		update_output_window($static_output);
513
		if($pkg_interface <> "console") {
514
			echo "\n<script language=\"JavaScript\">document.progressbar.style.visibility='hidden';</script>";
515
			echo "\n<script language=\"JavaScript\">document.progholder.style.visibility='hidden';</script>";
516
		}
517
		sleep(1);
518
		return;
519
	} else {
520
		$pkg_info = $config['installedpackages']['package'][$pkgid];
521
	}
522
	/* set up logging if needed */
523
	if(!$fd_log) {
524
		if(!$fd_log = fopen("{$g['tmp_path']}/pkg_mgr_{$pkg}.log", "w")) {
525
			update_output_window("Warning, could not open log for writing.");
526
		}
527
	}
528

    
529
	/* set up package logging streams */
530
	if($pkg_info['logging']) {
531
		mwexec("/usr/sbin/clog -i -s 32768 {$g['varlog_path']}/{$pkg_info['logging']['logfilename']}");
532
		chmod($g['varlog_path'] . '/' . $pkg_info['logging']['logfilename'], 0600);
533
		@fwrite($fd_log, "Adding text to file /etc/syslog.conf\n");
534
		mwexec("killall syslogd");
535
		system_syslogd_start();
536
	}
537

    
538
	/* make 'y' file */
539
	$fd = fopen("{$g['tmp_path']}/y", "w");
540
	for($line = 0; $line < 10; $line++) {
541
		fwrite($fd, "y\n");
542
	}
543
	fclose($fd);
544

    
545
	/* pkg_add the package and its dependencies */
546
	if($pkg_info['depends_on_package_base_url'] != "") {
547
		if($pkg_interface == "console") 
548
			echo "\n";
549
		update_status("Installing " . $pkg_info['name'] . " and its dependencies.");
550
		$static_output .= "Downloading " . $pkg_info['name'] . " and its dependencies... ";
551
		$static_orig = $static_output;
552
		$static_output .= "\n";
553
		update_output_window($static_output);
554
		foreach((array) $pkg_info['depends_on_package'] as $pkgdep) {
555
			$pkg_name = substr(reverse_strrchr($pkgdep, "."), 0, -1);
556
			if(isset($pkg_info['skip_install_checks'])) {
557
				$pkg_installed = true;
558
			} else {
559
				$pkg_installed = is_freebsd_pkg_installed($pkg_name);
560
			}
561
			if($pkg_installed == false) pkg_fetch_recursive($pkg_name, $pkgdep, 0, $pkg_info['depends_on_package_base_url']);
562
			$static_output = $static_orig . "done.\nChecking for successful package installation... ";
563
			update_output_window($static_output);
564
			/* make sure our package was successfully installed */
565
			if($pkg_installed == false) $pkg_installed = is_freebsd_pkg_installed($pkg_name);
566
			if($pkg_installed == true) {
567
				$static_output .= "done.\n";
568
				update_output_window($static_output);
569
				fwrite($fd_log, "pkg_add successfully completed.\n");
570
			} else {
571
				$static_output .= "failed!\n\nInstallation aborted.";
572
				update_output_window($static_output);
573
				fwrite($fd_log, "Package WAS NOT installed properly.\n");
574
				fclose($fd_log);
575
				if($pkg_interface <> "console") {
576
					echo "\n<script language=\"JavaScript\">document.progressbar.style.visibility='hidden';</script>";
577
					echo "\n<script language=\"JavaScript\">document.progholder.style.visibility='hidden';</script>";
578
				}
579
				sleep(1);
580
				die;
581
			}
582
		}
583
	}
584
	$configfile = substr(strrchr($pkg_info['config_file'], '/'), 1);
585
	if(file_exists("/usr/local/pkg/" . $configfile)) {
586
		$static_output .= "Loading package configuration... ";
587
		update_output_window($static_output);
588
		$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $configfile, "packagegui");
589
		$static_output .= "done.\n";
590
		update_output_window($static_output);
591
		$static_output .= "Configuring package components...\n";
592
		update_output_window($static_output);
593
		/* modify system files */
594
		if($pkg_config['modify_system']['item'] <> "") {
595
			$static_output .= "\tSystem files... ";
596
			update_output_window($static_output);
597
			foreach($pkg_config['modify_system']['item'] as $ms) {
598
				if($ms['textneeded']) {
599
					add_text_to_file($ms['modifyfilename'], $ms['textneeded']);
600
				}
601
			}
602
			$static_output .= "done.\n";
603
			update_output_window($static_output);
604
		}
605
		/* download additional files */
606
		if($pkg_config['additional_files_needed'] <> "") {
607
			$static_output .= "\tAdditional files... ";
608
			$static_orig = $static_output;
609
			update_output_window($static_output);
610
			foreach($pkg_config['additional_files_needed'] as $afn) {
611
				$filename = get_filename_from_url($afn['item'][0]);
612
				if($afn['chmod'] <> "") {
613
					$pkg_chmod = $afn['chmod'];
614
				} else {
615
					$pkg_chmod = "";
616
				}
617
				if($afn['prefix'] <> "") {
618
					$prefix = $afn['prefix'];
619
				} else {
620
					$prefix = "/usr/local/pkg/";
621
				}
622
				$static_output .= $filename . " ";
623
                                update_output_window($static_output);
624
				download_file_with_progress_bar($afn['item'][0], $prefix . $filename);
625
				if(stristr($filename, ".tgz") <> "") {
626
					fwrite($fd_log, "Extracting tarball to -C for " . $filename . "...\n");
627
					$tarout = "";
628
					exec("/usr/bin/tar xvzf " . $prefix . $filename . " -C / 2>&1", $tarout);
629
					fwrite($fd_log, print_r($tarout, true) . "\n");
630
				}
631
				if($pkg_chmod <> "") {
632
					fwrite($fd_log, "Changing file mode to {$pkg_chmod} for {$prefix}{$filename}\n");
633
					chmod($prefix . $filename, $pkg_chmod);
634
					system("/bin/chmod {$pkg_chmod} {$prefix}{$filename}");
635
				}
636
				$static_output = $static_orig;
637
                                update_output_window($static_output);
638
			}
639
			$static_output .= "done.\n";
640
			update_output_window($static_output);
641
		}
642
		/*   if a require exists, include it.  this will
643
		 *   show us where an error exists in a package
644
		 *   instead of making us blindly guess
645
		 */
646
		if($pkg_config['include_file'] <> "") {
647
			$static_output = "Loading package instructions...";
648
			update_output_window($static_output);
649
			fwrite($fd_log, "require_once('include_file')\n");
650
			require_once($pkg_config['include_file']);
651
		}
652
		/* sidebar items */
653
		if($pkg_config['menu'] != "") {
654
			$static_output .= "\tMenu items... ";
655
			update_output_window($static_output);
656
			if(is_array($pkg_config['menu'])) {
657
				foreach($pkg_config['menu'] as $menu) {
658
					if(is_array($config['installedpackages']['menu'])) {
659
						foreach($config['installedpackages']['menu'] as $amenu) {
660
							if($amenu['name'] == $menu['name']) continue 2;
661
						}
662
					}
663
					$config['installedpackages']['menu'][] = $menu;
664
				}
665
			}
666
			$static_output .= "done.\n";
667
			update_output_window($static_output);
668
		}
669
		/* services */
670
		if($pkg_config['service'] != "") {
671
			$static_output .= "\tServices... ";
672
			update_output_window($static_output);
673
			foreach($pkg_config['service'] as $service) {
674
				$config['installedpackages']['service'][] = $service;
675
			}
676
			$static_output .= "done.\n";
677
			update_output_window($static_output);
678
		}
679
		/* custom commands */
680
		$static_output .= "\tCustom commands... ";
681
		update_output_window($static_output);
682
		if($pkg_config['custom_php_global_functions'] <> "") {
683
			$static_output = "Executing custom_php_global_functions()...";
684
			update_output_window($static_output);
685
			eval_once($pkg_config['custom_php_global_functions']);
686
		}
687
		if($pkg_config['custom_php_install_command']) {
688
			$static_output = "Executing custom_php_install_command()...";
689
			update_output_window($static_output);
690
			eval_once($pkg_config['custom_php_install_command']);
691
		}
692
		if($pkg_config['custom_php_resync_config_command'] <> "") {
693
			$static_output = "Executing custom_php_resync_config_command()...";
694
			update_output_window($static_output);
695
			eval_once($pkg_config['custom_php_resync_config_command']);
696
		}
697
		$static_output .= "done.\n";
698
		update_output_window($static_output);
699
	} else {
700
		$static_output .= "Loading package configuration... failed!\n\nInstallation aborted.";
701
		update_output_window($static_output);
702
		fwrite($fd_log, "Unable to load package configuration. Installation aborted.\n");
703
		fclose($fd_log);
704
		if($pkg_interface <> "console") {
705
			echo "\n<script language=\"JavaScript\">document.progressbar.style.visibility='hidden';</script>";
706
			echo "\n<script language=\"JavaScript\">document.progholder.style.visibility='hidden';</script>";
707
		}
708
		sleep(1);
709
		return;
710
	}
711
}
712

    
713
function delete_package($pkg, $pkgid) {
714
	global $g, $config, $fd_log, $static_output;
715
	update_status("Removing package...");
716
	$static_output .= "Removing package... ";
717
	update_output_window($static_output);
718
	$pkgid = get_pkg_id($pkgid);
719
	$pkg_info = $config['installedpackages']['package'][$pkgid];
720

    
721
	$configfile = $pkg_info['configurationfile'];
722
	if(file_exists("/usr/local/pkg/" . $configfile)) {
723
		$static_output .= "\nLoading package configuration $configfile... ";
724
		update_output_window($static_output);
725
		$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $configfile, "packagegui");
726
		/*   if a require exists, include it.  this will
727
		 *   show us where an error exists in a package
728
		 *   instead of making us blindly guess
729
		 */
730
		if($pkg_config['include_file'] <> "") {
731
			$static_output .= "\nLoading package instructions...\n";
732
			update_output_window($static_output);
733
			require_once($pkg_config['include_file']);
734
		}
735
	}
736
	$static_output .= "\nStarting package deletion for {$pkg_info['name']}...\n";
737
	update_output_window($static_output);
738
	delete_package_recursive($pkg);
739
	remove_freebsd_package($pkg_info['name']);
740
	$static_output .= "done.\n";
741
	update_output_window($static_output);
742
	return;
743
}
744

    
745
function delete_package_recursive($pkg) {
746
	$info = "";
747
	exec("/usr/sbin/pkg_info -r " . $pkg . " 2>&1", $info);
748
	exec("cat {$g['tmp_path']}/y | /usr/sbin/pkg_delete " . $pkg ." > /dev/null 2>&1");
749
	remove_freebsd_package($pkg);
750
	$pkgdb = "";
751
	exec("/bin/ls /var/db/pkg", $pkgdb);
752
	if(stristr($info[0], "can't find package") != false) return;
753
	foreach($info as $line) {
754
		$depend = trim(array_pop(explode(":", $line)));
755
		if(in_array($depend, $pkgdb)) delete_package_recursive($depend);
756
	}
757
	$fd = fopen("{$g['tmp_path']}/y", "w");
758
	for($line = 0; $line < 10; $line++) {
759
		fwrite($fd, "y\n");
760
	}
761
	fclose($fd);
762
	return;
763
}
764

    
765
function delete_package_xml($pkg) {
766
	global $g, $config, $fd_log, $static_output, $pkg_interface;
767
	if(($pkgid = get_pkg_id($pkg)) == -1) {
768
		$static_output .= "The {$pkg} package is not installed.\n\nDeletion aborted.";
769
		update_output_window($static_output);
770
		if($pkg_interface <> "console") {
771
			echo "\n<script language=\"JavaScript\">document.progressbar.style.visibility='hidden';</script>";
772
			echo "\n<script language=\"JavaScript\">document.progholder.style.visibility='hidden';</script>";
773
		}
774
		ob_flush();
775
		sleep(1);
776
		return;
777
	}
778
	/* set up logging if needed */
779
	if(!$fd_log) {
780
		if(!$fd_log = fopen("{$g['tmp_path']}/pkg_mgr_{$pkg}.log", "w")) {
781
			update_output_window("Warning, could not open log for writing.");
782
		}
783
	}
784
	update_status("Removing {$pkg} components...");
785
	fwrite($fd_log, "Removing {$pkg} package... ");
786
	$static_output .= "Removing {$pkg} components...\n";
787
	update_output_window($static_output);
788
	/* parse package configuration */
789
	$packages = &$config['installedpackages']['package'];
790
	$menus = &$config['installedpackages']['menu'];
791
	$services = &$config['installedpackages']['service'];
792
	if(file_exists("/usr/local/pkg/" . $packages[$pkgid]['configurationfile'])) {
793
		$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $packages[$pkgid]['configurationfile'], "packagegui");
794
		/* remove menu items */
795
		if(is_array($pkg_config['menu'])) {
796
			$static_output .= "\tMenu items... ";
797
			update_output_window($static_output);
798
			foreach($menus as $menu) $instmenus[] = $menu['name'];
799
			foreach($pkg_config['menu'] as $menu) {
800
				foreach($instmenus as $key => $instmenu) {
801
					if($instmenu == $menu['name']) unset($menus[$key]);
802
				}
803
			}
804
			$static_output .= "done.\n";
805
			update_output_window($static_output);
806
		}
807
		/* remove services */
808
		if(is_array($pkg_config['service'])) {
809
			$static_output .= "\tServices... ";
810
			update_output_window($static_output);
811
			foreach($services as $service) $instservices[] = $service['name'];
812
			foreach($pkg_config['service'] as $service) {
813
				foreach($instservices as $key => $instservice) {
814
					if($instservice == $service['name']) {
815
						stop_service($service['name']);
816
						unset($services[$key]);
817
					}
818
				}
819
			}
820
			$static_output .= "done.\n";
821
			update_output_window($static_output);
822
		}
823
		/*   if a require exists, include it.  this will
824
		 *   show us where an error exists in a package
825
		 *   instead of making us blindly guess
826
		 */
827
		if($pkg_config['include_file'] <> "") {
828
			$static_output = "Loading package instructions...";
829
			update_output_window($static_output);
830
			fwrite($fd_log, "require_once('include_file')\n");
831
			if(file_exists($pkg_config['include_file']))
832
				require_once($pkg_config['include_file']);
833
			fwrite($fd_log, "require_once('include_file') included\n");
834
		}
835
		/* evalate this package's global functions and pre deinstall commands */
836
		if($pkg_config['custom_php_global_functions'] <> "")
837
			eval_once($pkg_config['custom_php_global_functions']);
838
		if($pkg_config['custom_php_pre_deinstall_command'] <> "")
839
			eval_once($pkg_config['custom_php_pre_deinstall_command']);
840
		/* remove all additional files */
841
		if($pkg_config['additional_files_needed'] <> "") {
842
			$static_output .= "\tAuxiliary files... ";
843
			update_output_window($static_output);
844
			foreach($pkg_config['additional_files_needed'] as $afn) {
845
				$filename = get_filename_from_url($afn['item'][0]);
846
				if($afn['prefix'] <> "") {
847
					$prefix = $afn['prefix'];
848
				} else {
849
					$prefix = "/usr/local/pkg/";
850
				}
851
				unlink_if_exists($prefix . $filename);
852
				if(file_exists($prefix . $filename))
853
				    mwexec("rm -rf {$prefix}{$filename}");
854
			}
855
			$static_output .= "done.\n";
856
			update_output_window($static_output);
857
		}
858
		/* system files */
859
		if($pkg_config['modify_system']['item'] <> "") {
860
			$static_output .= "\tSystem files... ";
861
			update_output_window($static_output);
862
			foreach($pkg_config['modify_system']['item'] as $ms) {
863
				if($ms['textneeded']) remove_text_from_file($ms['modifyfilename'], $ms['textneeded']);
864
			}
865
			$static_output .= "done.\n";
866
			update_output_window($static_output);
867
		}
868
		/* syslog */
869
		if($pkg_config['logging']['logfile_name'] <> "") {
870
			$static_output .= "\tSyslog entries... ";
871
			update_output_window($static_output);
872
			remove_text_from_file("/etc/syslog.conf", $pkg_config['logging']['facilityname'] . "\t\t\t\t" . $pkg_config['logging']['logfilename']);
873
			$static_output .= "done.\n";
874
			update_output_window($static_output);
875
		}
876
		/* deinstall commands */
877
		if($pkg_config['custom_php_deinstall_command'] <> "") {
878
			$static_output .= "\tDeinstall commands... ";
879
			update_output_window($static_output);
880
			eval_once($pkg_config['custom_php_deinstall_command']);
881
			$static_output .= "done.\n";
882
			update_output_window($static_output);
883
		}
884
		/* package XML file */
885
		$static_output .= "\tPackage XML... ";
886
		update_output_window($static_output);
887
		unlink_if_exists("/usr/local/pkg/" . $packages[$pkgid]['configurationfile']);
888
		$static_output .= "done.\n";
889
		update_output_window($static_output);
890
	}
891
	/* remove config.xml entries */
892
	$static_output .= "\tConfiguration... ";
893
	update_output_window($static_output);
894
	unset($config['installedpackages']['package'][$pkgid]);
895
	$static_output .= "done.\n";
896
	update_output_window($static_output);
897
	write_config("Removed {$pkg} package.");
898
	/* file cleanup */
899
	$ctag = file("/etc/crontab");
900
	foreach($ctag as $line) {
901
		if(trim($line) != "") $towrite[] = $line;
902
	}
903
	$tmptab = fopen("/tmp/crontab", "w");
904
	foreach($towrite as $line) {
905
		fwrite($tmptab, $line);
906
	}
907
	fclose($tmptab);
908
	rename("/tmp/crontab", "/etc/crontab");
909
}
910

    
911
function expand_to_bytes($size) {
912
	$conv = array(
913
			"G" =>	"3",
914
			"M" =>  "2",
915
			"K" =>  "1",
916
			"B" =>  "0"
917
		);
918
	$suffix = substr($size, -1);
919
	if(!in_array($suffix, array_keys($conv))) return $size;
920
	$size = substr($size, 0, -1);
921
	for($i = 0; $i < $conv[$suffix]; $i++) {
922
		$size *= 1024;
923
	}
924
	return $size;
925
}
926

    
927
function get_pkg_db() {
928
	global $g;
929
	return return_dir_as_array($g['vardb_path'] . '/pkg');
930
}
931

    
932
function walk_depend($depend, $pkgdb = "", $alreadyseen = "") {
933
	if(!$pkgdb) $pkgdb = get_pkg_db();
934
	if(!$alreadyseen) $alreadyseen = array();
935
	foreach($depend as $adepend) {
936
		$pkgname = reverse_strrchr($adepend['name'], '.');
937
		if(in_array($pkgname, $alreadyseen)) {
938
			continue;
939
		} elseif(!in_array($pkgname, $pkgdb)) {
940
			$size += expand_to_bytes($adepend['size']);
941
			$alreadyseen[] = $pkgname;
942
			if(is_array($adepend['depend'])) $size += walk_depend($adepend['depend'], $pkgdb, $alreadyseen);
943
		} else {
944
			continue;
945
		}
946
	}
947
	return $size;
948
}
949

    
950
function get_package_install_size($pkg = 'all', $pkg_info = "") {
951
	global $config, $g;
952
	if((!is_array($pkg)) and ($pkg != 'all')) $pkg = array($pkg);
953
	$pkgdb = get_pkg_db();
954
	if(!$pkg_info) $pkg_info = get_pkg_sizes($pkg);
955
	foreach($pkg as $apkg) {
956
		if(!$pkg_info[$apkg]) continue;
957
		$toreturn[$apkg] = expand_to_bytes(walk_depend(array($pkg_info[$apkg]), $pkgdb));
958
	}
959
	return $toreturn;
960
}
961

    
962
function squash_from_bytes($size, $round = "") {
963
	$conv = array(1 => "B", "K", "M", "G");
964
	foreach($conv as $div => $suffix) {
965
		$sizeorig = $size;
966
		if(($size /= 1024) < 1) {
967
			if($round) {
968
				$sizeorig = round($sizeorig, $round);
969
			}
970
			return $sizeorig . $suffix;
971
		}
972
	}
973
	return;
974
}
975

    
976
?>
(15-15/27)