Project

General

Profile

Download (32.4 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
	return pkg_call("update" . ($force ? " -f" : ""));
100
}
101

    
102
/* return an array with necessary environment vars for pkg */
103
function pkg_env($extra_env = array()) {
104
	global $config, $g;
105

    
106
	$pkg_env_vars = array(
107
		"LANG" => "C",
108
		"HTTP_USER_AGENT" => $user_agent,
109
		"ASSUME_ALWAYS_YES" => "true"
110
	);
111

    
112
	if ($g['platform'] == "nanobsd" ||
113
	    isset($config['system']['use_mfs_tmpvar'])) {
114
		$pkg_env_vars['PKG_DBDIR'] = '/root/var/db/pkg';
115
		$pkg_env_vars['PKG_CACHEDIR'] = '/root/var/cache/pkg';
116
	}
117

    
118
	foreach ($extra_env as $key => $value) {
119
		$pkg_env_vars[$key] = $value;
120
	}
121

    
122
	return $pkg_env_vars;
123
}
124

    
125
/* Execute a pkg call */
126
function pkg_call($params, $mute = false, $extra_env = array()) {
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
	$descriptorspec = array(
139
		1 => array("pipe", "w"), /* stdout */
140
		2 => array("pipe", "w")	 /* stderr */
141
	);
142

    
143
	conf_mount_rw();
144

    
145
	pkg_debug("pkg_call(): {$params}\n");
146
	$process = proc_open("/usr/sbin/pkg {$params}", $descriptorspec, $pipes,
147
	    '/', pkg_env($extra_env));
148

    
149
	if (!is_resource($process)) {
150
		conf_mount_ro();
151
		return false;
152
	}
153

    
154
	stream_set_blocking($pipes[1], 0);
155
	stream_set_blocking($pipes[2], 0);
156

    
157
	/* XXX: should be a tunnable? */
158
	$timeout = 300; // seconds
159
	$error_log = '';
160

    
161
	do {
162
		$write = array();
163
		$read = array($pipes[1], $pipes[2]);
164
		$except = array();
165

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

    
184
		$status = proc_get_status($process);
185
	} while ($status['running']);
186

    
187
	fclose($pipes[1]);
188
	fclose($pipes[2]);
189
	proc_close($process);
190

    
191
	conf_mount_ro();
192

    
193
	$rc = $status['exitcode'];
194

    
195
	pkg_debug("pkg_call(): rc = {$rc}\n");
196
	if ($rc == 0) {
197
		return true;
198
	}
199

    
200
	pkg_debug("pkg_call(): error_log\n{$error_log}\n");
201
	if (!$mute) {
202
		update_status("\n\n" .  sprintf(gettext(
203
		    "ERROR!!! An error occurred on pkg execution (rc = %d) with parameters '%s':"),
204
		    $rc, $params) . "\n" . $error_log . "\n");
205
	}
206

    
207
	return false;
208
}
209

    
210
/* Execute pkg with $params, fill stdout and stderr and return pkg rc */
211
function pkg_exec($params, &$stdout, &$stderr, $extra_env = array()) {
212
	global $g, $config;
213

    
214
	if (empty($params)) {
215
		return -1;
216
	}
217

    
218
	$user_agent = $g['product_name'] . '/' . $g['product_version'];
219
	if (!isset($config['system']['do_not_send_host_uuid'])) {
220
		$user_agent .= ' : ' . get_single_sysctl('kern.hostuuid');
221
	}
222

    
223
	$descriptorspec = array(
224
		1 => array("pipe", "w"), /* stdout */
225
		2 => array("pipe", "w")	 /* stderr */
226
	);
227

    
228
	conf_mount_rw();
229

    
230
	pkg_debug("pkg_exec(): {$params}\n");
231
	$process = proc_open("/usr/sbin/pkg {$params}", $descriptorspec, $pipes,
232
	    '/', pkg_env($extra_env));
233

    
234
	if (!is_resource($process)) {
235
		conf_mount_ro();
236
		return -1;
237
	}
238

    
239
	$stdout = '';
240
	while (($l = fgets($pipes[1])) !== FALSE) {
241
		$stdout .= $l;
242
	}
243
	fclose($pipes[1]);
244

    
245
	$stderr = '';
246
	while (($l = fgets($pipes[2])) !== FALSE) {
247
		$stderr .= $l;
248
	}
249
	fclose($pipes[2]);
250

    
251
	conf_mount_ro();
252

    
253
	return proc_close($process);
254
}
255

    
256
/* Compare 2 pkg versions and return:
257
 * '=' - versions are the same
258
 * '>' - $v1 > $v2
259
 * '<' - $v1 < $v2
260
 * '?' - Error
261
 */
