Project

General

Profile

Download (32.8 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 -f");
117

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

    
122
	return $rc;
123
}
124

    
125
/* return an array with necessary environment vars for pkg */
126
function pkg_env() {
127
	global $config, $g;
128

    
129
	$pkg_env_vars = array(
130
		"HTTP_USER_AGENT" => $user_agent,
131
		"ASSUME_ALWAYS_YES" => "true",
132
		"REPO_AUTOUPDATE" => "false"
133
	);
134

    
135
	if ($g['platform'] == "nanobsd" ||
136
	    isset($config['system']['use_mfs_tmpvar'])) {
137
		$pkg_env_vars['PKG_DBDIR'] = '/root/var/db/pkg';
138
		$pkg_env_vars['PKG_CACHEDIR'] = '/root/var/cache/pkg';
139
	}
140

    
141
	return $pkg_env_vars;
142
}
143

    
144
/* Execute a pkg call */
145
function pkg_call($params, $mute = false, $readonly = false) {
146
	global $g, $config;
147

    
148
	if (empty($params)) {
149
		return false;
150
	}
151

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

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

    
162
	if (!$readonly) {
163
		conf_mount_rw();
164
	}
165

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

    
170
	if (!is_resource($process)) {
171
		if (!$readonly) {
172
			conf_mount_ro();
173
		}
174
		return false;
175
	}
176

    
177
	stream_set_blocking($pipes[1], 0);
178
	stream_set_blocking($pipes[2], 0);
179

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

    
186
	do {
187
		$write = array();
188
		$read = array($pipes[1], $pipes[2]);
189
		$except = array();
190

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

    
209
		$status = proc_get_status($process);
210

    
211
		$now = time();
212

    
213
		if (($now - $started) >= $maxwaittime) {
214
			$rc = -1;
215
			proc_terminate($process);
216
			break;
217
		}
218

    
219
	} while ($status['running']);
220

    
221
	fclose($pipes[1]);
222
	fclose($pipes[2]);
223
	proc_close($process);
224

    
225
	if (!$readonly) {
226
		conf_mount_ro();
227
	}
228

    
229
	if (!isset($rc)) {
230
		$rc = $status['exitcode'];
231
	}
232

    
233
	pkg_debug("pkg_call(): rc = {$rc}\n");
234
	if ($rc == 0) {
235
		return true;
236
	}
237

    
238
	pkg_debug("pkg_call(): error_log\n{$error_log}\n");
239
	if (!$mute) {
240
		update_status("\n\n" .  sprintf(gettext(
241
		    "ERROR!!! An error occurred on pkg execution (rc = %d) with parameters '%s':"),
242
		    $rc, $params) . "\n" . $error_log . "\n");
243
	}
244

    
245
	return false;
246
}
247

    
248
/* Execute pkg with $params, fill stdout and stderr and return pkg rc */
249
function pkg_exec($params, &$stdout, &$stderr, $readonly = false) {
250
	global $g, $config;
251

    
252
	if (empty($params)) {
253
		return -1;
254
	}
255

    
256
	$user_agent = $g['product_name'] . '/' . $g['product_version'];
257
	if (!isset($config['system']['do_not_send_host_uuid'])) {
258
		$user_agent .= ' : ' . get_single_sysctl('kern.hostuuid');
259
	}
260

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

    
266
	if (!$readonly) {
267
		conf_mount_rw();
268
	}
269

    
270
	pkg_debug("pkg_exec(): {$params}\n");
271
	$process = proc_open("/usr/sbin/pkg {$params}", $descriptorspec, $pipes,
272
	    '/', pkg_env());
273

    
274
	if (!is_resource($process)) {
275
		if (!$readonly) {
276
			conf_mount_ro();
277
		}
278
		return -1;
279
	}
280

    
281
	$stdout = '';
282
	while (($l = fgets($pipes[1])) !== FALSE) {
283
		$stdout .= $l;
284
	}
285
	fclose($pipes[1]);
286

    
287
	$stderr = '';
288
	while (($l = fgets($pipes[2])) !== FALSE) {
289
		$stderr .= $l;
290
	}
291
	fclose($pipes[2]);
292

    
293
	if (!$readonly) {
294
		conf_mount_ro();
295
	}
296

    
297
	return proc_close($process);
298
}
299

    
300
/* Compare 2 pkg versions and return:
301
 * '=' - versions are the same
302
 * '>' - $v1 > $v2
303
 * '<' - $v1 < $v2
304
 * '?' - Error
305
 */
