Project

General

Profile

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

    
57
require_once("globals.inc");
58
require_once("service-utils.inc");
59

    
60
if (file_exists("/cf/conf/use_xmlreader")) {
61
	require_once("xmlreader.inc");
62
} else {
63
	require_once("xmlparse.inc");
64
}
65

    
66
require_once("pfsense-utils.inc");
67

    
68
if (!function_exists("pkg_debug")) {
69
	/* set up logging if needed */
70
	function pkg_debug($msg) {
71
		global $g, $debug, $fd_log;
72

    
73
		if (!$debug) {
74
			return;
75
		}
76

    
77
		if (!$fd_log) {
78
			if (!$fd_log = fopen("{$g['tmp_path']}/pkg_mgr_debug.log", "w")) {
79
				update_status(gettext("Warning, could not open log for writing.") . "\n");
80
			}
81
		}
82
		@fwrite($fd_log, $msg);
83
	}
84
}
85

    
86
/* Remove pkg_prefix from package name if it's present */
87
function pkg_remove_prefix(&$pkg_name) {
88
	global $g;
89

    
90
	if (substr($pkg_name, 0, strlen($g['pkg_prefix'])) == $g['pkg_prefix']) {
91
		$pkg_name = substr($pkg_name, strlen($g['pkg_prefix']));
92
	}
93
}
94

    
95
/* Execute pkg update when it's necessary */
96
function pkg_update($force = false) {
97
	global $g;
98

    
99
	$now = strftime('%s');
100
	$last_update_file="{$g['varrun_path']}/{$g['product_name']}-upgrade-last-update";
101
	if (!$force) {
102
		if (file_exists($last_update_file)) {
103
			$last_update = rtrim(file_get_contents($last_update_file), "\n");
104
			if (!is_numericint($last_update)) {
105
				$last_update = 0;
106
			}
107
		}
108

    
109
		if ($last_update > 0) {
110
			if ($now > $last_update && ($now - $last_update) <= (60 * 60)) {
111
				return true;
112
			}
113
		}
114
	}
115

    
116
	$rc = pkg_call("update");
117

    
118
	if ($rc) {
119
		file_put_contents($last_update_file, $now . "\n");
120
	}
121

    
122
	return $rc;
123
}
124

    
125
/* Execute a pkg call */
126
function pkg_call($params, $mute = false) {
127
	global $g, $config;
128

    
129
	if (empty($params)) {
130
		return false;
131
	}
132

    
133
	$user_agent = $g['product_name'] . '/' . $g['product_version'];
134
	if (!isset($config['system']['do_not_send_host_uuid'])) {
135
		$user_agent .= ' : ' . get_single_sysctl('kern.hostuuid');
136
	}
137

    
138
	$env = array(
139
		"HTTP_USER_AGENT" => $user_agent,
140
		"ASSUME_ALWAYS_YES" => "true",
141
		"REPO_AUTOUPDATE" => "false"
142
	);
143

    
144
	$descriptorspec = array(
145
		1 => array("pipe", "w"), /* stdout */
146
		2 => array("pipe", "w")	 /* stderr */
147
	);
148

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

    
152
	if (!is_resource($process)) {
153
		return false;
154
	}
155

    
156
	stream_set_blocking($pipes[1], 0);
157
	stream_set_blocking($pipes[2], 0);
158

    
159
	/* XXX: should be a tunnable? */
160
	$timeout = 300; // seconds
161
	$error_log = '';
162
	$started = time();
163
	$maxwaittime = 10; // Number of seconds to wait for a response fromteh pacakge we are calling
164

    
165
	do {
166
		$write = array();
167
		$read = array($pipes[1], $pipes[2]);
168
		$except = array();
169

    
170
		$stream = stream_select($read, $write, $except, null, $timeout);
171
		if ($stream !== FALSE && $stream > 0) {
172
			foreach ($read as $pipe) {
173
				$content = stream_get_contents($pipe);
174
				if ($content == '') {
175
					continue;
176
				}
177
				if ($pipe === $pipes[1]) {
178
					if (!$mute) {
179
						update_status($content);
180
					}
181
					flush();
182
				} else if ($pipe === $pipes[2]) {
183
					$error_log .= $content;
184
				}
185
			}
186
		}
187

    
188
		$status = proc_get_status($process);
189

    
190
		$now = time();
191

    
192
		if (($now - $started) >= $maxwaittime) {
193
			$rc = -1;
194
			proc_terminate($process);
195
			break;
196
		}
197

    
198
	} while ($status['running']);
199

    
200
	fclose($pipes[1]);
201
	fclose($pipes[2]);
202
	proc_close($process);
203

    
204
	if (!isset($rc)) {
205
		$rc = $status['exitcode'];
206
	}
207

    
208
	pkg_debug("pkg_call(): rc = {$rc}\n");
209
	if ($rc == 0) {
210
		return true;
211
	}
212

    
213
	pkg_debug("pkg_call(): error_log\n{$error_log}\n");
214
	if (!$mute) {
215
		update_status("\n\n" .  sprintf(gettext(
216
		    "ERROR!!! An error occurred on pkg execution (rc = %d) with parameters '%s':"),
217
		    $rc, $params) . "\n" . $error_log . "\n");
218
	}
219

    
220
	return false;
221
}
222

    
223
/* Execute pkg with $params, fill stdout and stderr and return pkg rc */
224
function pkg_exec($params, &$stdout, &$stderr) {
225
	global $g, $config;
226

    
227
	if (empty($params)) {
228
		return -1;
229
	}
230

    
231
	$user_agent = $g['product_name'] . '/' . $g['product_version'];
232
	if (!isset($config['system']['do_not_send_host_uuid'])) {
233
		$user_agent .= ' : ' . get_single_sysctl('kern.hostuuid');
234
	}
235

    
236
	$env = array(
237
		"HTTP_USER_AGENT" => $user_agent,
238
		"ASSUME_ALWAYS_YES" => "true",
239
		"REPO_AUTOUPDATE" => "false"
240
	);
241

    
242
	$descriptorspec = array(
243
		1 => array("pipe", "w"), /* stdout */
244
		2 => array("pipe", "w")	 /* stderr */
245
	);
246

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

    
250
	if (!is_resource($process)) {
251
		return -1;
252
	}
253

    
254
	$stdout = '';
255
	while (($l = fgets($pipes[1])) !== FALSE) {
256
		$stdout .= $l;
257
	}
258
	fclose($pipes[1]);
259

    
260
	$stderr = '';
261
	while (($l = fgets($pipes[2])) !== FALSE) {
262
		$stderr .= $l;
263
	}
264
	fclose($pipes[2]);
265

    
266
	return proc_close($process);
267
}
268

    
269
/* Compare 2 pkg versions and return:
270
 * '=' - versions are the same
271
 * '>' - $v1 > $v2
272
 * '<' - $v1 < $v2
273
 * '?' - Error
274
 */
