Project

General

Profile

Download (24.3 KB) Statistics
| Branch: | Tag: | Revision:
1
#!/bin/sh
2
#
3
# pfSense-upgrade
4
#
5
# part of pfSense (https://www.pfsense.org)
6
# Copyright (c) 2015-2016 Electric Sheep Fencing, LLC
7
# All rights reserved.
8
#
9
# Redistribution and use in source and binary forms, with or without
10
# modification, 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
usage() {
54
	echo "Usage: $(basename ${0}) [-46bdyf] [-u|-i PKG_NAME|-r PKG_NAME]" >&2
55
	echo "	-4          - Force IPv4"
56
	echo "	-6          - Force IPv6"
57
	echo "	-b          - Platform is booting" >&2
58
	echo "	-c          - Check if upgrade is necessary" >&2
59
	echo "	-d          - Turn on debug" >&2
60
	echo "	-f          - Force package installation" >&2
61
	echo "	-h          - Show this usage help" >&2
62
	echo "	-l          - Logfile path (defaults to /cf/conf/upgrade_log.txt)" >&2
63
	echo "	-n          - Dry run" >&2
64
	echo "	-p socket   - Write pkg progress to socket"
65
	echo "	-R          - Do not reboot (this can be dangerous)"
66
	echo "	-y          - Assume yes as the answer to any possible interaction" >&2
67
	echo "" >&2
68
	echo "The following parameters are mutually exclusive:" >&2
69
	echo "	-i PKG_NAME - Install package PKG_NAME" >&2
70
	echo "	-r PKG_NAME - Remove package PKG_NAME" >&2
71
	echo "	-u          - Update repository information" >&2
72
}
73

    
74
_echo() {
75
	local _n=""
76
	if [ "${1}" = "-n" ]; then
77
		shift
78
		_n="-n"
79
	fi
80

    
81
	if [ -z "${logfile}" ]; then
82
		logfile=/dev/null
83
	fi
84

    
85
	echo ${_n} "${1}" | tee -a ${logfile}
86
}
87

    
88
_exec() {
89
	local _cmd="${1}"
90
	local _msg="${2}"
91
	local _mute="${3}"
92
	local _ignore_result="${4}"
93
	local _stdout="${stdout}"
94

    
95
	if [ -z "${_cmd}" -o -z "${_msg}" ]; then
96
		return 1
97
	fi
98

    
99
	if [ "${_mute}" != "mute" ]; then
100
		_stdout=''
101
	fi
102

    
103
	_echo -n ">>> ${_msg}... "
104
	if [ -z "${_stdout}" ]; then
105
		_echo ""
106
		# Ref. http://stackoverflow.com/questions/1221833/bash-pipe-output-and-capture-exit-status
107
		exec 4>&1
108
		local _result=$({ { ${_cmd} 2>&1 3>&-; printf $? 1>&3; } 4>&- | \
109
			tee -a ${logfile} 1>&4; } 3>&1)
110
		exec 4>&-
111
	else
112
		# Ref. http://stackoverflow.com/questions/1221833/bash-pipe-output-and-capture-exit-status
113
		exec 4>&1
114
		local _result=$({ { ${_cmd} >${_stdout} 2>&1 3>&-; printf $? 1>&3; } 4>&- | \
115
			tee -a ${logfile} 1>&4; } 3>&1)
116
		exec 4>&-
117
	fi
118

    
119
	if [ ${_result} -eq 0 -o -n "${_ignore_result}" ]; then
120
		[ -n "${_stdout}" ] \
121
			&& _echo "done."
122
		return 0
123
	else
124
		[ -n "${_stdout}" ] \
125
			&& _echo "failed."
126
		_exit 1
127
	fi
128
}
129

    
130
_exit() {
131
	trap "-" 1 2 15 EXIT
132

    
133
	pkg_lock ${kernel_pkg}
134

    
135
	if [ -f "${pid_file}" ]; then
136
		rm -f ${pid_file}
137
	fi
138

    
139
	if [ -n "${chroot_dir}" ]; then
140
		umount -f ${chroot_dir} >/dev/null 2>&1
141
	fi
142

    
143
	if [ -z "${booting}" -o "${boot_stage}" != "2" ]; then
144
		/usr/local/bin/php /etc/rc.conf_mount_ro
145
	fi
146

    
147
	if [ -n "${nc_pid}" ] && ps -p ${nc_pid} >/dev/null 2>&1; then
148
		kill ${nc_pid}
149
	fi
150

    
151
	if [ -n "${delete_annotation}" ]; then
152
		pkg ${pkg_chroot} annotate -q -D ${kernel_pkg} next_stage
153
	fi
154

    
155
	if [ -n "${unlock_additional_pkgs}" ]; then
156
		pkg_unlock "${pkg_prefix}*"
157
	fi
158

    
159
	local _rc=${1:-"0"}
160

    
161
	# If EVENT_PIPE is defined, GUI is calling
162
	if [ -n "${progress_socket}" ]; then
163
		local _need_reboot_str=""
164
		[ -n "${need_reboot}" ] \
165
			&& _need_reboot_str=" __REBOOT_AFTER=${reboot_after}"
166
		_echo "__RC=${_rc}${_need_reboot_str}"
167
	fi
168

    
169
	exit ${_rc}
170
}
171

    
172
pkg_with_pb() {
173
	local _event_pipe=""
174

    
175
	if [ -n "${progress_socket}" ]; then
176
		if [ -e "${chroot_dir}${progress_socket}" ]; then
177
			rm -f ${chroot_dir}${progress_socket}
178
		fi
179

    
180
		_event_pipe="-o EVENT_PIPE=${progress_socket}"
181

    
182
		nc -lU ${chroot_dir}${progress_socket} >> ${progress_file} &
183
		nc_pid=$!
184

    
185
		while [ ! -e "${chroot_dir}${progress_socket}" ]; do
186
			sleep 0.1
187
		done
188
	fi
189

    
190
	pkg ${_event_pipe} $@
191
	local _pkg_result=$?
192
	nc_pid=""
193
	return ${_pkg_result}
194
}
195

    
196
fetch_upgrade_packages() {
197
	local _pkgs_to_fetch=""
198
	if [ "${platform}" = "nanobsd" ]; then
199
		local _pkg=""
200

    
201
		# Check if all non-auto packages installed on 2nd partition are
202
		# installed on current one, if not, mark them to be deleted by
203
		# pkg autoremove
204
		for _pkg in $(pkg ${pkg_chroot} query -e '%a == 0' %n); do
205
			if ! pkg info -e ${_pkg}; then
206
				_exec "pkg ${pkg_chroot} set -A 1 ${_pkg}" "Scheduling package ${_pkg} for removal"
207
			fi
208
		done
209

    
210
		# Check if all non-auto packages installed on current partition are
211
		# installed on 2nd one, if not, we need to fetch them
212
		for _pkg in $(pkg query -e '%a == 0' %n); do
213
			if ! pkg ${pkg_chroot} info -e ${_pkg}; then
214
				_pkgs_to_fetch="${_pkgs_to_fetch}${_pkgs_to_fetch:+ }${_pkg}"
215
			fi
216
		done
217

    
218
	fi
219

    
220
	_exec "pkg_with_pb ${pkg_chroot} upgrade -F" "Downloading upgrade packages"
221

    
222
	if [ -n "${_pkgs_to_fetch}" ]; then
223
		_exec "pkg_with_pb ${pkg_chroot} fetch -d ${_pkgs_to_fetch}" \
224
			"Fetching packages not present on upgrade partition"
225
	fi
226
}
227

    
228
pkg_lock() {
229
	local _pkg="${1}"
230

    
231
	if [ -z "${_pkg}" ]; then
232
		return
233
	fi
234

    
235
	if [ "$(pkg ${pkg_chroot} query %k ${_pkg})" = "0" ]; then
236
		_exec "pkg ${pkg_chroot} lock ${_pkg}" "Locking package ${_pkg}" mute
237
	fi
238
}
239

    
240
pkg_unlock() {
241
	local _pkg="${1}"
242

    
243
	if [ -z "${_pkg}" ]; then
244
		return
245
	fi
246

    
247
	if [ "$(pkg ${pkg_chroot} query %k ${_pkg})" = "1" ]; then
248
		_exec "pkg ${pkg_chroot} unlock ${_pkg}" "Unlocking package ${_pkg}" mute
249
	fi
250
}
251

    
252
pkg_update() {
253
	local _run_update=1
254

    
255
	local _force=""
256
	if [ "${1}" = "force" ]; then
257
		_force=" -f"
258
	fi
259

    
260
	_exec "pkg ${pkg_chroot} update${_force}" "Updating repositories metadata"
261
}
262

    
263
pkg_upgrade() {
264
	# figure out which kernel variant is running
265
	export kernel_pkg=$(pkg query %n $(pkg info ${product}-kernel-\* | grep -v -- -debug-))
266

    
267
	if [ -z "${kernel_pkg}" ]; then
268
		_echo "ERROR: It was not possible to identify which ${product} kernel is installed"
269
		_exit 1
270
	fi
271

    
272
	export next_stage=$(pkg annotate -q -S ${kernel_pkg} next_stage)
273

    
274
	if [ -n "${next_stage}" -a -n "${booting}" -a -n "${boot_stage}" ]; then
275
		if [ ${boot_stage} != ${next_stage} ]; then
276
			_exit 0
277
		fi
278
	fi
279

    
280
	# If it's booting and first stage didn't run, just exit
281
	if [ -n "${booting}" -a -z "${next_stage}" ]; then
282
		_exit 0
283
	fi
284

    
285
	unset need_reboot
286
	# First upgrade stage
287
	if [ -z "${next_stage}" ]; then
288
		if [ -f "${logfile}" ]; then
289
			rm -f ${logfile}
290
		fi
291

    
292
		pkg_update
293

    
294
		if [ "$(compare_pkg_version pkg)" = "<" ]; then
295
			_exec "pkg upgrade pkg" "Upgrading pkg" mute
296
			pkg_update force
297
		fi
298

    
299
		local _repo_pkg="${product}-repo"
300

    
301
		# Deprecated pa
302
		if is_pkg_installed ${product}-repo-devel; then
303
			_exec "pkg ${pkg_chroot} set -A 1 ${product}-repo-devel" \
304
				"Scheduling package ${product}-repo-devel for removal"
305
			_exec "pkg install ${_repo_pkg}" "Installing ${_repo_pkg}" mute
306
			_exec "pkg delete ${product}-repo-devel" "Removing ${product}-repo-devel" \
307
				mute ignore_result
308
			validate_repo_conf
309
			pkg_update force
310
		fi
311

    
312
		if [ "$(compare_pkg_version ${_repo_pkg})" = "<" ]; then
313
			cp /usr/local/etc/pkg/repos/${product}.conf \
314
				/tmp/${product}.conf.copy
315
			_exec "pkg upgrade ${_repo_pkg}" "Upgrading ${_repo_pkg}" mute
316
			# If conf differs, for an update
317
			if ! cmp -s /usr/local/etc/pkg/repos/${product}.conf /tmp/${product}.conf.copy; then
318
				pkg_update force
319

    
320
				# New repo may contain newer pkg
321
				if [ "$(compare_pkg_version pkg)" = "<" ]; then
322
					_exec "pkg upgrade pkg" "Upgrading pkg" mute
323
					pkg_update force
324
				fi
325
			fi
326
			rm -f /tmp/${product}.conf.copy
327
		fi
328

    
329
		if [ $(pkg upgrade -nq | wc -l) -le 1 ]; then
330
			_echo "Your packages are up to date"
331
			_exit 0
332
		fi
333

    
334
		if [ -n "${dry_run}" ]; then
335
			pkg_unlock ${kernel_pkg}
336
			pkg ${pkg_chroot} upgrade -nq 2>&1 | tee -a ${logfile}
337
			pkg_lock ${kernel_pkg}
338
			_exit 0
339
		fi
340

    
341
		local _meta_pkg=$(get_meta_pkg_name)
342
		if [ $(pkg upgrade -r ${product}-core -nq | wc -l) -gt 1 ]; then
343
			if [ "${platform}" = "nanobsd" ]; then
344
				_echo "**** WARNING ****"
345
				_echo "Duplicate slice required!!"
346
				_echo ""
347
				_echo "Before starting the upgrade process, the currently mounted nanobsd partition"
348
				_echo "needs to be cloned to the secondary partition, where the update will happen"
349
				_echo ""
350
				_echo "After installation a reboot will be required to switch partition."
351
				_echo ""
352
				if [ -z "${yes}" ]; then
353
					_echo -n "Proceed with upgrade? (y/N) "
354
					read answer
355
					if [ "${answer}" != "y" ]; then
356
						_echo "Aborting..."
357
						_exit 0
358
					fi
359
					# Do not make the user have to answer again.
360
					yes=1
361
				fi
362
				setup_nanobsd_env
363
			fi
364
			need_reboot=1
365
		elif pkg upgrade -r ${product} -nq ${_meta_pkg} >/dev/null 2>&1; then
366
			need_reboot=1
367
		fi
368

    
369
		pkg_unlock ${kernel_pkg}
370

    
371
		if [ -z "${yes}" ]; then
372
			# Show user which packages are going to be upgraded
373
			pkg ${pkg_chroot} upgrade -nq 2>&1 | tee -a ${logfile}
374

    
375
			_echo ""
376
			if [ -n "${need_reboot}" ]; then
377
				_echo "**** WARNING ****"
378
				_echo "Reboot will be required!!"
379
			fi
380
			_echo -n "Proceed with upgrade? (y/N) "
381
			read answer
382
			if [ "${answer}" != "y" ]; then
383
				_echo "Aborting..."
384
				_exit 0
385
			fi
386
		fi
387

    
388
		# Download all upgrade packages first
389
		fetch_upgrade_packages
390

    
391
		if [ $(pkg ${pkg_chroot} upgrade -nq ${kernel_pkg} | wc -l) -gt 1 ]; then
392
			_exec "pkg ${pkg_chroot} upgrade ${kernel_pkg}" "Upgrading ${product} kernel"
393
		fi
394

    
395
		pkg ${pkg_chroot} annotate -q -M ${kernel_pkg} next_stage 2
396
		next_stage=2
397

    
398
		if [ -n "${need_reboot}" -a "${platform}" != "nanobsd" ]; then
399
			do_reboot
400
			_exit 0
401
		fi
402
	fi
403

    
404
	if [ "${next_stage}" = "2" ]; then
405
		pkg_lock "${pkg_prefix}*"
406
		unlock_additional_pkgs=1
407

    
408
		# XXX: Workaround to upgrade strongswan
409
		# If those symlinks are present, pkg exit because it expects them
410
		# to be a directory
411
		if [ $(pkg ${pkg_chroot} upgrade -nq strongswan | wc -l) -gt 1 ]; then
412
			if [ -L ${chroot_dir}/usr/local/etc/ipsec.d ]; then
413
				rm -f ${chroot_dir}/usr/local/etc/ipsec.d
414
			fi
415
			if [ -L ${chroot_dir}/usr/local/etc/ipsec.conf ]; then
416
				rm -f ${chroot_dir}/usr/local/etc/ipsec.conf
417
			fi
418
			if [ -L ${chroot_dir}/usr/local/etc/strongswan.d ]; then
419
				rm -f ${chroot_dir}/usr/local/etc/strongswan.d
420
			fi
421
			if [ -L ${chroot_dir}/usr/local/etc/strongswan.conf ]; then
422
				rm -f ${chroot_dir}/usr/local/etc/strongswan.conf
423
			fi
424
		fi
425

    
426
		if [ $(pkg ${pkg_chroot} upgrade -nq | wc -l) -gt 1 ]; then
427
			delete_annotation=1
428
			_exec "pkg ${pkg_chroot} upgrade" "Upgrading necessary packages"
429
			delete_annotation=""
430
		fi
431

    
432
		# XXX: workaround for #5300
433
		sort -u ${chroot_dir}/usr/local/etc/php/extensions.ini > /tmp/extensions.ini
434
		mv /tmp/extensions.ini ${chroot_dir}/usr/local/etc/php/extensions.ini
435

    
436
		pkg ${pkg_chroot} annotate -q -M ${kernel_pkg} next_stage 3
437
		next_stage=3
438

    
439
		pkg_unlock "${pkg_prefix}*"
440
		unlock_additional_pkgs=""
441

    
442
		if [ -n "${need_reboot}" -a "${platform}" = "nanobsd" ]; then
443
			switch_active_nanobsd_partition
444
			do_reboot
445
			_exit 0
446
		fi
447

    
448
		if [ -n "${booting}" ]; then
449
			_exit 0
450
		fi
451
	fi
452

    
453
	if [ "${next_stage}" = "3" ]; then
454
		if [ $(pkg upgrade -nq | wc -l) -gt 1 ]; then
455
			delete_annotation=1
456
			_exec "pkg ${pkg_chroot} upgrade" "Upgrading necessary packages"
457
			delete_annotation=""
458
		fi
459

    
460
		pkg ${pkg_chroot} annotate -q -D ${kernel_pkg} next_stage
461

    
462
		# cleanup caches
463
		_exec "pkg ${pkg_chroot} autoremove" "Removing unnecessary packages" mute ignore_result
464
		_exec "pkg ${pkg_chroot} clean" "Cleanup pkg cache" mute ignore_result
465
	fi
466

    
467
	gitsync=$(/usr/local/sbin/read_xml_tag.sh boolean system/gitsync/synconupgrade)
468
	if [ "${gitsync}" = "true" ]; then
469
		repository_url=$(/usr/local/sbin/read_xml_tag.sh string system/gitsync/repositoryurl)
470
		branch=$(/usr/local/sbin/read_xml_tag.sh string system/gitsync/branch)
471

    
472
		# Repository URL is not mandatory
473
		if [ -n "${branch}" ]; then
474
			_exec "/usr/local/sbin/pfSsh.php playback gitsync \
475
				${repositoryurl} ${branch} --upgrading" \
476
				"Running gitsync" mute ignore_result
477
		fi
478
	fi
479
}
480

    
481
get_meta_pkg_name() {
482
	# figure out main meta package name
483
	if is_pkg_installed ${product}-vmware; then
484
		echo "${product}-vmware"
485
	elif is_pkg_installed ${product}; then
486
		echo "${product}"
487
	else
488
		_echo "ERROR: It was not possible to identify which ${product} meta package is installed"
489
		_exit 1
490
	fi
491
}
492

    
493
check_upgrade() {
494
	local _meta_pkg=$(get_meta_pkg_name)
495

    
496
	pkg_update
497

    
498
	if [ "$(compare_pkg_version ${_meta_pkg})" = "<" ]; then
499
		local _new_version=$(pkg rquery %v ${_meta_pkg})
500
		_echo "${_new_version} version of ${product} is available"
501
		_exit 2
502
	else
503
		for _pkg in $(pkg query -e "%n ~ ${product}-*" %n); do
504
			# Ignore additional packages
505
			if echo "${_pkg}" | grep -q "^${pkg_prefix}"; then
506
				continue
507
			fi
508
			if [ "$(compare_pkg_version ${_pkg})" = "<" ]; then
509
				local _new_version=$(pkg rquery %v ${_pkg})
510
				_echo "${_new_version} version of ${_pkg} is available"
511
				_exit 2
512
			fi
513
		done
514
	fi
515

    
516
	_echo "Your system is up to date"
517
	_exit 0
518
}
519

    
520
setup_nanobsd_env() {
521
	if [ "${platform}" != "nanobsd" ]; then
522
		return;
523
	fi
524

    
525
	chroot_dir=/tmp/nanobsd_upgrade
526
	mkdir -p ${chroot_dir} 2>/dev/null
527
	local _cur_partition=$(mount -p / | cut -f1)
528
	local _update_partition=$(echo ${_cur_partition} | sed -e 's,0$,2,; s,1$,0,; s,2$,1,')
529

    
530
	if [ ! -e "${_update_partition}" ]; then
531
		_echo "Secondary partition (${_update_partition}), used for upgrade not found"
532
		_exit 1
533
	fi
534

    
535
	# Remove /dev
536
	_update_partition=$(echo ${_update_partition} | sed 's,^/dev/,,')
537
	local _update_slice=$(glabel status -s | awk "\$1 == \"${_update_partition}\" { print \$3 }")
538

    
539
	if [ -z "${_update_slice}" -o ! -e "/dev/${_update_slice}" ]; then
540
		_echo "Secondary slice (${_update_slice}), use_update_sliced for upgrade not found"
541
		_exit 1
542
	fi
543

    
544
	_update_slice="/dev/${_update_slice}"
545

    
546
	# Clone slice using same logic from nanobsd_clone_slice()
547
	sysctl kern.geom.debugflags=16 >/dev/null 2>&1
548
	_exec "dd if=/dev/zero of=${_update_slice} bs=1m count=1" "Cleaning secondary partition" mute
549
	_exec "dd if=${_cur_partition} of=${_update_slice} bs=64k" "Duplicating current slice" mute
550
	_exec "tunefs -L ${_update_partition##*/} ${_update_slice}" "Restoring slice label" mute
551
	sysctl kern.geom.debugflags=0 >/dev/null 2>&1
552

    
553
	_exec "/sbin/fsck -y -t ufs /dev/${_update_partition}" "Testing duplicated partition integrity" mute
554
	_exec "mount /dev/${_update_partition} ${chroot_dir}" "Mounting second partition to run upgrade" mute
555

    
556
	# Make sure resolv.conf is present, otherwise upgrade may fail (bug #6557)
557
	local _resolv_conf=$(readlink -f /etc/resolv.conf)
558
	_exec "cp -f ${_resolv_conf} ${chroot_dir}/etc/resolv.conf" \
559
		"Copying resolv.conf to upgrade partition" mute ignore_result
560

    
561
	sed -i '' -e "s,^${_cur_partition},/dev/${_update_partition}," \
562
		${chroot_dir}/etc/fstab
563

    
564
	pkg_chroot="-c ${chroot_dir}"
565
}
566

    
567
switch_active_nanobsd_partition() {
568
	if [ "${platform}" != "nanobsd" ]; then
569
		return;
570
	fi
571

    
572
	local _cur_partition=$(mount -p / | cut -f1 | sed 's,^/dev/,,')
573
	local _disk=$(glabel status -s | \
574
		awk "\$1 == \"${_cur_partition}\" { print substr(\$3, 0, length(\$3)-3)}")
575
	local _i=$(echo ${_cur_partition} | cut -c ${#_cur_partition})
576

    
577
	if ! echo "${_i}" | egrep -q '^[0-9]$'; then
578
		_echo "Invalid partition label ${_cur_partition}"
579
		_exit 1
580
	fi
581

    
582
	# pfsense0 == part 1 / pfsense1 == part 2
583
	if [ ${_i} -eq 0 ]; then
584
		_i=2
585
	else
586
		_i=1
587
	fi
588

    
589
	_exec "gpart set -a active -i ${_i} ${_disk}" "Setting secondary partition as active" mute
590
}
591

    
592
is_pkg_installed() {
593
	local _pkg_name="${1}"
594
	shift
595
	local _pkg_chroot="$@"
596

    
597
	pkg ${_pkg_chroot} info -e ${_pkg_name}
598
	return $?
599
}
600

    
601
compare_pkg_version() {
602
	local _pkg_name="${1}"
603

    
604
	if ! is_pkg_installed ${_pkg_name} ${pkg_chroot}; then
605
		echo '!'
606
		return 1
607
	fi
608

    
609
	local _lver=$(pkg ${pkg_chroot} query %v ${_pkg_name})
610

    
611
	if [ -z "${_lver}" ]; then
612
		_echo "ERROR: It was not possible to determine ${_pkg_name} local version"
613
		_exit 1
614
	fi
615

    
616
	local _rver=$(pkg ${pkg_chroot} rquery %v ${_pkg_name})
617

    
618
	if [ -z "${_rver}" ]; then
619
		_echo "ERROR: It was not possible to determine ${_pkg_name} remote version"
620
		_exit 1
621
	fi
622

    
623
	local _version=$(pkg version -t ${_lver} ${_rver})
624

    
625
	if [ $? -ne 0 ]; then
626
		_echo "ERROR: Error comparing ${_pkg_name} local and remote versions"
627
		_exit 1
628
	fi
629

    
630
	echo ${_version}
631
	return 0
632
}
633

    
634
pkg_install() {
635
	local _pkg_name="${1}"
636

    
637
	local _force=""
638
	if [ -n "${2}" ]; then
639
		_force="-f"
640
	fi
641

    
642
	if [ -z "${_pkg_name}" ]; then
643
		_echo "ERROR: Blank package name"
644
		_exit 1
645
	fi
646

    
647
	if is_pkg_installed ${_pkg_name}; then
648
		local _cversion=$(compare_pkg_version ${_pkg_name})
649

    
650
		if [ -z "${_force}" ]; then
651
			if [ "${_cversion}" = "=" ]; then
652
				_echo "Package ${_pkg_name} is up to date"
653
				_exit 0
654
			elif [ "${_cversion}" = ">" ]; then
655
				_echo "Installed ${_pkg_name} version is newer than remote"
656
				_exit 0
657
			fi
658
		fi
659
		local _cmd="upgrade ${_force}"
660
		local _msg="Upgrading"
661
	else
662
		local _cmd="install"
663
		local _msg="Installing"
664
	fi
665

    
666
	_exec "pkg_with_pb ${_cmd}${dry_run:+ }${dry_run} ${_pkg_name}" "${_msg} ${_pkg_name}"
667
	_exec "pkg clean" "Cleaning up cache" mute ignore_result
668
}
669

    
670
# Reinstall every pfSense-pkg-* package
671
pkg_reinstall_all() {
672
	for _pkg in $(pkg query -e '%a == 0' %n); do
673
		case ${_pkg} in "${pkg_prefix}"* )
674
			_echo "Reinstalling ${_pkg}"
675
			pkg_install ${_pkg} 1
676
			;;
677
		esac
678
	done
679
}
680

    
681
pkg_delete() {
682
	local _pkg_name="${1}"
683

    
684
	if [ -z "${_pkg_name}" ]; then
685
		_echo "ERROR: Blank package name"
686
		_exit 1
687
	fi
688

    
689
	if ! is_pkg_installed ${_pkg_name}; then
690
		_echo "ERROR: Package ${_pkg_name} is not installed"
691
		_exit 1
692
	fi
693

    
694
	_exec "pkg_with_pb delete${dry_run:+ }${dry_run} ${_pkg_name}" "Removing ${_pkg_name}"
695
	_exec "pkg autoremove" "Removing stale packages" mute ignore_result
696
}
697

    
698
# Delete every pfSense-pkg-* package
699
pkg_delete_all() {
700
	for _pkg in $(pkg query -e '%a == 0' %n); do
701
		case ${_pkg} in "${pkg_prefix}"* )
702
			_echo "Removing ${_pkg}"
703
			pkg_delete ${_pkg}
704
			;;
705
		esac
706
	done
707
}
708

    
709
do_reboot() {
710
	if [ -z "${dont_reboot}" ]; then
711
		_echo "Upgrade is complete.  Rebooting in ${reboot_after} seconds."
712
		echo "Upgrade is complete.  Rebooting in ${reboot_after} seconds." | wall
713
		/etc/rc.notify_message -e -g -m "Upgrade is complete.  Rebooting in ${reboot_after} seconds." \
714
			>/dev/null 2>&1
715
		(sleep ${reboot_after} && /etc/rc.reboot) &
716
	else
717
		_echo "Upgrade is complete."
718
		echo "Upgrade is complete." | wall
719
		/etc/rc.notify_message -e -g -m "Upgrade is complete." >/dev/null 2>&1
720
	fi
721
}
722

    
723
validate_repo_conf() {
724
	# Make sure to use default repo conf when it doesn't exist
725
	pkg_repo_conf="/usr/local/etc/pkg/repos/${product}.conf"
726
	default_pkg_repo_conf_path="/usr/local/share/${product}/pkg/repos/${product}-repo.conf"
727

    
728
	pkg_repo_conf_path=$(/usr/local/sbin/read_xml_tag.sh string system/pkg_repo_conf_path)
729

    
730
	if [ -z "${pkg_repo_conf_path}" -o ! -f "${pkg_repo_conf_path}" ]; then
731
		pkg_repo_conf_path=${default_pkg_repo_conf_path}
732
	fi
733

    
734
	if [ -f "${pkg_repo_conf_path}" ]; then
735
		if [ -e "${pkg_repo_conf}" -a ! -L "${pkg_repo_conf}" ]; then
736
			rm -f ${pkg_repo_conf}
737
			ln -sf ${pkg_repo_conf_path} ${pkg_repo_conf}
738
		fi
739

    
740
		if [ "$(readlink ${pkg_repo_conf})" != "${pkg_repo_conf_path}" ]; then
741
			mkdir -p /usr/local/etc/pkg/repos
742
			ln -sf ${pkg_repo_conf_path} ${pkg_repo_conf}
743
		fi
744
	fi
745
}
746

    
747
export LANG=C
748

    
749
pid_file="/var/run/$(basename $0).pid"
750
logfile="/cf/conf/upgrade_log.txt"
751
stdout='/dev/null'
752

    
753
# Setup proxy settings
754
HTTP_PROXY=$(/usr/local/sbin/read_xml_tag.sh string system/proxyurl)
755
if [ "${HTTP_PROXY}" != "" ]; then
756
	HTTP_PROXY_PORT=$(/usr/local/sbin/read_xml_tag.sh string system/proxyport)