306
function pkg_version_compare($v1, $v2) {
307
	if (empty($v1) || empty($v2)) {
308
		return '?';
309
	}
310

    
311
	$rc = pkg_exec("version -t '{$v1}' '{$v2}'", $stdout, $stderr, true);
312

    
313
	if ($rc != 0) {
314
		return '?';
315
	}
316

    
317
	return str_replace("\n", "", $stdout);
318
}
319

    
320
/* Check if package is installed */
321
function is_pkg_installed($pkg_name) {
322
	global $g;
323

    
324
	if (empty($pkg_name)) {
325
		return false;
326
	}
327

    
328
	return pkg_call("info -e " . $pkg_name, true, true);
329
}
330

    
331
/* Install package, $pkg_name should not contain prefix */
332
function pkg_install($pkg_name, $force = false) {
333
	global $g;
334
	$result = false;
335

    
336
	$shortname = $pkg_name;
337
	pkg_remove_prefix($shortname);
338

    
339
	$pkg_force = "";
340
	if ($force) {
341
		$pkg_force = "-f ";
342
	}
343

    
344
	pkg_debug("Installing package {$shortname}\n");
345
	if ($force || !is_pkg_installed($pkg_name)) {
346
		$result = pkg_call("install -y " . $pkg_force . $pkg_name);
347
		/* Cleanup cacke to free disk space */
348
		pkg_call("clean -y");
349
	}
350

    
351
	return $result;
352
}
353

    
354
/* Delete package from FreeBSD, $pkg_name should not contain prefix */
355
function pkg_delete($pkg_name) {
356
	global $g;
357

    
358
	$shortname = $pkg_name;
359
	pkg_remove_prefix($shortname);
360

    
361
	pkg_debug("Removing package {$shortname}\n");
362
	if (is_pkg_installed($pkg_name)) {
363
		pkg_call("delete -y " . $pkg_name);
364
		/* Cleanup unecessary dependencies */
365
		pkg_call("autoremove -y");
366
	}
367
}
368

    
369
/* Check if package is present in config.xml */
370
function is_package_installed($package_name) {
371
	return (get_package_id($package_name) != -1);
372
}
373

    
374
/* Find package array index */
375
function get_package_id($package_name) {
376
	global $config;
377

    
378
	if (!is_array($config['installedpackages']['package'])) {
379
		return -1;
380
	}
381

    
382
	foreach ($config['installedpackages']['package'] as $idx => $pkg) {
383
		if ($pkg['name'] == $package_name ||
384
		    get_package_internal_name($pkg) == $package_name) {
385
			return $idx;
386
		}
387
	}
388

    
389
	return -1;
390
}
391

    
392
/* Keep backward compatibility since snort/suricata use this function */
393
function get_pkg_id($package_name) {
394
	return get_package_id($package_name);
395
}
396

    
397
/* Return internal_name when it's defined, otherwise, returns name */
398
function get_package_internal_name($package_data) {
399
	if (isset($package_data['internal_name']) && ($package_data['internal_name'] != "")) {
400
		/* e.g. name is Ipguard-dev, internal name is ipguard */
401
		return $package_data['internal_name'];
402
	} else {
403
		return $package_data['name'];
404
	}
405
}
406

    
407
// Get information about packages.
408
function get_pkg_info($pkgs = 'all', $info = 'all') {
409
	global $g, $input_errors;
410

    
411
	$out = '';
412
	$err = '';
413

    
414
	unset($pkg_filter);
415
	if (is_array($pkgs)) {
416
		$pkg_filter = $pkgs;
417
		$pkgs = 'all';
418
	}
419

    
420
	if ($pkgs == 'all') {
421
		$pkgs = $g['pkg_prefix'];
422
	}
423

    
424
	/* Make sure repo metadata is up2date */
425
	update_status("\n" .
426
	    gettext("Updating package repository metadada...") . "\n");
427

    
428
	if (!pkg_update()) {
429
		$input_errors[] = gettext(
430
		    "ERROR: An error occurred when updating packages repository. Aborting...")
431
		    . "\n";
432
		update_status("\n" . gettext(
433
		    "ERROR: An error occurred when updating packages repository. Aborting...")
434
		    . "\n");
435
		return array();
436
	}
437

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

    
440
	if ($rc != 0) {
441
		update_status("\n" . gettext(
442
		    "ERROR: Error trying to get packages list. Aborting...")
443
		    . "\n");
444
		update_status($err);
445
		$input_errors[] =  gettext("ERROR: Error trying to get packages list. Aborting...") . "\n";
446
		$input_errors[] =  $err;
447
		return array();
448
	}
449

    
450
	$result = array();
451
	$pkgs_info = explode("\n", $out);
452
	foreach ($pkgs_info as $pkg_info_json) {
453
		$pkg_info = json_decode($pkg_info_json, true);
454
		if (!isset($pkg_info['name'])) {
455
			continue;
456
		}
457

    
458
		if (isset($pkg_filter) && !in_array($pkg_info['name'], $pkg_filter)) {
459
			continue;
460
		}
461

    
462
		$pkg_info['shortname'] = $pkg_info['name'];
463
		pkg_remove_prefix($pkg_info['shortname']);
464

    
465
		/* XXX: Add it to globals.inc? */
466
		$pkg_info['changeloglink'] =
467
		    "https://github.com/pfsense/FreeBSD-ports/commits/devel/" .
468
		    $pkg_info['categories'][0] . '/' . $pkg_info['name'];
469

    
470
		if (is_pkg_installed($pkg_info['name'])) {
471
			$pkg_info['installed'] = true;
472

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

    
475
			if ($rc != 0) {
476
				update_status("\n" . gettext(
477
				    "ERROR: Error trying to get package version. Aborting...")
478
				    . "\n");
479
				update_status($err);
480
				$input_errors[] =  gettext("ERROR: Error trying to get package version. Aborting...") . "\n";
481
				$input_errors[] =  $err;
482
				return array();
483
			}
484

    
485
			$pkg_info['installed_version'] = str_replace("\n", "", $out);
486
		} else if (is_package_installed($pkg_info['shortname'])) {
487
			$pkg_info['broken'] = true;
488
		}
489

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

    
492
		$result[] = $pkg_info;
493
		unset($pkg_info);
494
	}
495

    
496
	/* Sort result alphabetically */
497
	usort($result, function($a, $b) {
498
		return(strcasecmp ($a['name'], $b['name']));
499
	});
500

    
501
	return $result;
502
}
503

    
504
/*
505
 * resync_all_package_configs() Force packages to setup their configuration and rc.d files.
506
 * This function may also print output to the terminal indicating progress.
507
 */