275
function pkg_version_compare($v1, $v2) {
276
	if (empty($v1) || empty($v2)) {
277
		return '?';
278
	}
279

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

    
282
	if ($rc != 0) {
283
		return '?';
284
	}
285

    
286
	return str_replace("\n", "", $stdout);
287
}
288

    
289
/* Check if package is installed */
290
function is_pkg_installed($pkg_name) {
291
	global $g;
292

    
293
	if (empty($pkg_name)) {
294
		return false;
295
	}
296

    
297
	return pkg_call("info -e " . $pkg_name, true);
298
}
299

    
300
/* Install package, $pkg_name should not contain prefix */
301
function pkg_install($pkg_name, $force = false) {
302
	global $g;
303
	$result = false;
304

    
305
	$shortname = $pkg_name;
306
	pkg_remove_prefix($shortname);
307

    
308
	$pkg_force = "";
309
	if ($force) {
310
		$pkg_force = "-f ";
311
	}
312

    
313
	pkg_debug("Installing package {$shortname}\n");
314
	if ($force || !is_pkg_installed($pkg_name)) {
315
		$result = pkg_call("install -y " . $pkg_force . $pkg_name);
316
		/* Cleanup cacke to free disk space */
317
		pkg_call("clean -y");
318
	}
319

    
320
	return $result;
321
}
322

    
323
/* Delete package from FreeBSD, $pkg_name should not contain prefix */
324
function pkg_delete($pkg_name) {
325
	global $g;
326

    
327
	$shortname = $pkg_name;
328
	pkg_remove_prefix($shortname);
329

    
330
	pkg_debug("Removing package {$shortname}\n");
331
	if (is_pkg_installed($pkg_name)) {
332
		pkg_call("delete -y " . $pkg_name);
333
		/* Cleanup unecessary dependencies */
334
		pkg_call("autoremove -y");
335
	}
336
}
337

    
338
/* Check if package is present in config.xml */
339
function is_package_installed($package_name) {
340
	return (get_package_id($package_name) != -1);
341
}
342

    
343
/* Find package array index */
344
function get_package_id($package_name) {
345
	global $config;
346

    
347
	if (!is_array($config['installedpackages']['package'])) {
348
		return -1;
349
	}
350

    
351
	foreach ($config['installedpackages']['package'] as $idx => $pkg) {
352
		if ($pkg['name'] == $package_name ||
353
		    get_package_internal_name($pkg) == $package_name) {
354
			return $idx;
355
		}
356
	}
357

    
358
	return -1;
359
}
360

    
361
/* Keep backward compatibility since snort/suricata use this function */
362
function get_pkg_id($package_name) {
363
	return get_package_id($package_name);
364
}
365

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

    
376
// Get information about packages.
377
function get_pkg_info($pkgs = 'all', $info = 'all') {
378
	global $g, $input_errors;
379

    
380
	$out = '';
381
	$err = '';
382

    
383
	unset($pkg_filter);
384
	if (is_array($pkgs)) {
385
		$pkg_filter = $pkgs;
386
		$pkgs = 'all';
387
	}
388

    
389
	if ($pkgs == 'all') {
390
		$pkgs = $g['pkg_prefix'];
391
	}
392

    
393
	/* Make sure repo metadata is up2date */
394
	update_status("\n" .
395
	    gettext("Updating package repository metadada...") . "\n");
396

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

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

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

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

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

    
431
		$pkg_info['shortname'] = $pkg_info['name'];
432
		pkg_remove_prefix($pkg_info['shortname']);
433

    
434
		/* XXX: Add it to globals.inc? */
435
		$pkg_info['changeloglink'] =
436
		    "https://github.com/pfsense/FreeBSD-ports/commits/devel/" .
437
		    $pkg_info['categories'][0] . '/' . $pkg_info['name'];
438

    
439
		if (is_pkg_installed($pkg_info['name'])) {
440
			$pkg_info['installed'] = true;
441

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

    
444
			if ($rc != 0) {
445
				update_status("\n" . gettext(
446
				    "ERROR: Error trying to get package version. Aborting...")
447
				    . "\n");
448
				update_status($err);
449
				$input_errors[] =  gettext("ERROR: Error trying to get package version. Aborting...") . "\n";
450
				$input_errors[] =  $err;
451
				return array();
452
			}
453

    
454
			$pkg_info['installed_version'] = str_replace("\n", "", $out);
455
		} else if (is_package_installed($pkg_info['shortname'])) {
456
			$pkg_info['broken'] = true;
457
		}
458

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

    
461
		$result[] = $pkg_info;
462
		unset($pkg_info);
463
	}