757
	if [ "${HTTP_PROXY_PORT}" != "" ]; then
758
		HTTP_PROXY="${HTTP_PROXY}:${HTTP_PROXY_PORT}"
759
	fi
760
	export HTTP_PROXY
761
fi
762

    
763
# pkg should not ask for confirmations
764
export ASSUME_ALWAYS_YES=true
765
export FETCH_TIMEOUT=5
766
export FETCH_RETRY=2
767

    
768
export product=$(/usr/local/bin/php -n /usr/local/sbin/read_global_var product_name pfSense)
769
export pkg_prefix=$(/usr/local/bin/php -n /usr/local/sbin/read_global_var pkg_prefix pfSense-pkg-)
770
export platform=$(cat /etc/platform)
771

    
772
USE_MFS_TMPVAR=$(/usr/local/sbin/read_xml_tag.sh boolean system/use_mfs_tmpvar)
773
if [ "${platform}" = "nanobsd" ] || [ "${USE_MFS_TMPVAR}" = "true" ]; then
774
	export PKG_DBDIR=/root/var/db/pkg
775
	export PKG_CACHEDIR=/root/var/cache/pkg
776
fi
777

    
778
product_version=$(cat /etc/version)
779
do_not_send_host_uuid=$(/usr/local/sbin/read_xml_tag.sh boolean system/do_not_send_host_uuid)
780
if [ "${do_not_send_host_uuid}" != "true" ]; then
781
	hostuuid=$(sysctl kern.hostuuid)