262
function pkg_version_compare($v1, $v2) {
263
	if (empty($v1) || empty($v2)) {
264
		return '?';
265
	}
266

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

    
269
	if ($rc != 0) {
270
		return '?';
271
	}
272

    
273
	return str_replace("\n", "", $stdout);
274
}
275

    
276
/* Check if package is installed */
277
function is_pkg_installed($pkg_name) {
278
	global $g;
279

    
280
	if (empty($pkg_name)) {
281
		return false;
282
	}
283

    
284
	return pkg_call("info -e " . $pkg_name, true);
285
}
286

    
287
/* Install package, $pkg_name should not contain prefix */
288
function pkg_install($pkg_name, $force = false) {
289
	global $g;
290
	$result = false;
291

    
292
	$shortname = $pkg_name;
293
	pkg_remove_prefix($shortname);
294

    
295
	$pkg_force = "";
296
	if ($force) {
297
		$pkg_force = "-f ";
298
	}
299

    
300
	pkg_debug("Installing package {$shortname}\n");
301
	if ($force || !is_pkg_installed($pkg_name)) {
302
		$result = pkg_call("install -y " . $pkg_force . $pkg_name);
303
		/* Cleanup cacke to free disk space */
304
		pkg_call("clean -y");
305
	}
306

    
307
	return $result;
308
}
309

    
310
/* Delete package from FreeBSD, $pkg_name should not contain prefix */
311
function pkg_delete($pkg_name) {
312
	global $g;
313

    
314
	$shortname = $pkg_name;
315
	pkg_remove_prefix($shortname);
316

    
317
	pkg_debug("Removing package {$shortname}\n");
318
	if (is_pkg_installed($pkg_name)) {
319
		pkg_call("delete -y " . $pkg_name);
320
		/* Cleanup unecessary dependencies */
321
		pkg_call("autoremove -y");
322
	}
323
}
324

    
325
/* Check if package is present in config.xml */
326
function is_package_installed($package_name) {
327
	return (get_package_id($package_name) != -1);
328
}
329

    
330
/* Find package array index */
331
function get_package_id($package_name) {
332
	global $config;
333

    
334
	if (!is_array($config['installedpackages']['package'])) {
335
		return -1;
336
	}
337

    
338
	foreach ($config['installedpackages']['package'] as $idx => $pkg) {
339
		if ($pkg['name'] == $package_name ||
340
		    get_package_internal_name($pkg) == $package_name) {
341
			return $idx;
342
		}
343
	}
344

    
345
	return -1;
346
}
347

    
348
/* Return internal_name when it's defined, otherwise, returns name */
349
function get_package_internal_name($package_data) {
350
	if (isset($package_data['internal_name']) && ($package_data['internal_name'] != "")) {
351
		/* e.g. name is Ipguard-dev, internal name is ipguard */
352
		return $package_data['internal_name'];
353
	} else {
354
		return $package_data['name'];
355
	}
356
}
357

    
358
// Get information about packages.
359
function get_pkg_info($pkgs = 'all', $info = 'all', $only_local = false) {
360
	global $g, $input_errors;
361

    
362
	$out = '';
363
	$err = '';
364

    
365
	unset($pkg_filter);
366
	if (is_array($pkgs)) {
367
		$pkg_filter = $pkgs;
368
		$pkgs = 'all';
369
	}
370

    
371
	if ($pkgs == 'all') {
372
		$pkgs = $g['pkg_prefix'];
373
	}
374

    
375
	$extra_param = "";
376
	if ($only_local) {
377
		$extra_param = "-U ";
378
	}
379

    
380
	$rc = pkg_exec("search {$extra_param}--raw-format json-compact " . $pkgs, $out, $err);
381

    
382
	if ($rc != 0) {
383
		update_status("\n" . gettext(
384
		    "ERROR: Error trying to get packages list. Aborting...")
385
		    . "\n");
386
		update_status($err);
387
		$input_errors[] =  gettext("ERROR: Error trying to get packages list. Aborting...") . "\n";
388
		$input_errors[] =  $err;
389
		return array();
390
	}
391

    
392
	$result = array();
393
	$pkgs_info = explode("\n", $out);
394
	foreach ($pkgs_info as $pkg_info_json) {
395
		$pkg_info = json_decode($pkg_info_json, true);
396
		if (!isset($pkg_info['name'])) {
397
			continue;
398
		}
399

    
400
		if (isset($pkg_filter) && !in_array($pkg_info['name'], $pkg_filter)) {
401
			continue;
402
		}
403

    
404
		$pkg_info['shortname'] = $pkg_info['name'];
405
		pkg_remove_prefix($pkg_info['shortname']);
406

    
407
		/* XXX: Add it to globals.inc? */
408
		$pkg_info['changeloglink'] =
409
		    "https://github.com/pfsense/FreeBSD-ports/commits/devel/" .
410
		    $pkg_info['categories'][0] . '/' . $pkg_info['name'];
411

    
412
		if (is_pkg_installed($pkg_info['name'])) {
413
			$pkg_info['installed'] = true;
414

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

    
417
			if ($rc != 0) {
418
				update_status("\n" . gettext(
419
				    "ERROR: Error trying to get package version. Aborting...")
420
				    . "\n");
421
				update_status($err);
422
				$input_errors[] =  gettext("ERROR: Error trying to get package version. Aborting...") . "\n";
423
				$input_errors[] =  $err;
424
				return array();
425
			}
426

    
427
			$pkg_info['installed_version'] = str_replace("\n", "", $out);
428
		} else if (is_package_installed($pkg_info['shortname'])) {
429
			$pkg_info['broken'] = true;
430
		}
431

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

    
434
		$result[] = $pkg_info;
435
		unset($pkg_info);
436
	}
437

    
438
	/* Sort result alphabetically */
439
	usort($result, function($a, $b) {
440
		return(strcasecmp ($a['name'], $b['name']));
441
	});
442

    
443
	return $result;
444
}
445

    
446
/*
447
 * If binary pkg is installed but post-install tasks were not
448
 * executed yet, do it now.
449
 * This scenario can happen when a pkg is pre-installed during
450
 * build phase, and at this point, cannot find a running system
451
 * to register itself in config.xml and also execute custom
452
 * install functions
453
 */
