Project

General

Profile

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

    
3
# Copyright (c) 2004-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}) [-bdy] [-u|-i PKG_NAME|-r PKG_NAME]" >&2
51
	echo "	-b          - Platform is booting" >&2
52
	echo "	-d          - Turn on debug" >&2
53
	echo "	-h          - Show this usage help" >&2
54
	echo "	-p FIFO     - Write pkg progress to FIFO"
55
	echo "	-y          - Consider yes as the answer for any possible interaction" >&2
56
	echo "" >&2
57
	echo "Following parameters are mutually exclusive:" >&2
58
	echo "	-i PKG_NAME - Install package PKG_NAME" >&2
59
	echo "	-r PKG_NAME - Remove package PKG_NAME" >&2
60
	echo "	-u          - Update repository information" >&2
61
}
62

    
63
_echo() {
64
	local _n=""
65
	if [ "${1}" = "-n" ]; then
66
		shift
67
		_n="-n"
68
	fi
69

    
70
	if [ -z "${logfile}" ]; then
71
		logfile=/dev/null
72
	fi
73

    
74
	echo ${_n} "${1}" | tee -a ${logfile}
75
}
76

    
77
_exec() {
78
	local _cmd="${1}"
79
	local _msg="${2}"
80
	local _mute="${3}"
81
	local _ignore_result="${4}"
82
	local _stdout="${stdout}"
83

    
84
	if [ -z "${_cmd}" -o -z "${_msg}" ]; then
85
		return 1
86
	fi
87

    
88
	if [ "${_mute}" != "mute" ]; then
89
		_stdout=''
90
	fi
91

    
92
	_echo -n ">>> ${_msg}... "
93
	if [ -z "${_stdout}" ]; then
94
		_echo ""
95
		${_cmd} 2>&1 | tee -a ${logfile}
96
	else
97
		${_cmd} >${_stdout} 2>&1 | tee -a ${logfile}
98
	fi
99
	local _result=$?
100

    
101
	if [ ${_result} -eq 0 -o -n "${_ignore_result}" ]; then
102
		[ -n "${_stdout}" ] \
103
			&& _echo "done."
104
		return 0
105
	else
106
		[ -n "${_stdout}" ] \
107
			&& _echo "failed."
108
		exit 1
109
	fi
110
}
111

    
112
_exit() {
113
	trap "-" 1 2 15 EXIT
114

    
115
	pkg_lock ${kernel_pkg}
116

    
117
	if [ -f "${pid_file}" ]; then
118
		rm -f ${pid_file}
119
	fi
120

    
121
	if [ -n "${chroot_dir}" ]; then
122
		umount -f ${chroot_dir} >/dev/null 2>&1
123
	fi
124

    
125
	if [ -z "${booting}" -o "${boot_stage}" != "2" ]; then
126
		/etc/rc.conf_mount_ro
127
	fi
128

    
129
	local _rc=${1:-"0"}
130

    
131
	# If EVENT_PIPE is defined, GUI is calling
132
	[ -n "${EVENT_PIPE}" ] \
133
		&& _echo "__RC=${_rc}"
134

    
135
	exit ${_rc}
136
}
137

    
138
fetch_upgrade_packages() {
139
	local _pkgs_to_fetch=""
140
	if [ "${platform}" = "nanobsd" ]; then
141
		local _pkg=""
142

    
143
		# Check if all non-auto packages installed on 2nd partition are
144
		# installed on current one, if not, mark them to be deleted by
145
		# pkg autoremove
146
		for _pkg in $(pkg ${pkg_chroot} query -e '%a == 0' %n); do
147
			if ! pkg info -e ${_pkg}; then
148
				_exec "pkg ${pkg_chroot} set -A 1 ${_pkg}" "Scheduling package ${_pkg} for removal"
149
			fi
150
		done
151

    
152
		# Check if all non-auto packages installed on current partition are
153
		# installed on 2nd one, if not, we need to fetch them
154
		for _pkg in $(pkg query -e '%a == 0' %n); do
155
			if ! pkg ${pkg_chroot} info -e ${_pkg}; then
156
				_pkgs_to_fetch="${_pkgs_to_fetch}${_pkgs_to_fetch:+ }${_pkg}"
157
			fi
158
		done
159

    
160
	fi
161

    
162
	_echo ">>> Downloading upgrade packages..."
163
	if ! pkg ${pkg_chroot} upgrade -F 2>&1 | tee -a ${logfile}; then
164
		_echo "ERROR: It was not possible to download packages"
165
		_exit 1
166
	fi
167

    
168
	if [ -n "${_pkgs_to_fetch}" ]; then
169
		_echo ">>> Fetching packages not present on upgrade partition..."
170
		if ! pkg ${pkg_chroot} fetch -d ${_pkgs_to_fetch} 2>&1 | tee -a ${logfile}; then
171
			_echo "ERROR: It was not possible to fetch packages"
172
			_exit 1
173
		fi
174
	fi
175
}
176

    
177
pkg_lock() {
178
	local _pkg="${1}"
179

    
180
	if [ -z "${_pkg}" ]; then
181
		return
182
	fi
183

    
184
	if [ "$(pkg ${pkg_chroot} query %k ${_pkg})" = "0" ]; then
185
		_exec "pkg ${pkg_chroot} lock ${_pkg}" "Locking package ${_pkg}" mute
186
	fi
187
}
188

    
189
pkg_unlock() {
190
	local _pkg="${1}"
191

    
192
	if [ -z "${_pkg}" ]; then
193
		return
194
	fi
195

    
196
	if [ "$(pkg ${pkg_chroot} query %k ${_pkg})" = "1" ]; then
197
		_exec "pkg ${pkg_chroot} unlock ${_pkg}" "Unlocking package ${_pkg}" mute
198
	fi
199
}
200

    
201
pkg_update() {
202
	local _run_update=1
203

    
204
	unset _force
205
	if [ "${1}" = "force" ]; then
206
		local _force=1
207
	fi
208

    
209
	if [ -z "${_force}" -a -f ${last_update_file} ]; then
210
		local _last_update=$(head -n 1 ${last_update_file})
211
		# Verify if content contain only numbers
212
		if echo "${_last_update}" | grep -E -q '^[0-9]+$'; then
213
			local _now=$(date +%s)
214
			# Only run update hourly, and if last update is in the future
215
			[ ${_now} -gt ${_last_update} -a $((${_now} - ${_last_update})) -le $((60 * 60)) ] \
216
				&& unset _run_update
217
		fi
218
	fi
219

    
220
	[ -z "${_run_update}" ] \
221
		&& return 0
222

    
223
	_exec "pkg ${pkg_chroot} update" "Updating repositories" mute
224
	date +%s > ${last_update_file}
225
}
226

    
227
pkg_upgrade() {
228
	# figure out which kernel variant is running
229
	export kernel_pkg=$(pkg query %n $(pkg info ${product}-kernel-\*))
230

    
231
	if [ -z "${kernel_pkg}" ]; then
232
		_echo "ERROR: It was not possible to identify which ${product} kernel is installed"
233
		_exit 1
234
	fi
235

    
236
	export next_stage=$(pkg annotate -q -S ${kernel_pkg} next_stage)
237

    
238
	if [ -n "${next_stage}" -a -n "${booting}" -a -n "${boot_stage}" ]; then
239
		if [ ${boot_stage} != ${next_stage} ]; then
240
			_exit 0
241
		fi
242
	fi
243

    
244
	# If it's booting and first stage didn't run, just exit
245
	if [ -n "${booting}" -a -z "${next_stage}" ]; then
246
		_exit 0
247
	fi
248

    
249
	unset need_reboot
250
	# First upgrade stage
251
	if [ -z "${next_stage}" ]; then
252
		if [ -f "${logfile}" ]; then
253
			rm -f ${logfile}
254
		fi
255

    
256
		pkg_update
257

    
258
		if [ "$(compare_pkg_version pkg)" = "<" ]; then
259
			_exec "pkg upgrade pkg" "Upgrading pkg" mute
260
			pkg_update force
261
		fi
262

    
263
		if [ $(pkg upgrade -nq | wc -l) -le 1 ]; then
264
			_echo "Your packages are up to date"
265
			_exit 0
266
		fi
267

    
268
		if [ $(pkg upgrade -r ${product}-core -nq | wc -l) -gt 1 ]; then
269
			setup_nanobsd_env
270
			need_reboot=1
271
		fi
272

    
273
		pkg_unlock ${kernel_pkg}
274

    
275
		if [ "${platform}" = "nanobsd" ] && \
276
		   [ $(pkg ${pkg_chroot} upgrade -nq | wc -l) -le 1 ]; then
277
			_echo "**** WARNING ****"
278
			_echo "Reboot will be required!!"
279
			_echo "Secondary partition is up to date"
280
			if [ -z "${yes}" ]; then
281
				_echo -n "Proceed with upgrade? (y/N) "
282
				read answer
283
				if [ "${answer}" != "y" ]; then
284
					_echo "Aborting..."
285
					_exit 0
286
				fi
287
			fi
288
			switch_active_nanobsd_partition
289
			/etc/rc.reboot &
290
			_exit 0
291
		fi
292

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

    
297
			_echo ""
298
			if [ -n "${need_reboot}" ]; then
299
				_echo "**** WARNING ****"
300
				_echo "Reboot will be required!!"
301
			fi
302
			_echo -n "Proceed with upgrade? (y/N) "
303
			read answer
304
			if [ "${answer}" != "y" ]; then
305
				_echo "Aborting..."
306
				_exit 0
307
			fi
308
		fi
309

    
310
		# Download all upgrade packages first
311
		fetch_upgrade_packages
312

    
313
		if [ $(pkg ${pkg_chroot} upgrade -nq ${kernel_pkg} | wc -l) -gt 1 ]; then
314
			_exec "pkg ${pkg_chroot} upgrade ${kernel_pkg}" "Upgrading ${product} kernel"
315
		fi
316

    
317
		pkg ${pkg_chroot} annotate -q -M ${kernel_pkg} next_stage 2
318
		next_stage=2
319

    
320
		if [ -n "${need_reboot}" -a "${platform}" != "nanobsd" ]; then
321
			_echo "Rebooting..."
322
			/etc/rc.reboot &
323
			_exit 0
324
		fi
325
	fi
326

    
327
	if [ "${next_stage}" = "2" ]; then
328
		pkg_lock "${pkg_prefix}*"
329

    
330
		if [ $(pkg ${pkg_chroot} upgrade -nq | wc -l) -gt 1 ]; then
331
			_echo "Upgrading necessary packages..."
332
			if ! pkg ${pkg_chroot} upgrade 2>&1 | tee -a ${logfile}; then
333
				pkg ${pkg_chroot} annotate -q -D ${kernel_pkg} next_stage
334
				pkg_unlock "${pkg_prefix}*"
335
				_echo "ERROR: An error occurred when upgrade was running..."
336
				_exit 1
337
			fi
338
		fi
339

    
340
		pkg ${pkg_chroot} annotate -q -M ${kernel_pkg} next_stage 3
341
		next_stage=3
342

    
343
		pkg_unlock "${pkg_prefix}*"
344

    
345
		if [ -n "${need_reboot}" -a "${platform}" = "nanobsd" ]; then
346
			switch_active_nanobsd_partition
347
			_echo "Rebooting..."
348
			/etc/rc.reboot &
349
			_exit 0
350
		fi
351

    
352
		if [ -n "${booting}" ]; then
353
			_exit 0
354
		fi
355
	fi
356

    
357
	if [ "${next_stage}" = "3" ]; then
358
		if [ $(pkg upgrade -nq | wc -l) -gt 1 ]; then
359
			_echo "Upgrading necessary packages..."
360
			if ! pkg ${pkg_chroot} upgrade 2>&1 | tee -a ${logfile}; then
361
				pkg ${pkg_chroot} annotate -q -D ${kernel_pkg} next_stage
362
				_echo "ERROR: An error occurred when upgrade was running..."
363
				_exit 1
364
			fi
365
		fi
366

    
367
		pkg ${pkg_chroot} annotate -q -D ${kernel_pkg} next_stage
368

    
369
		# cleanup caches
370
		_exec "pkg ${pkg_chroot} autoremove" "Removing unnecessary packages" mute ignore_result
371
		_exec "pkg ${pkg_chroot} clean" "Cleanup pkg cache" mute ignore_result
372
	fi
373
}
374

    
375
setup_nanobsd_env() {
376
	if [ "${platform}" != "nanobsd" ]; then
377
		return;
378
	fi
379

    
380
	chroot_dir=/tmp/nanobsd_upgrade
381
	mkdir -p ${chroot_dir} 2>/dev/null
382
	local _cur_partition=$(mount -p / | cut -f1)
383
	local _update_partition=$(echo ${_cur_partition} | sed -e 's,0$,2,; s,1$,0,; s,2$,1,')
384

    
385
	if [ ! -e "${_update_partition}" ]; then
386
		_echo "Secondary partition (${_update_partition}), used for upgrade not found"
387
		_exit 1
388
	fi
389

    
390
	_exec "mount ${_update_partition} ${chroot_dir}" "Mounting second partition to run upgrade" mute
391

    
392
	pkg_chroot="-c ${chroot_dir}"
393

    
394
	pkg_update force
395

    
396
	if [ "$(compare_pkg_version pkg)" = "<" ]; then
397
		_exec "pkg ${pkg_chroot} upgrade pkg" "Upgrading pkg" mute
398
		pkg_update force
399
	fi
400

    
401
}
402

    
403
switch_active_nanobsd_partition() {
404
	if [ "${platform}" != "nanobsd" ]; then
405
		return;
406
	fi
407

    
408
	local _cur_partition=$(mount -p / | cut -f1 | sed 's,^/dev/,,')
409
	local _disk=$(glabel status -s | \
410
		awk "\$1 == \"${_cur_partition}\" { print substr(\$3, 0, length(\$3)-3)}")
411
	local _i=$(echo ${_cur_partition} | cut -c ${#_cur_partition})
412

    
413
	if ! echo "${_i}" | egrep -q '^[0-9]$'; then
414
		_echo "Invalid partition label ${_cur_partition}"
415
		_exit 1
416
	fi
417

    
418
	# pfsense0 == part 1 / pfsense1 == part 2
419
	if [ ${_i} -eq 0 ]; then
420
		_i=2
421
	else
422
		_i=1
423
	fi
424

    
425
	_exec "gpart set -a active -i ${_i} ${_disk}" "Setting secondary partition as active" mute
426
}
427

    
428
is_pkg_installed() {
429
	local _pkg_name="${1}"
430
	shift
431
	local _pkg_chroot="$@"
432

    
433
	pkg ${_pkg_chroot} info -e ${_pkg_name}
434
	return $?
435
}
436

    
437
compare_pkg_version() {
438
	local _pkg_name="${1}"
439

    
440
	if ! is_pkg_installed ${_pkg_name} ${pkg_chroot}; then
441
		echo '!'
442
		return -1
443
	fi
444

    
445
	local _lver=$(pkg ${pkg_chroot} query %v ${_pkg_name})
446

    
447
	if [ -z "${_lver}" ]; then
448
		_echo "ERROR: It was not possible to determine ${_pkg_name} local version"
449
		_exit 1
450
	fi
451

    
452
	local _rver=$(pkg ${pkg_chroot} rquery %v ${_pkg_name})
453

    
454
	if [ -z "${_rver}" ]; then
455
		_echo "ERROR: It was not possible to determine ${_pkg_name} remote version"
456
		_exit 1
457
	fi
458

    
459
	local _version=$(pkg version -t ${_lver} ${_rver})
460

    
461
	if [ $? -ne 0 ]; then
462
		_echo "ERROR: Error comparing ${_pkg_name} local and remote versions"
463
		_exit 1
464
	fi
465

    
466
	echo ${_version}
467
	return 0
468
}
469

    
470
pkg_install() {
471
	local _pkg_name="${1}"
472

    
473
	if [ -z "${_pkg_name}" ]; then
474
		_echo "ERROR: Blank package name"
475
		_exit 1
476
	fi
477

    
478
	pkg_update
479

    
480
	if is_pkg_installed ${_pkg_name}; then
481
		local _cversion=$(compare_pkg_version ${_pkg_name})
482

    
483
		if [ "${_cversion}" = "=" ]; then
484
			_echo "Package ${_pkg_name} is up to date"
485
			_exit 0
486
		elif [ "${_cversion}" = ">" ]; then
487
			_echo "Installed ${_pkg_name} version is newer than remote"
488
			_exit 0
489
		fi
490
		local _cmd="upgrade"
491
		local _msg="Upgrading"
492
	else
493
		local _cmd="install"
494
		local _msg="Installing"
495
	fi
496

    
497
	_exec "pkg ${_cmd} ${_pkg_name}" "${_msg} ${_pkg_name}"
498
	_exec "pkg clean" "Cleaning up cache" mute ignore_result
499
}
500

    
501
pkg_delete() {
502
	local _pkg_name="${1}"
503

    
504
	if [ -z "${_pkg_name}" ]; then
505
		_echo "ERROR: Blank package name"
506
		_exit 1
507
	fi
508

    
509
	if ! is_pkg_installed ${_pkg_name}; then
510
		_echo "ERROR: Package ${_pkg_name} is not installed"
511
		_exit 1
512
	fi
513

    
514
	_exec "pkg delete ${_pkg_name}" "Removing ${_pkg_name}"
515
	_exec "pkg autoremove" "Removing stale packages" mute ignore_result
516
}
517

    
518
pid_file="/var/run/$(basename $0).pid"
519
last_update_file="/var/run/$(basename $0)-last-update"
520
logfile=/cf/conf/upgrade_log.txt
521
stdout='/dev/null'
522

    
523
# pkg should not ask for confirmations
524
export ASSUME_ALWAYS_YES=true
525

    
526
# Disable automatic update
527
export REPO_AUTOUPDATE=false
528

    
529
export product=$(/usr/local/bin/php -n /usr/local/sbin/read_global_var product_name pfSense)
530
export pkg_prefix=$(/usr/local/bin/php -n /usr/local/sbin/read_global_var pkg_prefix pfSense-pkg-)
531
export platform=$(cat /etc/platform)
532

    
533
USE_MFS_TMPVAR=$(/usr/local/sbin/read_xml_tag.sh boolean system/use_mfs_tmpvar)
534
if [ "${platform}" = "nanobsd" ] || [ "${USE_MFS_TMPVAR}" = "true" ]; then
535
	export PKG_DBDIR=/root/var/db/pkg
536
	export PKG_CACHEDIR=/root/var/cache/pkg
537
fi
538

    
539
# Upgrade process on nanobsd will happen in chroot
540
export pkg_chroot=""
541
export chroot_dir=""
542

    
543
unset booting
544
unset boot_stage
545
unset yes
546
unset progress_fifo
547
unset action
548
unset action_pkg
549
while getopts b:di:hp:r:uy opt; do
550
	case ${opt} in
551
		b)
552
			booting=1
553
			boot_stage="${OPTARG}"
554
			;;
555
		d)
