Project

General

Profile

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

    
65
require_once("globals.inc");
66
require_once("service-utils.inc");
67

    
68
if (file_exists("/cf/conf/use_xmlreader")) {
69
	require_once("xmlreader.inc");
70
} else {
71
	require_once("xmlparse.inc");
72
}
73

    
74
require_once("pfsense-utils.inc");
75

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

    
81
		if (!$debug) {
82
			return;
83
		}
84

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

    
94
global $g;
95
if (!isset($g['platform'])) {
96
	$g['platform'] = trim(file_get_contents("/etc/platform"));
97
}
98

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

    
103
	if (substr($pkg_name, 0, strlen($g['pkg_prefix'])) == $g['pkg_prefix']) {
104
		$pkg_name = substr($pkg_name, strlen($g['pkg_prefix']));
105
	}
106
}
107

    
108
/* Execute pkg update when it's necessary */
109
function pkg_update($force = false) {
110
	global $g;
111

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

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

    
123
		if ($last_update > 0) {
124
			if ($now > $last_update && ($now - $last_update) <= (60 * 60)) {
125
				return true;
126
			}
127
		}
128
	}
129

    
130
	$rc = pkg_call("update");
131

    
132
	if ($rc) {
133
		file_put_contents($last_update_file, $now . "\n");
134
	}
135

    
136
	return $rc;
137
}
138

    
139
/* Execute a pkg call */
140
function pkg_call($params, $mute = false) {
141
	global $static_output, $g, $config;
142

    
143
	if (empty($params)) {
144
		return false;
145
	}
146

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

    
152
	$env = array(
153
		"HTTP_USER_AGENT" => $user_agent,
154
		"ASSUME_ALWAYS_YES" => "true",
155
		"REPO_AUTOUPDATE" => "false"
156
	);
157

    
158
	$descriptorspec = array(
159
		1 => array("pipe", "w"), /* stdout */
160
		2 => array("pipe", "w")	 /* stderr */
161
	);
162

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

    
166
	if (!is_resource($process)) {
167
		return false;
168
	}
169

    
170
	stream_set_blocking($pipes[1], 0);
171
	stream_set_blocking($pipes[2], 0);
172

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

    
179
	do {
180
		$write = array();
181
		$read = array($pipes[1], $pipes[2]);
182
		$except = array();
183

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

    
203
		$status = proc_get_status($process);
204

    
205
		$now = time();
206

    
207
		if(($now - $started) >= $maxwaittime) {
208
			$rc = -1;
209
			proc_terminate($process);
210
			break;
211
		}
212

    
213
	} while ($status['running']);
214

    
215
	fclose($pipes[1]);
216
	fclose($pipes[2]);
217
	proc_close($process);
218

    
219
	if(!isset($rc)) {
220
		$rc = $status['exitcode'];
221
	}
222

    
223
	pkg_debug("pkg_call(): rc = {$rc}\n");
224
	if ($rc == 0) {
225
		return true;
226
	}
227

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

    
234
	return false;
235
}
236

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

    
241
	if (empty($params)) {
242
		return -1;
243
	}
244

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

    
250
	$env = array(
251
		"HTTP_USER_AGENT" => $user_agent,
252
		"ASSUME_ALWAYS_YES" => "true",
253
		"REPO_AUTOUPDATE" => "false"
254
	);
255

    
256
	$descriptorspec = array(
257
		1 => array("pipe", "w"), /* stdout */
258
		2 => array("pipe", "w")	 /* stderr */
259
	);
260

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

    
264
	if (!is_resource($process)) {
265
		return -1;
266
	}
267

    
268
	$stdout = '';
269
	while (($l = fgets($pipes[1])) !== FALSE) {
270
		$stdout .= $l;
271
	}
272
	fclose($pipes[1]);
273

    
274
	$stderr = '';
275
	while (($l = fgets($pipes[2])) !== FALSE) {
276
		$stderr .= $l;
277
	}
278
	fclose($pipes[2]);
279

    
280
	return proc_close($process);
281
}
282

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

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

    
296
	if ($rc != 0) {
297
		return '?';
298
	}
299

    
300
	return str_replace("\n", "", $stdout);