782
	export HTTP_USER_AGENT="${product}/${product_version}:${hostuuid}"
783
else
784
	export HTTP_USER_AGENT="${product}/${product_version}"
785
fi
786

    
787
validate_repo_conf
788

    
789
# Flags used in _exit
790
export delete_annotation=""
791
export unlock_additional_pkgs=""
792

    
793
# Upgrade process on nanobsd will happen in chroot
794
export pkg_chroot=""
795
export chroot_dir=""
796

    
797
# Save nc_pid to be able to kill it
798
export nc_pid=""
799

    
800
# Reboot after 10 seconds
801
export reboot_after=10
802

    
803
unset dry_run
804
unset dont_reboot
805
unset booting
806
unset boot_stage
807
unset force
808
unset yes
809
unset progress_file
810
unset progress_socket
811
unset action
812
unset action_pkg
813
unset force_ipv4
814
unset force_ipv6
815
while getopts 46b:cdfi:hp:l:nr:Ruy opt; do
816
	case ${opt} in
817
		4)
818
			if [ -n "${force_ipv6}" ]; then
819
				usage
820
				_exit 1
821
			fi
822
			force_ipv4=1
823
			;;
824
		6)
825
			if [ -n "${force_ipv4}" ]; then
826
				usage
827
				_exit 1
