Project

General

Profile

Download (24.2 KB) Statistics
| Branch: | Tag: | Revision:
1
#!/bin/sh
2

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

    
49
usage() {
50
	echo "Usage: $(basename ${0}) [-46bdyf] [-u|-i PKG_NAME|-r PKG_NAME]" >&2
51
	echo "	-4          - Force IPv4"
52
	echo "	-6          - Force IPv6"
53
	echo "	-b          - Platform is booting" >&2
54
	echo "	-c          - Check if upgrade is necessary" >&2
55
	echo "	-d          - Turn on debug" >&2
56
	echo "	-f          - Force package installation" >&2
57
	echo "	-h          - Show this usage help" >&2
58
	echo "	-l          - Logfile path (defaults to /cf/conf/upgrade_log.txt)" >&2
59
	echo "	-n          - Dry run" >&2
60
	echo "	-p socket   - Write pkg progress to socket"
61
	echo "	-R          - Do not reboot (this can be dangerous)"
62
	echo "	-y          - Assume yes as the answer to any possible interaction" >&2
63
	echo "" >&2
64
	echo "The following parameters are mutually exclusive:" >&2
65
	echo "	-i PKG_NAME - Install package PKG_NAME" >&2
66
	echo "	-r PKG_NAME - Remove package PKG_NAME" >&2
67
	echo "	-u          - Update repository information" >&2
68
}
69

    
70
_echo() {
71
	local _n=""
72
	if [ "${1}" = "-n" ]; then
73
		shift
74
		_n="-n"
75
	fi
76

    
77
	if [ -z "${logfile}" ]; then
78
		logfile=/dev/null
79
	fi
80

    
81
	echo ${_n} "${1}" | tee -a ${logfile}
82
}
83

    
84
_exec() {
85
	local _cmd="${1}"
86
	local _msg="${2}"
87
	local _mute="${3}"
88
	local _ignore_result="${4}"
89
	local _stdout="${stdout}"
90

    
91
	if [ -z "${_cmd}" -o -z "${_msg}" ]; then
92
		return 1
93
	fi
94

    
95
	if [ "${_mute}" != "mute" ]; then
96
		_stdout=''
97
	fi
98

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

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

    
126
_exit() {
127
	trap "-" 1 2 15 EXIT
128

    
129
	pkg_lock ${kernel_pkg}
130

    
131
	if [ -f "${pid_file}" ]; then
132
		rm -f ${pid_file}
133
	fi
134

    
135
	if [ -n "${chroot_dir}" ]; then
136
		umount -f ${chroot_dir} >/dev/null 2>&1
137
	fi
138

    
139
	if [ -z "${booting}" -o "${boot_stage}" != "2" ]; then
140
		/usr/local/bin/php /etc/rc.conf_mount_ro
141
	fi
142

    
143
	if [ -n "${nc_pid}" ] && ps -p ${nc_pid} >/dev/null 2>&1; then
144
		kill ${nc_pid}
145
	fi
146

    
147
	if [ -n "${delete_annotation}" ]; then
148
		pkg ${pkg_chroot} annotate -q -D ${kernel_pkg} next_stage
149
	fi
150

    
151
	if [ -n "${unlock_additional_pkgs}" ]; then
152
		pkg_unlock "${pkg_prefix}*"
153
	fi
154

    
155
	local _rc=${1:-"0"}
156

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

    
165
	exit ${_rc}
166
}
167

    
168
pkg_with_pb() {
169
	local _event_pipe=""
170

    
171
	if [ -n "${progress_socket}" ]; then
172
		if [ -e "${chroot_dir}${progress_socket}" ]; then
173
			rm -f ${chroot_dir}${progress_socket}
174
		fi
175

    
176
		_event_pipe="-o EVENT_PIPE=${progress_socket}"
177

    
178
		nc -lU ${chroot_dir}${progress_socket} >> ${progress_file} &
179
		nc_pid=$!
180

    
181
		while [ ! -e "${chroot_dir}${progress_socket}" ]; do
182
			sleep 0.1
183
		done
184
	fi
185

    
186
	pkg ${_event_pipe} $@
187
	local _pkg_result=$?
188
	nc_pid=""
189
	return ${_pkg_result}
190
}
191

    
192
fetch_upgrade_packages() {
193
	local _pkgs_to_fetch=""
194
	if [ "${platform}" = "nanobsd" ]; then
195
		local _pkg=""
196

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

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

    
214
	fi
215

    
216
	_exec "pkg_with_pb ${pkg_chroot} upgrade -F" "Downloading upgrade packages"
217

    
218
	if [ -n "${_pkgs_to_fetch}" ]; then
219
		_exec "pkg_with_pb ${pkg_chroot} fetch -d ${_pkgs_to_fetch}" \
220
			"Fetching packages not present on upgrade partition"
221
	fi
222
}
223

    
224
pkg_lock() {
225
	local _pkg="${1}"
226

    
227
	if [ -z "${_pkg}" ]; then
228
		return
229
	fi
230

    
231
	if [ "$(pkg ${pkg_chroot} query %k ${_pkg})" = "0" ]; then
232
		_exec "pkg ${pkg_chroot} lock ${_pkg}" "Locking package ${_pkg}" mute
233
	fi
234
}
235

    
236
pkg_unlock() {
237
	local _pkg="${1}"
238

    
239
	if [ -z "${_pkg}" ]; then
240
		return
241
	fi
242

    
243
	if [ "$(pkg ${pkg_chroot} query %k ${_pkg})" = "1" ]; then
244
		_exec "pkg ${pkg_chroot} unlock ${_pkg}" "Unlocking package ${_pkg}" mute
245
	fi
246
}
247

    
248
pkg_update() {
249
	local _run_update=1
250

    
251
	local _force=""
252
	if [ "${1}" = "force" ]; then
253
		_force=" -f"
254
	fi
255

    
256
	_exec "pkg ${pkg_chroot} update${_force}" "Updating repositories metadata"
257
}
258

    
259
pkg_upgrade() {
260
	# figure out which kernel variant is running
261
	export kernel_pkg=$(pkg query %n $(pkg info ${product}-kernel-\* | grep -v -- -debug-))
262

    
263
	if [ -z "${kernel_pkg}" ]; then
264
		_echo "ERROR: It was not possible to identify which ${product} kernel is installed"
265
		_exit 1
266
	fi
267

    
268
	export next_stage=$(pkg annotate -q -S ${kernel_pkg} next_stage)
269

    
270
	if [ -n "${next_stage}" -a -n "${booting}" -a -n "${boot_stage}" ]; then
271
		if [ ${boot_stage} != ${next_stage} ]; then
272
			_exit 0
273
		fi
274
	fi
275

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

    
281
	unset need_reboot
282
	# First upgrade stage
283
	if [ -z "${next_stage}" ]; then
284
		if [ -f "${logfile}" ]; then
285
			rm -f ${logfile}
286
		fi
287

    
288
		pkg_update
289

    
290
		if [ "$(compare_pkg_version pkg)" = "<" ]; then
291
			_exec "pkg upgrade pkg" "Upgrading pkg" mute
292
			pkg_update force
293
		fi
294

    
295
		local _repo_pkg="${product}-repo"
296

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

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

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

    
325
		if [ $(pkg upgrade -nq | wc -l) -le 1 ]; then
326
			_echo "Your packages are up to date"
327
			_exit 0
328
		fi
329

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

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

    
365
		pkg_unlock ${kernel_pkg}
366

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

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

    
384
		# Download all upgrade packages first
385
		fetch_upgrade_packages
386

    
387
		if [ $(pkg ${pkg_chroot} upgrade -nq ${kernel_pkg} | wc -l) -gt 1 ]; then
388
			_exec "pkg ${pkg_chroot} upgrade ${kernel_pkg}" "Upgrading ${product} kernel"
389
		fi
390

    
391
		pkg ${pkg_chroot} annotate -q -M ${kernel_pkg} next_stage 2
392
		next_stage=2
393

    
394
		if [ -n "${need_reboot}" -a "${platform}" != "nanobsd" ]; then
395
			do_reboot
396
			_exit 0
397
		fi
398
	fi
399

    
400
	if [ "${next_stage}" = "2" ]; then
401
		pkg_lock "${pkg_prefix}*"
402
		unlock_additional_pkgs=1
403

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

    
422
		if [ $(pkg ${pkg_chroot} upgrade -nq | wc -l) -gt 1 ]; then
423
			delete_annotation=1
424
			_exec "pkg ${pkg_chroot} upgrade" "Upgrading necessary packages"
425
			delete_annotation=""
426
		fi
427

    
428
		# XXX: workaround for #5300
429
		sort -u ${chroot_dir}/usr/local/etc/php/extensions.ini > /tmp/extensions.ini
430
		mv /tmp/extensions.ini ${chroot_dir}/usr/local/etc/php/extensions.ini
431

    
432
		pkg ${pkg_chroot} annotate -q -M ${kernel_pkg} next_stage 3
433
		next_stage=3
434

    
435
		pkg_unlock "${pkg_prefix}*"
436
		unlock_additional_pkgs=""
437

    
438
		if [ -n "${need_reboot}" -a "${platform}" = "nanobsd" ]; then
439
			switch_active_nanobsd_partition
440
			do_reboot
441
			_exit 0
442
		fi
443

    
444
		if [ -n "${booting}" ]; then
445
			_exit 0
446
		fi
447
	fi
448

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

    
456
		pkg ${pkg_chroot} annotate -q -D ${kernel_pkg} next_stage
457

    
458
		# cleanup caches
459
		_exec "pkg ${pkg_chroot} autoremove" "Removing unnecessary packages" mute ignore_result
460
		_exec "pkg ${pkg_chroot} clean" "Cleanup pkg cache" mute ignore_result
461
	fi
462

    
463
	gitsync=$(/usr/local/sbin/read_xml_tag.sh boolean system/gitsync/synconupgrade)
464
	if [ "${gitsync}" = "true" ]; then
465
		repository_url=$(/usr/local/sbin/read_xml_tag.sh string system/gitsync/repositoryurl)
466
		branch=$(/usr/local/sbin/read_xml_tag.sh string system/gitsync/branch)
467

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

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

    
489
check_upgrade() {
490
	local _meta_pkg=$(get_meta_pkg_name)
491

    
492
	pkg_update
493

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

    
512
	_echo "Your system is up to date"
513
	_exit 0
514
}
515

    
516
setup_nanobsd_env() {
517
	if [ "${platform}" != "nanobsd" ]; then
518
		return;
519
	fi
520

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

    
526
	if [ ! -e "${_update_partition}" ]; then
527
		_echo "Secondary partition (${_update_partition}), used for upgrade not found"
528
		_exit 1
529
	fi
530

    
531
	# Remove /dev
532
	_update_partition=$(echo ${_update_partition} | sed 's,^/dev/,,')
533
	local _update_slice=$(glabel status -s | awk "\$1 == \"${_update_partition}\" { print \$3 }")
534

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

    
540
	_update_slice="/dev/${_update_slice}"
541

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

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

    
552
	# Make sure resolv.conf is present, otherwise upgrade may fail (bug #6557)
553
	_exec "cp -f /etc/resolv.conf ${chroot_dir}/etc" "Copying resolv.conf to upgrade partition" mute
554

    
555
	sed -i '' -e "s,^${_cur_partition},/dev/${_update_partition}," \
556
		${chroot_dir}/etc/fstab
557

    
558
	pkg_chroot="-c ${chroot_dir}"
559
}
560

    
561
switch_active_nanobsd_partition() {
562
	if [ "${platform}" != "nanobsd" ]; then
563
		return;
564
	fi
565

    
566
	local _cur_partition=$(mount -p / | cut -f1 | sed 's,^/dev/,,')
567
	local _disk=$(glabel status -s | \
568
		awk "\$1 == \"${_cur_partition}\" { print substr(\$3, 0, length(\$3)-3)}")
569
	local _i=$(echo ${_cur_partition} | cut -c ${#_cur_partition})
570

    
571
	if ! echo "${_i}" | egrep -q '^[0-9]$'; then
572
		_echo "Invalid partition label ${_cur_partition}"
573
		_exit 1
574
	fi
575

    
576
	# pfsense0 == part 1 / pfsense1 == part 2
577
	if [ ${_i} -eq 0 ]; then
578
		_i=2
579
	else
580
		_i=1
581
	fi
582

    
583
	_exec "gpart set -a active -i ${_i} ${_disk}" "Setting secondary partition as active" mute
584
}
585

    
586
is_pkg_installed() {
587
	local _pkg_name="${1}"
588
	shift
589
	local _pkg_chroot="$@"
590

    
591
	pkg ${_pkg_chroot} info -e ${_pkg_name}
592
	return $?
593
}
594

    
595
compare_pkg_version() {
596
	local _pkg_name="${1}"
597

    
598
	if ! is_pkg_installed ${_pkg_name} ${pkg_chroot}; then
599
		echo '!'
600
		return 1
601
	fi
602

    
603
	local _lver=$(pkg ${pkg_chroot} query %v ${_pkg_name})
604

    
605
	if [ -z "${_lver}" ]; then
606
		_echo "ERROR: It was not possible to determine ${_pkg_name} local version"
607
		_exit 1
608
	fi
609

    
610
	local _rver=$(pkg ${pkg_chroot} rquery %v ${_pkg_name})
611

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

    
617
	local _version=$(pkg version -t ${_lver} ${_rver})
618

    
619
	if [ $? -ne 0 ]; then
620
		_echo "ERROR: Error comparing ${_pkg_name} local and remote versions"
621
		_exit 1
622
	fi
623

    
624
	echo ${_version}
625
	return 0
626
}
627

    
628
pkg_install() {
629
	local _pkg_name="${1}"
630

    
631
	local _force=""
632
	if [ -n "${2}" ]; then
633
		_force="-f"
634
	fi
635

    
636
	if [ -z "${_pkg_name}" ]; then
637
		_echo "ERROR: Blank package name"
638
		_exit 1
639
	fi
640

    
641
	if is_pkg_installed ${_pkg_name}; then
642
		local _cversion=$(compare_pkg_version ${_pkg_name})
643

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

    
660
	_exec "pkg_with_pb ${_cmd}${dry_run:+ }${dry_run} ${_pkg_name}" "${_msg} ${_pkg_name}"
661
	_exec "pkg clean" "Cleaning up cache" mute ignore_result
662
}
663

    
664
# Reinstall every pfSense-pkg-* package
665
pkg_reinstall_all() {
666
	for _pkg in $(pkg query -e '%a == 0' %n); do
667
		case ${_pkg} in "${pkg_prefix}"* )
668
			_echo "Reinstalling ${_pkg}"
669
			pkg_install ${_pkg} 1
670
			;;
671
		esac
672
	done
673
}
674

    
675
pkg_delete() {
676
	local _pkg_name="${1}"
677

    
678
	if [ -z "${_pkg_name}" ]; then
679
		_echo "ERROR: Blank package name"
680
		_exit 1
681
	fi
682

    
683
	if ! is_pkg_installed ${_pkg_name}; then
684
		_echo "ERROR: Package ${_pkg_name} is not installed"
685
		_exit 1
686
	fi
687

    
688
	_exec "pkg_with_pb delete${dry_run:+ }${dry_run} ${_pkg_name}" "Removing ${_pkg_name}"
689
	_exec "pkg autoremove" "Removing stale packages" mute ignore_result
690
}
691

    
692
# Delete every pfSense-pkg-* package
693
pkg_delete_all() {
694
	for _pkg in $(pkg query -e '%a == 0' %n); do
695
		case ${_pkg} in "${pkg_prefix}"* )
696
			_echo "Removing ${_pkg}"
697
			pkg_delete ${_pkg}
698
			;;
699
		esac
700
	done
701
}
702

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

    
717
validate_repo_conf() {
718
	# Make sure to use default repo conf when it doesn't exist
719
	pkg_repo_conf="/usr/local/etc/pkg/repos/${product}.conf"
720
	default_pkg_repo_conf_path="/usr/local/share/${product}/pkg/repos/${product}-repo.conf"
721

    
722
	pkg_repo_conf_path=$(/usr/local/sbin/read_xml_tag.sh string system/pkg_repo_conf_path)
723

    
724
	if [ -z "${pkg_repo_conf_path}" -o ! -f "${pkg_repo_conf_path}" ]; then
725
		pkg_repo_conf_path=${default_pkg_repo_conf_path}
726
	fi
727

    
728
	if [ -f "${pkg_repo_conf_path}" ]; then
729
		if [ -e "${pkg_repo_conf}" -a ! -L "${pkg_repo_conf}" ]; then
730
			rm -f ${pkg_repo_conf}
731
			ln -sf ${pkg_repo_conf_path} ${pkg_repo_conf}
732
		fi
733

    
734
		if [ "$(readlink ${pkg_repo_conf})" != "${pkg_repo_conf_path}" ]; then
735
			mkdir -p /usr/local/etc/pkg/repos
736
			ln -sf ${pkg_repo_conf_path} ${pkg_repo_conf}
737
		fi
738
	fi
739
}
740

    
741
export LANG=C
742

    
743
pid_file="/var/run/$(basename $0).pid"
744
logfile="/cf/conf/upgrade_log.txt"
745
stdout='/dev/null'
746

    
747
# Setup proxy settings
748
HTTP_PROXY=$(/usr/local/sbin/read_xml_tag.sh string system/proxyurl)
749
if [ "${HTTP_PROXY}" != "" ]; then
750
	HTTP_PROXY_PORT=$(/usr/local/sbin/read_xml_tag.sh string system/proxyport)
751
	if [ "${HTTP_PROXY_PORT}" != "" ]; then
752
		HTTP_PROXY="${HTTP_PROXY}:${HTTP_PROXY_PORT}"
753
	fi
754
	export HTTP_PROXY
755
fi
756

    
757
# pkg should not ask for confirmations
758
export ASSUME_ALWAYS_YES=true
759
export FETCH_TIMEOUT=5
760
export FETCH_RETRY=2
761

    
762
export product=$(/usr/local/bin/php -n /usr/local/sbin/read_global_var product_name pfSense)
763
export pkg_prefix=$(/usr/local/bin/php -n /usr/local/sbin/read_global_var pkg_prefix pfSense-pkg-)
764
export platform=$(cat /etc/platform)
765

    
766
USE_MFS_TMPVAR=$(/usr/local/sbin/read_xml_tag.sh boolean system/use_mfs_tmpvar)
767
if [ "${platform}" = "nanobsd" ] || [ "${USE_MFS_TMPVAR}" = "true" ]; then
768
	export PKG_DBDIR=/root/var/db/pkg
769
	export PKG_CACHEDIR=/root/var/cache/pkg
770
fi
771

    
772
product_version=$(cat /etc/version)
773
do_not_send_host_uuid=$(/usr/local/sbin/read_xml_tag.sh boolean system/do_not_send_host_uuid)
774
if [ "${do_not_send_host_uuid}" != "true" ]; then
775
	hostuuid=$(sysctl kern.hostuuid)
776
	export HTTP_USER_AGENT="${product}/${product_version}:${hostuuid}"
777
else
778
	export HTTP_USER_AGENT="${product}/${product_version}"
779
fi
780

    
781
validate_repo_conf
782

    
783
# Flags used in _exit
784
export delete_annotation=""
785
export unlock_additional_pkgs=""
786

    
787
# Upgrade process on nanobsd will happen in chroot
788
export pkg_chroot=""
789
export chroot_dir=""
790

    
791
# Save nc_pid to be able to kill it
792
export nc_pid=""
793

    
794
# Reboot after 10 seconds
795
export reboot_after=10
796

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

    
895
if [ -n "${force_ipv4}" ]; then
896
	export IP_VERSION="4"
897
elif [ -n "${force_ipv6}" ]; then
898
	export IP_VERSION="6"
899
fi
900

    
901
# Set default action when no parameter is set
902
: ${action:="upgrade"}
903

    
904
if pgrep -qF ${pid_file} >/dev/null 2>&1; then
905
	echo "Another instance is already running... Aborting!"
906
	exit 1
907
fi
908

    
909
if [ -z "${booting}" -o "${boot_stage}" != "2" ]; then
910
	/usr/local/bin/php /etc/rc.conf_mount_rw
911
fi
912

    
913
if [ -n "${booting}" ]; then
914
	export REPO_AUTOUPDATE=false
915
fi
916

    
917
echo $$ > ${pid_file}
918

    
919
trap _exit 1 2 15 EXIT
920

    
921
if [ "${action}" != "upgrade" -a -f "${logfile}" ]; then
922
	rm -f ${logfile}
923
fi
924

    
925
progress_file=${logfile%.*}.json
926

    
927
if [ -e "${progress_file}" ]; then
928
	rm -f ${progress_file}
929
fi
930

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

    
960
_exit 0
(9-9/22)