301
}
302

    
303
/* Check if package is installed */
304
function is_pkg_installed($pkg_name) {
305
	global $g;
306

    
307
	pkg_remove_prefix($pkg_name);
308

    
309
	return pkg_call("info -e " . $g['pkg_prefix'] . $pkg_name, true);
310
}
311

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

    
317
	pkg_remove_prefix($pkg_name);
318

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

    
326
	return $result;
327
}
328

    
329
/* Delete package from FreeBSD, $pkg_name should not contain prefix */
330
function pkg_delete($pkg_name) {
331
	global $g;
332

    
333
	pkg_remove_prefix($pkg_name);
334

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

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

    
348
/* Find package array index */
349
function get_package_id($package_name) {
350
	global $config;
351

    
352
	if (!is_array($config['installedpackages']['package'])) {
353
		return -1;
354
	}
355

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

    
363
	return -1;
364
}
365

    
366
/* Keep backward compatibility since snort/suricata use this function */
367
function get_pkg_id($package_name) {
368
	return get_package_id($package_name);
369
}
370

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

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

    
385
	$out = '';
386
	$err = '';
387

    
388
	unset($pkg_filter);
389
	if (is_array($pkgs)) {
390
		$pkg_filter = $pkgs;
391
		$pkgs = 'all';
392
	}
393

    
394
	if ($pkgs == 'all') {
395
		$pkgs = $g['pkg_prefix'];
396
	}
397

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

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

    
409

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

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

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

    
429
		if (isset($pkg_filter) && !in_array($pkg_info['name'], $pkg_filter)) {
430
			continue;
431
		}
432

    
433
		if (is_pkg_installed($pkg_info['name'])) {
434
			$pkg_info['installed'] = true;
435

    
436
			$rc = pkg_exec("query %v {$pkg_info['name']}", $out, $err);
437

    
438
			if ($rc != 0) {
439
				$static_output .= "\n" . gettext("ERROR: Error trying to get package version. Aborting...") . "\n";
440
				$static_output .= $err;
441
				$input_errors[] =  gettext("ERROR: Error trying to get package version. Aborting...") . "\n";
442
				$input_errors[] =  $err;
443
				update_status($static_output);
444
				return array();
445
			}
446

    
447
			$pkg_info['installed_version'] = str_replace("\n", "", $out);
448
		}
449

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

    
452
		$result[] = $pkg_info;
453
		unset($pkg_info);
454
	}
455

    
456
	/* Sort result alphabetically */
457
	usort($result, function($a, $b) {
458
		return(strcasecmp ($a['name'], $b['name']));
459
	});
460

    
461
	return $result;
462
}
463

    
464
/*
465
 * resync_all_package_configs() Force packages to setup their configuration and rc.d files.
466
 * This function may also print output to the terminal indicating progress.
467
 */
468
function resync_all_package_configs($show_message = false) {
469
	global $config, $pkg_interface, $g;
470

    
471
	log_error(gettext("Resyncing configuration for all packages."));
472

    
473
	if (!is_array($config['installedpackages']['package'])) {
474
		return;
475
	}
476

    
477
	if ($show_message == true) {
478
		echo "Syncing packages:";
479
	}
480

    
481
	conf_mount_rw();
482

    
483
	foreach ($config['installedpackages']['package'] as $idx => $package) {
484
		if (empty($package['name'])) {
485
			continue;
486
		}
487
		if ($show_message == true) {
488
			echo " " . $package['name'];
489
		}
490
		if (platform_booting() != true) {
491
			stop_service(get_package_internal_name($package));
492
		}
493
		sync_package($package['name']);
494
		if ($pkg_interface == "console") {
495
			echo "\n" . gettext("Syncing packages:");
496
		}
497
	}
498

    
499
	if ($show_message == true) {
500
		echo " done.\n";
501
	}
502

    
503
	@unlink("/conf/needs_package_sync");
504
	conf_mount_ro();
505
}
506

    
507
function uninstall_package($package_name) {
508
	global $config, $static_output;
509

    
510
	$internal_name = $package_name;
511
	$id = get_package_id($package_name);
512
	if ($id >= 0) {
513
		$internal_name = get_package_internal_name($config['installedpackages']['package'][$id]);
514
		stop_service($internal_name);
515
	}
516

    
517
	if (is_pkg_installed($internal_name)) {
518
		$static_output .= "Removing package...\n";
519
		update_output_window($static_output);
520
		pkg_delete($internal_name);
521
	} else {
522
		delete_package_xml($package_name);
523
	}
524

    
525
	$static_output .= gettext("done.") . "\n";
526
	update_output_window($static_output);
527
}
528

    
529
/* Run <custom_php_resync_config_command> */
530
function sync_package($package_name) {
531
	global $config, $builder_package_install;
532

    
533
	// If this code is being called by pfspkg_installer
534
	// which the builder system uses then return (ignore).
535
	if ($builder_package_install) {
536
		return;
537
	}
538

    
539
	if (empty($config['installedpackages']['package'])) {
540
		return;
541
	}
542

    
543
	if (($pkg_id = get_package_id($package_name)) == -1) {
544
		return; // This package doesn't really exist - exit the function.
545
	}
546

    
547
	if (!is_array($config['installedpackages']['package'][$pkg_id])) {
548
		return;	 // No package belongs to the pkg_id passed to this function.
549
	}
550

    
551
	$package =& $config['installedpackages']['package'][$pkg_id];
552
	if (!file_exists("/usr/local/pkg/" . $package['configurationfile'])) {
553
		log_error(sprintf(gettext("The %s package is missing its configuration file and must be reinstalled."), $package['name']));
554
		delete_package_xml($package['name']);
555
		return;
556
	}
557

    
558
	$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $package['configurationfile'], "packagegui");