464

    
465
	/* Sort result alphabetically */
466
	usort($result, function($a, $b) {
467
		return(strcasecmp ($a['name'], $b['name']));
468
	});
469

    
470
	return $result;
471
}
472

    
473
/*
474
 * resync_all_package_configs() Force packages to setup their configuration and rc.d files.
475
 * This function may also print output to the terminal indicating progress.
476
 */
477
function resync_all_package_configs($show_message = false) {
478
	global $config, $pkg_interface, $g;
479

    
480
	log_error(gettext("Resyncing configuration for all packages."));
481

    
482
	if (!is_array($config['installedpackages']['package'])) {
483
		return;
484
	}
485

    
486
	if ($show_message == true) {
487
		echo "Syncing packages:";
488
	}
489

    
490
	conf_mount_rw();
491

    
492
	foreach ($config['installedpackages']['package'] as $idx => $package) {
493
		if (empty($package['name'])) {
494
			continue;
495
		}
496
		if ($show_message == true) {
497
			echo " " . $package['name'];
498
		}
499
		if (platform_booting() != true) {
500
			stop_service(get_package_internal_name($package));
501
		}
502
		sync_package($package['name']);
503
		update_status(gettext("Syncing packages...") . "\n");
504
	}
505

    
506
	if ($show_message == true) {
507
		echo " done.\n";
508
	}
509

    
510
	@unlink("/conf/needs_package_sync");
511
	conf_mount_ro();
512
}
513

    
514
function uninstall_package($package_name) {
515
	global $config;
516

    
517
	$internal_name = $package_name;
518
	$id = get_package_id($package_name);
519
	if ($id >= 0) {
520
		$internal_name = get_package_internal_name($config['installedpackages']['package'][$id]);
521
		stop_service($internal_name);
522
	}
523
	$pkg_name = $g['pkg_prefix'] . $internal_name;
524

    
525
	if (is_pkg_installed($pkg_name)) {
526
		update_status(gettext("Removing package...") . "\n");
527
		pkg_delete($pkg_name);
528
	} else {
529
		delete_package_xml($package_name);
530
	}
531

    
532
	update_status(gettext("done.") . "\n");
533
}
534

    
535
/* Run <custom_php_resync_config_command> */
536
function sync_package($package_name) {
537
	global $config, $builder_package_install;
538

    
539
	// If this code is being called by pfspkg_installer
540
	// which the builder system uses then return (ignore).
541
	if ($builder_package_install) {
542
		return;
543
	}
544

    
545
	if (empty($config['installedpackages']['package'])) {
546
		return;
547
	}
548

    
549
	if (($pkg_id = get_package_id($package_name)) == -1) {
550
		return; // This package doesn't really exist - exit the function.
551
	}
552

    
553
	if (!is_array($config['installedpackages']['package'][$pkg_id])) {
554
		return;	 // No package belongs to the pkg_id passed to this function.
555
	}
556

    
557
	$package =& $config['installedpackages']['package'][$pkg_id];
558
	if (!file_exists("/usr/local/pkg/" . $package['configurationfile'])) {
559
		log_error(sprintf(gettext("The %s package is missing its configuration file and must be reinstalled."), $package['name']));
560
		delete_package_xml($package['name']);
561
		return;
562
	}
563

    
564
	$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $package['configurationfile'], "packagegui");
