Project

General

Profile

Download (30.5 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)  2004-2015  Electric Sheep Fencing, LLC. All rights reserved.
12
 *	Copyright (c)  2004, 2005 Scott Ullrich
13
 *	Copyright (c)  2005-2006 Colin Smith (ethethlay@gmail.com)
14
 *
15
 *	Redistribution and use in source and binary forms, with or without modification,
16
 *	are permitted provided that the following conditions are met:
17
 *
18
 *	1. Redistributions of source code must retain the above copyright notice,
19
 *		this list of conditions and the following disclaimer.
20
 *
21
 *	2. Redistributions in binary form must reproduce the above copyright
22
 *		notice, this list of conditions and the following disclaimer in
23
 *		the documentation and/or other materials provided with the
24
 *		distribution.
25
 *
26
 *	3. All advertising materials mentioning features or use of this software
27
 *		must display the following acknowledgment:
28
 *		"This product includes software developed by the pfSense Project
29
 *		 for use in the pfSense software distribution. (http://www.pfsense.org/).
30
 *
31
 *	4. The names "pfSense" and "pfSense Project" must not be used to
32
 *		 endorse or promote products derived from this software without
33
 *		 prior written permission. For written permission, please contact
34
 *		 coreteam@pfsense.org.
35
 *
36
 *	5. Products derived from this software may not be called "pfSense"
37
 *		nor may "pfSense" appear in their names without prior written
38
 *		permission of the Electric Sheep Fencing, LLC.
39
 *
40
 *	6. Redistributions of any form whatsoever must retain the following
41
 *		acknowledgment:
42
 *
43
 *	"This product includes software developed by the pfSense Project
44
 *	for use in the pfSense software distribution (http://www.pfsense.org/).
45
 *
46
 *	THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
47
 *	EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48
 *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
49
 *	PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
50
 *	ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
51
 *	SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
52
 *	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
53
 *	LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54
 *	HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
55
 *	STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
56
 *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
57
 *	OF THE POSSIBILITY OF SUCH DAMAGE.
58
 *
59
 *	====================================================================
60
 *
61
 */
62
/*
63
	pfSense_BUILDER_BINARIES:	/usr/bin/cd /usr/bin/tar	/usr/sbin/fifolog_create	/bin/chmod
64
	pfSense_BUILDER_BINARIES:	/usr/sbin/pkg_add	/usr/sbin/pkg_info	/usr/sbin/pkg_delete	/bin/rm
65
	pfSense_MODULE: pkg
66
*/
67

    
68
require_once("globals.inc");
69
require_once("service-utils.inc");
70

    
71
if (file_exists("/cf/conf/use_xmlreader")) {
72
	require_once("xmlreader.inc");
73
} else {
74
	require_once("xmlparse.inc");
75
}
76

    
77
require_once("pfsense-utils.inc");
78

    
79
if (!function_exists("pkg_debug")) {
80
	/* set up logging if needed */
81
	function pkg_debug($msg) {
82
		global $g, $debug, $fd_log;
83

    
84
		if (!$debug) {
85
			return;
86
		}
87

    
88
		if (!$fd_log) {
89
			if (!$fd_log = fopen("{$g['tmp_path']}/pkg_mgr_debug.log", "w")) {
90
				update_output_window("Warning, could not open log for writing.");
91
			}
92
		}
93
		@fwrite($fd_log, $msg);
94
	}
95
}
96

    
97
global $g;
98
if (!isset($g['platform'])) {
99
	$g['platform'] = trim(file_get_contents("/etc/platform"));
100
}
101

    
102
/* Remove pkg_prefix from package name if it's present */
103
function pkg_remove_prefix(&$pkg_name) {
104
	global $g;
105

    
106
	if (substr($pkg_name, 0, strlen($g['pkg_prefix'])) == $g['pkg_prefix']) {
107
		$pkg_name = substr($pkg_name, strlen($g['pkg_prefix']));
108
	}
109
}
110

    
111
/* Execute pkg update when it's necessary */
112
function pkg_update($force = false) {
113
	global $g;
114

    
115
	$now = strftime('%s');
116
	if (!$force) {
117
		$last_update_file="{$g['varrun_path']}/{$g['product_name']}-upgrade-last-update";
118

    
119
		if (file_exists($last_update_file)) {
120
			$last_update = rtrim(file_get_contents($last_update_file), "\n");
121
			if (!is_numericint($last_update)) {
122
				$last_update = 0;
123
			}
124
		}
125

    
126
		if ($last_update > 0) {
127
			if ($now > $last_update && ($now - $last_update) <= (60 * 60)) {
128
				return true;
129
			}
130
		}
131
	}
132

    
133
	$rc = pkg_call("update");
134

    
135
	if ($rc) {
136
		file_put_contents($last_update_file, $now . "\n");
137
	}
138

    
139
	return $rc;
140
}
141

    
142
/* Execute a pkg call */
143
function pkg_call($params, $mute = false) {
144
	global $static_output, $g, $config;
145

    
146
	if (empty($params)) {
147
		return false;
148
	}
149

    
150
	$user_agent = $g['product_name'] . '/' . $g['product_version'];
151
	if (!isset($config['system']['host_uuid'])) {
152
		$user_agent .= ' : ' . get_single_sysctl('kern.hostuuid');
153
	}
154

    
155
	$env = array(
156
		"HTTP_USER_AGENT" => $user_agent,
157
		"ASSUME_ALWAYS_YES" => "true",
158
		"REPO_AUTOUPDATE" => "false"
159
	);
160

    
161
	$descriptorspec = array(
162
		1 => array("pipe", "w"), /* stdout */
163
		2 => array("pipe", "w")	 /* stderr */
164
	);
165

    
166
	pkg_debug("pkg_call(): {$params}\n");
167
	$process = proc_open("/usr/sbin/pkg {$params}", $descriptorspec, $pipes, '/', $env);
168

    
169
	if (!is_resource($process)) {
170
		return false;
171
	}
172

    
173
	stream_set_blocking($pipes[1], 0);
174
	stream_set_blocking($pipes[2], 0);
175

    
176
	/* XXX: should be a tunnable? */
177
	$timeout = 300; // seconds
178
	$error_log = '';
179
	$started = time();
180
	$maxwaittime = 10; // Number of seconds to wait for a response fromteh pacakge we are calling
181

    
182
	do {
183
		$write = array();
184
		$read = array($pipes[1], $pipes[2]);
185
		$except = array();
186

    
187
		$stream = stream_select($read, $write, $except, null, $timeout);
188
		if ($stream !== FALSE && $stream > 0) {
189
			foreach ($read as $pipe) {
190
				$content = stream_get_contents($pipe);
191
				if ($content == '') {
192
					continue;
193
				}
194
				if ($pipe === $pipes[1]) {
195
					if (!$mute) {
196
						$static_output .= $content;
197
						update_output_window($static_output);
198
					}
199
					flush();
200
				} else if ($pipe === $pipes[2]) {
201
					$error_log .= $content;
202
				}
203
			}
204
		}
205

    
206
		$status = proc_get_status($process);
207

    
208
		$now = time();
209

    
210
		if(($now - $started) >= $maxwaittime) {
211
			$rc = -1;
212
			proc_terminate($process);
213
			break;
214
		}
215

    
216
	} while ($status['running']);
217

    
218
	fclose($pipes[1]);
219
	fclose($pipes[2]);
220
	proc_close($process);
221

    
222
	if(!isset($rc)) {
223
		$rc = $status['exitcode'];
224
	}
225

    
226
	pkg_debug("pkg_call(): rc = {$rc}\n");
227
	if ($rc == 0) {
228
		return true;
229
	}
230

    
231
	pkg_debug("pkg_call(): error_log\n{$error_log}\n");
232
	if (!$mute) {
233
		$static_output .= "\n\n" . sprintf(gettext("ERROR!!! An error occurred on pkg execution (rc = %d) with parameters '%s':"), $rc, $params) . "\n" . $error_log;
234
		update_output_window($static_output);
235
	}
236

    
237
	return false;
238
}
239

    
240
/* Execute pkg with $params, fill stdout and stderr and return pkg rc */
241
function pkg_exec($params, &$stdout, &$stderr) {
242
	global $g, $config;
243

    
244
	if (empty($params)) {
245
		return -1;
246
	}
247

    
248
	$user_agent = $g['product_name'] . '/' . $g['product_version'];
249
	if (!isset($config['system']['host_uuid'])) {
250
		$user_agent .= ' : ' . get_single_sysctl('kern.hostuuid');
251
	}
252

    
253
	$env = array(
254
		"HTTP_USER_AGENT" => $user_agent,
255
		"ASSUME_ALWAYS_YES" => "true",
256
		"REPO_AUTOUPDATE" => "false"
257
	);
258

    
259
	$descriptorspec = array(
260
		1 => array("pipe", "w"), /* stdout */
261
		2 => array("pipe", "w")	 /* stderr */
262
	);
263

    
264
	pkg_debug("pkg_exec(): {$params}\n");
265
	$process = proc_open("/usr/sbin/pkg {$params}", $descriptorspec, $pipes, '/', $env);
266

    
267
	if (!is_resource($process)) {
268
		return -1;
269
	}
270

    
271
	$stdout = '';
272
	while (($l = fgets($pipes[1])) !== FALSE) {
273
		$stdout .= $l;
274
	}
275
	fclose($pipes[1]);
276

    
277
	$stderr = '';
278
	while (($l = fgets($pipes[2])) !== FALSE) {
279
		$stderr .= $l;
280
	}
281
	fclose($pipes[2]);
282

    
283
	return proc_close($process);
284
}
285

    
286
/* Compare 2 pkg versions and return:
287
 * '=' - versions are the same
288
 * '>' - $v1 > $v2
289
 * '<' - $v1 < $v2
290
 * '?' - Error
291
 */
292
function pkg_version_compare($v1, $v2) {
293
	if (empty($v1) || empty($v2)) {
294
		return '?';
295
	}
296

    
297
	$rc = pkg_exec("version -t '{$v1}' '{$v2}'", $stdout, $stderr);
298

    
299
	if ($rc != 0) {
300
		return '?';
301
	}
302

    
303
	return str_replace("\n", "", $stdout);
304
}
305

    
306
/* Check if package is installed */
307
function is_pkg_installed($pkg_name) {
308
	global $g;
309

    
310
	pkg_remove_prefix($pkg_name);
311

    
312
	return pkg_call("info -e " . $g['pkg_prefix'] . $pkg_name, true);
313
}
314

    
315
/* Install package, $pkg_name should not contain prefix */
316
function pkg_install($pkg_name) {
317
	global $g;
318
	$result = false;
319

    
320
	pkg_remove_prefix($pkg_name);
321

    
322
	pkg_debug("Installing package {$pkg_name}\n");
323
	if (!is_pkg_installed($pkg_name)) {
324
		$result = pkg_call("install -y " . $g['pkg_prefix'] . $pkg_name);
325
		/* Cleanup cacke to free disk space */
326
		pkg_call("clean -y");
327
	}
328

    
329
	return $result;
330
}
331

    
332
/* Delete package from FreeBSD, $pkg_name should not contain prefix */
333
function pkg_delete($pkg_name) {
334
	global $g;
335

    
336
	pkg_remove_prefix($pkg_name);
337

    
338
	pkg_debug("Removing package {$pkg_name}\n");
339
	if (is_pkg_installed($pkg_name)) {
340
		pkg_call("delete -y " . $g['pkg_prefix'] . $pkg_name);
341
		/* Cleanup unecessary dependencies */
342
		pkg_call("autoremove -y");
343
	}
344
}
345

    
346
/* Check if package is present in config.xml */
347
function is_package_installed($package_name) {
348
	return (get_package_id($package_name) != -1);
349
}
350

    
351
/* Find package array index */
352
function get_package_id($package_name) {
353
	global $config;
354

    
355
	if (!is_array($config['installedpackages']['package'])) {
356
		return -1;
357
	}
358

    
359
	foreach ($config['installedpackages']['package'] as $idx => $pkg) {
360
		if ($pkg['name'] == $package_name ||
361
			get_package_internal_name($pkg) == $package_name) {
362
			return $idx;
363
		}
364
	}
365

    
366
	return -1;
367
}
368

    
369
/* Keep backward compatibility since snort/suricata use this function */
370
function get_pkg_id($package_name) {
371
	return get_package_id($package_name);
372
}
373

    
374
/* Return internal_name when it's defined, otherwise, returns name */
375
function get_package_internal_name($package_data) {
376
	if (isset($package_data['internal_name']) && ($package_data['internal_name'] != "")) {
377
		/* e.g. name is Ipguard-dev, internal name is ipguard */
378
		return $package_data['internal_name'];
379
	} else {
380
		return $package_data['name'];
381
	}
382
}
383

    
384
// Get information about packages.
385
function get_pkg_info($pkgs = 'all', $info = 'all') {
386
	global $g, $static_output, $input_errors;
387

    
388
	$out = '';
389
	$err = '';
390

    
391
	unset($pkg_filter);
392
	if (is_array($pkgs)) {
393
		$pkg_filter = $pkgs;
394
		$pkgs = 'all';
395
	}
396

    
397
	if ($pkgs == 'all') {
398
		$pkgs = $g['pkg_prefix'];
399
	}
400

    
401
	/* Make sure repo metadata is up2date */
402
	$static_output .= "\n" . gettext("Updating package repository metadada...") . "\n";
403
	update_status($static_output);
404

    
405
	if (!pkg_update()) {
406
		$input_errors[] = gettext("ERROR: An error occurred when updating packages repository. Aborting...") . "\n";
407
		$static_output .= "\n" . gettext("ERROR: An error occurred when updating packages repository. Aborting...") . "\n";
408
		update_status($static_output);
409
		return array();
410
	}
411

    
412

    
413
	$rc = pkg_exec("search -U --raw-format json-compact " . $pkgs, $out, $err);
414

    
415
	if ($rc != 0) {
416
		$static_output .= "\n" . gettext("ERROR: Error trying to get packages list. Aborting...") . "\n";
417
		$static_output .= $err;
418
		$input_errors[] =  gettext("ERROR: Error trying to get packages list. Aborting...") . "\n";
419
		$input_errors[] =  $err;
420
		update_status($static_output);
421
		return array();
422
	}
423

    
424
	$result = array();
425
	$pkgs_info = explode("\n", $out);
426
	foreach ($pkgs_info as $pkg_info_json) {
427
		$pkg_info = json_decode($pkg_info_json, true);
428
		if (!isset($pkg_info['name'])) {
429
			continue;
430
		}
431

    
432
		if (isset($pkg_filter) && !in_array($pkg_info['name'], $pkg_filter)) {
433
			continue;
434
		}
435

    
436
		if (is_pkg_installed($pkg_info['name'])) {
437
			$pkg_info['installed'] = true;
438
		}
439

    
440
		$pkg_info['desc'] = preg_replace('/\n+WWW:.*$/', '', $pkg_info['desc']);
441

    
442
		$result[] = $pkg_info;
443
		unset($pkg_info);
444
	}
445

    
446
	return $result;
447
}
448

    
449
/*
450
 * resync_all_package_configs() Force packages to setup their configuration and rc.d files.
451
 * This function may also print output to the terminal indicating progress.
452
 */
453
function resync_all_package_configs($show_message = false) {
454
	global $config, $pkg_interface, $g;
455

    
456
	log_error(gettext("Resyncing configuration for all packages."));
457

    
458
	if (!is_array($config['installedpackages']['package'])) {
459
		return;
460
	}
461

    
462
	if ($show_message == true) {
463
		echo "Syncing packages:";
464
	}
465

    
466
	conf_mount_rw();
467

    
468
	foreach ($config['installedpackages']['package'] as $idx => $package) {
469
		if (empty($package['name'])) {
470
			continue;
471
		}
472
		if ($show_message == true) {
473
			echo " " . $package['name'];
474
		}
475
		if (platform_booting() != true) {
476
			stop_service(get_package_internal_name($package));
477
		}
478
		sync_package($package['name']);
479
		if ($pkg_interface == "console") {
480
			echo "\n" . gettext("Syncing packages:");
481
		}
482
	}
483

    
484
	if ($show_message == true) {
485
		echo " done.\n";
486
	}
487

    
488
	@unlink("/conf/needs_package_sync");
489
	conf_mount_ro();
490
}
491

    
492
function uninstall_package($package_name) {
493
	global $config, $static_output;
494

    
495
	$internal_name = $package_name;
496
	$id = get_package_id($package_name);
497
	if ($id >= 0) {
498
		$internal_name = get_package_internal_name($config['installedpackages']['package'][$id]);
499
		stop_service($internal_name);
500
	}
501

    
502
	if (is_pkg_installed($internal_name)) {
503
		$static_output .= "Removing package...\n";
504
		update_output_window($static_output);
505
		pkg_delete($internal_name);
506
	} else {
507
		delete_package_xml($package_name);
508
	}
509

    
510
	$static_output .= gettext("done.") . "\n";
511
	update_output_window($static_output);
512
}
513

    
514
/* Run <custom_php_resync_config_command> */
515
function sync_package($package_name) {
516
	global $config, $builder_package_install;
517

    
518
	// If this code is being called by pfspkg_installer
519
	// which the builder system uses then return (ignore).
520
	if ($builder_package_install) {
521
		return;
522
	}
523

    
524
	if (empty($config['installedpackages']['package'])) {
525
		return;
526
	}
527

    
528
	if (($pkg_id = get_package_id($package_name)) == -1) {
529
		return; // This package doesn't really exist - exit the function.
530
	}
531

    
532
	if (!is_array($config['installedpackages']['package'][$pkg_id])) {
533
		return;	 // No package belongs to the pkg_id passed to this function.
534
	}
535

    
536
	$package =& $config['installedpackages']['package'][$pkg_id];
537
	if (!file_exists("/usr/local/pkg/" . $package['configurationfile'])) {
538
		log_error(sprintf(gettext("The %s package is missing its configuration file and must be reinstalled."), $package['name']));
539
		delete_package_xml($package['name']);
540
		return;
541
	}
542

    
543
	$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $package['configurationfile'], "packagegui");
544
	if (isset($pkg_config['nosync'])) {
545
		return;
546
	}
547

    
548
	/* Bring in package include files */
549
	if (!empty($pkg_config['include_file'])) {
550
		$include_file = $pkg_config['include_file'];
551
		if (file_exists($include_file)) {
552
			require_once($include_file);
553
		} else {
554
			log_error("Reinstalling package {$package['name']} because its include file({$include_file}) is missing!");
555
			uninstall_package($package['name']);
556
			if (install_package($package['name']) != 0) {
557
				log_error("Reinstalling package {$package['name']} failed. Take appropriate measures!!!");
558
				return;
559
			}
560
			if (file_exists($include_file)) {
561
				require_once($include_file);
562
			} else {
563
				return;
564
			}
565
		}
566
	}
567

    
568
	if (!empty($pkg_config['custom_php_global_functions'])) {
569
		eval($pkg_config['custom_php_global_functions']);
570
	}
571
	if (!empty($pkg_config['custom_php_resync_config_command'])) {
572
		eval($pkg_config['custom_php_resync_config_command']);
573
	}
574
}
575

    
576
/* Read info.xml installed by package and return an array */
577
function read_package_config($package_name) {
578
	global $g;
579

    
580
	$pkg_info_xml = '/usr/local/share/' . $g['pkg_prefix'] . $package_name . '/info.xml';
581

    
582
	if (!file_exists($pkg_info_xml)) {
583
		return false;
584
	}
585

    
586
	$pkg_info = parse_xml_config_pkg($pkg_info_xml, 'pfsensepkgs');
587

    
588
	if (empty($pkg_info)) {
589
		return false;
590
	}
591

    
592
	/* it always returns an array with 1 item */
593
	return $pkg_info['package'][0];
594
}
595

    
596
function get_after_install_info($package_name) {
597
	$pkg_config = read_package_config($package_name);
598

    
599
	if (isset($pkg_config['after_install_info'])) {
600
		return $pkg_config['after_install_info'];
601
	}
602

    
603
	return '';
604
}
605

    
606
function eval_once($toeval) {
607
	global $evaled;
608
	if (!$evaled) {
609
		$evaled = array();
610
	}
611
	$evalmd5 = md5($toeval);
612
	if (!in_array($evalmd5, $evaled)) {
613
		@eval($toeval);
614
		$evaled[] = $evalmd5;
615
	}
616
	return;
617
}
618

    
619
function install_package($package_name) {
620
	global $g, $config, $static_output, $pkg_interface;
621

    
622
	if ($pkg_interface == "console") {
623
		echo "\n";
624
	}
625

    
626
	return pkg_install($package_name);
627
}
628

    
629
function install_package_xml($package_name) {
630
	global $g, $config, $static_output, $pkg_interface;
631

    
632
	if (($pkg_info = read_package_config($package_name)) == false) {
633
		return false;
634
	}
635

    
636
	/* safe side. Write config below will send to ro again. */
637
	conf_mount_rw();
638

    
639
	pkg_debug(gettext("Beginning package installation.") . "\n");
640
	log_error(sprintf(gettext('Beginning package installation for %s .'), $pkg_info['name']));
641

    
642
	/* add package information to config.xml */
643
	$pkgid = get_package_id($pkg_info['name']);
644
	$static_output .= gettext("Saving updated package information...") . " ";
645
	update_output_window($static_output);
646
	if ($pkgid == -1) {
647
		$config['installedpackages']['package'][] = $pkg_info;
648
		$changedesc = sprintf(gettext("Installed %s package."), $pkg_info['name']);
649
		$to_output = gettext("done.") . "\n";
650
	} else {
651
		$config['installedpackages']['package'][$pkgid] = $pkg_info;
652
		$changedesc = sprintf(gettext("Overwrote previous installation of %s."), $pkg_info['name']);
653
		$to_output = gettext("overwrite!") . "\n";
654
	}
655
	unlink_if_exists('/conf/needs_package_sync');
656
	write_config("Intermediate config write during package install for {$pkg_info['name']}.");
657
	conf_mount_ro();
658
	$static_output .= $to_output;
659
	update_output_window($static_output);
660

    
661
	if (($pkgid = get_package_id($package_name)) == -1) {
662
		$static_output .= sprintf(gettext("The %s package is not installed.%sInstallation aborted."), $package_name, "\n\n");
663
		update_output_window($static_output);
664
		if ($pkg_interface <> "console") {
665
			echo "\n<script>document.getElementById('progressbar').style.visibility='hidden';</script>";
666
			echo "\n<script>document.getElementById('progholder').style.visibility='hidden';</script>";
667
		}
668

    
669
		uninstall_package($package_name);
670
		write_config($changedesc);
671
		log_error(sprintf(gettext("Failed to install package: %s."), $pkg_info['name']));
672
		$static_output .= gettext("Failed to install package.") . "\n";
673
		update_output_window($static_output);
674
		return false;
675
	}
676

    
677
	$configfile = substr(strrchr($pkg_info['config_file'], '/'), 1);
678
	if (file_exists("/usr/local/pkg/" . $configfile)) {
679
		$static_output .= gettext("Loading package configuration... ");
680
		update_output_window($static_output);
681
		$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $configfile, "packagegui");
682
		$static_output .= gettext("done.") . "\n";
683
		update_output_window($static_output);
684
		$static_output .= gettext("Configuring package components...\n");
685
		if (!empty($pkg_config['filter_rules_needed'])) {
686
			$config['installedpackages']['package'][$pkgid]['filter_rule_function'] = $pkg_config['filter_rules_needed'];
687
		}
688
		update_output_window($static_output);
689
		/* modify system files */
690

    
691
		/* if a require exists, include it.  this will
692
		 * show us where an error exists in a package
693
		 * instead of making us blindly guess
694
		 */
695
		$missing_include = false;
696
		if ($pkg_config['include_file'] <> "") {
697
			$static_output .= gettext("Loading package instructions...") . "\n";
698
			update_output_window($static_output);
699
			if (file_exists($pkg_config['include_file'])) {
700
				pkg_debug("require_once('{$pkg_config['include_file']}')\n");
701
				require_once($pkg_config['include_file']);
702
			} else {
703
				pkg_debug("Missing include {$pkg_config['include_file']}\n");
704
				$missing_include = true;
705
				$static_output .= "Include " . basename($pkg_config['include_file']) . " is missing!\n";
706
				update_output_window($static_output);
707

    
708
				uninstall_package($package_name);
709
				write_config($changedesc);
710
				log_error(sprintf(gettext("Failed to install package: %s."), $pkg_info['name']));
711
				$static_output .= gettext("Failed to install package.") . "\n";
712
				update_output_window($static_output);
713
				return false;
714
			}
715
		}
716

    
717
		/* custom commands */
718
		$static_output .= gettext("Custom commands...") . "\n";
719
		update_output_window($static_output);
720
		if ($missing_include == false) {
721
			if ($pkg_config['custom_php_global_functions'] <> "") {
722
				$static_output .= gettext("Executing custom_php_global_functions()...");
723
				update_output_window($static_output);
724
				eval_once($pkg_config['custom_php_global_functions']);
725
				$static_output .= gettext("done.") . "\n";
726
				update_output_window($static_output);
727
			}
728
			if ($pkg_config['custom_php_install_command']) {
729
				$static_output .= gettext("Executing custom_php_install_command()...");
730
				update_output_window($static_output);
731
				eval_once($pkg_config['custom_php_install_command']);
732
				$static_output .= gettext("done.") . "\n";
733
				update_output_window($static_output);
734
			}
735
			if ($pkg_config['custom_php_resync_config_command'] <> "") {
736
				$static_output .= gettext("Executing custom_php_resync_config_command()...");
737
				update_output_window($static_output);
738
				eval_once($pkg_config['custom_php_resync_config_command']);
739
				$static_output .= gettext("done.") . "\n";
740
				update_output_window($static_output);
741
			}
742
		}
743
		/* sidebar items */
744
		if (is_array($pkg_config['menu'])) {
745
			$static_output .= gettext("Menu items... ");
746
			update_output_window($static_output);
747
			foreach ($pkg_config['menu'] as $menu) {
748
				if (is_array($config['installedpackages']['menu'])) {
749
					foreach ($config['installedpackages']['menu'] as $amenu) {
750
						if ($amenu['name'] == $menu['name']) {
751
							continue 2;
752
						}
753
					}
754
				} else {
755
					$config['installedpackages']['menu'] = array();
756
				}
757
				$config['installedpackages']['menu'][] = $menu;
758
			}
759
			$static_output .= gettext("done.") . "\n";
760
			update_output_window($static_output);
761
		}
762
		/* services */
763
		if (is_array($pkg_config['service'])) {
764
			$static_output .= gettext("Services... ");
765
			update_output_window($static_output);
766
			foreach ($pkg_config['service'] as $service) {
767
				if (is_array($config['installedpackages']['service'])) {
768
					foreach ($config['installedpackages']['service'] as $aservice) {
769
						if ($aservice['name'] == $service['name']) {
770
							continue 2;
771
						}
772
					}
773
				} else {
774
					$config['installedpackages']['service'] = array();
775
				}
776
				$config['installedpackages']['service'][] = $service;
777
			}
778
			$static_output .= gettext("done.") . "\n";
779
			update_output_window($static_output);
780
		}
781
	} else {
782
		pkg_debug("Unable to find config file\n");
783
		$static_output .= gettext("Loading package configuration... failed!") . "\n\n" . gettext("Installation aborted.");
784
		update_output_window($static_output);
785
		pkg_debug(gettext("Unable to load package configuration. Installation aborted.") ."\n");
786
		if ($pkg_interface <> "console") {
787
			echo "\n<script>document.getElementById('progressbar').style.visibility='hidden';</script>";
788
			echo "\n<script>document.getElementById('progholder').style.visibility='hidden';</script>";
789
		}
790

    
791
		uninstall_package($package_name);
792
		write_config($changedesc);
793
		log_error(sprintf(gettext("Failed to install package: %s."), $pkg_info['name']));
794
		$static_output .= gettext("Failed to install package.") . "\n";
795
		update_output_window($static_output);
796
		return false;
797
	}
798

    
799
	/* set up package logging streams */
800
	if ($pkg_info['logging']) {
801
		system_syslogd_start();
802
	}
803

    
804
	$static_output .= gettext("Writing configuration... ");
805
	update_output_window($static_output);
806
	write_config($changedesc);
807
	log_error(sprintf(gettext("Successfully installed package: %s."), $pkg_info['name']));
808
	$static_output .= gettext("done.") . "\n";
809
	update_output_window($static_output);
810
	if ($pkg_info['after_install_info']) {
811
		update_output_window($pkg_info['after_install_info']);
812
	}
813

    
814
	return true;
815
}
816

    
817
function delete_package($package_name) {
818
	global $config, $g, $static_output;
819

    
820
	if (!is_package_installed($package_name)) {
821
		return;
822
	}
823

    
824
	$static_output .= sprintf(gettext("Starting package deletion for %s..."), $package_name);
825
	update_output_window($static_output);
826

    
827
	pkg_delete($package_name);
828
	$static_output .= "done.\n";
829
	update_output_window($static_output);
830

    
831
	return;
832
}
833

    
834
function delete_package_xml($package_name, $when = "post-deinstall") {
835
	global $g, $config, $static_output, $pkg_interface;
836

    
837
	conf_mount_rw();
838

    
839
	$pkgid = get_package_id($package_name);
840
	if ($pkgid == -1) {
841
		$static_output .= sprintf(gettext("The %s package is not installed.%sDeletion aborted."), $package_name, "\n\n");
842
		update_output_window($static_output);
843
		if ($pkg_interface <> "console") {
844
			echo "\n<script>document.getElementById('progressbar').style.visibility='hidden';</script>";
845
			echo "\n<script>document.getElementById('progholder').style.visibility='hidden';</script>";
846
		}
847
		ob_flush();
848
		sleep(1);
849
		conf_mount_ro();
850
		return;
851
	}
852
	pkg_debug(sprintf(gettext("Removing %s package... "), $package_name));
853
	$static_output .= sprintf(gettext("Removing %s components..."), $package_name) . "\n";
854
	update_output_window($static_output);
855
	/* parse package configuration */
856
	$packages = &$config['installedpackages']['package'];
857
	$menus =& $config['installedpackages']['menu'];
858
	$services = &$config['installedpackages']['service'];
859
	$pkg_info =& $packages[$pkgid];
860
	if (file_exists("/usr/local/pkg/" . $pkg_info['configurationfile'])) {
861
		$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $packages[$pkgid]['configurationfile'], "packagegui");
862
		/* remove menu items */
863
		if (is_array($pkg_config['menu'])) {
864
			$static_output .= gettext("Menu items... ");
865
			update_output_window($static_output);
866
			if (is_array($pkg_config['menu']) && is_array($menus)) {
867
				foreach ($pkg_config['menu'] as $menu) {
868
					foreach ($menus as $key => $instmenu) {
869
						if ($instmenu['name'] == $menu['name']) {
870
							unset($menus[$key]);
871
							break;
872
						}
873
					}
874
				}
875
			}
876
			$static_output .= gettext("done.") . "\n";
877
			update_output_window($static_output);
878
		}
879
		/* remove services */
880
		if (is_array($pkg_config['service'])) {
881
			$static_output .= gettext("Services... ");
882
			update_output_window($static_output);
883
			if (is_array($pkg_config['service']) && is_array($services)) {
884
				foreach ($pkg_config['service'] as $service) {
885
					foreach ($services as $key => $instservice) {
886
						if ($instservice['name'] == $service['name']) {
887
							if (platform_booting() != true) {
888
								stop_service($service['name']);
889
							}
890
							if ($service['rcfile']) {
891
								$prefix = RCFILEPREFIX;
892
								if (!empty($service['prefix'])) {
893
									$prefix = $service['prefix'];
894
								}
895
								if (file_exists("{$prefix}{$service['rcfile']}")) {
896
									@unlink("{$prefix}{$service['rcfile']}");
897
								}
898
							}
899
							unset($services[$key]);
900
						}
901
					}
902
				}
903
			}
904
			$static_output .= gettext("done.") . "\n";
905
			update_output_window($static_output);
906
		}
907
		/*
908
		 * XXX: Otherwise inclusion of config.inc again invalidates actions taken.
909
		 *	Same is done during installation.
910
		 */
911
		write_config("Intermediate config write during package removal for {$package_name}.");
912

    
913
		/*
914
		 * If a require exists, include it.	 this will
915
		 * show us where an error exists in a package
916
		 * instead of making us blindly guess
917
		 */
918
		$missing_include = false;
919
		if ($pkg_config['include_file'] <> "") {
920
			$static_output .= gettext("Loading package instructions...") . "\n";
921
			update_output_window($static_output);
922
			if (file_exists($pkg_config['include_file'])) {
923
				pkg_debug("require_once(\"{$pkg_config['include_file']}\")\n");
924
				require_once($pkg_config['include_file']);
925
			} else {
926
				pkg_debug("Missing include {$pkg_config['include_file']}\n");
927
				$missing_include = true;
928
				update_output_window($static_output);
929
				$static_output .= "Include file " . basename($pkg_config['include_file']) . " could not be found for inclusion.\n";
930
			}
931
		}
932
		/* ermal
933
		 * NOTE: It is not possible to handle parse errors on eval.
934
		 * So we prevent it from being run at all to not interrupt all the other code.
935
		 */
936
		if ($when == "deinstall" && $missing_include == false) {
937
			/* evaluate this package's global functions and pre deinstall commands */
938
			if ($pkg_config['custom_php_global_functions'] <> "") {
939
				eval_once($pkg_config['custom_php_global_functions']);
940
			}
941
			if ($pkg_config['custom_php_pre_deinstall_command'] <> "") {
942
				eval_once($pkg_config['custom_php_pre_deinstall_command']);
943
			}
944
		}
945
		/* deinstall commands */
946
		if ($when == "post-deinstall" && $pkg_config['custom_php_deinstall_command'] <> "") {
947
			$static_output .= gettext("Deinstall commands... ");
948
			update_output_window($static_output);
949
			if ($missing_include == false) {
950
				eval_once($pkg_config['custom_php_deinstall_command']);
951
				$static_output .= gettext("done.") . "\n";
952
			} else {
953
				$static_output .= "\nNot executing custom deinstall hook because an include is missing.\n";
954
			}
955
			update_output_window($static_output);
956
		}
957
	}