454
function register_all_installed_packages() {
455
	global $g, $config, $pkg_interface;
456

    
457
	$pkg_info = get_pkg_info('all', 'all', true);
458

    
459
	foreach ($pkg_info as $pkg) {
460
		if (!isset($pkg['installed'])) {
461
			continue;
462
		}
463

    
464
		pkg_remove_prefix($pkg['name']);
465

    
466
		if (is_package_installed($pkg['name'])) {
467
			continue;
468
		}
469

    
470
		update_status(sprintf(gettext(
471
		    "Running last steps of %s installation.") . "\n",
472
		    $pkg['name']));
473
		install_package_xml($pkg['name']);
474
	}
475
}
476

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

    
484
	log_error(gettext("Resyncing configuration for all packages."));
485

    
486
	if (!is_array($config['installedpackages']['package'])) {
487
		return;
488
	}
489

    
490
	if ($show_message == true) {
491
		echo "Syncing packages:";
492
	}
493

    
494
	conf_mount_rw();
495

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

    
510
	if ($show_message == true) {
511
		echo " done.\n";
512
	}
513

    
514
	@unlink("/conf/needs_package_sync");
515
	conf_mount_ro();
516
}
517

    
518
function uninstall_package($package_name) {
519
	global $config;
520

    
521
	$internal_name = $package_name;
522
	$id = get_package_id($package_name);
523
	if ($id >= 0) {
524
		$internal_name = get_package_internal_name($config['installedpackages']['package'][$id]);
525
		stop_service($internal_name);
526
	}
527
	$pkg_name = $g['pkg_prefix'] . $internal_name;
528

    
529
	if (is_pkg_installed($pkg_name)) {
530
		update_status(gettext("Removing package...") . "\n");
531
		pkg_delete($pkg_name);
532
	} else {
533
		delete_package_xml($package_name);
534
	}
535

    
536
	update_status(gettext("done.") . "\n");
537
}
538

    
539
/* Run <custom_php_resync_config_command> */
540
function sync_package($package_name) {
541
	global $config, $builder_package_install;
542

    
543
	// If this code is being called by pfspkg_installer
544
	// which the builder system uses then return (ignore).
545
	if ($builder_package_install) {
546
		return;
547
	}
548

    
549
	if (empty($config['installedpackages']['package'])) {
550
		return;
551
	}
552

    
553
	if (($pkg_id = get_package_id($package_name)) == -1) {
554
		return; // This package doesn't really exist - exit the function.
555
	}
556

    
557
	if (!is_array($config['installedpackages']['package'][$pkg_id])) {
558
		return;	 // No package belongs to the pkg_id passed to this function.
559
	}
560

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

    
568
	$pkg_config = parse_xml_config_pkg("/usr/local/pkg/" . $package['configurationfile'], "packagegui");
569
	if (isset($pkg_config['nosync'])) {
570
		return;
571
	}
572

    
573
	/* Bring in package include files */
574
	if (!empty($pkg_config['include_file'])) {
575
		$include_file = $pkg_config['include_file'];
576
		if (file_exists($include_file)) {
577
			require_once($include_file);
578
		} else {
579
			log_error(sprintf(gettext('Reinstalling package %1$s because its include file(%2$s) is missing!'), $package['name'], $include_file));
580
			uninstall_package($package['name']);
581
			if (install_package($package['name']) != 0) {
582
				log_error(sprintf(gettext("Reinstalling package %s failed. Take appropriate measures!!!"), $package['name']));
583
				return;
584
			}
585
			if (file_exists($include_file)) {
586
				require_once($include_file);
587
			} else {
588
				return;
589
			}
590
		}
591
	}
592

    
593
	if (!empty($pkg_config['custom_php_global_functions'])) {
594
		eval($pkg_config['custom_php_global_functions']);
595
	}
596
	if (!empty($pkg_config['custom_php_resync_config_command'])) {
597
		eval($pkg_config['custom_php_resync_config_command']);
598
	}
599
}
600

    
601
/* Read info.xml installed by package and return an array */
602
function read_package_config($package_name) {
603
	global $g;
604

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

    
607
	if (!file_exists($pkg_info_xml)) {
608
		return false;
609
	}
610

    
611
	$pkg_info = parse_xml_config_pkg($pkg_info_xml, 'pfsensepkgs');
612

    
613
	if (empty($pkg_info)) {
614
		return false;
615
	}
616

    
617
	/* it always returns an array with 1 item */
618
	return $pkg_info['package'][0];
619
}
620

    
621
/* Read package configurationfile and return an array */
622
function read_package_configurationfile($package_name) {
623
	global $config, $g;
624

    
625
	$pkg_config = array();
626
	$id = get_package_id($package_name);
627

    
628
	if ($id < 0 || !isset($config['installedpackages']['package'][$id]['configurationfile'])) {
629
		return $pkg_config;
630
	}
631

    
632
	$pkg_configurationfile = $config['installedpackages']['package'][$id]['configurationfile'];
633

    
634
	if (empty($pkg_configurationfile) || !file_exists('/usr/local/pkg/' . $pkg_configurationfile)) {
635
		return $pkg_config;
636
	}
637

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

    
640
	return $pkg_config;
641
}
642

    
643
function get_after_install_info($package_name) {
644
	$pkg_config = read_package_config($package_name);
645

    
646
	if (isset($pkg_config['after_install_info'])) {
647
		return $pkg_config['after_install_info'];
648
	}
649

    
650
	return '';
651
}
652

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

    
666
function install_package_xml($package_name) {
667
	global $g, $config, $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
	update_status(gettext("Saving updated package information...") . "\n");
682
	if ($pkgid == -1) {
683
		$config['installedpackages']['package'][] = $pkg_info;
684
		$changedesc = sprintf(gettext("Installed %s package."), $pkg_info['name']);
685
		$to_output = gettext("done.") . "\n";
686
	} else {
687
		$config['installedpackages']['package'][$pkgid] = $pkg_info;
688
		$changedesc = sprintf(gettext("Overwrote previous installation of %s."), $pkg_info['name']);
689
		$to_output = gettext("overwrite!") . "\n";
690
	}
691
	unlink_if_exists('/conf/needs_package_sync');
692
	write_config(sprintf(gettext("Intermediate config write during package install for %s."), $pkg_info['name']));
693
	conf_mount_ro();
694
	update_status($to_output);
695

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

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

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

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

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

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

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

    
804
	/* set up package logging streams */
805
	if ($pkg_info['logging']) {
806
		system_syslogd_start();
807
	}
808

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

    
817
	return true;
818
}
819

    
820
function delete_package_xml($package_name, $when = "post-deinstall") {
821
	global $g, $config, $pkg_interface;
822

    
823
	conf_mount_rw();
824

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

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

    
939
	if ($when == "post-deinstall") {
940
		/* remove config.xml entries */
941
		update_status(gettext("Configuration... "));
942
		unset($config['installedpackages']['package'][$pkgid]);
943
		update_status(gettext("done.") . "\n");
944
		write_config(sprintf(gettext("Removed %s package."), $package_name));
945
	}
946

    
947
	/* remove package entry from /etc/syslog.conf if needed */
948
	/* this must be done after removing the entries from config.xml */
949
	if ($need_syslog_restart) {
950
		system_syslogd_start();
951
	}
952

    
953
	conf_mount_ro();
954
}
955

    
956
/*
957
 * Used during upgrade process or retore backup process, verify all
958
 * packages installed in config.xml and install pkg accordingly
959
 */