828
			fi
829
			force_ipv6=1
830
			;;
831
		b)
832
			booting=1
833
			boot_stage="${OPTARG}"
834
			;;
835
		c)
836
			action="check"
837
			;;
838
		d)
839
			stdout=''
840
			;;
841
		f)
842
			force=1
843
			;;
844
		i)
845
			if [ -n "${action}" ]; then
846
				usage
847
				_exit 1
848
			fi
849
			action="install"
850
			action_pkg="${OPTARG}"
851
			;;
852
		h)
853
			usage
854
			_exit 0
855
			;;
856
		l)
857
			logfile="${OPTARG}"
858
			if [ -z "${logfile}" ]; then
859
				usage
860
				_exit 1
861
			fi
862
			;;
863
		n)
864
			dry_run="-n"
865
			;;
866
		p)
867
			progress_socket="${OPTARG}"
868
			if [ -z "${progress_socket}" ]; then
869
				usage
870
				_exit 1
871
			fi
872
			;;
873
		r)
874
			if [ -n "${action}" ]; then
875
				usage
876
				_exit 1
877
			fi
878
			action="delete"
879
			action_pkg="${OPTARG}"
880
			;;
881
		R)
882
			dont_reboot=1
883
			;;
884
		u)
885
			if [ -n "${action}" ]; then