559
	if (isset($pkg_config['nosync'])) {
560
		return;
561
	}
562

    
563
	/* Bring in package include files */
564
	if (!empty($pkg_config['include_file'])) {
565
		$include_file = $pkg_config['include_file'];
566
		if (file_exists($include_file)) {
567
			require_once($include_file);
568
		} else {
569
			log_error("Reinstalling package {$package['name']} because its include file({$include_file}) is missing!");
570
			uninstall_package($package['name']);
571
			if (install_package($package['name']) != 0) {
572
				log_error("Reinstalling package {$package['name']} failed. Take appropriate measures!!!");
573
				return;
574
			}
575
			if (file_exists($include_file)) {
576
				require_once($include_file);
577
			} else {
578
				return;
579
			}
580
		}
581
	}
582

    
583
	if (!empty($pkg_config['custom_php_global_functions'])) {
584
		eval($pkg_config['custom_php_global_functions']);
585
	}
586
	if (!empty($pkg_config['custom_php_resync_config_command'])) {
587
		eval($pkg_config['custom_php_resync_config_command']);
588
	}
589
}
590

    
591
/* Read info.xml installed by package and return an array */
592
function read_package_config($package_name) {
593
	global $g;
594

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

    
597
	if (!file_exists($pkg_info_xml)) {
598
		return false;
599
	}
600

    
601
	$pkg_info = parse_xml_config_pkg($pkg_info_xml, 'pfsensepkgs');
602

    
603
	if (empty($pkg_info)) {
604
		return false;
605
	}
606

    
607
	/* it always returns an array with 1 item */
608
	return $pkg_info['package'][0];
609
}
610

    
611
/* Read package configurationfile and return an array */
612
function read_package_configurationfile($package_name) {
613
	global $config, $g;
614

    
615
	$pkg_config = array();
616
	$id = get_package_id($package_name);
617

    
618
	if ($id < 0 || !isset($config['installedpackages']['package'][$id]['configurationfile'])) {
619
		return $pkg_config;
620
	}
621

    
622
	$pkg_configurationfile = $config['installedpackages']['package'][$id]['configurationfile'];
623

    
624
	if (empty($pkg_configurationfile) || !file_exists('/usr/local/pkg/' . $pkg_configurationfile)) {
625
		return $pkg_config;
626
	}
627

    
628
	$pkg_config = parse_xml_config_pkg('/usr/local/pkg/' . $pkg_configurationfile, "packagegui");
629

    
630
	return $pkg_config;
631
}
632

    
633
function get_after_install_info($package_name) {
634
	$pkg_config = read_package_config($package_name);
635

    
636
	if (isset($pkg_config['after_install_info'])) {
637
		return $pkg_config['after_install_info'];
638
	}
639

    
640
	return '';
641
}
642

    
643
function eval_once($toeval) {
644
	global $evaled;
645
	if (!$evaled) {
646
		$evaled = array();
647
	}
648
	$evalmd5 = md5($toeval);
649
	if (!in_array($evalmd5, $evaled)) {
650
		@eval($toeval);
651
		$evaled[] = $evalmd5;
652
	}
653
	return;
654
}
655

    
656
function install_package($package_name) {
657
	global $g, $config, $static_output, $pkg_interface;
658

    
659
	if ($pkg_interface == "console") {
660
		echo "\n";
661
	}
662

    
663
	return pkg_install($package_name);
664
}
665

    
666
function install_package_xml($package_name) {
667
	global $g, $config, $static_output, $pkg_interface;
668

    
669
	if (($pkg_info = read_package_config($package_name)) == false) {
670
		return false;
671
	}
672

    
673
	/* safe side. Write config below will send to ro again. */
674
	conf_mount_rw();
675

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

    
679
	/* add package information to config.xml */
680
	$pkgid = get_package_id($pkg_info['name']);
681
	$static_output .= gettext("Saving updated package information...") . " ";
682
	update_output_window($static_output);
683
	if ($pkgid == -1) {
684
		$config['installedpackages']['package'][] = $pkg_info;
685
		$changedesc = sprintf(gettext("Installed %s package."), $pkg_info['name']);
686
		$to_output = gettext("done.") . "\n";
687
	} else {
688
		$config['installedpackages']['package'][$pkgid] = $pkg_info;
689
		$changedesc = sprintf(gettext("Overwrote previous installation of %s."), $pkg_info['name']);
690
		$to_output = gettext("overwrite!") . "\n";
691
	}
692
	unlink_if_exists('/conf/needs_package_sync');
693
	write_config("Intermediate config write during package install for {$pkg_info['name']}.");
694
	conf_mount_ro();
695
	$static_output .= $to_output;
696
	update_output_window($static_output);
697

    
698
	if (($pkgid = get_package_id($package_name)) == -1) {
699
		$static_output .= sprintf(gettext("The %s package is not installed.%sInstallation aborted."), $package_name, "\n\n");
700
		update_output_window($static_output);
701
		if ($pkg_interface <> "console") {
702
			echo "\n<script>document.getElementById('progressbar').style.visibility='hidden';</script>";
703
			echo "\n<script>document.getElementById('progholder').style.visibility='hidden';</script>";
704
		}
705

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

    
714
	$configfile = substr(strrchr($pkg_info['config_file'], '/'), 1);
715
	if (file_exists("/usr/local/pkg/" . $configfile)) {
716
		$static_output .= gettext("Loading package configuration... ");
717
		update_output_window($static_output);
718
		$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $configfile, "packagegui");
719
		$static_output .= gettext("done.") . "\n";
720
		update_output_window($static_output);
721
		$static_output .= gettext("Configuring package components...\n");
722
		if (!empty($pkg_config['filter_rules_needed'])) {
723
			$config['installedpackages']['package'][$pkgid]['filter_rule_function'] = $pkg_config['filter_rules_needed'];
724
		}
725
		update_output_window($static_output);
726
		/* modify system files */
727

    
728
		/* if a require exists, include it.  this will
729
		 * show us where an error exists in a package
730
		 * instead of making us blindly guess
731
		 */
732
		$missing_include = false;
733
		if ($pkg_config['include_file'] <> "") {
734
			$static_output .= gettext("Loading package instructions...") . "\n";
735
			update_output_window($static_output);
736
			if (file_exists($pkg_config['include_file'])) {
737
				pkg_debug("require_once('{$pkg_config['include_file']}')\n");
738
				require_once($pkg_config['include_file']);
739
			} else {
740
				pkg_debug("Missing include {$pkg_config['include_file']}\n");
741
				$missing_include = true;
742
				$static_output .= "Include " . basename($pkg_config['include_file']) . " is missing!\n";
743
				update_output_window($static_output);
744

    
745
				uninstall_package($package_name);
746
				write_config($changedesc);
747
				log_error(sprintf(gettext("Failed to install package: %s."), $pkg_info['name']));
748
				$static_output .= gettext("Failed to install package.") . "\n";
749
				update_output_window($static_output);
750
				return false;
751
			}
752
		}
753

    
754
		/* custom commands */
755
		$static_output .= gettext("Custom commands...") . "\n";
756
		update_output_window($static_output);
757
		if ($missing_include == false) {
758
			if ($pkg_config['custom_php_global_functions'] <> "") {
759
				$static_output .= gettext("Executing custom_php_global_functions()...");
760
				update_output_window($static_output);
761
				eval_once($pkg_config['custom_php_global_functions']);
762
				$static_output .= gettext("done.") . "\n";
763
				update_output_window($static_output);
764
			}
765
			if ($pkg_config['custom_php_install_command']) {
766
				$static_output .= gettext("Executing custom_php_install_command()...");
767
				update_output_window($static_output);
768
				eval_once($pkg_config['custom_php_install_command']);
769
				$static_output .= gettext("done.") . "\n";
770
				update_output_window($static_output);
771
			}
772
			if ($pkg_config['custom_php_resync_config_command'] <> "") {
773
				$static_output .= gettext("Executing custom_php_resync_config_command()...");
774
				update_output_window($static_output);
775
				eval_once($pkg_config['custom_php_resync_config_command']);
776
				$static_output .= gettext("done.") . "\n";
777
				update_output_window($static_output);
778
			}
779
		}
780
		/* sidebar items */
781
		if (is_array($pkg_config['menu'])) {
782
			$static_output .= gettext("Menu items... ");
783
			update_output_window($static_output);
784
			foreach ($pkg_config['menu'] as $menu) {
785
				if (is_array($config['installedpackages']['menu'])) {
786
					foreach ($config['installedpackages']['menu'] as $amenu) {
787
						if ($amenu['name'] == $menu['name']) {
788
							continue 2;
789
						}
790
					}
791
				} else {
792
					$config['installedpackages']['menu'] = array();
793
				}
794
				$config['installedpackages']['menu'][] = $menu;
795
			}
796
			$static_output .= gettext("done.") . "\n";
797
			update_output_window($static_output);
798
		}
799
		/* services */
800
		if (is_array($pkg_config['service'])) {
801
			$static_output .= gettext("Services... ");
802
			update_output_window($static_output);
803
			foreach ($pkg_config['service'] as $service) {
804
				if (is_array($config['installedpackages']['service'])) {
805
					foreach ($config['installedpackages']['service'] as $aservice) {
806
						if ($aservice['name'] == $service['name']) {
807
							continue 2;
808
						}
809
					}
810
				} else {
811
					$config['installedpackages']['service'] = array();
812
				}
813
				$config['installedpackages']['service'][] = $service;
814
			}
815
			$static_output .= gettext("done.") . "\n";
816
			update_output_window($static_output);
817
		}
818
	} else {
819
		pkg_debug("Unable to find config file\n");
820
		$static_output .= gettext("Loading package configuration... failed!") . "\n\n" . gettext("Installation aborted.");
821
		update_output_window($static_output);
822
		pkg_debug(gettext("Unable to load package configuration. Installation aborted.") ."\n");
823
		if ($pkg_interface <> "console") {
824
			echo "\n<script>document.getElementById('progressbar').style.visibility='hidden';</script>";
825
			echo "\n<script>document.getElementById('progholder').style.visibility='hidden';</script>";
826
		}
827

    
828
		uninstall_package($package_name);
829
		write_config($changedesc);
830
		log_error(sprintf(gettext("Failed to install package: %s."), $pkg_info['name']));
831
		$static_output .= gettext("Failed to install package.") . "\n";
832
		update_output_window($static_output);
833
		return false;
834
	}
835

    
836
	/* set up package logging streams */
837
	if ($pkg_info['logging']) {
838
		system_syslogd_start();
839
	}
840

    
841
	$static_output .= gettext("Writing configuration... ");
842
	update_output_window($static_output);
843
	write_config($changedesc);
844
	log_error(sprintf(gettext("Successfully installed package: %s."), $pkg_info['name']));
845
	$static_output .= gettext("done.") . "\n";
846
	update_output_window($static_output);
847
	if ($pkg_info['after_install_info']) {
848
		update_output_window($pkg_info['after_install_info']);
849
	}
850

    
851
	return true;
852
}
853

    
854
function delete_package($package_name) {
855
	global $config, $g, $static_output;
856

    
857
	if (!is_package_installed($package_name)) {
858
		return;
859
	}
860

    
861
	$static_output .= sprintf(gettext("Starting package deletion for %s..."), $package_name);
862
	update_output_window($static_output);
863

    
864
	pkg_delete($package_name);
865
	$static_output .= "done.\n";
866
	update_output_window($static_output);
867

    
868
	return;
869
}
870

    
871
function delete_package_xml($package_name, $when = "post-deinstall") {
872
	global $g, $config, $static_output, $pkg_interface;
873

    
874
	conf_mount_rw();
875

    
876
	$pkgid = get_package_id($package_name);
877
	if ($pkgid == -1) {
878
		$static_output .= sprintf(gettext("The %s package is not installed.%sDeletion aborted."), $package_name, "\n\n");
879
		update_output_window($static_output);
880
		if ($pkg_interface <> "console") {
881
			echo "\n<script>document.getElementById('progressbar').style.visibility='hidden';</script>";
882
			echo "\n<script>document.getElementById('progholder').style.visibility='hidden';</script>";
883
		}
884
		ob_flush();
885
		sleep(1);
886
		conf_mount_ro();
887
		return;
888
	}
889
	pkg_debug(sprintf(gettext("Removing %s package... "), $package_name));
890
	$static_output .= sprintf(gettext("Removing %s components..."), $package_name) . "\n";
891
	update_output_window($static_output);
892
	/* parse package configuration */
893
	$packages = &$config['installedpackages']['package'];
894
	$menus =& $config['installedpackages']['menu'];
895
	$services = &$config['installedpackages']['service'];
896
	$pkg_info =& $packages[$pkgid];
897
	if (file_exists("/usr/local/pkg/" . $pkg_info['configurationfile'])) {
898
		$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $packages[$pkgid]['configurationfile'], "packagegui");
899
		/* remove menu items */
900
		if (is_array($pkg_config['menu'])) {
901
			$static_output .= gettext("Menu items... ");
902
			update_output_window($static_output);
903
			if (is_array($pkg_config['menu']) && is_array($menus)) {
904
				foreach ($pkg_config['menu'] as $menu) {
905
					foreach ($menus as $key => $instmenu) {
906
						if ($instmenu['name'] == $menu['name']) {
907
							unset($menus[$key]);
908
							break;
909
						}
910
					}
911
				}
912
			}
913
			$static_output .= gettext("done.") . "\n";
914
			update_output_window($static_output);
915
		}
916
		/* remove services */
917
		if (is_array($pkg_config['service'])) {
918
			$static_output .= gettext("Services... ");
919
			update_output_window($static_output);
920
			if (is_array($pkg_config['service']) && is_array($services)) {
921
				foreach ($pkg_config['service'] as $service) {
922
					foreach ($services as $key => $instservice) {
923
						if ($instservice['name'] == $service['name']) {
924
							if (platform_booting() != true) {
925
								stop_service($service['name']);
926
							}
927
							if ($service['rcfile']) {
928
								$prefix = RCFILEPREFIX;
929
								if (!empty($service['prefix'])) {
930
									$prefix = $service['prefix'];
931
								}
932
								if (file_exists("{$prefix}{$service['rcfile']}")) {
933
									@unlink("{$prefix}{$service['rcfile']}");
934
								}
935
							}
936
							unset($services[$key]);
937
						}
938
					}
939
				}
940
			}
941
			$static_output .= gettext("done.") . "\n";
942
			update_output_window($static_output);
943
		}
944
		/*
945
		 * XXX: Otherwise inclusion of config.inc again invalidates actions taken.
946
		 *	Same is done during installation.
947
		 */
948
		write_config("Intermediate config write during package removal for {$package_name}.");
949

    
950
		/*
951
		 * If a require exists, include it.	 this will
952
		 * show us where an error exists in a package
953
		 * instead of making us blindly guess
954
		 */
955
		$missing_include = false;
956
		if ($pkg_config['include_file'] <> "") {
957
			$static_output .= gettext("Loading package instructions...") . "\n";
958
			update_output_window($static_output);
959
			if (file_exists($pkg_config['include_file'])) {
960
				pkg_debug("require_once(\"{$pkg_config['include_file']}\")\n");
961
				require_once($pkg_config['include_file']);
962
			} else {
963
				pkg_debug("Missing include {$pkg_config['include_file']}\n");
964
				$missing_include = true;
965
				update_output_window($static_output);
966
				$static_output .= "Include file " . basename($pkg_config['include_file']) . " could not be found for inclusion.\n";
967
			}
968
		}
969
		/* ermal
970
		 * NOTE: It is not possible to handle parse errors on eval.
971
		 * So we prevent it from being run at all to not interrupt all the other code.
972
		 */
973
		if ($when == "deinstall" && $missing_include == false) {
974
			/* evaluate this package's global functions and pre deinstall commands */
975
			if ($pkg_config['custom_php_global_functions'] <> "") {
976
				eval_once($pkg_config['custom_php_global_functions']);
977
			}
978
			if ($pkg_config['custom_php_pre_deinstall_command'] <> "") {
979
				eval_once($pkg_config['custom_php_pre_deinstall_command']);
980
			}
981
		}
982
		/* deinstall commands */
983
		if ($when == "post-deinstall" && $pkg_config['custom_php_deinstall_command'] <> "") {
984
			$static_output .= gettext("Deinstall commands... ");
985
			update_output_window($static_output);
986
			if ($missing_include == false) {
987
				eval_once($pkg_config['custom_php_deinstall_command']);
988
				$static_output .= gettext("done.") . "\n";
989
			} else {
990
				$static_output .= "\nNot executing custom deinstall hook because an include is missing.\n";
991
			}
992
			update_output_window($static_output);
993
		}
994
	}