556
			stdout=''
557
			;;
558
		i)
559
			if [ -n "${action}" ]; then
560
				usage
561
				_exit 1
562
			fi
563
			action="install"
564
			action_pkg="${OPTARG}"
565
			;;
566
		h)
567
			usage
568
			_exit 0
569
			;;
570
		p)
571
			progress_fifo="${OPTARG}"
572
			;;
573
		r)
574
			if [ -n "${action}" ]; then
575
				usage
576
				_exit 1
577
			fi
578
			action="delete"
579
			action_pkg="${OPTARG}"
580
			;;
581
		u)
582
			if [ -n "${action}" ]; then
583
				usage
584
				_exit 1
585
			fi
586
			action="update"
587
			;;
588
		y)
589
			yes=1
590
			;;
591
		*)
592
			usage
593
			_exit 1
594
			;;
595
	esac
596
done
597

    
598
# Set default action when no parameter is set
599
: ${action:="upgrade"}
600

    
601
if pgrep -qF ${pid_file} >/dev/null 2>&1; then
602
	echo "Another instance is already running... Aborting!"
603
	exit 1
604
fi
605

    
606
if [ -z "${booting}" -o "${boot_stage}" != "2" ]; then
607
	/etc/rc.conf_mount_rw
608
fi
609

    
610
echo $$ > ${pid_file}
611

    
612
trap _exit 1 2 15 EXIT
613

    
614
if [ -n "${progress_fifo}" ]; then
615
	if [ ! -e "${progress_fifo}" ]; then
616
		mkfifo ${progress_fifo}
617
	fi
618
	if [ ! -p "${progress_fifo}" ]; then
619
		_echo "ERROR: ${progress_fifo} is not a FIFO"
620
		_exit 1
621
	fi
622
	export EVENT_PIPE="${progress_fifo}"
623
fi
624

    
625
case "${action}" in
626
	upgrade)
627
		pkg_upgrade
628
		;;
629
	update)
630
		pkg_update force
631
		;;
632
	install)
633
		pkg_install ${action_pkg}
634
		;;
635
	delete)
636
		pkg_delete ${action_pkg}
637
		;;
638
	*)
639
		_echo "ERROR: Invalid action!"
640
		_exit 1
641
esac
642

    
643
_exit 0
(10-10/22)