886
				usage
887
				_exit 1
888
			fi
889
			action="update"
890
			;;
891
		y)
892
			yes=1
893
			;;
894
		*)
895
			usage
896
			_exit 1
897
			;;
898
	esac
899
done
900

    
901
if [ -n "${force_ipv4}" ]; then
902
	export IP_VERSION="4"
903
elif [ -n "${force_ipv6}" ]; then
904
	export IP_VERSION="6"
905
fi
906

    
907
# Set default action when no parameter is set
908
: ${action:="upgrade"}
909

    
910
if pgrep -qF ${pid_file} >/dev/null 2>&1; then
911
	echo "Another instance is already running... Aborting!"
912
	exit 1
913
fi
914

    
915
if [ -z "${booting}" -o "${boot_stage}" != "2" ]; then
916
	/usr/local/bin/php /etc/rc.conf_mount_rw
917
fi
918

    
919
if [ -n "${booting}" ]; then
920
	export REPO_AUTOUPDATE=false
921
fi
922

    
923
echo $$ > ${pid_file}
924

    
925
trap _exit 1 2 15 EXIT
926

    
927
if [ "${action}" != "upgrade" -a -f "${logfile}" ]; then
928
	rm -f ${logfile}
929
fi
930

    
931
progress_file=${logfile%.*}.json
932

    
933
if [ -e "${progress_file}" ]; then
934
	rm -f ${progress_file}
935
fi
936

    
937
case "${action}" in
938
	check)
939
		check_upgrade
940
		;;
941
	upgrade)
942
		pkg_upgrade
943
		;;
944
	update)
945
		pkg_update force
946
		;;
947
	install)
948
		if [ ${action_pkg} == "ALL_PACKAGES" ] && [ -n ${force} ]; then
949
			pkg_reinstall_all
950
		else
951
			pkg_install ${action_pkg} ${force}
952
		fi
953
		;;
954
	delete)
955
		if [ ${action_pkg} == "ALL_PACKAGES" ] && [ -n ${force} ]; then
956
			pkg_delete_all
957
		else
958
			pkg_delete ${action_pkg}
959
		fi
960
		;;
961
	*)
962
		_echo "ERROR: Invalid action!"
963
		_exit 1
964
esac
965

    
966
_exit 0
(9-9/22)