508
function resync_all_package_configs($show_message = false) {
509
	global $config, $pkg_interface, $g;
510

    
511
	log_error(gettext("Resyncing configuration for all packages."));
512

    
513
	if (!is_array($config['installedpackages']['package'])) {
514
		return;
515
	}
516

    
517
	if ($show_message == true) {
518
		echo "Syncing packages:";
519
	}
520

    
521
	conf_mount_rw();
522

    
523
	foreach ($config['installedpackages']['package'] as $idx => $package) {
524
		if (empty($package['name'])) {
525
			continue;
526
		}
527
		if ($show_message == true) {
528
			echo " " . $package['name'];
529
		}
530
		if (platform_booting() != true) {
531
			stop_service(get_package_internal_name($package));
532
		}
533
		sync_package($package['name']);
534
		update_status(gettext("Syncing packages...") . "\n");
535
	}
536

    
537
	if ($show_message == true) {
538
		echo " done.\n";
539
	}
540

    
541
	@unlink("/conf/needs_package_sync");
542
	conf_mount_ro();
543
}
544

    
545
function uninstall_package($package_name) {
546
	global $config;
547

    
548
	$internal_name = $package_name;
549
	$id = get_package_id($package_name);
550
	if ($id >= 0) {
551
		$internal_name = get_package_internal_name($config['installedpackages']['package'][$id]);
552
		stop_service($internal_name);
553
	}
554
	$pkg_name = $g['pkg_prefix'] . $internal_name;
555

    
556
	if (is_pkg_installed($pkg_name)) {
557
		update_status(gettext("Removing package...") . "\n");
558
		pkg_delete($pkg_name);
559
	} else {
560
		delete_package_xml($package_name);
561
	}
562

    
563
	update_status(gettext("done.") . "\n");
564
}
565

    
566
/* Run <custom_php_resync_config_command> */
567
function sync_package($package_name) {
568
	global $config, $builder_package_install;
569

    
570
	// If this code is being called by pfspkg_installer
571
	// which the builder system uses then return (ignore).
572
	if ($builder_package_install) {
573
		return;
574
	}
575

    
576
	if (empty($config['installedpackages']['package'])) {
577
		return;
578
	}
579

    
580
	if (($pkg_id = get_package_id($package_name)) == -1) {
581
		return; // This package doesn't really exist - exit the function.
582
	}
583

    
584
	if (!is_array($config['installedpackages']['package'][$pkg_id])) {
585
		return;	 // No package belongs to the pkg_id passed to this function.
586
	}
587

    
588
	$package =& $config['installedpackages']['package'][$pkg_id];
589
	if (!file_exists("/usr/local/pkg/" . $package['configurationfile'])) {
590
		log_error(sprintf(gettext("The %s package is missing its configuration file and must be reinstalled."), $package['name']));
591
		delete_package_xml($package['name']);
592
		return;
593
	}
594

    
595
	$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $package['configurationfile'], "packagegui");