565
	if (isset($pkg_config['nosync'])) {
566
		return;
567
	}
568

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

    
589
	if (!empty($pkg_config['custom_php_global_functions'])) {
590
		eval($pkg_config['custom_php_global_functions']);
591
	}
592
	if (!empty($pkg_config['custom_php_resync_config_command'])) {
593
		eval($pkg_config['custom_php_resync_config_command']);
594
	}
595
}
596

    
597
/* Read info.xml installed by package and return an array */
598
function read_package_config($package_name) {
599
	global $g;
600

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

    
603
	if (!file_exists($pkg_info_xml)) {
604
		return false;
605
	}
606

    
607
	$pkg_info = parse_xml_config_pkg($pkg_info_xml, 'pfsensepkgs');
608

    
609
	if (empty($pkg_info)) {
610
		return false;
611
	}
612

    
613
	/* it always returns an array with 1 item */
614
	return $pkg_info['package'][0];
615
}
616

    
617
/* Read package configurationfile and return an array */
618
function read_package_configurationfile($package_name) {
619
	global $config, $g;
620

    
621
	$pkg_config = array();
622
	$id = get_package_id($package_name);
623

    
624
	if ($id < 0 || !isset($config['installedpackages']['package'][$id]['configurationfile'])) {
625
		return $pkg_config;
626
	}
627

    
628
	$pkg_configurationfile = $config['installedpackages']['package'][$id]['configurationfile'];
629

    
630
	if (empty($pkg_configurationfile) || !file_exists('/usr/local/pkg/' . $pkg_configurationfile)) {
631
		return $pkg_config;
632
	}
633

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

    
636
	return $pkg_config;
637
}
638

    
639
function get_after_install_info($package_name) {
640
	$pkg_config = read_package_config($package_name);
641

    
642
	if (isset($pkg_config['after_install_info'])) {
643
		return $pkg_config['after_install_info'];
644
	}
645

    
646
	return '';
647
}
648

    
649
function eval_once($toeval) {
650
	global $evaled;
651
	if (!$evaled) {
652
		$evaled = array();
653
	}
654
	$evalmd5 = md5($toeval);
655
	if (!in_array($evalmd5, $evaled)) {
656
		@eval($toeval);
657
		$evaled[] = $evalmd5;
658
	}
659
	return;
660
}
661

    
662
function install_package_xml($package_name) {
663
	global $g, $config, $pkg_interface;
664

    
665
	if (($pkg_info = read_package_config($package_name)) == false) {
666
		return false;
667
	}
668

    
669
	/* safe side. Write config below will send to ro again. */
670
	conf_mount_rw();
671

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

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

    
692
	if (($pkgid = get_package_id($package_name)) == -1) {
693
		update_status(sprintf(gettext("The %s package is not installed.%sInstallation aborted."), $package_name, "\n\n"));
694

    
695
		uninstall_package($package_name);
696
		write_config($changedesc);
697
		log_error(sprintf(gettext("Failed to install package: %s."), $pkg_info['name']));
698
		update_status(gettext("Failed to install package.") . "\n");
699
		return false;
700
	}
701

    
702
	if (file_exists("/usr/local/pkg/" . $pkg_info['configurationfile'])) {
703
		update_status(gettext("Loading package configuration... "));
704
		$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $pkg_info['configurationfile'], "packagegui");
705
		update_status(gettext("done.") . "\n");
706
		update_status(gettext("Configuring package components...") . "\n");
707
		if (!empty($pkg_config['filter_rules_needed'])) {
708
			$config['installedpackages']['package'][$pkgid]['filter_rule_function'] = $pkg_config['filter_rules_needed'];
709
		}
710
		/* modify system files */
711

    
712
		/* if a require exists, include it.  this will
713
		 * show us where an error exists in a package
714
		 * instead of making us blindly guess
715
		 */
716
		$missing_include = false;
717
		if ($pkg_config['include_file'] <> "") {
718
			update_status(gettext("Loading package instructions...") . "\n");
719
			if (file_exists($pkg_config['include_file'])) {
720
				pkg_debug("require_once('{$pkg_config['include_file']}')\n");
721
				require_once($pkg_config['include_file']);
722
			} else {
723
				pkg_debug("Missing include {$pkg_config['include_file']}\n");
724
				$missing_include = true;
725
				update_status("Include " . basename($pkg_config['include_file']) . " is missing!\n");
726

    
727
				uninstall_package($package_name);
728
				write_config($changedesc);
729
				log_error(sprintf(gettext("Failed to install package: %s."), $pkg_info['name']));
730
				update_status(gettext("Failed to install package.") . "\n");
731
				return false;
732
			}
733
		}
734

    
735
		/* custom commands */
736
		update_status(gettext("Custom commands...") . "\n");
737
		if ($missing_include == false) {
738
			if ($pkg_config['custom_php_global_functions'] <> "") {
739
				update_status(gettext("Executing custom_php_global_functions()..."));
740
				eval_once($pkg_config['custom_php_global_functions']);
741
				update_status(gettext("done.") . "\n");
742
			}
743
			if ($pkg_config['custom_php_install_command']) {
744
				update_status(gettext("Executing custom_php_install_command()..."));
745
				eval_once($pkg_config['custom_php_install_command']);
746
				update_status(gettext("done.") . "\n");
747
			}
748
			if ($pkg_config['custom_php_resync_config_command'] <> "") {
749
				update_status(gettext("Executing custom_php_resync_config_command()..."));
750
				eval_once($pkg_config['custom_php_resync_config_command']);
751
				update_status(gettext("done.") . "\n");
752
			}
753
		}
754
		/* sidebar items */
755
		if (is_array($pkg_config['menu'])) {
756
			update_status(gettext("Menu items... "));
757
			foreach ($pkg_config['menu'] as $menu) {
758
				if (is_array($config['installedpackages']['menu'])) {
759
					foreach ($config['installedpackages']['menu'] as $amenu) {
760
						if ($amenu['name'] == $menu['name']) {
761
							continue 2;
762
						}
763
					}
764
				} else {
765
					$config['installedpackages']['menu'] = array();
766
				}
767
				$config['installedpackages']['menu'][] = $menu;
768
			}
769
			update_status(gettext("done.") . "\n");
770
		}
771
		/* services */
772
		if (is_array($pkg_config['service'])) {
773
			update_status(gettext("Services... "));
774
			foreach ($pkg_config['service'] as $service) {
775
				if (is_array($config['installedpackages']['service'])) {
776
					foreach ($config['installedpackages']['service'] as $aservice) {
777
						if ($aservice['name'] == $service['name']) {
778
							continue 2;
779
						}
780
					}
781
				} else {
782
					$config['installedpackages']['service'] = array();
783
				}
784
				$config['installedpackages']['service'][] = $service;
785
			}
786
			update_status(gettext("done.") . "\n");
787
		}
788
	} else {
789
		pkg_debug("Unable to find config file\n");
790
		update_status(gettext("Loading package configuration... failed!") . "\n\n" . gettext("Installation aborted."));
791
		pkg_debug(gettext("Unable to load package configuration. Installation aborted.") ."\n");
792

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

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

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

    
813
	return true;
814
}
815

    
816
function delete_package_xml($package_name, $when = "post-deinstall") {
817
	global $g, $config, $pkg_interface;
818

    
819
	conf_mount_rw();
820

    
821
	$pkgid = get_package_id($package_name);
822
	if ($pkgid == -1) {
823
		update_status(sprintf(gettext("The %s package is not installed.%sDeletion aborted."), $package_name, "\n\n"));
824
		ob_flush();
825
		sleep(1);
826
		conf_mount_ro();
827
		return;
828
	}
829
	pkg_debug(sprintf(gettext("Removing %s package... "), $package_name));
830
	update_status(sprintf(gettext("Removing %s components..."), $package_name) . "\n");
831
	/* parse package configuration */
832
	$packages = &$config['installedpackages']['package'];
833
	$menus =& $config['installedpackages']['menu'];
834
	$services = &$config['installedpackages']['service'];
835
	$pkg_info =& $packages[$pkgid];
836
	if (file_exists("/usr/local/pkg/" . $pkg_info['configurationfile'])) {
837
		$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $packages[$pkgid]['configurationfile'], "packagegui");
838
		/* remove menu items */
839
		if (is_array($pkg_config['menu'])) {
840
			update_status(gettext("Menu items... "));
841
			if (is_array($pkg_config['menu']) && is_array($menus)) {
842
				foreach ($pkg_config['menu'] as $menu) {
843
					foreach ($menus as $key => $instmenu) {
844
						if ($instmenu['name'] == $menu['name']) {
845
							unset($menus[$key]);
846
							break;
847
						}
848
					}
849
				}
850
			}
851
			update_status(gettext("done.") . "\n");
852
		}
853
		/* remove services */
854
		if (is_array($pkg_config['service'])) {
855
			update_status(gettext("Services... "));
856
			if (is_array($pkg_config['service']) && is_array($services)) {
857
				foreach ($pkg_config['service'] as $service) {
858
					foreach ($services as $key => $instservice) {
859
						if ($instservice['name'] == $service['name']) {
860
							if (platform_booting() != true) {
861
								stop_service($service['name']);
862
							}
863
							if ($service['rcfile']) {
864
								$prefix = RCFILEPREFIX;
865
								if (!empty($service['prefix'])) {
866
									$prefix = $service['prefix'];
867
								}
868
								if (file_exists("{$prefix}{$service['rcfile']}")) {
869
									@unlink("{$prefix}{$service['rcfile']}");
870
								}
871
							}
872
							unset($services[$key]);
873
						}
874
					}
875
				}
876
			}
877
			update_status(gettext("done.") . "\n");
878
		}
879
		/*
880
		 * XXX: Otherwise inclusion of config.inc again invalidates actions taken.
881
		 *	Same is done during installation.
882
		 */
883
		write_config("Intermediate config write during package removal for {$package_name}.");
884

    
885
		/*
886
		 * If a require exists, include it.	 this will
887
		 * show us where an error exists in a package
888
		 * instead of making us blindly guess
889
		 */
890
		$missing_include = false;
891
		if ($pkg_config['include_file'] <> "") {
892
			update_status(gettext("Loading package instructions...") . "\n");
893
			if (file_exists($pkg_config['include_file'])) {
894
				pkg_debug("require_once(\"{$pkg_config['include_file']}\")\n");
895
				require_once($pkg_config['include_file']);
896
			} else {
897
				pkg_debug("Missing include {$pkg_config['include_file']}\n");
898
				$missing_include = true;
899
				update_status("Include file " . basename($pkg_config['include_file']) . " could not be found for inclusion.\n");
900
			}
901
		}
902
		/* ermal
903
		 * NOTE: It is not possible to handle parse errors on eval.
904
		 * So we prevent it from being run at all to not interrupt all the other code.
905
		 */
906
		if ($when == "deinstall" && $missing_include == false) {
907
			/* evaluate this package's global functions and pre deinstall commands */
908
			if ($pkg_config['custom_php_global_functions'] <> "") {
909
				eval_once($pkg_config['custom_php_global_functions']);
910
			}
911
			if ($pkg_config['custom_php_pre_deinstall_command'] <> "") {
912
				eval_once($pkg_config['custom_php_pre_deinstall_command']);
913
			}
914
		}
915
		/* deinstall commands */
916
		if ($when == "post-deinstall" && $pkg_config['custom_php_deinstall_command'] <> "") {
917
			update_status(gettext("Deinstall commands... "));
918
			if ($missing_include == false) {
919
				eval_once($pkg_config['custom_php_deinstall_command']);
920
				update_status(gettext("done.") . "\n");
921
			} else {
922
				update_status("\nNot executing custom deinstall hook because an include is missing.\n");
923
			}
924
		}
925
	}
