Project

General

Profile

Download (10.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}) [-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
	local _rc=${1:-"0"}
124

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

    
129
	exit ${_rc}
130
}
131

    
132
pkg_upgrade_first_step() {
133
	# figure out which kernel variant is running
134
	kernel_pkg=$(pkg query %n $(pkg info pfSense-kernel-\*))
135

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

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

    
146
	kernel_version_compare=$(compare_pkg_version ${kernel_pkg})
147

    
148
	if [ "${kernel_version_compare}" = "<" ]; then
149
		kernel_update=1
150
		if [ "$(pkg query %k ${kernel_pkg})" = "1" ]; then
151
			_exec "pkg unlock ${kernel_pkg}" "Unlocking kernel package" mute ignore_result
152
		fi
153
	elif [ "${kernel_version_compare}" = "=" ]; then
154
		kernel_update=0
155
	elif [ "${kernel_version_compare}" = ">" ]; then
156
		_echo "ERROR: You are using a newer kernel version than remote repository"
157
		_exit 1
158
	else
159
		_echo "ERROR: Error comparing pfSense kernel local and remote versions"
160
		_exit 1
161
	fi
162

    
163
	# XXX find a samrter way to do it
164
	l=$(pkg upgrade -nq | wc -l)
165
	if [ ${l} -le 1 ]; then
166
		_echo "Your packages are up to date"
167
		_exit 0
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 pfSense 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
		need_reboot=1
254
	fi
255

    
256
	pkg_upgrade_second_step
257

    
258
	if [ -n "${need_reboot}" ]; then
259
		_echo "Rebooting..."
260
		/etc/rc.reboot
261
	fi
262
}
263

    
264
is_pkg_installed() {
265
	local _pkg_name="${1}"
266

    
267
	pkg info -e ${_pkg_name}
268
	return $?
269
}
270

    
271
compare_pkg_version() {
272
	local _pkg_name="${1}"
273

    
274
	if ! is_pkg_installed ${_pkg_name}; then
275
		echo '!'
276
		return -1
277
	fi
278

    
279
	local _lver=$(pkg query %v ${_pkg_name})
280

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

    
286
	local _rver=$(pkg rquery %v ${_pkg_name})
287

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

    
293
	local _version=$(pkg version -t ${_lver} ${_rver})
294

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

    
300
	echo ${_version}
301
	return 0
302
}
303

    
304
pkg_install() {
305
	local _pkg_name="${1}"
306

    
307
	if [ -z "${_pkg_name}" ]; then
308
		_echo "ERROR: Blank package name"
309
		_exit 1
310
	fi
311

    
312
	pkg_update
313

    
314
	if is_pkg_installed ${_pkg_name}; then
315
		local _cversion=$(compare_pkg_version ${_pkg_name})
316

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

    
331
	_exec "pkg ${_cmd} ${_pkg_name}" "${_msg} ${_pkg_name}"
332
	_exec "pkg clean" "Cleaning up cache" mute ignore_result
333
}
334

    
335
pkg_delete() {
336
	local _pkg_name="${1}"
337

    
338
	if [ -z "${_pkg_name}" ]; then
339
		_echo "ERROR: Blank package name"
340
		_exit 1
341
	fi
342

    
343
	if ! is_pkg_installed ${_pkg_name}; then
344
		_echo "ERROR: Package ${_pkg_name} is not installed"
345
		_exit 1
346
	fi
347

    
348
	_exec "pkg delete ${_pkg_name}" "Removing ${_pkg_name}"
349
	_exec "pkg autoremove" "Removing stale packages" mute ignore_result
350
}
351

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

    
357
# File used to detect second call, after kernel update and reboot
358
upgrade_in_progress="/cf/conf/upgrade_in_progress"
359

    
360
# pkg should not ask for confirmations
361
export ASSUME_ALWAYS_YES=true
362

    
363
# Disable automatic update
364
export REPO_AUTOUPDATE=false
365

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

    
415
# Set default action when no parameter is set
416
: ${action:="upgrade"}
417

    
418
if pgrep -qF ${pid_file} >/dev/null 2>&1; then
419
	echo "Another instance is already running... Aborting!"
420
	exit 1
421
fi
422

    
423
echo $$ > ${pid_file}
424

    
425
trap _exit 1 2 15 EXIT
426

    
427
if [ -n "${progress_fifo}" ]; then
428
	if [ ! -e "${progress_fifo}" ]; then
429
		mkfifo ${progress_fifo}
430
	fi
431
	if [ ! -p "${progress_fifo}" ]; then
432
		_echo "ERROR: ${progress_fifo} is not a FIFO"
433
		_exit 1
434
	fi
435
	export EVENT_PIPE="${progress_fifo}"
436
fi
437

    
438
case "${action}" in
439
	upgrade)
440
		pkg_upgrade
441
		;;
442
	update)
443
		pkg_update force
444
		;;
445
	install)
446
		pkg_install ${action_pkg}
447
		;;
448
	delete)
449
		pkg_delete ${action_pkg}
450
		;;
451
	*)
452
		_echo "ERROR: Invalid action!"
453
		_exit 1
454
esac
455

    
456
_exit 0
(10-10/20)