Project

General

Profile

Download (15.4 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 "	-l          - Logfile name in /cf/conf/ (defaults to upgrade_log.txt)" >&2
55
	echo "	-p FIFO     - Write pkg progress to FIFO"
56
	echo "	-y          - Consider yes as the answer for any possible interaction" >&2
57
	echo "" >&2
58
	echo "Following parameters are mutually exclusive:" >&2
59
	echo "	-i PKG_NAME - Install package PKG_NAME" >&2
60
	echo "	-r PKG_NAME - Remove package PKG_NAME" >&2
61
	echo "	-u          - Update repository information" >&2
62
}
63

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

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

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

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

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

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

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

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

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

    
116
	pkg_lock ${kernel_pkg}
117

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

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

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

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

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

    
136
	exit ${_rc}
137
}
138

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

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

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

    
161
	fi
162

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

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

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

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

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

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

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

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

    
202
pkg_update() {
203
	local _run_update=1
204

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

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

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

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

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

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

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

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

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

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

    
257
		pkg_update
258

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

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

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

    
274
		pkg_unlock ${kernel_pkg}
275

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

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

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

    
311
		# Download all upgrade packages first
312
		fetch_upgrade_packages
313

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

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

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

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

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

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

    
344
		pkg_unlock "${pkg_prefix}*"
345

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

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

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

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

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

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

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

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

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

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

    
395
	pkg_update force
396

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

    
402
}
403

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
479
	pkg_update
480

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

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

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

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

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

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

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

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

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

    
527
# Disable automatic update
528
export REPO_AUTOUPDATE=false
529

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

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

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

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

    
602
# Set default action when no parameter is set
603
: ${action:="upgrade"}
604

    
605
if pgrep -qF ${pid_file} >/dev/null 2>&1; then
606
	echo "Another instance is already running... Aborting!"
607
	exit 1
608
fi
609

    
610
if [ -z "${booting}" -o "${boot_stage}" != "2" ]; then
611
	/etc/rc.conf_mount_rw
612
fi
613

    
614
echo $$ > ${pid_file}
615

    
616
trap _exit 1 2 15 EXIT
617

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

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

    
647
_exit 0
(10-10/23)