926
	/* syslog */
927
	$need_syslog_restart = false;
928
	if (is_array($pkg_info['logging']) && $pkg_info['logging']['logfilename'] <> "") {
929
		update_status("Syslog entries... ");
930
		@unlink("{$g['varlog_path']}/{$pkg_info['logging']['logfilename']}");
931
		update_status("done.\n");
932
		$need_syslog_restart = true;
933
	}
934

    
935
	/* remove config.xml entries */
936
	update_status(gettext("Configuration... "));
937
	unset($config['installedpackages']['package'][$pkgid]);
938
	update_status(gettext("done.") . "\n");
939
	write_config("Removed {$package_name} package.\n");
940

    
941
	/* remove package entry from /etc/syslog.conf if needed */
942
	/* this must be done after removing the entries from config.xml */
943
	if ($need_syslog_restart) {
944
		system_syslogd_start();
945
	}
946

    
947
	conf_mount_ro();
948
}
949

    
950
/*
951
 * Used during upgrade process or retore backup process, verify all
952
 * packages installed in config.xml and install pkg accordingly
953
 */
954
function package_reinstall_all() {
955
	global $g, $config, $pkg_interface;
956

    
957
	if (!isset($config['installedpackages']['package']) ||
958
	    !is_array($config['installedpackages']['package'])) {
959
		return true;
960
	}
961

    
962
	$upgrade = (file_exists('/conf/needs_package_sync') && platform_booting());
963

    
964
	/* During boot after upgrade, wait for internet connection */
965
	if ($upgrade) {
966
		update_status(gettext("Waiting for internet connection to update pkg metadata and fini package reinstallation"));
967
		while (true) {
968
			if (pkg_update(true)) {
969
				break;
970
			}
971
			update_status('.');
972
			sleep(1);
973
		}
974
		update_status("\n");
975
	} else {
976
		if (!pkg_update()) {
977
			return false;
978
		}
979
	}
980

    
981
	$pkg_info = get_pkg_info();
982

    
983
	foreach ($config['installedpackages']['package'] as $package) {
984
		$found = false;
985
		$internal_name = get_package_internal_name($package);
986
		foreach ($pkg_info as $pkg) {
987
			pkg_remove_prefix($pkg['name']);
988
			if ($pkg['name'] == $internal_name) {
989
				$found = true;
990
				break;
991
			}
992
		}
993

    
994
		if (!$found) {
995
			if (!function_exists("file_notice")) {
996
				require_once("notices.inc");
997
			}
998

    
999
			file_notice(gettext("Package reinstall"),
1000
			    sprintf(gettext("Package %s does not exist in current %s version and it has been removed."), $package['name'], $g['product_name']));
1001
			uninstall_package($package['name']);
1002
		}
1003
	}
1004

    
1005
	/* Obsoleted packages were removed, lets reinstall all remaining */
1006
	foreach ($config['installedpackages']['package'] as $package) {
1007
		$internal_name = get_package_internal_name($package);
1008
		pkg_install($g['pkg_prefix'] . $internal_name, true);
1009
	}
1010

    
1011
	return true;
1012
}
1013

    
1014
function stop_packages() {
1015
	require_once("config.inc");
1016
	require_once("functions.inc");
1017
	require_once("filter.inc");
1018
	require_once("shaper.inc");
1019
	require_once("captiveportal.inc");
1020
	require_once("pkg-utils.inc");
1021
	require_once("pfsense-utils.inc");
1022
	require_once("service-utils.inc");
1023

    
1024
	global $config, $g;
1025

    
1026
	log_error("Stopping all packages.");
1027

    
1028
	$rcfiles = glob(RCFILEPREFIX . "*.sh");
1029
	if (!$rcfiles) {
1030
		$rcfiles = array();
1031
	} else {
1032
		$rcfiles = array_flip($rcfiles);
1033
		if (!$rcfiles) {
1034
			$rcfiles = array();
1035
		}
1036
	}
1037

    
1038
	if (is_array($config['installedpackages']['package'])) {
1039
		foreach ($config['installedpackages']['package'] as $package) {
1040
			echo " Stopping package {$package['name']}...";
1041
			$internal_name = get_package_internal_name($package);
1042
			stop_service($internal_name);
1043
			unset($rcfiles[RCFILEPREFIX . strtolower($internal_name) . ".sh"]);
1044
			echo "done.\n";
1045
		}
1046
	}
1047

    
1048
	foreach ($rcfiles as $rcfile => $number) {
1049
		$shell = @popen("/bin/sh", "w");
1050
		if ($shell) {
1051
			echo " Stopping {$rcfile}...";
1052
			if (!@fwrite($shell, "{$rcfile} stop >>/tmp/bootup_messages 2>&1")) {
1053
				if ($shell) {
1054
					pclose($shell);
1055
				}
1056
				$shell = @popen("/bin/sh", "w");
1057
			}
1058
			echo "done.\n";
1059
			pclose($shell);
1060
		}
1061
	}
1062
}
1063

    
1064
/* Identify which meta package is installed */
1065
function get_meta_pkg_name() {
1066
	global $g;
1067

    
1068
	/* XXX: Use pkg annotation */
1069
	if (is_pkg_installed($g['product_name'])) {
1070
		return $g['product_name'];
1071
	} else if (is_pkg_installed($g['product_name'] . '-vmware')) {
1072
		return $g['product_name'] . '-vmware';
1073
	}
1074
	return false;
1075
}
1076

    
1077
/* Identify which base package is installed */
1078
function get_base_pkg_name() {
1079
	global $g;
1080

    
1081
	/* XXX: Use pkg annotation */
1082
	if (is_pkg_installed($g['product_name'] . '-base-' . $g['platform'])) {
1083
		return $g['product_name'];
1084
		return $g['product_name'] . '-base-' . $g['platform'];
1085
	} else if (is_pkg_installed($g['product_name'] . '-base')) {
1086
		return $g['product_name'] . '-base';
1087
	}
1088
	return false;
1089
}
1090

    
1091
/* Verify if system needs upgrade (meta package or base) */
1092
function get_system_pkg_version() {
1093
	global $g;
1094

    
1095
	$base_pkg = get_base_pkg_name();
1096
	$meta_pkg = get_meta_pkg_name();
1097

    
1098
	if (!$base_pkg || !$meta_pkg) {
1099
		return false;
1100
	}
1101

    
1102
	$info = get_pkg_info($base_pkg);
1103
	$pkg_name = $base_pkg;
1104

    
1105
	$pkg_info = array();
1106
	foreach ($info as $item) {
1107
		if ($item['name'] == $base_pkg) {
1108
			$pkg_info = $item;
1109
		}
1110
	}
1111

    
1112
	if (empty($pkg_info) ||
1113
	    $pkg_info['version'] == $pkg_info['installed_version']) {
1114
		$info = get_pkg_info($meta_pkg);
1115
		$pkg_name = $meta_pkg;
1116

    
1117
		foreach ($info as $item) {
1118
			if ($item['name'] == $meta_pkg) {
1119
				$pkg_info = $item;
1120
			}
1121
		}
1122
	}
1123

    
1124
	if (empty($pkg_info)) {
1125
		return false;
1126
	}
1127

    
1128
	return array(
1129
	    'pkg_name'          => $pkg_name,
1130
	    'version'           => $pkg_info['version'],
1131
	    'installed_version' => $pkg_info['installed_version']
1132
	);
1133
}
1134

    
1135
/* Switch between stable and devel repos */
1136
function pkg_switch_repo($devel = false) {
1137
	global $g;
1138

    
1139
	$repo_stable = $g['product_name'] . '-repo';
1140
	$repo_devel = $g['product_name'] . '-repo-devel';
1141

    
1142
	if ($devel) {
1143
		$repo_target = $repo_devel;
1144
	} else {
1145
		$repo_target = $repo_stable;
1146
	}
1147

    
1148
	if (is_pkg_installed($repo_target)) {
1149
		/* It's already installed */
1150
		return true;
1151
	}
1152

    
1153
	/*
1154
	 * Since both install files in the same place, just
1155
	 * call pkg_install for target and current one will
1156
	 * be replaced
1157
	 */
1158
	return pkg_install($repo_target, true);
1159
}
1160

    
1161
?>
(40-40/65)