Project

General

Profile

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

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

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

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

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

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

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

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

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

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

    
114
	if [ -n "${kernel_pkg}" ]; then
115
		if [ "$(pkg query %k ${kernel_pkg})" = "0" ]; then
116
			_exec "pkg lock ${kernel_pkg}" "Locking kernel package" mute ignore_result
117
		fi
118
	fi
119
	if [ -f "${pid_file}" ]; then
120
		rm -f ${pid_file}
121
	fi
122

    
123
	/etc/rc.conf_mount_ro
124

    
125
	local _rc=${1:-"0"}
126

    
127
	# If EVENT_PIPE is defined, GUI is calling
128
	[ -n "${EVENT_PIPE}" ] \
129
		&& _echo "__RC=${_rc}"
130

    
131
	exit ${_rc}
132
}
133

    
134
pkg_upgrade_first_step() {
135
	# figure out which kernel variant is running
136
	kernel_pkg=$(pkg query %n $(pkg info ${product}-kernel-\*))
137

    
138
	if [ -z "${kernel_pkg}" ]; then
139
		_echo "ERROR: It was not possible to identify which ${product} kernel is installed"
140
		_exit 1
141
	fi
142

    
143
	if [ "$(compare_pkg_version pkg)" = "<" ]; then
144
		_exec "pkg upgrade pkg" "Upgrading pkg" mute
145
		pkg_update force
146
	fi
147

    
148
	if [ $(pkg upgrade -nq | wc -l) -le 1 ]; then
149
		_echo "Your packages are up to date"
150
		_exit 0
151
	fi
152

    
153
	kernel_version_compare=$(compare_pkg_version ${kernel_pkg})
154

    
155
	if [ "${kernel_version_compare}" = "<" ]; then
156
		kernel_update=1
157
		if [ "$(pkg query %k ${kernel_pkg})" = "1" ]; then
158
			_exec "pkg unlock ${kernel_pkg}" "Unlocking kernel package" mute ignore_result
159
		fi
160
	elif [ "${kernel_version_compare}" = "=" ]; then
161
		kernel_update=0
162
	elif [ "${kernel_version_compare}" = ">" ]; then
163
		_echo "ERROR: You are using a newer kernel version than remote repository"
164
		_exit 1
165
	else
166
		_echo "ERROR: Error comparing ${product} kernel local and remote versions"
167
		_exit 1
168
	fi
169

    
170
	if [ -z "${yes}" ]; then
171
		# Show user which packages are going to be upgraded
172
		pkg upgrade -nq 2>&1 | tee -a ${logfile}
173

    
174
		_echo ""
175
		if [ ${kernel_update} -eq 1 ]; then
176
			_echo "**** WARNING ****"
177
			_echo "Reboot will be required!!"
178
		fi
179
		_echo -n "Proceed with upgrade? (y/N) "
180
		read answer
181
		if [ "${answer}" != "y" ]; then
182
			_echo "Aborting..."
183
			_exit 0
184
		fi
185
	fi
186

    
187
	_echo ">>> Downloading packages..."
188
	if ! pkg upgrade -F 2>&1 | tee -a ${logfile}; then
189
		_echo "ERROR: It was not possible to download packages"
190
		_exit 1
191
	fi
192

    
193
	# First upgrade kernel and reboot
194
	if [ ${kernel_update} -eq 1 ]; then
195
		_exec "pkg upgrade ${kernel_pkg}" "Upgrading ${product} kernel"
196
		touch ${upgrade_in_progress}
197
		_echo "Rebooting..."
198
		/etc/rc.reboot
199
	fi
200
}
201

    
202
pkg_upgrade_second_step() {
203
	_echo "Upgrading necessary packages..."
204
	if ! pkg upgrade 2>&1 | tee -a ${logfile}; then
205
		_echo "ERROR: An error occurred when upgrade was running..."
206
		_exit 1
207
	fi
208

    
209
	_exec "pkg autoremove" "Removing unnecessary packages" mute ignore_result
210
	_exec "pkg clean" "Cleanup pkg cache" mute ignore_result
211

    
212
	# cleanup caches
213

    
214
	rm -f ${upgrade_in_progress}
215
}
216

    
217
pkg_update() {
218
	local _run_update=1
219

    
220
	unset _force
221
	if [ "${1}" = "force" ]; then
222
		local _force=1
223
	fi
224

    
225
	if [ -z "${_force}" -a -f ${last_update_file} ]; then
226
		local _last_update=$(head -n 1 ${last_update_file})
227
		# Verify if content contain only numbers
228
		if echo "${_last_update}" | grep -E -q '^[0-9]+$'; then
229
			local _now=$(date +%s)
230
			# Only run update hourly, and if last update is in the future
231
			[ ${_now} -gt ${_last_update} -a $((${_now} - ${_last_update})) -le $((60 * 60)) ] \
232
				&& unset _run_update
233
		fi
234
	fi
235

    
236
	[ -z "${_run_update}" ] \
237
		&& return 0
238

    
239
	_exec "pkg update" "Updating repositories" mute
240
	date +%s > ${last_update_file}
241
}
242

    
243
pkg_upgrade() {
244
	unset need_reboot
245
	if [ ! -f "${upgrade_in_progress}" ]; then
246
		pkg_update
247

    
248
		if [ -f "${logfile}" ]; then
249
			rm -f ${logfile}
250
		fi
251

    
252
		pkg_upgrade_first_step
253

    
254
		if [ $(pkg upgrade -r ${product}-core -nq | wc -l) -le 1 ]; then
255
			need_reboot=1
256
		fi
257
	fi
258

    
259
	pkg_upgrade_second_step
260

    
261
	if [ -n "${need_reboot}" ]; then
262
		_echo "Rebooting..."
263
		/etc/rc.reboot
264
	fi
265
}
266

    
267
is_pkg_installed() {
268
	local _pkg_name="${1}"
269

    
270
	pkg info -e ${_pkg_name}
271
	return $?
272
}
273

    
274
compare_pkg_version() {
275
	local _pkg_name="${1}"
276

    
277
	if ! is_pkg_installed ${_pkg_name}; then
278
		echo '!'
279
		return -1
280
	fi
281

    
282
	local _lver=$(pkg query %v ${_pkg_name})
283

    
284
	if [ -z "${_lver}" ]; then
285
		_echo "ERROR: It was not possible to determine ${_pkg_name} local version"
286
		_exit 1
287
	fi
288

    
289
	local _rver=$(pkg rquery %v ${_pkg_name})
290

    
291
	if [ -z "${_rver}" ]; then
292
		_echo "ERROR: It was not possible to determine ${_pkg_name} remote version"
293
		_exit 1
294
	fi
295

    
296
	local _version=$(pkg version -t ${_lver} ${_rver})
297

    
298
	if [ $? -ne 0 ]; then
299
		_echo "ERROR: Error comparing ${_pkg_name} local and remote versions"
300
		_exit 1
301
	fi
302

    
303
	echo ${_version}
304
	return 0
305
}
306

    
307
pkg_install() {
308
	local _pkg_name="${1}"
309

    
310
	if [ -z "${_pkg_name}" ]; then
311
		_echo "ERROR: Blank package name"
312
		_exit 1
313
	fi
314

    
315
	pkg_update
316

    
317
	if is_pkg_installed ${_pkg_name}; then
318
		local _cversion=$(compare_pkg_version ${_pkg_name})
319

    
320
		if [ "${_cversion}" = "=" ]; then
321
			_echo "Package ${_pkg_name} is up to date"
322
			_exit 0
323
		elif [ "${_cversion}" = ">" ]; then
324
			_echo "Installed ${_pkg_name} version is newer than remote"
325
			_exit 0
326
		fi
327
		local _cmd="upgrade"
328
		local _msg="Upgrading"
329
	else
330
		local _cmd="install"
331
		local _msg="Installing"
332
	fi
333

    
334
	_exec "pkg ${_cmd} ${_pkg_name}" "${_msg} ${_pkg_name}"
335
	_exec "pkg clean" "Cleaning up cache" mute ignore_result
336
}
337

    
338
pkg_delete() {
339
	local _pkg_name="${1}"
340

    
341
	if [ -z "${_pkg_name}" ]; then
342
		_echo "ERROR: Blank package name"
343
		_exit 1
344
	fi
345

    
346
	if ! is_pkg_installed ${_pkg_name}; then
347
		_echo "ERROR: Package ${_pkg_name} is not installed"
348
		_exit 1
349
	fi
350

    
351
	_exec "pkg delete ${_pkg_name}" "Removing ${_pkg_name}"
352
	_exec "pkg autoremove" "Removing stale packages" mute ignore_result
353
}
354

    
355
pid_file="/var/run/$(basename $0).pid"
356
last_update_file="/var/run/$(basename $0)-last-update"
357
logfile=/cf/conf/upgrade_log.txt
358
stdout='/dev/null'
359

    
360
# File used to detect second call, after kernel update and reboot
361
upgrade_in_progress="/cf/conf/upgrade_in_progress"
362

    
363
# pkg should not ask for confirmations
364
export ASSUME_ALWAYS_YES=true
365

    
366
# Disable automatic update
367
export REPO_AUTOUPDATE=false
368

    
369
export product=$(/usr/local/bin/php -n /usr/local/sbin/read_global_var product_name pfSense)
370

    
371
unset yes
372
unset progress_fifo
373
unset action
374
unset action_pkg
375
while getopts di:hp:r:uy opt; do
376
	case ${opt} in
