Project

General

Profile

Download (32.7 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * pkg-utils.inc
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2005-2006 Colin Smith (ethethlay@gmail.com)
7
 * Copyright (c) 2004-2016 Electric Sheep Fencing, LLC
8
 * All rights reserved.
9
 *
10
 * Licensed under the Apache License, Version 2.0 (the "License");
11
 * you may not use this file except in compliance with the License.
12
 * You may obtain a copy of the License at
13
 *
14
 * http://www.apache.org/licenses/LICENSE-2.0
15
 *
16
 * Unless required by applicable law or agreed to in writing, software
17
 * distributed under the License is distributed on an "AS IS" BASIS,
18
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
 * See the License for the specific language governing permissions and
20
 * limitations under the License.
21
 */
22

    
23
require_once("globals.inc");
24
require_once("service-utils.inc");
25

    
26
if (file_exists("/cf/conf/use_xmlreader")) {
27
	require_once("xmlreader.inc");
28
} else {
29
	require_once("xmlparse.inc");
30
}
31

    
32
require_once("pfsense-utils.inc");
33

    
34
if (!function_exists("pkg_debug")) {
35
	/* set up logging if needed */
36
	function pkg_debug($msg) {
37
		global $g, $debug, $fd_log;
38

    
39
		if (!$debug) {
40
			return;
41
		}
42

    
43
		if (!$fd_log) {
44
			if (!$fd_log = fopen("{$g['tmp_path']}/pkg_mgr_debug.log", "w")) {
45
				update_status(gettext("Warning, could not open log for writing.") . "\n");
46
			}
47
		}
48
		@fwrite($fd_log, $msg);
49
	}
50
}
51

    
52
/* Validate if pkg name is valid */
53
function pkg_valid_name($pkgname) {
54
	global $g;
55

    
56
	$pattern = "/^{$g['pkg_prefix']}[a-zA-Z0-9\.\-_]+$/";
57
	return preg_match($pattern, $pkgname);
58
}
59

    
60
/* Remove pkg_prefix from package name if it's present */
61
function pkg_remove_prefix(&$pkg_name) {
62
	global $g;
63

    
64
	if (substr($pkg_name, 0, strlen($g['pkg_prefix'])) == $g['pkg_prefix']) {
65
		$pkg_name = substr($pkg_name, strlen($g['pkg_prefix']));
66
	}
67
}
68

    
69
/* Execute pkg update when it's necessary */
70
function pkg_update($force = false) {
71
	global $g;
72

    
73
	return pkg_call("update" . ($force ? " -f" : ""));
74
}
75

    
76
/* return an array with necessary environment vars for pkg */
77
function pkg_env($extra_env = array()) {
78
	global $config, $g;
79

    
80
	$pkg_env_vars = array(
81
		"LANG" => "C",
82
		"HTTP_USER_AGENT" => $user_agent,
83
		"ASSUME_ALWAYS_YES" => "true",
84
		"FETCH_TIMEOUT" => 5,
85
		"FETCH_RETRY" => 2
86
	);
87

    
88
	if (!empty($config['system']['proxyurl'])) {
89
		$http_proxy = $config['system']['proxyurl'];
90
		if (!empty($config['system']['proxyport'])) {
91
			$http_proxy .= ':' . $config['system']['proxyport'];
92
		}
93
		$pkg_env_vars['HTTP_PROXY'] = $http_proxy;
94
	}
95

    
96
	if ($g['platform'] == "nanobsd" ||
97
	    isset($config['system']['use_mfs_tmpvar'])) {
98
		$pkg_env_vars['PKG_DBDIR'] = '/root/var/db/pkg';
99
		$pkg_env_vars['PKG_CACHEDIR'] = '/root/var/cache/pkg';
100
	}
101

    
102
	foreach ($extra_env as $key => $value) {
103
		$pkg_env_vars[$key] = $value;
104
	}
105

    
106
	return $pkg_env_vars;
107
}
108

    
109
/* Execute a pkg call */
110
function pkg_call($params, $mute = false, $extra_env = array()) {
111
	global $g, $config;
112

    
113
	if (empty($params)) {
114
		return false;
115
	}
116

    
117
	$user_agent = $g['product_name'] . '/' . $g['product_version'];
118
	if (!isset($config['system']['do_not_send_host_uuid'])) {
119
		$user_agent .= ' : ' . get_single_sysctl('kern.hostuuid');
120
	}
121

    
122
	$descriptorspec = array(
123
		1 => array("pipe", "w"), /* stdout */
124
		2 => array("pipe", "w")	 /* stderr */
125
	);
126

    
127
	conf_mount_rw();
128

    
129
	pkg_debug("pkg_call(): {$params}\n");
130
	$process = proc_open("/usr/sbin/pkg {$params}", $descriptorspec, $pipes,
131
	    '/', pkg_env($extra_env));
132

    
133
	if (!is_resource($process)) {
134
		conf_mount_ro();
135
		return false;
136
	}
137

    
138
	stream_set_blocking($pipes[1], 0);
139
	stream_set_blocking($pipes[2], 0);
140

    
141
	/* XXX: should be a tunnable? */
142
	$timeout = 300; // seconds
143
	$error_log = '';
144

    
145
	do {
146
		$write = array();
147
		$read = array($pipes[1], $pipes[2]);
148
		$except = array();
149

    
150
		$stream = stream_select($read, $write, $except, null, $timeout);
151
		if ($stream !== FALSE && $stream > 0) {
152
			foreach ($read as $pipe) {
153
				$content = stream_get_contents($pipe);
154
				if ($content == '') {
155
					continue;
156
				}
157
				if ($pipe === $pipes[1]) {
158
					if (!$mute) {
159
						update_status($content);
160
					}
161
					flush();
162
				} else if ($pipe === $pipes[2]) {
163
					$error_log .= $content;
164
				}
165
			}
166
		}
167

    
168
		$status = proc_get_status($process);
169
	} while ($status['running']);
170

    
171
	fclose($pipes[1]);
172
	fclose($pipes[2]);
173
	proc_close($process);
174

    
175
	conf_mount_ro();
176

    
177
	$rc = $status['exitcode'];
178

    
179
	pkg_debug("pkg_call(): rc = {$rc}\n");
180
	if ($rc == 0) {
181
		return true;
182
	}
183

    
184
	pkg_debug("pkg_call(): error_log\n{$error_log}\n");
185
	if (!$mute) {
186
		update_status("\n\n" .  sprintf(gettext(
187
		    "ERROR!!! An error occurred on pkg execution (rc = %d) with parameters '%s':"),
188
		    $rc, $params) . "\n" . $error_log . "\n");
189
	}
190

    
191
	return false;
192
}
193

    
194
/* Execute pkg with $params, fill stdout and stderr and return pkg rc */
195
function pkg_exec($params, &$stdout, &$stderr, $extra_env = array()) {
196
	global $g, $config;
197

    
198
	if (empty($params)) {
199
		return -1;
200
	}
201

    
202
	$user_agent = $g['product_name'] . '/' . $g['product_version'];
203
	if (!isset($config['system']['do_not_send_host_uuid'])) {
204
		$user_agent .= ' : ' . get_single_sysctl('kern.hostuuid');
205
	}
206

    
207
	$descriptorspec = array(
208
		1 => array("pipe", "w"), /* stdout */
209
		2 => array("pipe", "w")	 /* stderr */
210
	);
211

    
212
	conf_mount_rw();
213

    
214
	pkg_debug("pkg_exec(): {$params}\n");
215
	$process = proc_open("/usr/sbin/pkg {$params}", $descriptorspec, $pipes,
216
	    '/', pkg_env($extra_env));
217

    
218
	if (!is_resource($process)) {
219
		conf_mount_ro();
220
		return -1;
221
	}
222

    
223
	$stdout = '';
224
	while (($l = fgets($pipes[1])) !== FALSE) {
225
		$stdout .= $l;
226
	}
227
	fclose($pipes[1]);
228

    
229
	$stderr = '';
230
	while (($l = fgets($pipes[2])) !== FALSE) {
231
		$stderr .= $l;
232
	}
233
	fclose($pipes[2]);
234

    
235
	conf_mount_ro();
236

    
237
	return proc_close($process);
238
}
239

    
240
/* Compare 2 pkg versions and return:
241
 * '=' - versions are the same
242
 * '>' - $v1 > $v2
243
 * '<' - $v1 < $v2
244
 * '?' - Error
245
 */
246
function pkg_version_compare($v1, $v2) {
247
	if (empty($v1) || empty($v2)) {
248
		return '?';
249
	}
250

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

    
253
	if ($rc != 0) {
254
		return '?';
255
	}
256

    
257
	return str_replace("\n", "", $stdout);
258
}
259

    
260
/* Check if package is installed */
261
function is_pkg_installed($pkg_name) {
262
	global $g;
263

    
264
	if (empty($pkg_name)) {
265
		return false;
266
	}
267

    
268
	return pkg_call("info -e " . $pkg_name, true);
269
}
270

    
271
/* Install package, $pkg_name should not contain prefix */
272
function pkg_install($pkg_name, $force = false) {
273
	global $g;
274
	$result = false;
275

    
276
	$shortname = $pkg_name;
277
	pkg_remove_prefix($shortname);
278

    
279
	$pkg_force = "";
280
	if ($force) {
281
		$pkg_force = "-f ";
282
	}
283

    
284
	pkg_debug("Installing package {$shortname}\n");
285
	if ($force || !is_pkg_installed($pkg_name)) {
286
		$result = pkg_call("install -y " . $pkg_force . $pkg_name);
287
		/* Cleanup cacke to free disk space */
288
		pkg_call("clean -y");
289
	}
290

    
291
	return $result;
292
}
293

    
294
/* Delete package from FreeBSD, $pkg_name should not contain prefix */
295
function pkg_delete($pkg_name) {
296
	global $g;
297

    
298
	$shortname = $pkg_name;
299
	pkg_remove_prefix($shortname);
300

    
301
	pkg_debug("Removing package {$shortname}\n");
302
	if (is_pkg_installed($pkg_name)) {
303
		pkg_call("delete -y " . $pkg_name);
304
		/* Cleanup unecessary dependencies */
305
		pkg_call("autoremove -y");
306
	}
307
}
308

    
309
/* Check if package is present in config.xml */
310
function is_package_installed($package_name) {
311
	return (get_package_id($package_name) != -1);
312
}
313

    
314
/* Find package array index */
315
function get_package_id($package_name) {
316
	global $config;
317

    
318
	if (!is_array($config['installedpackages']['package'])) {
319
		return -1;
320
	}
321

    
322
	foreach ($config['installedpackages']['package'] as $idx => $pkg) {
323
		if ($pkg['name'] == $package_name ||
324
		    get_package_internal_name($pkg) == $package_name) {
325
			return $idx;
326
		}
327
	}
328

    
329
	return -1;
330
}
331

    
332
/* Return internal_name when it's defined, otherwise, returns name */
333
function get_package_internal_name($package_data) {
334
	if (isset($package_data['internal_name']) && ($package_data['internal_name'] != "")) {
335
		/* e.g. name is Ipguard-dev, internal name is ipguard */
336
		return $package_data['internal_name'];
337
	} else {
338
		return $package_data['name'];
339
	}
340
}
341

    
342
// Get information about packages.
343
function get_pkg_info($pkgs = 'all', $info = 'all', $only_local = false) {
344
	global $g, $input_errors;
345

    
346
	$out = '';
347
	$err = '';
348

    
349
	unset($pkg_filter);
350
	if (is_array($pkgs)) {
351
		$pkg_filter = $pkgs;
352
		$pkgs = 'all';
353
	}
354

    
355
	if ($pkgs == 'all') {
356
		$pkgs = $g['pkg_prefix'];
357
	}
358

    
359
	if (!function_exists('is_subsystem_dirty')) {
360
		require_once("util.inc");
361
	}
362

    
363
	/* Do not run remote operations if pkg has a lock */
364
	if (is_subsystem_dirty('pkg')) {
365
		$only_local = true;
366
		$lock = false;
367
	} else {
368
		$lock = true;
369
	}
370

    
371
	$extra_param = "";
372
	if ($only_local) {
373
		$extra_param = "-U ";
374
	}
375

    
376
	if ($lock) {
377
		mark_subsystem_dirty('pkg');
378
	}
379
	$rc = pkg_exec("search {$extra_param}-R --raw-format json-compact " . $pkgs, $out, $err);
380
	if ($lock) {
381
		clear_subsystem_dirty('pkg');
382
	}
383

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

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

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

    
406
		$pkg_info['shortname'] = $pkg_info['name'];
407
		pkg_remove_prefix($pkg_info['shortname']);
408

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

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

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

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

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

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

    
436
		$result[] = $pkg_info;
437
		unset($pkg_info);
438
	}
439

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

    
445
	return $result;
446
}
447

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

    
459
	$pkg_info = get_pkg_info('all', 'all', true);