958
	/* syslog */
959
	$need_syslog_restart = false;
960
	if (is_array($pkg_info['logging']) && $pkg_info['logging']['logfilename'] <> "") {
961
		$static_output .= "Syslog entries... ";
962
		update_output_window($static_output);
963
		@unlink("{$g['varlog_path']}/{$pkg_info['logging']['logfilename']}");
964
		$static_output .= "done.\n";
965
		update_output_window($static_output);
966
		$need_syslog_restart = true;
967
	}
968

    
969
	/* remove config.xml entries */
970
	$static_output .= gettext("Configuration... ");
971
	update_output_window($static_output);
972
	unset($config['installedpackages']['package'][$pkgid]);
973
	$static_output .= gettext("done.") . "\n";
974
	update_output_window($static_output);
975
	write_config("Removed {$package_name} package.\n");
976

    
977
	/* remove package entry from /etc/syslog.conf if needed */
978
	/* this must be done after removing the entries from config.xml */
979
	if ($need_syslog_restart) {
980
		system_syslogd_start();
981
	}
982

    
983
	conf_mount_ro();
984
}
985

    
986
function pkg_reinstall_all() {
987
	global $g, $config;
988

    
989
	// XXX: implement
990
	return;
991
}
992

    
993
function stop_packages() {
994
	require_once("config.inc");
995
	require_once("functions.inc");
996
	require_once("filter.inc");
997
	require_once("shaper.inc");
998
	require_once("captiveportal.inc");
999
	require_once("pkg-utils.inc");
1000
	require_once("pfsense-utils.inc");
1001
	require_once("service-utils.inc");
1002

    
1003
	global $config, $g;
1004

    
1005
	log_error("Stopping all packages.");
1006

    
1007
	$rcfiles = glob(RCFILEPREFIX . "*.sh");
1008
	if (!$rcfiles) {
1009
		$rcfiles = array();
1010
	} else {
1011
		$rcfiles = array_flip($rcfiles);
1012
		if (!$rcfiles) {
1013
			$rcfiles = array();
1014
		}
1015
	}
1016

    
1017
	if (is_array($config['installedpackages']['package'])) {
1018
		foreach ($config['installedpackages']['package'] as $package) {
1019
			echo " Stopping package {$package['name']}...";
1020
			$internal_name = get_package_internal_name($package);
1021
			stop_service($internal_name);
1022
			unset($rcfiles[RCFILEPREFIX . strtolower($internal_name) . ".sh"]);
1023
			echo "done.\n";
1024
		}
1025
	}
1026

    
1027
	foreach ($rcfiles as $rcfile => $number) {
1028
		$shell = @popen("/bin/sh", "w");
1029
		if ($shell) {
1030
			echo " Stopping {$rcfile}...";
1031
			if (!@fwrite($shell, "{$rcfile} stop >>/tmp/bootup_messages 2>&1")) {
1032
				if ($shell) {
1033
					pclose($shell);
1034
				}
1035
				$shell = @popen("/bin/sh", "w");
1036
			}
1037
			echo "done.\n";
1038
			pclose($shell);
1039
		}
1040
	}
1041
}
1042

    
1043
?>
(41-41/67)