377
		d)
378
			stdout=''
379
			;;
380
		i)
381
			if [ -n "${action}" ]; then
382
				usage
383
				_exit 1
384
			fi
385
			action="install"
386
			action_pkg="${OPTARG}"
387
			;;
388
		h)
389
			usage
390
			_exit 0
391
			;;
392
		p)
393
			progress_fifo="${OPTARG}"
394
			;;
395
		r)
396
			if [ -n "${action}" ]; then
397
				usage
398
				_exit 1
399
			fi
400
			action="delete"
401
			action_pkg="${OPTARG}"
402
			;;
403
		u)
404
			if [ -n "${action}" ]; then
405
				usage
406
				_exit 1
407
			fi
408
			action="update"
409
			;;
410
		y)
411
			yes=1
412
			;;
413
		*)
414
			usage
415
			_exit 1
416
			;;
417
	esac
418
done
419

    
420
# Set default action when no parameter is set
421
: ${action:="upgrade"}
422

    
423
if pgrep -qF ${pid_file} >/dev/null 2>&1; then
424
	echo "Another instance is already running... Aborting!"
425
	exit 1
426
fi
427

    
428
/etc/rc.conf_mount_rw
429

    
430
echo $$ > ${pid_file}
431

    
432
trap _exit 1 2 15 EXIT
433

    
434
if [ -n "${progress_fifo}" ]; then
435
	if [ ! -e "${progress_fifo}" ]; then
436
		mkfifo ${progress_fifo}
437
	fi
438
	if [ ! -p "${progress_fifo}" ]; then
439
		_echo "ERROR: ${progress_fifo} is not a FIFO"
440
		_exit 1
441
	fi
442
	export EVENT_PIPE="${progress_fifo}"
443
fi
444

    
445
case "${action}" in
446
	upgrade)
447
		pkg_upgrade
448
		;;
449
	update)
450
		pkg_update force
451
		;;
452
	install)
453
		pkg_install ${action_pkg}
454
		;;
455
	delete)
456
		pkg_delete ${action_pkg}
457
		;;
458
	*)
459
		_echo "ERROR: Invalid action!"
460
		_exit 1
461
esac
462

    
463
_exit 0
(10-10/22)