995
	/* syslog */
996
	$need_syslog_restart = false;
997
	if (is_array($pkg_info['logging']) && $pkg_info['logging']['logfilename'] <> "") {
998
		$static_output .= "Syslog entries... ";
999
		update_output_window($static_output);
1000
		@unlink("{$g['varlog_path']}/{$pkg_info['logging']['logfilename']}");
1001
		$static_output .= "done.\n";
1002
		update_output_window($static_output);
1003
		$need_syslog_restart = true;
1004
	}
1005

    
1006
	/* remove config.xml entries */
1007
	$static_output .= gettext("Configuration... ");
1008
	update_output_window($static_output);
1009
	unset($config['installedpackages']['package'][$pkgid]);
1010
	$static_output .= gettext("done.") . "\n";
1011
	update_output_window($static_output);
1012
	write_config("Removed {$package_name} package.\n");
1013

    
1014
	/* remove package entry from /etc/syslog.conf if needed */
1015
	/* this must be done after removing the entries from config.xml */
1016
	if ($need_syslog_restart) {
1017
		system_syslogd_start();
1018
	}
1019

    
1020
	conf_mount_ro();
1021
}
1022

    
1023
function pkg_reinstall_all() {
1024
	global $g, $config;
1025

    
1026
	// XXX: implement
1027
	return;
1028
}
1029

    
1030
function stop_packages() {
1031
	require_once("config.inc");
1032
	require_once("functions.inc");
1033
	require_once("filter.inc");
1034
	require_once("shaper.inc");
1035
	require_once("captiveportal.inc");
1036
	require_once("pkg-utils.inc");
1037
	require_once("pfsense-utils.inc");
1038
	require_once("service-utils.inc");
1039

    
1040
	global $config, $g;
1041

    
1042
	log_error("Stopping all packages.");
1043

    
1044
	$rcfiles = glob(RCFILEPREFIX . "*.sh");
1045
	if (!$rcfiles) {
1046
		$rcfiles = array();
1047
	} else {
1048
		$rcfiles = array_flip($rcfiles);
1049
		if (!$rcfiles) {
1050
			$rcfiles = array();
1051
		}
1052
	}
1053

    
1054
	if (is_array($config['installedpackages']['package'])) {
1055
		foreach ($config['installedpackages']['package'] as $package) {
1056
			echo " Stopping package {$package['name']}...";
1057
			$internal_name = get_package_internal_name($package);
1058
			stop_service($internal_name);
1059
			unset($rcfiles[RCFILEPREFIX . strtolower($internal_name) . ".sh"]);
1060
			echo "done.\n";
1061
		}
1062
	}
1063

    
1064
	foreach ($rcfiles as $rcfile => $number) {
1065
		$shell = @popen("/bin/sh", "w");
1066
		if ($shell) {
1067
			echo " Stopping {$rcfile}...";
1068
			if (!@fwrite($shell, "{$rcfile} stop >>/tmp/bootup_messages 2>&1")) {
1069
				if ($shell) {
1070
					pclose($shell);
1071
				}
1072
				$shell = @popen("/bin/sh", "w");
1073
			}
1074
			echo "done.\n";
1075
			pclose($shell);
1076
		}
1077
	}
1078
}
1079

    
1080
?>
(41-41/67)