960
function package_reinstall_all() {
961
	global $g, $config, $pkg_interface;
962

    
963
	if (!isset($config['installedpackages']['package']) ||
964
	    !is_array($config['installedpackages']['package'])) {
965
		return true;
966
	}
967

    
968
	$upgrade = (file_exists('/conf/needs_package_sync') && platform_booting());
969

    
970
	/* During boot after upgrade, wait for internet connection */
971
	if ($upgrade) {
972
		update_status(gettext("Waiting for internet connection to update pkg metadata and finish package reinstallation"));
973
		while (true) {
974
			if (pkg_update(true)) {
975
				break;
976
			}
977
			update_status('.');
978
			sleep(1);
979
		}
980
		update_status("\n");
981
	}
982

    
983
	$pkg_info = get_pkg_info();
984

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

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

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

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

    
1013
	return true;
1014
}
1015

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

    
1026
	global $config, $g;
1027

    
1028
	log_error(gettext("Stopping all packages."));
1029

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

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

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

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

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

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

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

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

    
1097
	$base_pkg = get_base_pkg_name();
1098
	$meta_pkg = get_meta_pkg_name();
1099

    
1100
	if (!$base_pkg || !$meta_pkg) {
1101
		return false;
1102
	}
1103

    
1104
	$info = get_pkg_info($base_pkg);
1105
	$pkg_name = $base_pkg;
1106

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

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

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

    
1126
	if (empty($pkg_info)) {
1127
		return false;
1128
	}
1129

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

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

    
1141
	$repo_stable = $g['product_name'] . '-repo';
1142
	$repo_devel = $g['product_name'] . '-repo-devel';
1143

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

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

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

    
1163
?>
(40-40/65)