596
	if (isset($pkg_config['nosync'])) {
597
		return;
598
	}
599

    
600
	/* Bring in package include files */
601
	if (!empty($pkg_config['include_file'])) {
602
		$include_file = $pkg_config['include_file'];
603
		if (file_exists($include_file)) {
604
			require_once($include_file);
605
		} else {
606
			log_error("Reinstalling package {$package['name']} because its include file({$include_file}) is missing!");
607
			uninstall_package($package['name']);
608
			if (install_package($package['name']) != 0) {
609
				log_error("Reinstalling package {$package['name']} failed. Take appropriate measures!!!");
610
				return;
611
			}
612
			if (file_exists($include_file)) {
613
				require_once($include_file);
614
			} else {
615
				return;
616
			}
617
		}
618
	}
619

    
620
	if (!empty($pkg_config['custom_php_global_functions'])) {
621
		eval($pkg_config['custom_php_global_functions']);
622
	}
623
	if (!empty($pkg_config['custom_php_resync_config_command'])) {
624
		eval($pkg_config['custom_php_resync_config_command']);
625
	}
626
}
627

    
628
/* Read info.xml installed by package and return an array */
629
function read_package_config($package_name) {
630
	global $g;
631

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

    
634
	if (!file_exists($pkg_info_xml)) {
635
		return false;
636
	}
637

    
638
	$pkg_info = parse_xml_config_pkg($pkg_info_xml, 'pfsensepkgs');
639

    
640
	if (empty($pkg_info)) {
641
		return false;
642
	}
643

    
644
	/* it always returns an array with 1 item */
645
	return $pkg_info['package'][0];
646
}
647

    
648
/* Read package configurationfile and return an array */
649
function read_package_configurationfile($package_name) {
650
	global $config, $g;
651

    
652
	$pkg_config = array();
653
	$id = get_package_id($package_name);
654

    
655
	if ($id < 0 || !isset($config['installedpackages']['package'][$id]['configurationfile'])) {
656
		return $pkg_config;
657
	}
658

    
659
	$pkg_configurationfile = $config['installedpackages']['package'][$id]['configurationfile'];
660

    
661
	if (empty($pkg_configurationfile) || !file_exists('/usr/local/pkg/' . $pkg_configurationfile)) {
662
		return $pkg_config;
663
	}
664

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

    
667
	return $pkg_config;
668
}
669

    
670
function get_after_install_info($package_name) {
671
	$pkg_config = read_package_config($package_name);
672

    
673
	if (isset($pkg_config['after_install_info'])) {
674
		return $pkg_config['after_install_info'];
675
	}
676

    
677
	return '';
678
}
679

    
680
function eval_once($toeval) {
681
	global $evaled;
682
	if (!$evaled) {
683
		$evaled = array();
684
	}
685
	$evalmd5 = md5($toeval);
686
	if (!in_array($evalmd5, $evaled)) {
687
		@eval($toeval);
688
		$evaled[] = $evalmd5;
689
	}
690
	return;
691
}
692

    
693
function install_package_xml($package_name) {
694
	global $g, $config, $pkg_interface;
695

    
696
	if (($pkg_info = read_package_config($package_name)) == false) {
697
		return false;
698
	}
699

    
700
	/* safe side. Write config below will send to ro again. */
701
	conf_mount_rw();
702

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

    
706
	/* add package information to config.xml */
707
	$pkgid = get_package_id($pkg_info['name']);
708
	update_status(gettext("Saving updated package information...") . "\n");
709
	if ($pkgid == -1) {
710
		$config['installedpackages']['package'][] = $pkg_info;
711
		$changedesc = sprintf(gettext("Installed %s package."), $pkg_info['name']);
712
		$to_output = gettext("done.") . "\n";
713
	} else {
714
		$config['installedpackages']['package'][$pkgid] = $pkg_info;
715
		$changedesc = sprintf(gettext("Overwrote previous installation of %s."), $pkg_info['name']);
716
		$to_output = gettext("overwrite!") . "\n";
717
	}
718
	unlink_if_exists('/conf/needs_package_sync');
719
	write_config("Intermediate config write during package install for {$pkg_info['name']}.");
720
	conf_mount_ro();
721
	update_status($to_output);
722

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

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

    
733
	if (file_exists("/usr/local/pkg/" . $pkg_info['configurationfile'])) {
734
		update_status(gettext("Loading package configuration... "));
735
		$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $pkg_info['configurationfile'], "packagegui");
736
		update_status(gettext("done.") . "\n");
737
		update_status(gettext("Configuring package components...") . "\n");
738
		if (!empty($pkg_config['filter_rules_needed'])) {
739
			$config['installedpackages']['package'][$pkgid]['filter_rule_function'] = $pkg_config['filter_rules_needed'];
740
		}
741
		/* modify system files */
742

    
743
		/* if a require exists, include it.  this will
744
		 * show us where an error exists in a package
745
		 * instead of making us blindly guess
746
		 */
747
		$missing_include = false;
748
		if ($pkg_config['include_file'] <> "") {
749
			update_status(gettext("Loading package instructions...") . "\n");
750
			if (file_exists($pkg_config['include_file'])) {
751
				pkg_debug("require_once('{$pkg_config['include_file']}')\n");
752
				require_once($pkg_config['include_file']);
753
			} else {
754
				pkg_debug("Missing include {$pkg_config['include_file']}\n");
755
				$missing_include = true;
756
				update_status("Include " . basename($pkg_config['include_file']) . " is missing!\n");
757

    
758
				uninstall_package($package_name);
759
				write_config($changedesc);
760
				log_error(sprintf(gettext("Failed to install package: %s."), $pkg_info['name']));
761
				update_status(gettext("Failed to install package.") . "\n");
762
				return false;
763
			}
764
		}
765

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

    
824
		uninstall_package($package_name);
825
		write_config($changedesc);
826
		log_error(sprintf(gettext("Failed to install package: %s."), $pkg_info['name']));
827
		update_status(gettext("Failed to install package.") . "\n");
828
		return false;
829
	}