460

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

    
466
		pkg_remove_prefix($pkg['name']);
467

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

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

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

    
486
	log_error(gettext("Resyncing configuration for all packages."));
487

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

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

    
496
	conf_mount_rw();
497

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

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

    
516
	@unlink("/conf/needs_package_sync");
517
	conf_mount_ro();
518
}
519

    
520
function uninstall_package($package_name) {
521
	global $config;
522

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

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

    
538
	update_status(gettext("done.") . "\n");
539
}
540

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

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

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

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

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

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

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

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

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

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

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

    
609
	if (!file_exists($pkg_info_xml)) {
610
		return false;
611
	}
612

    
613
	$pkg_info = parse_xml_config_pkg($pkg_info_xml, 'pfsensepkgs');
614

    
615
	if (empty($pkg_info)) {
616
		return false;
617
	}
618

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

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

    
627
	$pkg_config = array();
628
	$id = get_package_id($package_name);
629

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

    
634
	$pkg_configurationfile = $config['installedpackages']['package'][$id]['configurationfile'];
635

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

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

    
642
	return $pkg_config;
643
}
644

    
645
function get_after_install_info($package_name) {
646
	$pkg_config = read_package_config($package_name);
647

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

    
652
	return '';
653
}
654

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

    
668
function install_package_xml($package_name) {
669
	global $g, $config, $pkg_interface;
670

    
671
	if (($pkg_info = read_package_config($package_name)) == false) {
672
		return false;
673
	}
674

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

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

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

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

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

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

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

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

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

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

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

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

    
819
	return true;
820
}
821

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

    
825
	conf_mount_rw();