830

    
831
	/* set up package logging streams */
832
	if ($pkg_info['logging']) {
833
		system_syslogd_start();
834
	}
835

    
836
	update_status(gettext("Writing configuration... "));
837
	write_config($changedesc);
838
	log_error(sprintf(gettext("Successfully installed package: %s."), $pkg_info['name']));
839
	update_status(gettext("done.") . "\n");
840
	if ($pkg_info['after_install_info']) {
841
		update_status($pkg_info['after_install_info']);
842
	}
843

    
844
	return true;
845
}
846

    
847
function delete_package_xml($package_name, $when = "post-deinstall") {
848
	global $g, $config, $pkg_interface;
849

    
850
	conf_mount_rw();
851

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

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

    
966
	if ($when == "post-deinstall") {
967
		/* remove config.xml entries */
968
		update_status(gettext("Configuration... "));
969
		unset($config['installedpackages']['package'][$pkgid]);
970
		update_status(gettext("done.") . "\n");
971
		write_config("Removed {$package_name} package.\n");
972
	}
973

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

    
980
	conf_mount_ro();
981
}
982

    
983
/*
984
 * Used during upgrade process or retore backup process, verify all
985
 * packages installed in config.xml and install pkg accordingly
986
 */
987
function package_reinstall_all() {
988
	global $g, $config, $pkg_interface;
989

    
990
	if (!isset($config['installedpackages']['package']) ||
991
	    !is_array($config['installedpackages']['package'])) {
992
		return true;
993
	}
994

    
995
	$upgrade = (file_exists('/conf/needs_package_sync') && platform_booting());
996

    
997
	/* During boot after upgrade, wait for internet connection */
998
	if ($upgrade) {
999
		update_status(gettext("Waiting for internet connection to update pkg metadata and fini package reinstallation"));
1000
		while (true) {
1001
			if (pkg_update(true)) {
1002
				break;
1003
			}
1004
			update_status('.');
1005
			sleep(1);
1006
		}
1007
		update_status("\n");
1008
	} else {
1009
		if (!pkg_update()) {
1010
			return false;
1011
		}
1012
	}
1013

    
1014
	$pkg_info = get_pkg_info();
1015

    
1016
	foreach ($config['installedpackages']['package'] as $package) {
1017
		$found = false;
1018
		$internal_name = get_package_internal_name($package);
1019
		foreach ($pkg_info as $pkg) {
1020
			pkg_remove_prefix($pkg['name']);
1021
			if ($pkg['name'] == $internal_name) {
1022
				$found = true;
1023
				break;
1024
			}
1025
		}
1026

    
1027
		if (!$found) {
1028
			if (!function_exists("file_notice")) {
1029
				require_once("notices.inc");
1030
			}
1031

    
1032
			file_notice(gettext("Package reinstall"),
1033
			    sprintf(gettext("Package %s does not exist in current %s version and it has been removed."), $package['name'], $g['product_name']));
1034
			uninstall_package($package['name']);
1035
		}
1036
	}
1037

    
1038
	/* Obsoleted packages were removed, lets reinstall all remaining */
1039
	foreach ($config['installedpackages']['package'] as $package) {
1040
		$internal_name = get_package_internal_name($package);
1041
		pkg_install($g['pkg_prefix'] . $internal_name, true);
1042
	}
1043

    
1044
	return true;
1045
}
1046

    
1047
function stop_packages() {
1048
	require_once("config.inc");
1049
	require_once("functions.inc");
1050
	require_once("filter.inc");
1051
	require_once("shaper.inc");
1052
	require_once("captiveportal.inc");
1053
	require_once("pkg-utils.inc");
1054
	require_once("pfsense-utils.inc");
1055
	require_once("service-utils.inc");
1056

    
1057
	global $config, $g;
1058

    
1059
	log_error("Stopping all packages.");
1060

    
1061
	$rcfiles = glob(RCFILEPREFIX . "*.sh");
1062
	if (!$rcfiles) {
1063
		$rcfiles = array();
1064
	} else {
1065
		$rcfiles = array_flip($rcfiles);
1066
		if (!$rcfiles) {
1067
			$rcfiles = array();
1068
		}
1069
	}
1070

    
1071
	if (is_array($config['installedpackages']['package'])) {
1072
		foreach ($config['installedpackages']['package'] as $package) {
1073
			echo " Stopping package {$package['name']}...";
1074
			$internal_name = get_package_internal_name($package);
1075
			stop_service($internal_name);
1076
			unset($rcfiles[RCFILEPREFIX . strtolower($internal_name) . ".sh"]);
1077
			echo "done.\n";
1078
		}
1079
	}
1080

    
1081
	foreach ($rcfiles as $rcfile => $number) {
1082
		$shell = @popen("/bin/sh", "w");
1083
		if ($shell) {
1084
			echo " Stopping {$rcfile}...";
1085
			if (!@fwrite($shell, "{$rcfile} stop >>/tmp/bootup_messages 2>&1")) {
1086
				if ($shell) {
1087
					pclose($shell);
1088
				}
1089
				$shell = @popen("/bin/sh", "w");
1090
			}
1091
			echo "done.\n";
1092
			pclose($shell);
1093
		}
1094
	}
1095
}
1096

    
1097
/* Identify which meta package is installed */
1098
function get_meta_pkg_name() {
1099
	global $g;
1100

    
1101
	/* XXX: Use pkg annotation */
1102
	if (is_pkg_installed($g['product_name'])) {
1103
		return $g['product_name'];
1104
	} else if (is_pkg_installed($g['product_name'] . '-vmware')) {
1105
		return $g['product_name'] . '-vmware';
1106
	}
1107
	return false;
1108
}
1109

    
1110
/* Identify which base package is installed */
1111
function get_base_pkg_name() {
1112
	global $g;
1113

    
1114
	/* XXX: Use pkg annotation */
1115
	if (is_pkg_installed($g['product_name'] . '-base-' . $g['platform'])) {
1116
		return $g['product_name'];
1117
		return $g['product_name'] . '-base-' . $g['platform'];
1118
	} else if (is_pkg_installed($g['product_name'] . '-base')) {
1119
		return $g['product_name'] . '-base';
1120
	}
1121
	return false;
1122
}
1123

    
1124
/* Verify if system needs upgrade (meta package or base) */
1125
function get_system_pkg_version() {
1126
	global $g;
1127

    
1128
	$base_pkg = get_base_pkg_name();
1129
	$meta_pkg = get_meta_pkg_name();
1130

    
1131
	if (!$base_pkg || !$meta_pkg) {
1132
		return false;
1133
	}
1134

    
1135
	$info = get_pkg_info($base_pkg);
1136
	$pkg_name = $base_pkg;
1137

    
1138
	$pkg_info = array();
1139
	foreach ($info as $item) {
1140
		if ($item['name'] == $base_pkg) {
1141
			$pkg_info = $item;
1142
		}
1143
	}
1144

    
1145
	if (empty($pkg_info) ||
1146
	    $pkg_info['version'] == $pkg_info['installed_version']) {
1147
		$info = get_pkg_info($meta_pkg);
1148
		$pkg_name = $meta_pkg;
1149

    
1150
		foreach ($info as $item) {
1151
			if ($item['name'] == $meta_pkg) {
1152
				$pkg_info = $item;
1153
			}
1154
		}
1155
	}
1156

    
1157
	if (empty($pkg_info)) {
1158
		return false;
1159
	}
1160

    
1161
	return array(
1162
	    'pkg_name'          => $pkg_name,
1163
	    'version'           => $pkg_info['version'],
1164
	    'installed_version' => $pkg_info['installed_version']
1165
	);
1166
}
1167

    
1168
/* Switch between stable and devel repos */
1169
function pkg_switch_repo($devel = false) {
1170
	global $g;
1171

    
1172
	$repo_stable = $g['product_name'] . '-repo';
1173
	$repo_devel = $g['product_name'] . '-repo-devel';
1174

    
1175
	if ($devel) {
1176
		$repo_target = $repo_devel;
1177
	} else {
1178
		$repo_target = $repo_stable;
1179
	}
1180

    
1181
	if (is_pkg_installed($repo_target)) {
1182
		/* It's already installed */
1183
		return true;
1184
	}
1185

    
1186
	/*
1187
	 * Since both install files in the same place, just
1188
	 * call pkg_install for target and current one will
1189
	 * be replaced
1190
	 */
1191
	return pkg_install($repo_target, true);
1192
}
1193

    
1194
?>
(40-40/65)