826

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

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

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

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

    
955
	conf_mount_ro();
956
}
957

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

    
965
	$upgrade = (file_exists('/conf/needs_package_sync') && platform_booting());
966

    
967
	if ((!isset($config['installedpackages']['package']) ||
968
	    !is_array($config['installedpackages']['package'])) && !$upgrade) {
969
		return true;
970
	}
971

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

    
986
		if ($ntries == 0) {
987
			file_notice(gettext("Package reinstall"),
988
			    gettext("Package reinstall process was ABORTED due to lack of internet connectivity"));
989
			return false;
990
		}
991
	}
992

    
993
	$pkg_info = get_pkg_info();
994

    
995
	if ($upgrade &&
996
	    file_exists("{$g['cf_conf_path']}/packages_to_reinstall_after_upgrade.txt")) {
997
		$package_list = file("{$g['cf_conf_path']}/packages_to_reinstall_after_upgrade.txt",
998
		    FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
999
		unlink_if_exists("{$g['cf_conf_path']}/packages_to_reinstall_after_upgrade.txt");
1000
	} else {
1001
		if (!isset($config['installedpackages']['package']) || !is_array($config['installedpackages']['package'])) {
1002
			return true;
1003
		}
1004
		$package_list = array();
1005
		foreach ($config['installedpackages']['package'] as $package) {
1006
			$package_list[] = get_package_internal_name($package);
1007
		}
1008
	}
1009

    
1010
	foreach ($package_list as $package) {
1011
		$found = false;
1012
		foreach ($pkg_info as $pkg) {
1013
			pkg_remove_prefix($pkg['name']);
1014
			if ($pkg['name'] == $package) {
1015
				pkg_install($g['pkg_prefix'] . $package, true);
1016
				$found = true;
1017
				break;
1018
			}
1019
		}
1020

    
1021
		if (!$found) {
1022
			if (!function_exists("file_notice")) {
1023
				require_once("notices.inc");
1024
			}
1025

    
1026
			file_notice(gettext("Package reinstall"),
1027
			    sprintf(gettext("Package %s does not exist in current %s version and it has been removed."),
1028
			    $package, $g['product_name']));
1029
			uninstall_package($package);
1030
		}
1031
	}
1032

    
1033
	return true;
1034
}
1035

    
1036
function stop_packages() {
1037
	require_once("config.inc");
1038
	require_once("functions.inc");
1039
	require_once("filter.inc");
1040
	require_once("shaper.inc");
1041
	require_once("captiveportal.inc");
1042
	require_once("pkg-utils.inc");
1043
	require_once("pfsense-utils.inc");
1044
	require_once("service-utils.inc");
1045

    
1046
	global $config, $g;
1047

    
1048
	log_error(gettext("Stopping all packages."));
1049

    
1050
	$rcfiles = glob(RCFILEPREFIX . "*.sh");
1051
	if (!$rcfiles) {
1052
		$rcfiles = array();
1053
	} else {
1054
		$rcfiles = array_flip($rcfiles);
1055
		if (!$rcfiles) {
1056
			$rcfiles = array();
1057
		}
1058
	}
1059

    
1060
	if (is_array($config['installedpackages']['package'])) {
1061
		foreach ($config['installedpackages']['package'] as $package) {
1062
			echo " Stopping package {$package['name']}...";
1063
			$internal_name = get_package_internal_name($package);
1064
			stop_service($internal_name);
1065
			unset($rcfiles[RCFILEPREFIX . strtolower($internal_name) . ".sh"]);
1066
			echo "done.\n";
1067
		}
1068
	}
1069

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

    
1086
/* Identify which meta package is installed */
1087
function get_meta_pkg_name() {
1088
	global $g;
1089

    
1090
	/* XXX: Use pkg annotation */
1091
	if (is_pkg_installed($g['product_name'])) {
1092
		return $g['product_name'];
1093
	} else if (is_pkg_installed($g['product_name'] . '-vmware')) {
1094
		return $g['product_name'] . '-vmware';
1095
	}
1096
	return false;
1097
}
1098

    
1099
/* Identify which base package is installed */
1100
function get_base_pkg_name() {
1101
	global $g;
1102

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

    
1112
/* Verify if system needs upgrade (meta package or base) */
1113
function get_system_pkg_version($baseonly = false) {
1114
	global $g;
1115

    
1116
	$base_pkg = get_base_pkg_name();
1117
	$meta_pkg = get_meta_pkg_name();
1118

    
1119
	if (!$base_pkg || !$meta_pkg) {
1120
		return false;
1121
	}
1122

    
1123
	$info = get_pkg_info($base_pkg);
1124
	$pkg_name = $base_pkg;
1125

    
1126
	$pkg_info = array();
1127
	foreach ($info as $item) {
1128
		if ($item['name'] == $base_pkg) {
1129
			$pkg_info = $item;
1130
		}
1131
	}
1132

    
1133
	if (empty($pkg_info) || (!$baseonly && ($pkg_info['version'] == $pkg_info['installed_version']))) {
1134
		$info = get_pkg_info($meta_pkg);
1135
		$pkg_name = $meta_pkg;
1136

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

    
1144
	if (empty($pkg_info)) {
1145
		return false;
1146
	}
1147

    
1148
	return array(
1149
	    'pkg_name'          => $pkg_name,
1150
	    'version'           => $pkg_info['version'],
1151
	    'installed_version' => $pkg_info['installed_version']
1152
	);
1153
}
1154

    
1155
/* List available repos */
1156
function pkg_list_repos() {
1157
	global $g;
1158

    
1159
	$path = "/usr/local/share/{$g['product_name']}/pkg/repos";
1160

    
1161
	$default_descr = @file_get_contents($path . "/{$g['product_name']}-repo.descr");
1162

    
1163
	$default = array(
1164
	    'name' => 'Default',
1165
	    'path' => $path . "/{$g['product_name']}-repo.conf",
1166
	    'descr' => $default_descr
1167
	);
1168

    
1169
	$result = array($default);
1170

    
1171
	$conf_files = glob("{$path}/{$g['product_name']}-repo-*.conf");
1172
	foreach ($conf_files as $conf_file) {
1173
		$descr_file = preg_replace('/.conf$/', '.descr', $conf_file);
1174
		if (file_exists($descr_file)) {
1175
			$descr_content = file($descr_file);
1176
			$descr = chop($descr_content[0]);
1177
		} else {
1178
			$descr = 'Unknown';
1179
		}
1180
		if (!preg_match('/-repo-(.*).conf/', $conf_file, $matches)) {
1181
			continue;
1182
		}
1183
		$entry = array(
1184
		    'name' => ucfirst(strtolower($matches[1])),
1185
		    'path' => $conf_file,
1186
		    'descr' => $descr
1187
		);
1188
		$result[] = $entry;
1189
	}
1190

    
1191
	return $result;
1192
}
1193

    
1194
/* Switch between stable and devel repos */
1195
function pkg_switch_repo($path) {
1196
	global $g;
1197

    
1198
	safe_mkdir("/usr/local/etc/pkg/repos");
1199
	@unlink("/usr/local/etc/pkg/repos/{$g['product_name']}.conf");
1200
	@symlink($path, "/usr/local/etc/pkg/repos/{$g['product_name']}.conf");
1201

    
1202
	return pkg_update(true);
1203
}
1204

    
1205
?>
(31-31/53)