View | Details | Raw Unified | Return to bug 193003 | Differences between
and this patch

Collapse All | Expand All

(-)/usr/ports/sysutils/bsdadminscripts/Makefile (-2 / +12 lines)
Lines 1-9 Link Here
1
# Created by: Dominic Fandrey <lon_kamikaze@gmx.de>
1
# Created by: Dominic Fandrey <lon_kamikaze@gmx.de>
2
# $FreeBSD: head/sysutils/bsdadminscripts/Makefile 366079 2014-08-25 14:12:18Z marino $
2
# $FreeBSD$
3
3
4
PORTNAME=	bsdadminscripts
4
PORTNAME=	bsdadminscripts
5
PORTVERSION=	6.1.1
5
PORTVERSION=	6.1.1
6
PORTREVISION=	6
6
PORTREVISION=	7
7
CATEGORIES=	sysutils ports-mgmt
7
CATEGORIES=	sysutils ports-mgmt
8
MASTER_SITES=	SF/${PORTNAME}/${PORTNAME}
8
MASTER_SITES=	SF/${PORTNAME}/${PORTNAME}
9
9
Lines 13-22 Link Here
13
LICENSE=	BSD2CLAUSE
13
LICENSE=	BSD2CLAUSE
14
14
15
NO_BUILD=	yes
15
NO_BUILD=	yes
16
17
TMP=/tmp
18
VAR=/var
19
16
PORTDOCS=	ABOUT CHANGES INSTALL NOTES THANKS
20
PORTDOCS=	ABOUT CHANGES INSTALL NOTES THANKS
17
21
18
OPTIONS_DEFINE=	DOCS
22
OPTIONS_DEFINE=	DOCS
19
23
24
SUB_FILES=	pkg_libchk pkg_upgrade uma
25
SUB_LIST=	TMP=${TMP} PREFIX=${PREFIX} VAR=${VAR} PORTS=${PORTSDIR}
26
20
.include <bsd.port.options.mk>
27
.include <bsd.port.options.mk>
21
28
22
.if ! ${PORT_OPTIONS:MDOCS}
29
.if ! ${PORT_OPTIONS:MDOCS}
Lines 31-42 Link Here
31
		-datadir=${STAGEDIR}${DATADIR} \
38
		-datadir=${STAGEDIR}${DATADIR} \
32
		${EVALDOCS}
39
		${EVALDOCS}
33
.for n in pkg_libchk pkg_upgrade uma
40
.for n in pkg_libchk pkg_upgrade uma
41
	${MV} ${WRKDIR}/${n} ${WRKSRC}/src
34
	${INSTALL_SCRIPT} ${WRKSRC}/src/${n} ${STAGEDIR}${PREFIX}/sbin
42
	${INSTALL_SCRIPT} ${WRKSRC}/src/${n} ${STAGEDIR}${PREFIX}/sbin
35
.endfor
43
.endfor
36
	${INSTALL_DATA} ${WRKSRC}/src/buildflags.mk ${STAGEDIR}${DATADIR}
44
	${INSTALL_DATA} ${WRKSRC}/src/buildflags.mk ${STAGEDIR}${DATADIR}
37
	${INSTALL_DATA} ${WRKSRC}/src/buildflags.conf.sample \
45
	${INSTALL_DATA} ${WRKSRC}/src/buildflags.conf.sample \
38
		${STAGEDIR}${PREFIX}/etc
46
		${STAGEDIR}${PREFIX}/etc
39
	${INSTALL_DATA} ${WRKSRC}/src/uma.conf.sample ${STAGEDIR}${PREFIX}/etc
47
	${INSTALL_DATA} ${WRKSRC}/src/uma.conf.sample ${STAGEDIR}${PREFIX}/etc
48
40
.for f in bsdadminscripts buildflags.awk buildflags.conf buildflags.mk \
49
.for f in bsdadminscripts buildflags.awk buildflags.conf buildflags.mk \
41
	distviper pkg_libchk pkg_upgrade pkg_validate portconfig rcstart uma
50
	distviper pkg_libchk pkg_upgrade pkg_validate portconfig rcstart uma
42
	${INSTALL_MAN} ${WRKSRC}/src/${f}.1 ${STAGEDIR}${MAN1PREFIX}/man/man1
51
	${INSTALL_MAN} ${WRKSRC}/src/${f}.1 ${STAGEDIR}${MAN1PREFIX}/man/man1
Lines 46-51 Link Here
46
	${MKDIR} ${STAGEDIR}${ETCDIR}
55
	${MKDIR} ${STAGEDIR}${ETCDIR}
47
	${MV} ${STAGEDIR}${PREFIX}/etc/*.sample ${STAGEDIR}${ETCDIR}
56
	${MV} ${STAGEDIR}${PREFIX}/etc/*.sample ${STAGEDIR}${ETCDIR}
48
	${RM} -rf ${STAGEDIR}${PREFIX}/etc/*.sample
57
	${RM} -rf ${STAGEDIR}${PREFIX}/etc/*.sample
58
49
.if ${PORT_OPTIONS:MDOCS}
59
.if ${PORT_OPTIONS:MDOCS}
50
	${MKDIR} ${STAGEDIR}${DOCSDIR}
60
	${MKDIR} ${STAGEDIR}${DOCSDIR}
51
	cd ${WRKSRC} && ${INSTALL_DATA} ${PORTDOCS} ${STAGEDIR}${DOCSDIR}
61
	cd ${WRKSRC} && ${INSTALL_DATA} ${PORTDOCS} ${STAGEDIR}${DOCSDIR}
(-)/usr/ports/sysutils/bsdadminscripts/files/patch-pkg_libchk (-75 lines)
Lines 1-75 Link Here
1
--- src/pkg_libchk.orig	2009-04-19 17:57:16.000000000 +0200
2
+++ src/pkg_libchk	2013-06-26 22:01:57.000000000 +0200
3
@@ -23,6 +23,8 @@
4
 
5
 readonly name=pkg_libchk
6
 readonly version=1.6.1
7
+readonly osname=`uname -s`
8
+readonly pkgng=`make -f /usr/share/mk/bsd.port.mk -V WITH_PKGNG`
9
 
10
 # Use a line break as delimiter.
11
 IFS='
12
@@ -206,7 +208,7 @@ dependencyMissing() {
13
 	# We cannot handle non-native binaries,
14
 	# so assume everything is in order.
15
 	if ! readelf -e "$1" 2>&1 | \
16
-		grep -E "^[[:space:]]*OS/ABI:[[:space:]]*UNIX - $OSTYPE\$" \
17
+		grep -E "^[[:space:]]*OS/ABI:[[:space:]]*UNIX - $osname\$" \
18
 		> /dev/null
19
 	then
20
 		return 2
21
@@ -405,10 +407,17 @@ statusSet 'Preparing ...'
22
 
23
 # Get the packages to work on.
24
 test -z "$packages" && packages="-a"
25
-packages="$(pkg_info -E $packages)"
26
-test -z "$recursive" -a -z "$Recursive" || packages="$packages
27
-$(pkg_info -q $recursive $Recursive "$packages" 2> /dev/null | \
28
-sed -E 's|^@pkgdep[[:space:]]*||1')"
29
+if [ -n "$pkgng" ]; then
30
+	packages="$(pkg info -q $packages)"
31
+	test -z "$recursive" -a -z "$Recursive" || packages="$packages
32
+	$(pkg info -q $recursive $Recursive "$packages" 2> /dev/null | \
33
+	sed -E 's|^@pkgdep[[:space:]]*||1')"
34
+else
35
+	packages="$(pkg_info -E $packages)"
36
+	test -z "$recursive" -a -z "$Recursive" || packages="$packages
37
+	$(pkg_info -q $recursive $Recursive "$packages" 2> /dev/null | \
38
+	sed -E 's|^@pkgdep[[:space:]]*||1')"
39
+fi
40
 
41
 # Create the regexp to match ldd output
42
 match_expr="$compat=> not found|dependency .+ not found"
43
@@ -420,9 +429,15 @@ package_num=0
44
 # Check each selected package.
45
 for package in $packages; {
46
 	package_num="$(($package_num + 1))"
47
-	test $origin \
48
-		&& package_name="$(pkg_info -qo "$package")" \
49
-		|| package_name="$package"
50
+	if [ -n "$pkgng" ]; then
51
+		test $origin \
52
+			&& package_name="$(pkg info -qo "$package")" \
53
+			|| package_name="$package"
54
+	else
55
+		test $origin \
56
+			&& package_name="$(pkg_info -qo "$package")" \
57
+			|| package_name="$package"
58
+	fi
59
 
60
 	# Print what we're doing.
61
 	statusSet "Starting job $package_num of $package_amount: $package_name"
62
@@ -432,7 +447,12 @@ for package in $packages; {
63
 		# Remember freeing the semaphore.
64
 		trap 'semaphoreFree jobs' EXIT
65
 
66
-		files="$(pkg_info -qL "$package")"
67
+		files=""
68
+		if [ -n "$pkgng" ]; then
69
+			files="$(pkg info -lq "$package")"
70
+		else
71
+			files="$(pkg_info -qL "$package")"
72
+		fi
73
 		# Get the programs libraries in case it doesn't use the
74
 		# operating system to find its libraries.
75
 		libraries="$(echo "$files" | grep -E '\.so[\.0-9]*$')"
(-)/usr/ports/sysutils/bsdadminscripts/files/pkg_libchk.in (+484 lines)
Line 0 Link Here
1
#!/bin/sh -f
2
#
3
# Copyright (c) 2007-2009
4
# Dominic Fandrey <kamikaze@bsdforen.de>
5
#
6
# Redistribution and use in source and binary forms, with or without
7
# modification, are permitted provided that the following conditions
8
# are met:
9
# 1. Redistributions of source code must retain the above copyright
10
#    notice, this list of conditions and the following disclaimer.
11
#
12
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
13
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
14
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
15
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
16
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
17
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
18
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
19
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
21
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22
#
23
24
readonly name=pkg_libchk
25
readonly version=1.6.1
26
readonly osname=`uname -s`
27
readonly pkgng=`make -f /usr/share/mk/bsd.port.mk -V WITH_PKGNG`
28
29
# Use a line break as delimiter.
30
IFS='
31
'
32
33
# Filename prefix for shared data
34
sharedprefix="%%TMP%%/$$"
35
shared="locks"
36
37
#
38
# This function remembers a lock to allow later deletion with the 
39
# lockUnregisterAll() function.
40
#
41
# @param $1
42
#	The name of the lock.
43
lockRegister() {
44
	local lock
45
	lock="$sharedprefix-$shared"
46
	lockf -k "$lock" sh -c "
47
		if ! grep -qE '^$1\$' '$lock'; then
48
			echo '$1' >> '$lock'
49
		fi
50
	"
51
}
52
53
#
54
# Unregisters all locks.
55
#
56
lockUnregisterAll() {
57
	wait
58
	for register in $(cat "$sharedprefix-$shared"); {
59
		lockf "$sharedprefix-$register" wait
60
	}
61
	lockf "$sharedprefix-$shared" wait
62
}
63
64
#
65
# This function creates a semaphore.
66
#
67
# @param $1
68
#	The name of the semaphore.
69
# @param $2
70
#	The size of the semaphore.
71
#
72
semaphoreCreate() {
73
	local lock
74
	lockRegister "semaphore-$1"
75
	lock="$sharedprefix-semaphore-$1"
76
	lockf -k "$lock" echo "$2" > "$lock"
77
	eval "semaphore_$1_size=$2"
78
}
79
80
#
81
# This function waits until the semaphore is free und registers its use.
82
# Everything that uses this also has to call the semaphoreFree() function.
83
#
84
# @param $1
85
#	The name of the semaphore.
86
#
87
semaphoreUse() {
88
	local lock semaphores
89
	lock="$sharedprefix-semaphore-$1"
90
	while ! lockf -k "$lock" sh -c "
91
			state=\$(cat '$lock')
92
			if [ \"\$state\" -gt 0 ]; then
93
				echo \"\$((\$state - 1))\" > '$lock'
94
				exit 0
95
			fi
96
			exit 1
97
		"; do
98
		sleep 0.1
99
	done
100
}
101
102
#
103
# This function frees a semaphore.
104
#
105
# @param $1
106
#	The name of the semaphore.
107
#
108
semaphoreFree() {
109
	local lock
110
	lock="$sharedprefix-semaphore-$1"
111
	lockf -k "$lock" sh -c "
112
		state=\"\$((\"\$(cat '$lock')\" + 1))\"
113
		echo \"\$state\" > '$lock'
114
	"
115
}
116
117
#
118
# This function sets a new status and prints it.
119
#
120
# @param $1
121
#	The status message.
122
# @param $clean
123
#	If set status handling is disabled.
124
#
125
statusSet() {
126
	# In clean mode status handling is disabled.
127
	test -z "$clean" || return 0
128
	local lock
129
	lock="$sharedprefix-status"
130
	lockf -k "$lock" sh -c "
131
		status=\"\$(cat '$lock')\"
132
		echo '$1' > '$lock'
133
		printf \"\\r%-\${#status}s\\r\" '$1' > /dev/tty
134
	"
135
}
136
137
#
138
# This function prints a message and the current status behind it.
139
#
140
# @param $1
141
#	The message to print.
142
# @param $clean
143
#	If set the status will not be printed.
144
#
145
statusPrint() {
146
	if [ -z "$clean" ]; then
147
		local lock
148
		lock="$sharedprefix-status"
149
		lockf -k "$lock" sh -c "
150
			status=\"\$(cat '$lock')\"
151
			printf \"%-\${#status}s\\r\" '' > /dev/tty
152
			echo '$1'
153
			printf '%s\\r' \"\$status\" > /dev/tty
154
		"
155
	else
156
		echo "$1"
157
	fi
158
}
159
160
#
161
# Waits for a semaphore to be completely free and counts down the remaining
162
# number of locks.
163
#
164
# @param $1
165
#	The semaphore to watch.
166
# @param $2
167
#	The status message to print, insert %d in the place where the number
168
#	of remaining locks belong.
169
#
170
semaphoreCountDown() {
171
	local free size
172
	while read -t1 free < "$sharedprefix-semaphore-$1"; do
173
		size=$(eval "echo \$semaphore_$1_size")
174
		statusSet "$(printf "$2" $(( $size - $free )))"
175
		test "$free" -eq "$size" && break
176
		sleep 0.1
177
	done
178
	wait
179
}
180
181
# Clean up upon exit.
182
trap '
183
	semaphoreCountDown jobs "Terminated by signal, waiting for %d jobs to die."
184
	echo > /dev/tty
185
	lockUnregisterAll
186
	exit 255
187
' int term
188
189
#
190
# This function checks whether a given binary or library directly depends
191
# on a missing library.
192
# It goes a long way to prevent all kinds of false positives.
193
# It always returns 2 (false) for Linux and other non-native libraries
194
# and binaries.
195
# It also checks whether the missing dependency is really a direct dependency
196
# (indirect dependencies have to be fixed somewhere else).
197
#
198
# @param $1
199
#	The library or binary to check.
200
# @return
201
#	Returns 0 (true) if a library is missing.
202
#	Returns 1 if everything is all right.
203
#	Returns 2 if the check cannot be performed (not a native library).
204
#
205
dependencyMissing() {
206
	local missing file direct libfound
207
208
	# We cannot handle non-native binaries,
209
	# so assume everything is in order.
210
	if ! readelf -e "$1" 2>&1 | \
211
		grep -E "^[[:space:]]*OS/ABI:[[:space:]]*UNIX - $osname\$" \
212
		> /dev/null
213
	then
214
		return 2
215
	# Nothing is missing.
216
	elif ! missing="$(ldd "$1" 2>&1 | grep -E "$match_expr")"; then
217
		return 1
218
	fi
219
220
	# The return status. The value 1 assumes that this is a false positive.
221
	status=1
222
223
	# Only report misses for direct dependencies.
224
	direct="$(
225
			readelf -d "$1" 2> /dev/null | \
226
				grep 'Shared library:' | \
227
				sed -E -e 's|^[^[]*\[||1' -e 's|\]$||1'
228
	)"
229
230
	# Compare every missing depency with the list of direct dependencies
231
	# and report that the dependency is missing if the missing file is
232
	# a direct dependency.
233
	for file in $missing; {
234
		# Strip the missing file of additional information.
235
		file="$(echo "$file" | sed -E \
236
			-e 's| => .*$||1' \
237
			-e 's|^[[:space:]]*||1' \
238
			-e 's|^.*dependency ||1' \
239
			-e 's| not found$||1'
240
		)"
241
242
		# If in mean mode we do not check for false positives.
243
		if [ -n "$mean" ]; then
244
			test -n "$raw" && return 0
245
			statusPrint "$package_name: $1 misses $file"
246
			continue
247
		fi
248
249
		# Handle the case where a library is not found, but exists
250
		# somewhere in the package. This is for packages that do not
251
		# rely on the OS to find libraries.
252
		libfound=
253
		for library in $(echo "$libraries" | grep -E "/$file\$"); {
254
			# The library exists after all.
255
			test -e "$library" && libfound=1 && break
256
		}
257
		if test "$libfound"; then
258
			test -n "$verbose" && statusPrint "$package_name: \
259
located: $1 misses $file found at $library."
260
			continue
261
		fi
262
263
		# Compare the file with the list of direct dependencies.
264
		# If it's not in than it's only an indirect dependency and
265
		# cannot be fixed by rebuilding this port.
266
		if echo "$direct" | grep -E "^$file\$" > /dev/null; then
267
			test -n "$raw" && return 0
268
			statusPrint "$package_name: $1 misses $file"
269
			status=0
270
		elif [ -n "$verbose" ]; then
271
			statusPrint "$package_name: inderect: $1 \
272
misses $file is an inderect dependency."
273
		fi
274
	}
275
276
	return $status
277
}
278
279
#
280
# Checks the parameters for options.
281
#
282
# @param $packages
283
#	The parameters to pkg_info -E that will result in the
284
#	names of the packages to work on.
285
# @param $recursive
286
#	Contains the appropriate parameter to get the
287
#	dependencies of the given packages from pkg_info.
288
# @param $Recursive
289
#	Contains the appropriate parameter to get the
290
#	packages depending on the given packages from pkg_info.
291
# @param $raw
292
#	Is set to trigger raw printing.
293
# @param $clean
294
#	Is set to trigger printing without status messages.
295
# @param $verbose
296
#	Is set to be verbose about false positives.
297
# @param $mean
298
#	Is set to switch into mean mode. That means no
299
#	checking of false positives.
300
# @param $compat
301
#	Delete to avoid detecting compat libraries as misses.
302
# @param $origin
303
#	Is set to turn the print origin mode on.
304
# @semaphore jobs
305
#	Is set to limit the amount of parallel jobs.
306
#
307
readParams() {
308
	local option
309
310
	for option {
311
		case "$option" in
312
			"-a" | "--all")
313
				packages="-a"
314
			;;
315
			"-c" | "--clean")
316
				clean=1
317
			;;
318
			"-h" | "--help")
319
				printHelp
320
			;;
321
			-j* | --jobs*)
322
				local jobs
323
				jobs="${option#-j}"
324
				jobs="${jobs#--jobs}"
325
				if [ "$jobs" -ne "$jobs" ] 2> /dev/null; then
326
					echo "The -j option must be followed" \
327
						"by a number."
328
					exit 3
329
				elif [ "$jobs" -lt 1 ]; then
330
					echo "The -j option must specify at" \
331
						"least 1 job."
332
					exit 3
333
				else
334
					semaphoreCreate jobs "$jobs"
335
				fi
336
			;;
337
			"-m" | "--mean")
338
				mean=1
339
			;;
340
			"-n" | "--no-compat")
341
				compat=
342
			;;
343
			"-o" | "--origin")
344
				origin=1
345
			;;
346
			"-q" | "--raw")
347
				raw=1
348
				if [ -n "$verbose" ]; then
349
					echo "The parameters -v and -q may" \
350
						"not be used at the same time."
351
					exit 2
352
				fi
353
			;;
354
			"-r" | "--recursive")
355
				recursive="-r"
356
			;;
357
			"-R" | "--upward-recursive")
358
				Recursive="-R"
359
			;;
360
			"-v" | "--verbose")
361
				verbose=1
362
				if [ -n "$raw" ]; then
363
					echo "The parameters -q and -v may" \
364
						"not be used at the same time."
365
					exit 2
366
				fi
367
			;;
368
			-? | --*)
369
				echo "Unknown parameter \"$option\"."
370
				exit 1
371
			;;
372
			-*)
373
				readParams "${option%${option#-?}}"
374
				readParams "-${option#-?}"
375
			;;
376
			*)
377
				packages="$packages${packages:+$IFS}$option"
378
			;;
379
		esac
380
	}
381
}
382
383
#
384
# Display a short help message.
385
#
386
printHelp() {
387
	echo "$name v$version
388
usage:	$name [-a] [-c] [-h] [-jN] [-m] [-n] [-o] [-q] [-r] [-R] [-v] [packages]"
389
        exit 0
390
}
391
392
# Create the expression to match to find files linking against compat libraries.
393
# This can be emptied by readParams to deactivate that feature.
394
prefix="$(make -f /usr/share/mk/bsd.port.mk -VPREFIX 2> /dev/null || \
395
	echo '%%PREFIX%%')"
396
compat="=> $prefix/lib/compat|"
397
398
# Create the semaphore with CPU cores * 2 jobs.
399
semaphoreCreate jobs "$(($(sysctl -n hw.ncpu 2> /dev/null || echo 1) * 2))"
400
# Register the status lock.
401
lockRegister status
402
403
# Read the parameters.
404
readParams "$@"
405
406
statusSet 'Preparing ...'
407
408
# Get the packages to work on.
409
test -z "$packages" && packages="-a"
410
if [ -n "$pkgng" ]; then
411
	packages="$(pkg info -q $packages)"
412
	test -z "$recursive" -a -z "$Recursive" || packages="$packages
413
	$(pkg info -q $recursive $Recursive "$packages" 2> /dev/null | \
414
	sed -E 's|^@pkgdep[[:space:]]*||1')"
415
else
416
	packages="$(pkg_info -E $packages)"
417
	test -z "$recursive" -a -z "$Recursive" || packages="$packages
418
	$(pkg_info -q $recursive $Recursive "$packages" 2> /dev/null | \
419
	sed -E 's|^@pkgdep[[:space:]]*||1')"
420
fi
421
422
# Create the regexp to match ldd output
423
match_expr="$compat=> not found|dependency .+ not found"
424
425
# The packages to check.
426
package_amount="$(echo "$packages" | wc -l | sed 's|[[:space:]]||g')"
427
package_num=0
428
429
# Check each selected package.
430
for package in $packages; {
431
	package_num="$(($package_num + 1))"
432
	if [ -n "$pkgng" ]; then
433
		test $origin \
434
			&& package_name="$(pkg info -qo "$package")" \
435
			|| package_name="$package"
436
	else
437
		test $origin \
438
			&& package_name="$(pkg_info -qo "$package")" \
439
			|| package_name="$package"
440
	fi
441
442
	# Print what we're doing.
443
	statusSet "Starting job $package_num of $package_amount: $package_name"
444
445
	semaphoreUse jobs
446
	(
447
		# Remember freeing the semaphore.
448
		trap 'semaphoreFree jobs' EXIT
449
450
		files=""
451
		if [ -n "$pkgng" ]; then
452
			files="$(pkg info -lq "$package")"
453
		else
454
			files="$(pkg_info -qL "$package")"
455
		fi
456
		# Get the programs libraries in case it doesn't use the
457
		# operating system to find its libraries.
458
		libraries="$(echo "$files" | grep -E '\.so[\.0-9]*$')"
459
460
		outdated=0
461
		broken=
462
463
		# Check each file of each package.
464
		for file in $files; {
465
			if [ ! -L "$file" -a \( \
466
				-x "$file" -o \
467
				-n "$(echo "$file" | grep -E '\.so[\.0-9]*$')" \
468
			 \) ]; then
469
				if dependencyMissing "$file"; then
470
					if [ -n "$raw" ]; then
471
						statusPrint "$package_name"
472
						break 1
473
					fi
474
				fi
475
			fi
476
		}
477
	) &
478
}
479
480
semaphoreCountDown jobs "Waiting for %d remaining jobs to finish."
481
statusSet
482
lockUnregisterAll
483
484
exit 0
(-)/usr/ports/sysutils/bsdadminscripts/files/pkg_upgrade.in (+2239 lines)
Line 0 Link Here
1
#!/bin/sh -f
2
#
3
# Copyright (c) 2009
4
# Dominic Fandrey <kamikaze@bsdforen.de>
5
#
6
# Redistribution and use in source and binary forms, with or without
7
# modification, are permitted provided that the following conditions
8
# are met:
9
# 1. Redistributions of source code must retain the above copyright
10
#    notice, this list of conditions and the following disclaimer.
11
#
12
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
13
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
14
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
15
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
16
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
17
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
18
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
19
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
21
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22
#
23
24
readonly version=1.1
25
readonly name=pkg_upgrade
26
27
# Error table.
28
readonly ERR_LOCK=1
29
readonly ERR_ARG=2
30
readonly ERR_INDEX=3
31
readonly ERR_FETCH=4
32
readonly ERR_SORT=5
33
readonly ERR_BACKUP_MISS=6
34
readonly ERR_BACKUP_UNKNOWN=7
35
readonly ERR_INSTALL=8
36
readonly ERR_USER=9
37
readonly ERR_TERM=10
38
readonly ERR_PACKAGE_FORMAT=11
39
readonly ERR_CONFLICT=12
40
41
# Constant assignments.
42
readonly logfile="%%VAR%%/log/$name.log"
43
readonly pid=$$
44
45
# Get some environment variables from uma. This includes PACKAGESITE,
46
# TMPDIR and PKG_INDEX.
47
eval "$(uma env $pid)"
48
49
# The remote package repository, derived from PACKAGESITE.
50
# If this matches the PACKAGES environment variable all downloading operations
51
# will be omitted.
52
readonly packagerepos="${PACKAGESITE%/*?}"
53
54
# Environment variables.
55
: ${PACKAGES="$(make -V PACKAGES -f /usr/share/mk/bsd.port.mk 2> /dev/null)"}
56
PACKAGES="${PACKAGES:-%%PORTS%%/packages}"
57
: ${PKG_DBDIR=%%VAR%%/db/pkg}
58
: ${TMPDIR=%%TMP%%}
59
: ${PKG_TMPDIR=$TMPDIR}
60
61
# This is where backup packages will be stored.
62
readonly packagebackup="$PACKAGES/$name-backup"
63
# This is where the download manager will listen for messages.
64
readonly queueMessages="$TMPDIR/pkg_upgrade.messages.queue"
65
66
# Export environment variables to ensure that every tool uses the same ones.
67
export ARCH PACKAGEROOT PACKAGESITE FTP_TIMEOUT PKG_INDEX
68
export PACKAGEROOT_MIRRORS PACKAGESITE_MIRRORS
69
export PACKAGES PKG_DBDIR TMPDIR PKG_TMPDIR
70
71
# Direct index access.
72
readonly IDX_PKG=0
73
readonly IDX_ORIGIN=1
74
readonly IDX_PREFIX=2
75
readonly IDX_COMMENT=3
76
readonly IDX_DESCRIPTION=4
77
readonly IDX_MAINTAINER=5
78
readonly IDX_CATEGORIES=6
79
readonly IDX_DIRECTDEPENDS=7
80
readonly IDX_DEPENDS=8
81
readonly IDX_WWW=9
82
readonly IDX_PERLVERSION=10
83
readonly IDX_PERLMODULES=11
84
85
# Input field seperator without spaces.
86
IFS='
87
'
88
89
# Parameter flags.
90
pAll=
91
pNoBackup=
92
pClean=
93
pExitOnConflict=
94
pForce=
95
pFetchOnly=
96
pInteractive=
97
pJobs=
98
pListDiscarded=
99
pNoActions=
100
pNoLogging=
101
pParanoid=
102
pRecursive=
103
pReplaceConflicts=
104
pMoreRecursive=
105
pUpwardRecursive=
106
pMoreUpwardRecursive=
107
pVerbose=
108
109
# The categories for packages.
110
older=
111
newer=
112
unindexed=
113
multiple=
114
error=
115
116
# A cache for the pkgDepends function.
117
dependsChecked=
118
119
# The names of packages that do not have a verified download.
120
pending=
121
122
#
123
# The list of packages to upgrade.
124
#
125
126
# <origin>;<newPackage>
127
upgrade=
128
upgradeDepends=
129
upgradeDepending=
130
131
# The <newOrgin>;<newPackage> part can also be found in $upgrade.
132
# <newOrigin>;<newPackage>|<oldOrigin>;<oldPackage>
133
replace=
134
135
# A list of dependency substitutions for new packages.
136
# <originalOrigin>;<originalName>|<newDependencyOrigin>;<newDependencyName>
137
substituteDepends=
138
139
# The current status line.
140
status=
141
142
# The ports directory as used in the index file.
143
idxports=
144
145
#
146
# Table Of Functions
147
# In order of appearance.
148
#
149
# getIndex()		Fetch the latest INDEX
150
# getLock()		Acquire a lock
151
# printStatus()		Print status messages on the terminal
152
# error()		Terminate with an error message
153
# warn()		Print a warning on stderr
154
# verbose()		Print a message, but only in verbose mode
155
# log()			Log activity into a log file
156
# getIdxEscape()	Escape origins and packages for regular expressions
157
# getIdxRows()		Filter index rows with an escaped expression
158
# getIdxRowsEscaped()	Filter index rows with an expression
159
# getIdxColumn()	Get a certain column from index rows
160
# pkgAll()		Make a list of outdated packages
161
# pkgDepends()		Check dependencies
162
# pkgDepending()	Check upwards dependencies
163
# pkgDependencies()	Run all dependency checks
164
# printProgress()	Print numerical progress output
165
# pkgSort()		Sort packages by dependency
166
# printTask()		Print the tasks to perform for a package
167
# pkgList()		List all tasks in 'no actions' mode
168
# pkgDownload()		Download all required packages
169
# pkgUpgrade()		Upgrade all scheduled packages
170
# substituteDepends()	Adjust dependencies of upgraded packages
171
# upgradePackage()	Upgrade a given package
172
# identifyPackage()	Identify a package by a user given string
173
# printHelp()		Print program parameters and terminate
174
# readParams()		Read the command line parameters
175
# readContents()	Read the +CONTENTS of a package file
176
# downloadManager()	Start a background download manager
177
# downloadManagerFetch()
178
#			Try to fetch a package from a mirror
179
# downloadManagerMsgRetry()
180
#			Tell the download manager to retry a download
181
# downloadManagerMsgFinished()
182
#			Tell the download manager a download has been completed
183
# downloadManagerMsgRequest()
184
#			Request a download from the download manager
185
# downloadManagerMsgExit()
186
#			Tell the download manager to terminate
187
# validatePackage()	Validate a downloaded package
188
# 
189
190
191
#
192
# Update the local copy of the index and start the download manager.
193
#
194
# @param idxports
195
#	This is set to the ports directory used in the index file. This is
196
#	required for many index operations. If already set the index is
197
#	assumed to be up to date and nothing is done.
198
# @param pVerbose
199
#	Activate verbose output.
200
#
201
getIndex() {
202
	# The index has already been updated.
203
	if [ -n "$idxports" ]; then
204
		return 0
205
	fi
206
207
	# Free the lock upon termination.
208
	trap "uma unlock $pid" EXIT
209
210
	# First acquire the lock.
211
	getLock
212
213
	verbose "Synchronize the local index copy with the package server."
214
215
	# Try to update the index.
216
	if ! uma $pVerbose fetch ftpindex $pid; then
217
		exit $ERR_INDEX
218
	fi
219
220
	# Set the ports directory used in the index.
221
	idxports="$(getIdxColumn $IDX_ORIGIN "$(head -n 1 "$PKG_INDEX")")"
222
	idxports="${idxports%/*/*}"
223
224
	# Start the download manager.
225
	downloadManager
226
}
227
228
#
229
# Acquires the uma (Update Manager) lock. And spawns a process that locks
230
# onto PKG_DBDIR to block the ports from messing with us.
231
#
232
getLock() {
233
	# Acquire the lock.
234
	if ! uma lock $pid; then
235
		if [ "$USER" != "root" ]; then
236
			error $ERR_LOCK "The command $name has to be run as root."
237
		else
238
		 	error $ERR_LOCK "The uma (Update MAnager) lock could not be acquired, it appears the package/ports infrastructure is in use."
239
		fi
240
	fi
241
242
	# Lock onto PKG_DBDIR to avoid ports getting into our way.
243
	# The ports tree locks onto PKG_DBDIR during install and deinstall.
244
	# Since it does not use uma we use this lock to make sure the ports
245
	# tree does not get into our way later.
246
	if ! lockf -kst 0 "$PKG_DBDIR" sh -c "lockf -k '$PKG_DBDIR' sh -c 'while kill -0  $pid 2> /dev/null; do sleep 2; done' &"; then
247
		error $ERR_LOCK "Locking $PKG_DBDIR failed, the ports tree might be in use."
248
	fi
249
}
250
251
#
252
# Prints a status message to the terminal device /dev/tty.
253
#
254
# @param 1
255
#	The message to print
256
# @param status
257
#	The last printed message, used for clearing the status line before
258
#	printing a new status.
259
# @param pClean
260
#	If set, do not print status messages.
261
#
262
printStatus() {
263
	test -n "$pClean" && return 0
264
	printf "\r%${#status}s\r%s\r" '' "$1" > /dev/tty
265
	status="$1"
266
}
267
268
#
269
# Exits with the given error and message on stderr.
270
#
271
# @param 1
272
#	The error number to exit with.
273
# @param 2
274
#	The message to exit with.
275
#
276
error() {
277
	# Clear the status line.
278
	printStatus
279
	echo "$name: $2" 1>&2
280
	exit "$1"
281
}
282
283
#
284
# Writes a warning message to stderr.
285
#
286
# @param 1
287
#	The message to write.
288
#
289
warn() {
290
	# Clear the status line.
291
	printStatus
292
	echo "$name: $1" 1>&2
293
}
294
295
#
296
# Outputs verbose messages on stdout.
297
#
298
# @param @
299
#	All the parameters to be output.
300
# @param pVerbose
301
#	If this is not set, do not output anything.
302
#
303
verbose() {
304
	test -z "$pVerbose" && return 0
305
	echo "$@"
306
}
307
308
#
309
# Logs the given message into a log file.
310
#
311
# The following format is used.
312
#
313
# <UTC timestamp> - <date> - (<error>|DONE): <message>
314
#
315
# UTC timestamp := The output of 'date -u '+%s'
316
# date := The output of 'date'
317
#
318
# @param 1
319
#	The error number for the log, if this is 0, the message will be
320
#	preceded by "DONE:" instead of "ERROR($1):".
321
# @param 2
322
#	The message to log.
323
# @param logfile
324
#	The name of the file to log into.
325
# @param pNoLogging
326
#	If set, logging is not performed.
327
#
328
log() {
329
	test -n "$pNoLogging" && return 0
330
331
	if [ $1 -eq 0 ]; then
332
		echo "$(date -u '+%s') - $(date) - DONE: $2" >> $logfile
333
	else
334
		echo "$(date -u '+%s') - $(date) - ERROR($1): $2" >> $logfile
335
	fi
336
}
337
338
#
339
# An escape function for package names fed to the getIdxColumn function.
340
# This function reads from the standard input unless a file is named
341
# in the parameters.
342
# Note that the escaping is done for extended regular expressions, however
343
# only characters that can appear in package names are escaped.
344
#
345
# @param @
346
#	More parameters can be added to the sed command.
347
#
348
getIdxEscape() {
349
	sed -E -e 's/([+.])/\\\1/g' "$@"
350
}
351
352
#
353
# Outputs all rows of the index that match a given pattern in a column.
354
# The pattern should not match '|'.
355
#
356
# @param 1
357
#	The column that has to match the pattern.
358
# @param 2
359
#	The pattern that has to be matched, an extended regular expression.
360
# @param 3
361
#	Optional, the rows to match against instead of using the index file.
362
#
363
getIdxRows() {
364
	if [ -z "$3" ]; then
365
		grep -E "^([^|]*\|){$1}($2)(\|.*)?\$" "$PKG_INDEX"
366
	else
367
		echo "$3" | grep -E "^([^|]*\|){$1}($2)(\|.*)?\$"
368
	fi
369
}
370
371
#
372
# Outputs all rows of the index that match a given string.
373
# The string should not contain '|'.
374
#
375
# @param 1
376
#	The column that has to match the string.
377
# @param 2
378
#	The string that has to be matched.
379
# @param 3
380
#	Optional, the rows to match against instead of using the index file.
381
#	
382
getIdxRowsEscaped() {
383
	getIdxRows $1 "$(echo "$2" | getIdxEscape)" "$3"
384
}
385
386
#
387
# Outputs a column of each index row piped into it.
388
#
389
# @param 1
390
#	The column to output.
391
# @param 2
392
#	The rows to output the columns from.
393
#
394
getIdxColumn() {
395
	echo "$2" | sed -E "s,^([^|]*\|){$1}([^|]*)\|.*,\2,1"
396
}
397
398
#
399
# Stores all the packages not in sync with the index file in categories.
400
#
401
# @param older
402
#	The list of packages older than those in the index.
403
# @param newer
404
#	The list of packages newer than those in the index.
405
# @param unindexed
406
#	The list of packages not in the index.
407
# @param multiple
408
#	The list of packages that have multiple index entries.
409
# @param error
410
#	The list of packages with broken package database entries.
411
# @param pForce
412
#	If set, register all installed packages in the index as outdated.
413
# @param pAll
414
#	If set, add all outdated packages to the list of packages to upgrade.
415
# @param pListDiscarded
416
#	If set, list all the packages that are ignored.
417
# @param upgrade
418
#	The list to add packages to if pAll is set.
419
#
420
pkgAll() {
421
	local package pkgname origin operator row discarded
422
423
	# There's nothing to be done if all of the following conditions are
424
	# met:
425
	# - Nothing is yet listed for upgrading, so we do not need a list
426
	#   of outdated packages for dependency checking.
427
	# - The updating of all packages is not requested.
428
	# - The listing of ignored (i.e. not indexed) packages is not
429
	#   requested.
430
	test -z "$upgrade" -a -z "$pAll" -a -z "$pListDiscarded" && return 0
431
432
	verbose "Make a list of outdated packages."
433
434
	printStatus "Reading version information of installed packages ..."
435
436
	if [ -n "$pForce" ]; then
437
		# In force mode it is assumed that all installed packages to
438
		# be found in the index are outdated.
439
		for package in $(pkg_version -Io "${PKG_INDEX}"); {
440
			origin="${package%% *}"
441
			row="$(getIdxRowsEscaped $IDX_ORIGIN "$idxports/$origin")"
442
			pkgname="$(getIdxColumn $IDX_PKG "$row")"
443
			printStatus "Checking <$pkgname>."
444
			operator="${package##* }"
445
			case "$operator" in
446
				'?')
447
					unindexed="$unindexed${unindexed:+$IFS}$origin"
448
				;;
449
				'!')
450
					error="$error${error:+$IFS}$origin"
451
				;;
452
				*)
453
					older="$older${older:+$IFS}$origin;$pkgname"
454
				;;
455
			esac
456
		}
457
	else
458
		# Categorize installed packages and their relations to the
459
		# index.
460
		for package in $(pkg_version -IoL = ${PKG_INDEX}); {
461
			origin="${package%% *}"
462
			row="$(getIdxRowsEscaped $IDX_ORIGIN "$idxports/$origin")"
463
			pkgname="$(getIdxColumn $IDX_PKG "$row")"
464
			printStatus "Checking <${pkgname:-$(pkg_info -qO $origin)}>."
465
			operator="${package##* }"
466
			case "$operator" in
467
				'<')
468
					older="$older${older:+$IFS}$origin;$pkgname"
469
				;;
470
				'>')
471
					newer="$newer${newer:+$IFS}$origin;$pkgname"
472
				;;
473
				'?')
474
					unindexed="$unindexed${unindexed:+$IFS}$origin"
475
				;;
476
				'*')
477
					multiple="$multiple${multiple:+$IFS}$origin"
478
				;;
479
				'!')
480
					error="$error${error:+$IFS}$origin"
481
				;;
482
			esac
483
		}
484
	fi
485
486
	printStatus "Assemble checked packages ..."
487
488
	# Remove packages to upgrade from the list of outdated packages.
489
	for package in $upgrade; {
490
		older="$(echo "$older" | grep -vx "$package")"
491
	}
492
493
	# Append outdated packages to the list of packages to update if all
494
	# packages are to be updated.
495
	if [ -n "$pAll" ]; then
496
		downloadManagerMsgRequest "$older"
497
		upgrade="$upgrade${older:+${upgrade:+$IFS}}$older"
498
		older=
499
	fi
500
501
	# Clear the status line.
502
	printStatus
503
504
	# Print the discarded packages.
505
	if [ -n "$pListDiscarded" ]; then
506
		verbose "List discarded packages."
507
508
		discarded="$unindexed$IFS$multipleIFS$error"
509
		discarded="$(echo "$discarded" | grep -vFx '' | sort -u)"
510
511
		test -n "$discarded" && echo "$discarded"
512
	fi
513
}
514
515
#
516
# Adds all missing dependencies to the list of packages to upgrade.
517
#
518
# @param 1
519
#	This is used to check the dependencies of newly added depending
520
#	packages.
521
# @param upgrade
522
#	The primary list of packages to upgrade (read only).
523
# @param upgradeDepends
524
#	The list to add packages to upgrade to.
525
# @param older
526
#	The list of outdated packages. Packages for upgrading are removed from
527
#	it.
528
# @param dependsChecked
529
#	A list of already checked dependencies, to avoid double checks.
530
# @param pRecursive
531
#	If set, also add outdated dependencies to the upgrade list.
532
# @param pMoreRecursive
533
#	If set, also update the dependencies of depending packages.
534
# @param pForce
535
#	If set together with pRecursive, add all dependencies to the upgrade
536
#	list.
537
#
538
pkgDepends() {
539
	local pkgname package row rows depends origin escapedPkg upgradeList
540
541
	printStatus "Preparing dependency checks ..."
542
543
	# In thorough mode the depencies of depending packages are updated, too.
544
	upgradeList="${1:-$upgrade}"
545
546
	# Luckily packages know their indirect dependencies, too. This way
547
	# it is not necessary to check for dependencies recursively.
548
	depends=
549
	for package in $upgradeList; {
550
		row="$(getIdxRowsEscaped $IDX_ORIGIN "$idxports/${package%;*}")"
551
		row="$(getIdxColumn $IDX_DEPENDS "$row")"
552
		depends="$depends${depends:+${row:+ }}$row"
553
	}
554
555
	# Reformat depends and throw out duplicates.
556
	depends="$(
557
		echo "$depends" | sed "s/ /\\$IFS/g" | sort -u
558
	)"
559
560
	# Do some prefiltering.
561
	rows="$(getIdxRowsEscaped $IDX_PKG "$(echo "$depends" | rs -TC\|)")"
562
563
	# Check for missing or outdated dependencies.
564
	for pkgname in $depends; {
565
		escapedPkg="$(echo "$pkgname" | getIdxEscape)"
566
567
		# Skip packages already checked.
568
		if echo "$dependsChecked" | grep -qFx "$pkgname"; then
569
			continue
570
		fi
571
		dependsChecked="$dependsChecked${dependsChecked:+$IFS}$pkgname"
572
573
		printStatus "Check dependency <$pkgname>."
574
575
		# Skip this if this package is already scheduled for updating.
576
		if echo "$upgrade${upgradeDepending:+$IFS$upgradeDepending}" | grep -qF ";$pkgname"; then
577
			continue
578
		fi
579
580
		row="$(getIdxRows $IDX_PKG "$escapedPkg" "$rows")"
581
582
		# If this package could not be identified this is an index
583
		# incosistency, that can only be ignored.
584
		if [ -z "$row" ]; then
585
			warn "Ignore index inconsistency, the dependency <$pkgname> is not in the index." 1>&2
586
			continue
587
		fi
588
589
		origin="$(getIdxColumn $IDX_ORIGIN "$row")"
590
		origin="${origin#$idxports/}"
591
		package="$origin;$(getIdxColumn $IDX_PKG "$row")"
592
593
		#
594
		# Deal with dependencies according to set parameters.
595
		#
596
		if [ -z "$(pkg_info -qO "$origin")" ]; then
597
			# The depency is not installed.
598
			upgradeDepends="$upgradeDepends${upgradeDepends:+$IFS}$package"
599
			# Request a package download.
600
			downloadManagerMsgRequest "$package"
601
		elif [ -n "$pMoreRecursive" -o -n "$pRecursive" -a -z "$1" ]; then
602
			# Check whether the dependency is outdated.
603
			if echo "$older" | grep -qFx "$package"; then
604
				upgradeDepends="$upgradeDepends${upgradeDepends:+$IFS}$package"
605
				older="$(echo "$older" | grep -vFx "$package")"
606
				# Request a package download.
607
				downloadManagerMsgRequest "$package"
608
			fi
609
		fi
610
	}
611
}
612
613
#
614
# Checks whether packages depending on the packages to update require updating.
615
#
616
# @param 1
617
#	This is used to check the depending packages of newly added
618
#	dependencies.
619
# @param older
620
#	The list of outdated packages. If pForce is set, this includes all
621
#	installed packages listed in the index.
622
# @param upgrade
623
#	The primary list of packages to upgrade (read only).
624
# @param upgradeDepending
625
#	The list of depending packages to upgrade.
626
# @param pUpwardRecursive
627
#	If not set nothing is done.
628
# @param pMoreUpwardRecursive
629
#	Also check the depending packages of depencencies.
630
# @param pAll
631
#	If this is set do nothing.
632
#
633
pkgDepending() {
634
	# Without the upwardRecursive option this is completely
635
	# unnecessary.
636
	if [ -z "$pUpwardRecursive" ]; then
637
		return 0
638
	fi
639
640
	# If all packages are already going to be upgraded, there is no
641
	# need for this.
642
	if [ -n "$pAll" ]; then
643
		return 0
644
	fi
645
646
	# Only update depending packages of dependencies in thorough mode.
647
	if [ -n "$1" -a -z "$pMoreUpwardRecursive" ]; then
648
		return 0
649
	fi
650
651
	local package pkgname origin row depends escapedPkg upgradeList
652
653
	printStatus "Preparing upwards dependency checks ..."
654
655
	# In thorough mode the depencies of depending packages are updated, too.
656
	upgradeList="${1:-$upgrade}"
657
658
	# Do some prefiltering.
659
	rows="$(getIdxRowsEscaped $IDX_ORIGIN "$(
660
		echo "$older" | rs -TC\| | sed -E "s'([^;|]*);[^|]*'$idxports/\1'g"
661
	)")"
662
663
	# For each outdated package, check whether it depends on a package
664
	# to upgrade. In force mode outdated packages are all packages, so
665
	# the difference does not have to be made here.
666
	for package in $older; {
667
		# Skip this if this package is already scheduled for updating.
668
		if echo "$upgrade${upgradeDepends:+$IFS$upgradeDepends}${upgradeDepending:+$IFS$upgradeDepending}" | grep -qFx "$package"; then
669
			continue
670
		fi
671
672
		printStatus "Check for upwards dependency <${package#*;}>."
673
674
		origin="${package%;*}"
675
		row="$(getIdxRowsEscaped $IDX_ORIGIN "$idxports/$origin" "$rows")"
676
677
		# Ignore unindexed packages.
678
		if [ -z "$row" ]; then
679
			continue
680
		fi
681
682
		depends="$(getIdxColumn $IDX_DEPENDS "$row")"
683
684
		# It has no dependencies, so it cannot depend on anything
685
		# in the upgrade list.
686
		if [ -z "$depends" ]; then
687
			continue
688
		fi
689
690
		# Reformat dependencies.
691
		depends="$(echo "$depends" | sed -Ee "s/([^ ]+)/;\1/g" -e "s/ /\\$IFS/g")"
692
693
		# Check every dependency for matching the upgrade packages.
694
		if echo "$upgradeList" | grep -qF "$depends"; then
695
			upgradeDepending="$upgradeDepending${upgradeDepending:+$IFS}$package"
696
			older="$(echo "$older" | grep -vFx "$package")"
697
			downloadManagerMsgRequest "$package"
698
		fi
699
	}
700
}
701
702
#
703
# This function calls pkgDepending and pkgDepends until no new packages
704
# show up for updating. All the clever stuff happens in those functions.
705
#
706
# @param upgrade
707
#	The list of packages to upgrade.
708
# @param upgradeDepends
709
#	The list of dependencies to add to the list of packages to upgrade.
710
# @param upgradeDepending
711
#	The list of depending packages to add to the list of packages
712
#	to upgrade.
713
#
714
pkgDependencies() {
715
	test -z "$upgrade" && return 0
716
717
	verbose "Perform dependency checks."
718
719
	# Run the primary dependency checks.
720
	pkgDepending
721
	downloadManagerMsgRequest "$upgradeDepending"
722
	pkgDepends
723
	downloadManagerMsgRequest "$upgradeDepends"
724
725
	# The idea is to keep on checking until nothing new shows up.
726
	# Whether that is the case depends on the level of recursiveness.
727
	while [ -n "$upgradeDepends$upgradeDepending" ]; do
728
		if [ -n "$upgradeDepends" ]; then
729
			# Deal with packages depending on the updated packages.
730
			pkgDepending "$upgradeDepends"
731
			upgrade="$upgradeDepends$IFS$upgrade"
732
			upgradeDepends=
733
		fi
734
735
		if [ -n "$upgradeDepending" ]; then
736
			# Deal with missing or outdated dependencies.
737
			pkgDepends "$upgradeDepending"
738
			upgrade="$upgrade$IFS$upgradeDepending"
739
			upgradeDepending=
740
		fi
741
	done
742
743
	# Clear the status line.
744
	printStatus
745
}
746
747
#
748
# Prints a progress message to the terminal device /dev/tty.
749
#
750
# @param 1
751
#	Total amount of operations to do.
752
# @param 2
753
#	The amount of operations performed.
754
# @param 3
755
#	The name of the package that is currently operated on.
756
# @param 4
757
#	The text prepending the progress information.
758
# @param status
759
#	The last printed message, used for clearing the status line before
760
#	printing a new status.
761
# @param pClean
762
#	If set, do not print progress messages.
763
#
764
printProgress() {
765
	test -n "$pClean" && return 0
766
	printf "\r%${#status}s\r$4 %${#1}s of %${#1}s (%3s%%) <$3>.\r" '' "$2" "$1" "$(($2 * 100 / $1))" > /dev/tty
767
	status="$4 $1 of $1 (100%) <$3>."
768
}
769
770
#
771
# Sorts the packages to upgrade by dependency.
772
#
773
# The trick is to have a list of already sorted packages. Each package added
774
# to the list is inserted right behind its last dependency already present
775
# there.
776
# Packages without any dependencies in the sorted list are prepended. This
777
# way it is ensured that they end up before all already sorted packages
778
# that depend on them, without additional checking.
779
#
780
# @param upgrade
781
#	The list of packages to sort.
782
# @param pParanoid
783
#	If set, make cyclic dependency checks.
784
#
785
pkgSort() {
786
	local rows sorted package row depends dependency pkgname
787
	local totalCount count
788
789
	test -z "$upgrade" && return 0
790
791
	verbose "Sort packages by dependency."
792
793
	printStatus "Prepare sorting of packages ..."
794
795
	# Limit rows to whatever is currently required.
796
	rows="$(getIdxRowsEscaped $IDX_ORIGIN "$(
797
		echo "$upgrade" | getIdxEscape -e 's/;.*//1' -e "s,^,$idxports/,1" | rs -TC\|
798
	)")"
799
800
	# The number of packages
801
	totalCount=$(($(echo "$upgrade" | wc -l)))
802
	count=0
803
804
	# Sort each package into the list of sorted packages.
805
	sorted=
806
	for package in $upgrade; {
807
		count=$(($count + 1))
808
		pkgname="${package#*;}"
809
		printProgress $totalCount $count "$pkgname" 'Sort'
810
811
		# Get the list of dependencies that should be updated before
812
		# the current package.
813
		row="$(getIdxRowsEscaped $IDX_PKG "$pkgname" "$rows")"
814
		depends="$(getIdxColumn $IDX_DEPENDS "$row" | sed -E "s/ /\\$IFS/g")"
815
816
		# Get the last matching dependency in the list.
817
		dependency="$(echo "$sorted" | grep -Fx "$depends" | tail -n 1)"
818
819
		# If there is no match, just prepend to the list.
820
		if [ -z "$dependency" ]; then
821
			sorted="$pkgname${sorted:+$IFS$sorted}"
822
			continue
823
		fi
824
825
		# Insert right behind the match.
826
		dependency="$(echo "$dependency" | getIdxEscape)"
827
		sorted="$(echo "$sorted" | sed -E "s/^$dependency$/$dependency\\$IFS$pkgname/1")"
828
	}
829
830
	# Perform optional cyclic dependency check.
831
	if [ -n "$pParanoid" ]; then
832
		printStatus "Validate sorting order ..."
833
	
834
		# Validate the sort order.
835
		count=0
836
		for pkgname in $sorted; {
837
			count=$(($count + 1))
838
			printProgress $totalCount $count "$pkgname" 'Validate'
839
	
840
			# Get the list of dependencies that should be updated before
841
			# the current package.
842
			row="$(getIdxRowsEscaped $IDX_PKG "$pkgname" "$rows")"
843
			depends="$(getIdxColumn $IDX_DEPENDS "$row" | sed -E "s/ /\\$IFS/g")"
844
	
845
			# Append the package to the list of dependencies to match.
846
			depends="${depends:+$depends$IFS}$pkgname"
847
	
848
			# Get the last match in the list.
849
			dependency="$(echo "$sorted" | grep -Fx "$depends" | tail -n 1)"
850
			# The last match has to be the package.
851
			if [ "$dependency" != "$pkgname" ]; then
852
				error $ERR_SORT "The package <$pkgname> was not sorted properly, a likely cause is a circular dependency."
853
			fi
854
		}
855
	fi
856
857
	printStatus "Assemble sorted packages ..."
858
859
	# Replace package names with <origin>;<package> pairs.
860
	for package in $upgrade; {
861
		pkgname="$(echo "${package#*;}" | getIdxEscape)"
862
		sorted="$(echo "$sorted" | sed -E "s'^$pkgname\$'$package'1")"
863
	}
864
	
865
	upgrade="$sorted"
866
	printStatus
867
}
868
869
#
870
# Prints the update/replace/install task.
871
#
872
# @param 1
873
#	The package to upgrade/install.
874
# @param replace
875
#	The list of packages to replace.
876
#
877
printTask() {
878
	local package newPkgname newOrigin oldPkgname oldOrigin
879
880
	# Get the name and origin of the new package.
881
	newPkgname="${1#*;}"
882
	newOrigin="${1%;*}"
883
884
	# Look for a package the new one replaces.
885
	package="$(echo "$replace" | grep -F "$1|")"
886
887
	# Look for a package this one replaces.
888
	# The current package actually replaces another one.
889
	if [ -n "$package" ]; then
890
		# Get the name and origin of the old package.
891
		package="${package#*|}"
892
		oldPkgname="${package#*;}"
893
		oldOrigin="${package%;*}"
894
895
		echo "Replace <$oldPkgname> ($oldOrigin) with <$newPkgname> ($newOrigin)"
896
		return 0
897
	fi
898
899
	# Check whether there's an old version of this package around.
900
	package="$(pkg_info -qO "$newOrigin")"
901
902
	# An older package with this origin is installed.
903
	if [ -n "$package" ]; then
904
		echo "Update <$package> to <$newPkgname> ($newOrigin)"
905
		return 0
906
	fi
907
908
	# Aparently this package will be newly installed.
909
	echo "Install <$newPkgname> ($newOrigin)"
910
}
911
912
#
913
# List the packages that are going to be upgraded, installed and replaced.
914
# If the 'no actions' mode is active.
915
#
916
# @param upgrade
917
#	The list of packages to upgrade.
918
# @param pNoActions
919
#	Print the list of tasks.
920
#
921
pkgList() {
922
	# Only list packages in "no actions" mode.
923
	test -z "$pNoActions" && return 0
924
925
	test -z "$upgrade" && return 0
926
927
	local package
928
929
	verbose "The following packages will be updated:"
930
931
	for package in $upgrade; {
932
		printTask "$package"
933
	}
934
}
935
936
#
937
# Wait for downloaded packages and validate them.
938
#
939
# @param upgrade
940
#	The list of packages to download.
941
# @param pending
942
#	The list of pending downloads.
943
# @param packagerepos
944
#	The location of the remote package repository (derived from
945
#	PACKAGESITE). If this is identical with the local repository,
946
#	the download manager was not started.
947
# @param pNoActions
948
#	Do not download anything.
949
#
950
pkgDownload() {
951
	test -n "$pNoActions" && return 0
952
953
	test -z "$upgrade" && return 0
954
	
955
	local package total count line
956
957
	verbose "Validate downloaded packages."
958
959
	printStatus "Waiting for downloads ..."
960
961
	# Create a list of the package names to validate.
962
	# Entries are removed from this list by validatePackage().
963
	pending="$(echo "$upgrade" | sed 's/.*;//1')"
964
965
	# The total number of packages to validate.
966
	total="$(($(echo "$upgrade" | wc -l)))"
967
968
	# Check whether the download manager is available.
969
	if [ "$PACKAGES" = "$packagerepos" ]; then
970
		#
971
		# The local repository is identical with the remote repository
972
		# so the assumption is all packages should already be there.
973
		#
974
975
		# Validate all packages.
976
		for package in $pending; {
977
			count=$(($count + 1))
978
			printProgress $total $count "$package" "Validate"
979
			validatePackage "$package"
980
		}
981
	else
982
		#
983
		# The download manager is available, so hang on to its message
984
		# queue and proceed with validating as packages are finished.
985
		#
986
		count=0
987
988
		while [ -n "$pending" ]; do
989
			read line
990
			case "$line" in
991
				finished:*)
992
					count=$(($count + 1))
993
					package="${line##*;}"
994
					printProgress $total $count "$package" "Validate"
995
					validatePackage "$package"
996
				;;
997
			esac
998
		done < "$queueMessages"
999
1000
		# Stop the download manager.
1001
		downloadManagerMsgExit
1002
	fi
1003
1004
	# Clear the status line.
1005
	printStatus
1006
}
1007
1008
#
1009
# Upgrade each package.
1010
#
1011
# @param upgrade
1012
#	The list of packages to upgrade.
1013
# @param conflictReplace
1014
#	This list is reset for conflict handling.
1015
# @param pNoActions
1016
#	Do not update anything.
1017
# @param pFetchOnly
1018
#	Do not update anything.
1019
#
1020
pkgUpgrade() {
1021
	test -n "$pNoActions" -o -n "$pFetchOnly" && return 0
1022
1023
	test -z "$upgrade" && return 0
1024
1025
	local package
1026
1027
	verbose "Install $(($(echo "$upgrade" | wc -l))) package(s)."
1028
1029
	for package in $upgrade; {
1030
		upgradePackage "$package"
1031
	}
1032
}
1033
1034
#
1035
# To handle conflicts this function removes dependencies from a given package
1036
# and appends one or more new ones to take their place. Also the +REQUIRED_BY
1037
# files of the appended dependencies are updated.
1038
#
1039
# @param 1
1040
#	The name of the package to which to apply the substitutions.
1041
# @param substituteDepends
1042
#	The list of dependency substitutions that should take place.
1043
#
1044
substituteDepends() {
1045
	# End here if there's nothing to substitute.
1046
	test -z "$substituteDepends" && return 0
1047
1048
	local line originalOrigin originalPkgname newOrigin newPkgname
1049
	local contents append remove requiredBy
1050
1051
	printStatus "Adjust the dependencies of <$1> ..."
1052
1053
	# Get the contents file.
1054
	contents="$(cat "$PKG_DBDIR/$1/+CONTENTS")"
1055
1056
	# Because there can be several substitutions for a single package
1057
	# the new ones will be added to the end of the +CONTENTS file and all
1058
	# the matches will be removed later.
1059
	append=
1060
	remove=
1061
	for line in $substituteDepends; {
1062
		# Get original origin and package name from the line.
1063
		originalOrigin="${line%%;*}"
1064
		originalPkgname="${line%|*}"
1065
		originalPkgname="${originalPkgname#*;}"
1066
1067
		# Continue with the next line if this one does not match.
1068
		if ! echo "$contents" | grep -qFx "@pkgdep $originalPkgname"; then
1069
			continue
1070
		fi
1071
1072
		# Get new origin and package name from the line.
1073
		newOrigin="${line#*|}"
1074
		newPkgname="${newOrigin#*;}"
1075
		newOrigin="${newOrigin%;*}"
1076
1077
		warn "Add dependency <$newPkgname> ($newOrigin)."
1078
1079
		# Remember what to append and what to remove.
1080
		remove="${remove:+$remove$IFS}@pkgdep $originalPkgname$IFS@comment DEPORIGIN:$originalOrigin"
1081
		# Just for the very unlikely case that two dependencies get
1082
		# replaced for conflicting with the same package, check that
1083
		# a dependency is not added twice.
1084
		if ! echo "$append" | grep -qFx "@pkgdep $newPkgname"; then
1085
			append="$append$IFS@pkgdep $newPkgname$IFS@comment DEPORIGIN:$newOrigin"
1086
		fi
1087
		
1088
		# Make an entry for the package in the +REQUIRED_BY file of
1089
		# of the dependency to append.
1090
		requiredBy="$(cat "$PKG_DBDIR/$newPkgname/+REQUIRED_BY" 2> /dev/null)"
1091
		requiredBy="${requiredBy:+$requiredBy$IFS}$1"
1092
		echo "$requiredBy" | sort -u > "$PKG_DBDIR/$newPkgname/+REQUIRED_BY"
1093
	}
1094
1095
	# Remove the original dependency entries.
1096
	contents="$(echo "$contents" | grep -vFx "$remove")"
1097
	# Write the new file. Note that $append always starts with a newline.
1098
	echo "$contents$append" > "$PKG_DBDIR/$1/+CONTENTS"
1099
}
1100
1101
#
1102
# Install the given package. This is where the magic happens.
1103
#
1104
# @param replace
1105
#	The list of packages to replace (read only).
1106
# @param substituteDepends
1107
#	A list of dependency substitutions that should take place for each
1108
#	newly installed package to resolve conflicting packages.
1109
# @param packagebackup
1110
#	The location for backup packages. This is derived from PACKAGES.
1111
# @param pNoBackup
1112
#	If set, delete backups after successful completion.
1113
#
1114
upgradePackage() {
1115
	local task targetPackage targetPkgname targetOrigin package replace
1116
	local escapedPkg removePackages origin file conflict conflicting
1117
	local replacePkgdep requiredBy count
1118
	local signal
1119
1120
	# Get a string with the current upgrade task.
1121
	task="$(printTask "$1")"
1122
	echo "===> $task"
1123
1124
	targetPackage="$1"
1125
	targetPkgname="${1#*;}"
1126
	targetOrigin="${1%;*}"
1127
1128
	printStatus "Prepare installation of <$targetPkgname> ..."
1129
1130
	# Get the packages to replace with this one. Several packages can be
1131
	# replaced with a single one.
1132
	escapedPkg="$(echo "$targetPackage" | getIdxEscape)"
1133
	replace="$(echo "$replace" | grep -Ex "$escapedPkg\|.*" | sed -E "s'^$escapedPkg\|''1")"
1134
1135
	# Append the current package to the list of packages to replace.
1136
	replace="${replace:+$replace$IFS}$targetPackage"
1137
1138
	# Create the list of outdated packages that have to be backed up
1139
	# and for which pkgdb adjustments have to be made after successful
1140
	# installation of the new package.
1141
	# Also create the necessary sed expressions to update the
1142
	# package database.
1143
	removePackages=
1144
	replacePkgdep=
1145
	for package in $replace; {
1146
		origin="${package%;*}"
1147
		package="$(pkg_info -qO "$origin")"
1148
		test -z "$package" && continue
1149
		removePackages="$removePackages${removePackages:+$IFS}$package"
1150
		package="$(echo "$package" | getIdxEscape)"
1151
		replacePkgdep="$replacePkgdep -e 's|^@pkgdep $package\$|@pkgdep $targetPkgname|1'"
1152
		if [ "$origin" != "$targetOrigin" ]; then
1153
			replacePkgdep="$replacePkgdep -e 's|^@comment DEPORIGIN: $origin\$|@comment DEPORIGIN:$targetOrigin|1'"
1154
		fi
1155
1156
	}
1157
1158
	# Get a list of conflicting packages. The conflicts list is
1159
	# provided by readContents().
1160
	readContents "$PACKAGES/All/$targetPkgname.tbz"
1161
	conflicting=
1162
	for conflict in $conflicts; {
1163
		# Match the conflict pattern against installed packages.
1164
		for conflict in $(pkg_info -E "$conflict"); {
1165
			escapedPkg="$(echo "$conflict" | getIdxEscape)"
1166
			# Only add to the conflicting list if the conflicting
1167
			# package is not in the list of packages to replace.
1168
			if ! echo "$removePackages" | grep -qEx "$escapedPkg"; then
1169
				conflicting="${conflicting:+$conflicting$IFS}$conflict"
1170
			fi
1171
		}
1172
	}
1173
	# Remove duplicated entries.
1174
	conflicting="$(echo "$conflicting" | sort -u)"
1175
1176
	# Check whether any conflicts were found.
1177
	if [ -n "$conflicting" ]; then
1178
		# What happens now depends on the user preferences.
1179
		if [ -n "$pExitOnConflict" ]; then
1180
			# The user has chosen to bail out when a conflict
1181
			# occurs.
1182
			log $ERR_CONFLICT "$task"
1183
			error $ERR_CONFLICT "The package <$targetPkgname> conflicts with the following packages:$IFS$conflicting"
1184
		elif [ -n "$pReplaceConflicts" ]; then
1185
			# The user has chosen that conflicting packages should
1186
			# be replaced as if they were explicitly listed for
1187
			# replacing.
1188
			conflicts=
1189
			for package in $conflicting; {
1190
				warn "The package <$package> conflicts with <$targetPkgname> and will be replaced."
1191
				removePackages="$removePackages${removePackages:+$IFS}$package"
1192
				origin="$(pkg_info -qo "$package")"
1193
				# The next line is just for prettier log output.
1194
				conflicts="${conflicts:+$conflicts, }<$package> ($origin)"
1195
				package="$(echo "$package" | getIdxEscape)"
1196
				replacePkgdep="$replacePkgdep -e 's|^@pkgdep $package\$|@pkgdep $targetPkgname|1'"
1197
				if [ "$origin" != "$targetOrigin" ]; then
1198
					replacePkgdep="$replacePkgdep -e 's|^@comment DEPORIGIN: $origin\$|@comment DEPORIGIN:$targetOrigin|1'"
1199
				fi
1200
			}
1201
			log 0 "Conflict <$targetPkgname> ($targetOrigin) remove package(s) $conflicts"
1202
		else
1203
			# The default action is to assume that the conflicting
1204
			# packages fulfill the required functionality.
1205
			conflicts=
1206
			for package in $conflicting; {
1207
				warn "The package <$targetPkgname> will not be installed in favour of <$package>, because they conflict."
1208
				origin="$(pkg_info -qo "$package")"
1209
				# Record the necessary substitutions.
1210
				# TODO: Later versions will have to store this
1211
				# for resume.
1212
				substituteDepends="${substituteDepends:+$substituteDepends$IFS}$targetPackage|$origin;$package"
1213
				# This is just for prettier log output.
1214
				conflicts="${conflicts:+$conflicts, }<$package> ($origin)"
1215
			}
1216
			# Log the conflict resolution.
1217
			log 0 "Conflict <$targetPkgname> ($targetOrigin) favour package(s) $conflicts"
1218
			# Skip to the next package.
1219
			return 0
1220
		fi
1221
	fi
1222
1223
	# Backup packages.
1224
	mkdir -p "$packagebackup"
1225
	for package in $removePackages; {
1226
		printStatus "Backup <$package>."
1227
		pkg_create -b "$package" "$packagebackup/$package"
1228
		case $? in
1229
			0)
1230
				# Everything went well.
1231
			;;
1232
			1)
1233
				# If this happens someone's been messing with
1234
				# the packages just milliseconds ago.
1235
				log $ERR_BACKUP_MISS "$task"
1236
				error $ERR_BACKUP_MISS "The backup of <$package> failed. The package is missing."
1237
			;;
1238
			2)
1239
				# Fortunately pkg_create backs up as much as
1240
				# as is possible. That the backup (and hence
1241
				# the present package) is incomplete is all
1242
				# the more reason to upgrade.
1243
				# I do not understand why portmaster is
1244
				# interactive in this case.
1245
				warn "Ignoring incomplete backup of <$package>."
1246
			;;
1247
			*)
1248
				# Well, I've got no idea at all what else
1249
				# could go wrong. Too bad the return codes
1250
				# of pkg_create are not documented.
1251
				log $ERR_BACKUP_UNKNOWN "$task"
1252
				error $ERR_BACKUP_UNKNOWN "The backup of <$package> failed for unknown reasons."
1253
			;;
1254
		esac
1255
	}
1256
1257
	# Block SIGINT (CTRL-C), because that would really wrack havoc upon
1258
	# the package database in the following section.
1259
	signal=
1260
	trap "signal=$ERR_USER" sigint
1261
	trap "signal=$ERR_TERM" sigterm
1262
1263
	# Delete packages.
1264
	requiredBy=
1265
	count=-1
1266
	for package in $removePackages; {
1267
		printStatus "Delete <$package>."
1268
		# Remember +REQUIRED_BY contents for roll-back.
1269
		count=$(($count + 1))
1270
		local "requiredBy$count"
1271
		setvar "requiredBy$count" "$(cat "$PKG_DBDIR/$package/+REQUIRED_BY" 2> /dev/null)"
1272
		# Remember +REQUIRED_BY contents for the new package.
1273
		requiredBy="${requiredBy:+$requiredBy$IFS}$(cat "$PKG_DBDIR/$package/+REQUIRED_BY" 2> /dev/null)"
1274
		# Finally delete the package.
1275
		pkg_delete -f "$package"
1276
	}
1277
1278
	# Update the package database.
1279
	printStatus "Update package database for <$targetPkgname>."
1280
	if [ -n "$replacePkgdep" ]; then
1281
		for file in $(find "$PKG_DBDIR" -name '+CONTENTS'); {
1282
			eval "sed -Ei '.$name' $replacePkgdep '$file'"
1283
		}
1284
	fi
1285
1286
	# If an old version of this package was favoured in a conflict,
1287
	# the substituteDepends list has to be changed.
1288
	substituteDepends="$(echo "$substituteDepends" | sed "s'\|$targetOrigin;.*'|$targetPackage'1")"
1289
1290
	# Try to install the new package.
1291
	printStatus "Install <$targetPkgname>."
1292
	if ! env PKG_PATH="$PACKAGES/All" pkg_add -f "$targetPkgname"; then
1293
		# Installation went wrong, roll back!
1294
		printStatus "Roll back changes for <$targetPkgname>."
1295
		for file in $(find "$PKG_DBDIR" -name "*.$name"); {
1296
			mv -f "$file" "${file%.$name}"
1297
		}
1298
		count=-1
1299
		for package in $removePackages; {
1300
			# Restore package.
1301
			env PKG_PATH="$packagebackup" pkg_add -f "$package"
1302
			# Recover +REQUIRED_BY file.
1303
			count=$(($count + 1))
1304
			eval "echo \"\$requiredBy$count\"" > "$PKG_DBDIR/$package/+REQUIRED_BY"
1305
			# Remove the backup if set.
1306
			test -n "$pNoBackup" && rm "$packagebackup/$package.tbz"
1307
		}
1308
		log $ERR_INSTALL "$task"
1309
		error $ERR_INSTALL "The installation of <$targetPkgname> failed."
1310
	fi
1311
1312
	# Add the +REQUIRED_BY contents of all deleted packages to the
1313
	# +REQUIRED_BY file of the new one.
1314
	requiredBy="$(echo "$(cat "$PKG_DBDIR/$targetPkgname/+REQUIRED_BY" 2> /dev/null)$IFS$requiredBy" | grep -vFx '' | sort -u)"
1315
	echo "$requiredBy" > "$PKG_DBDIR/$targetPkgname/+REQUIRED_BY"
1316
1317
	# Make dependency substitutions from conflict resolving.
1318
	substituteDepends "$targetPkgname"
1319
1320
	# Log successful completion of the task.
1321
	log 0 "$task"
1322
1323
	# Remove backups if set.
1324
	if [ -n "$pNoBackup" ]; then
1325
		for package in $removePackages; {
1326
			printStatus "Remove backup of <$package>."
1327
			rm "$packagebackup/$package.tbz"
1328
		}
1329
	fi
1330
1331
	# Remove package database backups.
1332
	# TODO: Later versions will instead store them to allow a rollback.
1333
	printStatus "Remove database backups for <$targetPkgname>."
1334
	find "$PKG_DBDIR" -name "*.$name" -exec rm \{\} \;
1335
1336
	# Clear the status line.
1337
	printStatus
1338
	echo "=> $task succeeded"
1339
1340
	# Bail out if SIGINT or SIGTERM were encountered.
1341
	if [ -n "$signal" ]; then
1342
		error $signal "The process was interrupted."
1343
	fi
1344
1345
	# Reactivate default signal handlers.
1346
	trap - sigint sigterm
1347
}
1348
1349
#
1350
# Identify the package by a given string. Outputs the origin of all matched
1351
# packages, as well as the package name of the newest available package.
1352
# The output is in the following shape:
1353
#	<origin>;<package>
1354
#
1355
# The shell wildcards '*' and '?' are supported.
1356
# Origin and package names with wildcards are matched against installed
1357
# packages. Unambiguous package names and origins are matched against the
1358
# index.
1359
#
1360
# @param 1
1361
#	The package identifier to find matches for.
1362
#
1363
identifyPackage() {
1364
	local packages package mangledPackage rows matchingRows mangledRows
1365
	local origins origin guess escapedPkg
1366
1367
	# Check for wildcards.
1368
	guess=
1369
	if echo "$1" | grep -qE '\*|\?|\[.*]'; then
1370
		guess=1
1371
	fi
1372
	package="$1"
1373
1374
	# Distuinguish between origins and packages.
1375
	case "$package" in
1376
		*/*)
1377
			# An origin has been given.
1378
			if [ -n "$guess" ]; then
1379
				# Wildcards present, match against installed
1380
				# packages.
1381
1382
				# Get all matching packages.
1383
				packages="$(pkg_info -qO "$package")"
1384
1385
				# Convert for use in a regular expression.
1386
				package="$(echo "$package" | getIdxEscape -e 's/\*/[^|]*/g' -e 's/\?/[^|]/g')"
1387
				# Get rows matching the given package origin.
1388
				# This is a performance tweak, so the whole
1389
				# index will not have to be parsed in the
1390
				# following output loop.
1391
				rows="$(getIdxRows $IDX_ORIGIN "$idxports/$package")"
1392
1393
				# Output all matching packages.
1394
				for package in $packages; {
1395
					# Get the origin.
1396
					origin="$(pkg_info -qo "$package")"
1397
1398
					# Match this package origin against the
1399
					# previously filtered rows.
1400
					package="$(getIdxRowsEscaped $IDX_ORIGIN "$idxports/$origin" "$rows")"
1401
					# Get the package name of the newest
1402
					# package from the index.
1403
					package="$(getIdxColumn $IDX_PKG "$package")"
1404
					# Output origin/package pair.
1405
					echo "$origin;$package"
1406
				}
1407
1408
				# If no matches have been found, terminate.
1409
				if [ -z "$packages" ]; then
1410
					error $ERR_ARG "Package origin <$package> not matched by any installed package!" 1>&2
1411
				fi
1412
			else
1413
				# There is an unambigious origin, match it
1414
				# against the index.
1415
				origin="$package"
1416
				# Get the index row.
1417
				rows="$(getIdxRowsEscaped $IDX_ORIGIN "$idxports/$origin")"
1418
				# Get the package name column.
1419
				package="$(getIdxColumn $IDX_PKG "$rows")"
1420
				# Output origin/package pair, if a package for
1421
				# the given origin was found.
1422
				if [ -n "$package" ]; then
1423
					# Output origin/package pair.
1424
					echo "$origin;$package"
1425
				else
1426
					error $ERR_ARG "Package origin <$origin> not in index!" 1>&2
1427
				fi
1428
			fi
1429
		;;
1430
		*)
1431
			# A package name has been given.
1432
			if [ -n "$guess" ]; then
1433
				# Wildcards present, match against installed
1434
				# packages.
1435
1436
				# Get the origins of matching packages.
1437
				origins="$(pkg_info -qo "$package")"
1438
1439
				# Prepare the package name for use in a
1440
				# regular expression.
1441
				package="$(echo "$package" | getIdxEscape -e 's/\*/[^|]*/g' -e 's/\?/[^|]/g')"
1442
				# Get rows matching the given package name.
1443
				# This is a performance tweak, so the whole
1444
				# index will not have to be parsed in the
1445
				# following output loop.
1446
				rows="$(getIdxRows $IDX_PKG "$package")"
1447
				# Output all matching packages.
1448
				for origin in $origins; {
1449
					# Get the index row for this origin.
1450
					package="$(getIdxRowsEscaped $IDX_ORIGIN "$idxports/$origin" "$rows")"
1451
					# Get the latest package name from the
1452
					# index.
1453
					package="$(getIdxColumn $IDX_PKG "$package")"
1454
					# Output origin/package pair.
1455
					echo "$origin;$package"
1456
				}
1457
1458
				# If no matches have been found, terminate.
1459
				if [ -z "$origins" ]; then
1460
					error $ERR_ARG "Package identifier <$package> not matched!" 1>&2
1461
				fi
1462
			else
1463
				# A package name without wildcards has been
1464
				# given. This is expected to either be an exact
1465
				# package name or a LATEST_LINK name.
1466
1467
				# TODO: This would be much better if
1468
				# LATEST_LINK was known. This is information
1469
				# simply missing in the index.
1470
				# To make up for this some guessing is done in
1471
				# case of no matches or more than one match.
1472
				# But this fails for apache13 and probably
1473
				# other packages as well.
1474
1475
				# First try whether it is the current version
1476
				# of a package.
1477
				origin="$(pkg_info -qo "$package" 2> /dev/null)"
1478
				if [ -n "$origin" ]; then
1479
					# Get the matching index rows.
1480
					rows="$(getIdxRowsEscaped $IDX_ORIGIN "$idxports/$origin")"
1481
				fi
1482
1483
				# If it's not a current version, match against
1484
				# the index.
1485
				if [ -z "$rows" ]; then
1486
					# Get the matching rows. This should be
1487
					# only one, but it won't be for ports
1488
					# that define a proprietary LATEST_LINK.
1489
					escapedPkg="$(echo "$package" | getIdxEscape)"
1490
					rows="$(getIdxRows $IDX_PKG "$escapedPkg(-[^-]+)?")"
1491
				fi
1492
1493
				# No match, start some guessing.
1494
				# This fails for packages with a version tail,
1495
				# which is just what is wanted.
1496
				if [ -z "$rows" ]; then
1497
					# Assume this is a LATEST_LINK kind
1498
					# package name and remove the trailing
1499
					# numbers.
1500
					mangledPackage="$(echo "$package" | sed -E 's/[0-9]+$//1')"
1501
					# Get the matching rows, this is likely
1502
					# to be too many (i.e. more than one).
1503
					rows="$(getIdxRows $IDX_PKG "$mangledPackage-[^-]+")"
1504
				fi
1505
1506
				# If there is more than one matching row,
1507
				# try to match against the origin.
1508
				if [ "$(($(echo "$rows" | wc -l)))" -gt "1" ]; then
1509
					# Match against the origin.
1510
					rows="$(getIdxRows $IDX_ORIGIN "[^|]*/$package" "$rows")"
1511
1512
					# If there is still more than one
1513
					# match, match against the origins
1514
					# of existing packages.
1515
					if [ "$(($(echo "$rows" | wc -l)))" -gt "1" ]; then
1516
						for origin in $(getIdxColumn $IDX_ORIGIN "$rows"); {
1517
							test -n "$(pkg_info -qO "$origin")" \
1518
								&& matchingRows="$matchingRows${matchingRows:+$IFS}$(getIdxRowsEscaped $IDX_ORIGIN "$origin" "$rows")"
1519
						}
1520
						rows="$matchingRows"
1521
					fi
1522
					
1523
					# Either a single origin is matched or
1524
					# it's time to bail out and give up.
1525
					if [ "$(($(echo "$rows" | wc -l)))" -ne "1" ]; then
1526
						# The wrong amount of matches
1527
						# has occured. Bail out.
1528
						error $ERR_ARG "Package identifier <$package> not unambiguously matched!" 1>&2
1529
					fi
1530
				fi
1531
1532
				# Output if a package has been matched.
1533
				if [ -n "$rows" ]; then
1534
					# Get the origin of the given package.
1535
					origin="$(getIdxColumn $IDX_ORIGIN "$rows")"
1536
					# Geth the package name.
1537
					package="$(getIdxColumn $IDX_PKG "$rows")"
1538
					# Output origin/package pair.
1539
					echo "${origin#$idxports/};$package"
1540
				else
1541
					error $ERR_ARG "Package identifier <$package> not in index!" 1>&2
1542
				fi
1543
			fi
1544
		;;
1545
	esac
1546
}
1547
1548
#
1549
# Prints the parameter list and terminates the program.
1550
#
1551
printHelp() {
1552
	printf "$name v$version
1553
usage:
1554
	$name -h
1555
	$name -a [-b] [-bcCdfFlnpvX] [-o new existing] [update] [install]
1556
	$name [-bcCdfFlnpvX] [-r [-r]] [-R [-R]] [-o new existing]
1557
	%${#name}s [update] [install]\n" ''
1558
	exit 0
1559
}
1560
1561
#
1562
# Parse the command line parameters.
1563
#
1564
# @param upgrade
1565
#	A list of packages to upgrade.
1566
# @param depth
1567
#	This is used by the function to store the recursion depth and
1568
#	should be unset when calling it.
1569
# @param origin
1570
#	This is used by the function across differtent recursion depths to
1571
#	remember whether a package origin is expected.
1572
# @param pAll
1573
#	Is set if all packages should be update.
1574
# @param pNoBackup
1575
#	Is set if backups could not be fetched.
1576
# @param pClean
1577
#	Is set to turn off status messages.
1578
# @param pReplaceConflicts
1579
#	Is set to replace conflicting packages with new ones instead of
1580
#	leaving them alone.
1581
# @param pExitOnConflict
1582
#	Is set to stop the program if a conflict is encountered.
1583
# @param pForce
1584
#	Is set to force the update of packages that are not really updated.
1585
# @param pFetchOnly
1586
#	Is set to only fetch packages instead of installing/upgrading them.
1587
# @param pInteractive
1588
#	TODO: Reserved for future versions (resume/roll-back).
1589
# @param pJobs
1590
#	TODO: Reserved for future versions (pkg_libchk tests).
1591
# @param pListDiscarded
1592
#	Is set to activate the listing of packages that are ignored because
1593
#	they are not set in the INDEX.
1594
# @param pNoActions
1595
#	Is set if no actions should be performed but a list of what would have
1596
#	been done should get printed.
1597
# @param pNoLogging
1598
#	Turn off logging.
1599
# @param pParanoid
1600
#	Is set to activate cyclic dependency checks.
1601
# @param pRecursive
1602
#	Is set to activate updating of dependencies.
1603
# @param pMoreRecursive
1604
#	Is set to activate updating of dependencies of depending packages.
1605
# @param pUpwardRecursive
1606
#	Is set to activate updating of depending packages.
1607
# @param pMoreUpwardRecursive
1608
#	Is set to activate updating of packages depending on dependencies.
1609
# @param pVerbose
1610
#	Is set to activate informative output.
1611
#
1612
readParams() {
1613
	local arg package escapedPkg depth
1614
	# Store the recursion depth. Note that counting down is dealt with
1615
	# by making depth local.
1616
	depth=$((${depth:--1} + 1))
1617
1618
	# This is used to remember whether the next parameter should
1619
	# be a replacing package or a packge to be replaced.
1620
	origin=${origin:-0}
1621
1622
	for arg {
1623
		#
1624
		# Handle package replacements.
1625
		#
1626
		if [ $origin -eq 1 ]; then
1627
			# Store the replacement.
1628
			package="$(identifyPackage "$arg")" || exit $?
1629
			if [ -z "$package" -o "$(($(echo "$package" | wc -l)))" -ne "1" ]; then
1630
				error $ERR_ARG "The package identifier <$arg> is not unambiguous."
1631
			fi
1632
			upgrade="$upgrade${upgrade:+$IFS}$package"
1633
			replace="$replace${replace:+$IFS}$package"
1634
			origin=2
1635
			# Request the download.
1636
			downloadManagerMsgRequest "$package"
1637
			continue
1638
		fi
1639
		if [ $origin -eq 2 ]; then
1640
			# Store what to replace.
1641
			# This is taken from the package database not the index.
1642
1643
			case "$arg" in
1644
				*/*)
1645
					# Assume arg is an origin.
1646
					package="$(pkg_info -qO "$arg")"
1647
					package="$(pkg_info -qo "$package" 2> /dev/null);$package"
1648
				;;
1649
				*)
1650
					# Assume arg is a package identifier.
1651
					package="$(pkg_info -qo "$arg" 2> /dev/null);$(pkg_info -E "$arg" 2> /dev/null)"
1652
1653
					# Maybe arg is a package identifier
1654
					# without a version tail.
1655
					if [ "$package" = ";" ]; then
1656
						package="$(pkg_info -qo "$arg-*" 2> /dev/null);$(pkg_info -E "$arg-*" 2> /dev/null)"
1657
					fi
1658
				;;
1659
			esac
1660
1661
			# Arg is not installed.
1662
			if [ "$package" = ";" ]; then
1663
				error $ERR_ARG "The package <$arg> is not installed and thus cannot be replaced."
1664
			fi
1665
			# It appears arg is an identifier that is
1666
			# not unambiguous.
1667
			if [ "$(($(echo "$package" | wc -l)))" -ne "1" ]; then
1668
				error $ERR_ARG "The package identifier <$arg> is not unambiguous."
1669
			fi
1670
			# A package can only be replaced once.
1671
			escapedPkg="$(echo "$package" | getIdxEscape)"
1672
			if echo "$replace" | grep -qEx ".*\|$escapedPkg"; then
1673
				error $ERR_ARG "The package <$arg> is already listed for replacement."
1674
			fi
1675
			replace="$replace|$package"
1676
			origin=0
1677
			continue
1678
		fi
1679
1680
		#
1681
		# Identify arguments.
1682
		#
1683
		case "$arg" in
1684
			"-a" | "--all")
1685
				pAll=1
1686
				if [ -n "$pRecursive" ]; then
1687
					error $ERR_ARG "Recursiveness has no effect, because all packages are already selected for processing."
1688
				fi
1689
				if [ -n "$pUpwardRecursive" ]; then
1690
					error $ERR_ARG "Upward recursiveness has no effect, because all packages are already selected for processing."
1691
				fi
1692
			;;
1693
			"-b" | "--no-backup")
1694
				pNoBackup=1
1695
			;;
1696
			"-c" | "--clean")
1697
				pClean=-c
1698
			;;
1699
			"-C" | "--replace-conflicts")
1700
				if [ -n "$pExitOnConflict" ]; then
1701
					error $ERR_ARG "The 'replace conflicts' and 'exit on conflict' modes are mutually exclusive."
1702
				fi
1703
				pReplaceConflicts=1
1704
			;;
1705
			"-d" | "--list-discarded")
1706
				pListDiscarded=1
1707
			;;
1708
			"-f" | "--force")
1709
				pForce=1
1710
			;;
1711
			"-F" | "--fetch-only")
1712
				if [ -n "$pNoActions" ]; then
1713
					error $ERR_ARG "The 'no actions' and 'fetch only' modes are mutually exclusive."
1714
				fi
1715
				pFetchOnly=1
1716
			;;
1717
			"-h" | "--help")
1718
				printHelp
1719
			;;
1720
			"-i" | "--interactive")
1721
				# TODO: not yet used
1722
				pInteractive=1
1723
			;;
1724
			-j* | --jobs*)
1725
				# TODO: not yet used
1726
				pJobs="$arg"
1727
				if ! pkg_libchk "$pJobs" DUMMY/DUMMY 1>&2; then
1728
					exit $ERR_ARG
1729
				fi
1730
			;;
1731
			"-l" | "--no-logging")
1732
				pNoLogging=1
1733
			;;
1734
			"-n" | "--no-actions")
1735
				if [ -n "$pFetchOnly" ]; then
1736
					error $ERR_ARG "The 'no actions' and 'fetch only' modes are mutually exclusive."
1737
				fi
1738
				pNoActions=1
1739
			;;
1740
			"-o" | "--origin")
1741
				# Make sure the local index copy is up to date.
1742
				getIndex
1743
				origin=1
1744
			;;
1745
			"-p" | "--paranoid")
1746
				pParanoid=1
1747
			;;
1748
			"-r" | "--recursive")
1749
				if [ -n "$pMoreRecursive" ]; then
1750
					error $ERR_ARG "There are only two levels of recursiveness."
1751
				elif [ -n "$pRecursive" ]; then
1752
					pMoreRecursive=1
1753
				else
1754
					pRecursive=1
1755
				fi
1756
				if [ -n "$pAll" ]; then
1757
					error $ERR_ARG "Recursiveness has no effect, because all packages are already selected for processing."
1758
				fi
1759
			;;
1760
			"-R" | "--upward-recursive")
1761
				if [ -n "$pMoreUpwardRecursive" ]; then
1762
					error $ERR_ARG "There are only two levels of upward recursiveness."
1763
				elif [ -n "$pUpwardRecursive" ]; then
1764
					pMoreUpwardRecursive=1
1765
				else
1766
					pUpwardRecursive=1
1767
				fi
1768
				if [ -n "$pAll" ]; then
1769
					error $ERR_ARG "Upward recursiveness has no effect, because all packages are already selected for processing."
1770
				fi
1771
			;;
1772
			"-v" | "--verbose")
1773
				pVerbose=-v
1774
			;;
1775
			"-X" | "--exit-on-conflict")
1776
				if [ -n "$pReplaceConflicts" ]; then
1777
					error $ERR_ARG "The 'exit on conflict' and 'replace conflicts' modes are mutually exclusive."
1778
				fi
1779
				pExitOnConflict=1
1780
			;;
1781
			-? | --*)
1782
				error $ERR_ARG "Unknown parameter \"$arg\"."
1783
			;;
1784
			-*)
1785
				# Split parmeters.
1786
				readParams "${arg%%${arg#-?}}" "-${arg#-?}"
1787
			;;
1788
			*)
1789
				# Make sure the local index copy is up to date.
1790
				getIndex
1791
				# Add package to the list of packages to
1792
				# upgrade/install.
1793
				package="$(identifyPackage "$arg")" || exit $?
1794
				upgrade="$upgrade${upgrade:+$IFS}$package"
1795
				# Request the download.
1796
				downloadManagerMsgRequest "$package"
1797
			;;
1798
		esac
1799
	}
1800
1801
	#
1802
	# Only perform the following steps if this is the root call
1803
	# to this function (recursion depth = 0).
1804
	#
1805
	if [ $depth -eq 0 ]; then
1806
		#
1807
		# Deal with missing parameters.
1808
		#
1809
		if [ $origin -eq 1 ]; then
1810
			error $ERR_ARG "Incomplete parameters, missing origin."
1811
		fi
1812
		if [ $origin -eq 2 ]; then
1813
			error $ERR_ARG "Incomplete parameters, missing package to replace."
1814
		fi
1815
1816
		#
1817
		# Deal with invalid levels of recursiveness.
1818
		#
1819
		if [ -n "$pMoreRecursive" -a -z "$pUpwardRecursive" ]; then
1820
			error $ERR_ARG "Thorough recursiveness can only be used in conjunction with upwards recursiveness."
1821
		fi
1822
1823
		#
1824
		# Remove duplicates in the list of packages to upgrade.
1825
		#
1826
		upgrade="$(echo "$upgrade" | sort -u)"
1827
		# Reset global variables.
1828
		origin=
1829
	fi
1830
}
1831
1832
#
1833
# Reads all the required +CONTENTS information from a package.
1834
# The information is stored in variables.
1835
#
1836
# @param 1
1837
#	The name of the package file.
1838
# @param pkgname
1839
#	The name of the package.
1840
# @param origin
1841
#	The origin of the package.
1842
# @param depends
1843
#	The dependencies of the package in the format "<origin>;<package>",
1844
#	in reverse order.
1845
# @param conflicts
1846
#	A list of regular expressions that can be used to identify conflicting
1847
#	packages.
1848
#
1849
readContents() {
1850
	local contents line format
1851
	contents="$(tar -xOf "$1" '+CONTENTS')"
1852
	format=
1853
1854
	pkgname=
1855
	origin=
1856
	depends=
1857
	conflicts=
1858
	for line in $contents; {
1859
		case "$line" in
1860
			@name\ *)
1861
				pkgname="${line#@name }"
1862
			;;
1863
			@pkgdep\ *)
1864
				depends=";${line#@pkgdep }${depends:+$IFS}$depends"
1865
			;;
1866
			@comment\ *)
1867
				line="${line#@comment }"
1868
				case "$line" in
1869
					DEPORIGIN:*)
1870
						depends="${line#*:}$depends"
1871
					;;
1872
					PKG_FORMAT_REVISION:*)
1873
						format="${line#*:}"
1874
					;;
1875
					ORIGIN:*)
1876
						origin="${line#*:}"
1877
					;;
1878
				esac
1879
			;;
1880
			@conflicts\ *)
1881
				conflicts="${conflicts:+$conflicts$IFS}${line#@conflicts }"
1882
			;;
1883
		esac
1884
	}
1885
1886
	if [ "$format" != "1.1" ]; then
1887
		error $ERR_PACKAGE_FORMAT "Unknown package format in <$1>, bailing out!"
1888
	fi
1889
1890
	return 0
1891
}
1892
1893
#
1894
# Starts a download manager that can be instructed through a queue.
1895
# A process that wants to know what's going on with the download manager
1896
# can simply read from the queue as well.
1897
#
1898
# The download manager keeps as many downloads running as there are
1899
# PACKAGESITE_MIRRORS. Should a download fail, it is retried as soon
1900
# as no untried downloads remain. Every download is only retried once.
1901
# A download is never attempted from the master server.
1902
#
1903
# @param queueMessages
1904
#	The queue to create and read from.
1905
# @param packagerepos
1906
#	The location of the remote package repository (derived from
1907
#	PACKAGESITE). If this is identical with the local repository,
1908
#	the download manager will not be started.
1909
# @param pNoActions
1910
#	If set, the download manager will not be started.
1911
#
1912
downloadManager() {
1913
	# No actions mode, this includes no downloads.
1914
	test -n "$pNoActions" && return 0
1915
1916
	# Packages are locally available, no downloads.
1917
	test "$PACKAGES" = "$packagerepos" && return 0
1918
1919
	verbose "Start the download manager."
1920
1921
	# Initialize the queue.
1922
	rm "$queueMessages" 2> /dev/null
1923
	touch "$queueMessages"
1924
1925
	#
1926
	# The following block is forked away.
1927
	# Note that all variable assignments happen in a separate process
1928
	# and hence have no effect on the outside.
1929
	#
1930
	(
1931
		# Remove the queue when exiting and get rid of pending jobs.
1932
		trap "
1933
			kill \$(jobs -ls) > /dev/null 2>&1
1934
			rm '$queueMessages' 2> /dev/null
1935
			exit
1936
		" EXIT sigint sigterm
1937
1938
		# The jobs yet to be done.
1939
		jobs=
1940
		# The available mirrors.
1941
		mirrors="$PACKAGESITE_MIRRORS"
1942
		# The jobs that should be retried.
1943
		retry=
1944
		# The jobs that have been retried.
1945
		retried=
1946
		# The last line read from the socket.
1947
		line=
1948
1949
		# Keep on running as long as the father process is around.
1950
		# Note that this while loop has the message queue as stdin.
1951
		while kill -0 "$pid" 2> /dev/null; do
1952
			# Check for a message in the queue.
1953
			# There is nothing to be done, if there was no message,
1954
			# none the less it times out to allow the terminal
1955
			# to catch signals.
1956
			read -t 2 line
1957
			# Process messages.
1958
			case "$line" in
1959
				finished:*)
1960
					# A download has been finished.
1961
					# Add the mirror that was used to
1962
					# the list of available mirrors.
1963
					mirror="${line#finished:}"
1964
					mirror="${mirror%;*}"
1965
					mirrors="${mirrors:+$mirrors$IFS}$mirror"
1966
				;;
1967
				retry:*)
1968
					# A download was not finished
1969
					# successfuly.
1970
					mirror="${line#retry:}"
1971
					job="${mirror##*;}"
1972
					mirror="${mirror%;*}"
1973
					if echo "$retried" | grep -qFx "$job"; then
1974
						# If this package has already
1975
						# had a retry, mark it as
1976
						# finished to hand it over
1977
						# to the package validation
1978
						# that can fetch from the
1979
						# master server.
1980
						downloadManagerMsgFinished "$mirror" "$job"
1981
					else
1982
						# The first retry request.
1983
						# Free the mirror and list
1984
						# the package for retry.
1985
						mirrors="${mirrors:+$mirrors$IFS}$mirror"
1986
						retry="${retry:+$retry$IFS}$job"
1987
					fi
1988
				;;
1989
				request:*)
1990
					# Append requested downloads to the
1991
					# list of available jobs.
1992
					jobs="${jobs:+$jobs$IFS}${line#request:}"
1993
				;;
1994
				exit)
1995
					# The download manager has been told
1996
					# to terminate.
1997
					break
1998
				;;
1999
			esac
2000
			# Delete the line, so it cannot be read again in the
2001
			# next iteration, if reading from the queue has
2002
			# timed out.
2003
			line=
2004
2005
			# If any mirrors are available and there are jobs
2006
			# in the queue, now is the time to dispatch them.
2007
			while [ -n "$jobs" -a -n "$mirrors" ]; do
2008
				mirror="${mirrors%%$IFS*}"
2009
				mirrors="${mirrors#$mirror}"
2010
				mirrors="${mirrors#$IFS}"
2011
				job="${jobs%%$IFS*}"
2012
				jobs="${jobs#$job}"
2013
				jobs="${jobs#$IFS}"
2014
				downloadManagerFetch "$mirror" "$job" &
2015
			done
2016
2017
			# If we have run out of jobs, give the retry stuff.
2018
			# a try.
2019
			while [ -n "$retry" -a -n "$mirrors" ]; do
2020
				mirror="${mirrors%%$IFS*}"
2021
				mirrors="${mirrors#$mirror}"
2022
				mirrors="${mirrors#$IFS}"
2023
				job="${retry%%$IFS*}"
2024
				retry="${retry#$job}"
2025
				retry="${retry#$IFS}"
2026
				# Remember that this job has been retried.
2027
				retried="${retried:+$retried$IFS}$job"
2028
				downloadManagerFetch "$mirror" "$job" &
2029
			done
2030
		done < "$queueMessages"
2031
	) &
2032
}
2033
2034
#
2035
# This is forked off by the download manager to download a package from
2036
# a mirror.
2037
# If the package is already present a download is not attempted.
2038
#
2039
# @param 1
2040
#	The mirror to download from.
2041
# @param 2
2042
#	The name of the package to download.
2043
#
2044
downloadManagerFetch() {
2045
	# Get rid of pending jobs.
2046
	trap "
2047
		kill \$(jobs -ls) > /dev/null 2>&1
2048
		exit
2049
	" EXIT sigint sigterm
2050
2051
	# Only do something if the package is not present.
2052
	if ! [ -e "$PACKAGES/All/$2.tbz" ]; then
2053
		# Create the download location.
2054
		mkdir -p "$PACKAGES/All" 2> /dev/null
2055
2056
		# Attempt download from mirror.
2057
		# This is forked off, to allow the shell to catch signals.
2058
		fetch -qmo "$PACKAGES/All/$2.tbz" "${1%/*?}/All/$2.tbz" > /dev/null 2>&1 &
2059
		if ! wait $!; then
2060
			# Release the mirror and mark the package for a retry.
2061
			downloadManagerMsgRetry "$1" "$2"
2062
			return 0
2063
		fi
2064
	fi
2065
2066
	# Release the mirror and mark package finished.
2067
	downloadManagerMsgFinished "$1" "$2"
2068
}
2069
2070
#
2071
# Tells the download manager, that a download was unsuccessful.
2072
#
2073
# @param 1
2074
#	The mirror that was used.
2075
# @param 2
2076
#	The name of the package that was not downloaded.
2077
# @param queueMessages
2078
#	The message queue to the download manager.
2079
#
2080
downloadManagerMsgRetry() {
2081
	# Do not send anything without a queue.
2082
	test ! -e "$queueMessages" && return 0
2083
2084
	lockf -k "$queueMessages" sh -c "echo 'retry:$1;$2' >> '$queueMessages'"
2085
}
2086
2087
#
2088
# Tells the download manager, that a download has been finished.
2089
#
2090
# @param 1
2091
#	The mirror that was used.
2092
# @param 2
2093
#	The name of the downloaded package.
2094
# @param queueMessages
2095
#	The message queue to the download manager.
2096
#
2097
downloadManagerMsgFinished() {
2098
	# Do not send anything without a queue.
2099
	test ! -e "$queueMessages" && return 0
2100
2101
	lockf -k "$queueMessages" sh -c "echo 'finished:$1;$2' >> '$queueMessages'"
2102
}
2103
2104
#
2105
# Requests the download of packages from the download manager.
2106
#
2107
# @param 1
2108
#	A list of packages for download.
2109
# @param queueMessages
2110
#	The message queue to the download manager.
2111
#
2112
downloadManagerMsgRequest() {
2113
	# Do not send anything without a queue.
2114
	test ! -e "$queueMessages" && return 0
2115
2116
	local request
2117
	for request in $1; {
2118
		lockf -k "$queueMessages" sh -c "echo 'request:${request#*;}' >> '$queueMessages'"
2119
	}
2120
}
2121
2122
#
2123
# Instructs the download manager to terminate.
2124
#
2125
# @param queueMessages
2126
#	The message queue to the download manager.
2127
#
2128
downloadManagerMsgExit() {
2129
	# Do not send anything without a queue.
2130
	test ! -e "$queueMessages" && return 0
2131
2132
	lockf -k "$queueMessages" sh -c "echo 'exit' >> '$queueMessages'"
2133
}
2134
2135
#
2136
# Validates a single package. Validation means it checks whether a package
2137
# is a complete tar archive. Damaged or missing packages will be (re)downloaded
2138
# from the master server (the one named by PACKAGESITE).
2139
# If the package is a valid tar archive the +CONTENTS file will be checked,
2140
# as well.
2141
#
2142
# @param 1
2143
#	The name of the package to validate.
2144
# @param packagerepos
2145
#	The location of the remote package collection. This is derived from
2146
#	PACKAGESITE.
2147
# @param pending
2148
#	The list of pending packages.
2149
# @return
2150
#	Return 0 on success.
2151
#
2152
validatePackage() {
2153
	local package
2154
	package="$1.tbz"
2155
2156
	# Check whether the package is intact and present.
2157
	if ! tar -tf "$PACKAGES/All/$package" > /dev/null 2>&1; then
2158
		# If the package repository and the local package collection
2159
		# are identical, there's no chance to get the package if it's
2160
		# not already there.
2161
		if [ "$PACKAGES" = "$packagerepos" ]; then
2162
			error $ERR_FETCH "The package <$package> is not present."
2163
		fi
2164
2165
		# Clean up whatever crap is there.
2166
		rm "$PACKAGES/All/$package" 2> /dev/null
2167
2168
		# Try to get the package from the master server.
2169
		fetch -mo "$PACKAGES/All/$package" "$packagerepos/All/$package"
2170
2171
		# Check whether the package is present.
2172
		if ! [ -e "$PACKAGES/All/$package" ]; then
2173
			error $ERR_FETCH "The package <$package> could not be fetched."
2174
		fi
2175
2176
		# Check whether the package is a valid tar archive.
2177
		if ! tar -tf "$PACKAGES/All/$package" > /dev/null 2>&1; then
2178
			error $ERR_FETCH "The package <$package> could not be read."
2179
		fi
2180
	fi
2181
2182
	# Check whether we can read the package +CONTENTS format.
2183
	readContents "$PACKAGES/All/$package"
2184
2185
	# Remove this package from the list of pending packages.
2186
	pending="$(echo "$pending" | grep -vFx "$1")"
2187
2188
	# The package is present and intact.
2189
	return 0
2190
}
2191
2192
#
2193
# Let's get it on! The declarative part is finally over.
2194
#
2195
2196
# Ignore some signals that should not occur.
2197
trap 'warn "Discard signal SIGHUP."' sighup
2198
trap 'warn "Discard signal SIGUSR1."' sigusr1
2199
trap 'warn "Discard signal SIGUSR2."' sigusr2
2200
2201
#
2202
# Parse command line parameters.
2203
#
2204
readParams "$@"
2205
2206
# Make sure the index is available for the following operations.
2207
getIndex
2208
2209
#
2210
# Populate the list of packages out of sync with the index.
2211
#
2212
pkgAll
2213
2214
#
2215
# Perform dependency checking.
2216
#
2217
pkgDependencies
2218
2219
#
2220
# Sort packages by their dependencies.
2221
#
2222
pkgSort
2223
2224
#
2225
# Display tasks.
2226
#
2227
pkgList
2228
2229
#
2230
# Download packages.
2231
#
2232
pkgDownload
2233
2234
#
2235
# Upgrade packages.
2236
#
2237
pkgUpgrade
2238
2239
exit 0
(-)/usr/ports/sysutils/bsdadminscripts/files/uma.in (+436 lines)
Line 0 Link Here
1
#!/bin/sh -f
2
#
3
# Copyright (c) 2009
4
# Dominic Fandrey <kamikaze@bsdforen.de>
5
#
6
# Redistribution and use in source and binary forms, with or without
7
# modification, are permitted provided that the following conditions
8
# are met:
9
# 1. Redistributions of source code must retain the above copyright
10
#    notice, this list of conditions and the following disclaimer.
11
#
12
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
13
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
14
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
15
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
16
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
17
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
18
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
19
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
21
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22
#
23
24
readonly version=1.1.1
25
readonly name=uma
26
27
# Return value.
28
errno=0
29
# Allow things to fail properly by ignoring SIGINT in the main process.
30
trap '' int
31
32
# Used to activate verbose output.
33
verbose=
34
# Will be set if files are locally available.
35
local=
36
37
vardir="%%VAR%%"
38
lock="$vardir/run/$name.lock"
39
lockpid="$vardir/run/$name.pid"
40
identpid="$vardir/run/$name.ident.pid"
41
conf="%%PREFIX%%/etc/$name.conf"
42
43
# Use line breaks as a delimiter.
44
IFS='
45
'
46
# Timezone UTC for age comparisons.
47
export TZ=UTC
48
49
# The bit position of errors.
50
readonly ERR_LOCK=0
51
readonly ERR_ARG=1
52
readonly ERR_FETCH_PORTS=2
53
readonly ERR_FETCH_VULNDB=3
54
readonly ERR_FETCH_INDEX=4
55
readonly ERR_EXTRACT_PORTS=5
56
readonly ERR_UPDATE_PORTS=6
57
58
#
59
# Get environment variables.
60
#
61
62
# Load the configuration file if present.
63
if [ -e "$conf" ]; then
64
	. "$conf"
65
fi
66
67
# Local index location.
68
: ${PKG_INDEX="$vardir/db/uma/FTPINDEX"}
69
: ${FTP_TIMEOUT=60}
70
71
# Logic from src/usr.sbin/pkg_install/add/main.c, plus the possibility to
72
# override the architecture with ARCH.
73
: ${PACKAGEROOT="ftp://ftp.freebsd.org"}
74
: ${ARCH="$(uname -m)"}
75
branch="$(uname -r | tr '[:upper:]' '[:lower:]')"
76
number="${branch%%.*}"
77
branch="${branch##*-}"
78
case "$branch" in
79
	release)
80
		branch=$number-$branch
81
	;;
82
	stable|current)
83
		branch=${number%%.*}-$branch
84
	;;
85
	*)
86
		# Fallback to stable for prerelease and the like.
87
		branch=${number%%.*}-stable
88
	;;
89
esac
90
: ${BRANCH=$branch}
91
: ${PACKAGESITE="$PACKAGEROOT/pub/FreeBSD/ports/$ARCH/packages-$BRANCH/Latest"}
92
packagetree="${PACKAGESITE%/*?}"
93
ftp="${PACKAGESITE#*://}"
94
ftp="${ftp%%/*}"
95
96
#
97
# Generate PACKAGESITE_MIRRORS if only PACKAGEROOT_MIRRORS are given.
98
# Note that PACKAGEROOT_MIRRORS and PACKAGESITE_MIRRORS are supposed to be
99
# a ";" or line feed separated list. Semicolons will be converted to line
100
# feeds in any case.
101
#
102
103
# Set PACKAGEROOT_MIRRORS if not set.
104
if [ -z "$PACKAGEROOT_MIRRORS" ]; then
105
	PACKAGEROOT_MIRRORS=
106
	for i in $(jot 14); {
107
		PACKAGEROOT_MIRRORS="${PACKAGEROOT_MIRRORS:+$PACKAGEROOT_MIRRORS$IFS}ftp://ftp$i.FreeBSD.org"
108
	}
109
fi
110
111
# Convert semicolon in PACKAGEROOT_MIRRORS.
112
PACKAGEROOT_MIRRORS="$(echo "$PACKAGEROOT_MIRRORS" | sed "s/;/\\$IFS/g")"
113
# Build PACKAGESITE_MIRRORS.
114
if [ -z "${PACKAGESITE_MIRRORS}" ]; then
115
	PACKAGESITE_MIRRORS=
116
	for MIRROR in $PACKAGEROOT_MIRRORS; {
117
		PACKAGESITE_MIRRORS="${PACKAGESITE_MIRRORS:+$PACKAGESITE_MIRRORS$IFS}$MIRROR/pub/FreeBSD/ports/$ARCH/packages-$BRANCH/Latest"
118
	}
119
fi
120
# Convert semicolon in PACKAGESITE_MIRRORS.
121
PACKAGESITE_MIRRORS="$(echo "$PACKAGESITE_MIRRORS" | sed "s/;/\\$IFS/g")"
122
123
# Remove duplicates.
124
PACKAGEROOT_MIRRORS="$(echo "$PACKAGEROOT_MIRRORS" | sort -u)"
125
PACKAGESITE_MIRRORS="$(echo "$PACKAGESITE_MIRRORS" | sort -u)"
126
127
# Determine portsdir
128
portsdir=$(make -V PORTSDIR -f /usr/share/mk/bsd.port.mk 2> /dev/null)
129
portsdir="${portsdir:-%%PORTS%%}"
130
131
export ARCH BRANCH PKG_INDEX FTP_TIMEOUT PACKAGEROOT PACKAGESITE
132
export PACKAGEROOT_MIRRORS PACKAGESITE_MIRRORS
133
134
#
135
# This function is called by a trap when the script exits in verbose mode.
136
# It reads errno to construct error messages.
137
#
138
# @param errno
139
#	The exit status of the script.
140
#
141
verbose() {
142
	if [ $(($errno >> $ERR_LOCK & 1)) -eq 1 ]; then
143
		echo "ERROR($((1 << $ERR_LOCK))): Lock owned by someone else."
144
	fi
145
	if [ $(($errno >> $ERR_ARG & 1)) -eq 1 ]; then
146
		echo "ERROR($((1 << $ERR_ARG))): An unknown parameter was supplied."
147
	fi
148
	if [ $(($errno >> $ERR_FETCH_PORTS & 1)) -eq 1 ]; then
149
		echo "ERROR($((1 << $ERR_FETCH_PORTS))): Fetching the ports tree failed."
150
	fi
151
	if [ $(($errno >> $ERR_FETCH_VULNDB & 1)) -eq 1 ]; then
152
		echo "ERROR($((1 << $ERR_FETCH_VULNDB))): Fetching security database failed."
153
	fi
154
	if [ $(($errno >> $ERR_FETCH_INDEX & 1)) -eq 1 ]; then
155
		echo "ERROR($((1 << $ERR_FETCH_INDEX))): Fetching remote INDEX failed."
156
	fi
157
	if [ $(($errno >> $ERR_EXTRACT_PORTS & 1)) -eq 1 ]; then
158
		echo "ERROR($((1 << $ERR_EXTRACT_PORTS))): Extracting the ports tree failed."
159
	fi
160
	if [ $(($errno >> $ERR_UPDATE_PORTS & 1)) -eq 1 ]; then
161
		echo "ERROR($((1 << $ERR_UPDATE_PORTS))): Updating the ports tree failed."
162
	fi
163
}
164
165
#
166
# This function spawns a process that takes over a lock.
167
#
168
# @param pid
169
#	The PID of the process that requested the lock.
170
# @param lock
171
#	The location of the lock file.
172
# @param lockpid
173
#	The location of the PID file for the lock holding process.
174
#
175
secureLock() {
176
	lockf "$lock" sh -c "
177
		trap 'exit 0' term
178
		echo '$pid' > '$lock'
179
		echo \"\$\$\" > '$lockpid'
180
		trap 'rm \"$lockpid\"; exit 0' EXIT
181
		while kill -0 '$pid' 2> /dev/null; do
182
			sleep 2
183
		done
184
	" 2> /dev/null &
185
}
186
187
#
188
# Checks whether the currently requesting process holds the lock.
189
#
190
# @param pid
191
#	The PID of the process that requested the lock.
192
# @param lock
193
#	The location of the lock file.
194
# @return
195
#	Returns 0 if the lock is held for the requesting process or 1
196
#	if the lock is missing or owned by another process.
197
#
198
hasLock() {
199
	test "$pid" -eq "$(cat "$lock" 2> /dev/null)" 2> /dev/null
200
	return $?
201
}
202
203
#
204
# Creates a lock for the requesting process.
205
# 
206
# @param pid
207
#	The PID of the process that requested the lock.
208
# @param lock
209
#	The location of the lock file.
210
# @param lockpid
211
#	The location of the PID file for the lock holding process.
212
# @param portsdir
213
#	The location of the FreeBSD ports tree.
214
# @return
215
#	Returns 0 on success, 1 on failure.
216
#
217
lock() {
218
	local location
219
220
	# The requestor already holds the lock.
221
	hasLock && return 0
222
223
	# The process requesting the lock does not exist.
224
	kill -0 "$pid" 2> /dev/null || return 1 $(errno=1)
225
226
	# Follow symlinks
227
	location="$(pwd)"
228
	if cd "$portsdir" && portsdir="$(pwd -P)"; then
229
		# Portsdir exists, so we can test for make activity. This
230
		# does not cover all cases, but it covers a lot.
231
		if fstat "$portsdir" | awk '{print $2}' | grep -q make; then
232
			errno=1
233
			return 1
234
		fi
235
	fi
236
	cd "$location"
237
238
	# Try acquiring the lock.
239
	lockf -st 0 "$lock" "$0" secure $pid 2> /dev/null || return 1 $(errno=1)
240
	# Wait until the locking process is properly set up.
241
	while ! [ -e "$lockpid" -a -e "$lock" ]; do
242
		sleep 0.1
243
	done
244
	return 0
245
}
246
247
#
248
# Frees a lock unless it is held for another process than the requestor.
249
# 
250
# @param lock
251
#	The location of the lock file.
252
# @param lockpid
253
#	The location of the PID file for the lock holding process.
254
# @return
255
#	Returns 0 on success, 1 on failure.
256
#
257
unlock() {
258
	if hasLock; then
259
		# Free the lock.
260
		kill -TERM "$(cat "$lockpid")"
261
		# Wait for the locking process to clean up.
262
		while [ -e "$lockpid" -o -e "$lock" ]; do
263
			sleep 0.1
264
		done
265
		return 0
266
	else
267
		errno=1
268
		return 1
269
	fi
270
}
271
272
#
273
# Prints the command and available parameters.
274
#
275
# @param name
276
#	The name of the script.
277
# @param version
278
#	The version of the script.
279
#
280
printHelp() {
281
	echo "$name v$version
282
usage:
283
	$name [-hv] [pid] [fetch] [extract] [update] [...]
284
	$name [-hv] [pid] fetch [ports] [audit] [ftpindex]
285
	$name [-hv] [pid] extract [ports]
286
	$name [-hv] [pid] update [ports]
287
	$name [-hv] lock [pid]
288
	$name [-hv] unlock [pid]"
289
}
290
291
#
292
# Reads the parameters and creates variables that indicates the presence
293
# of these parameters.
294
#
295
# The last numeric value is treated as the requestor PID. It also deals
296
#
297
# @param @
298
#	All parameters to process.
299
# @param verbose
300
#	Set to 1 if verbose mode is activated.
301
# @param cmd_*
302
#	Set by this function to indicate the presence of a parameter.
303
#
304
readParams() {
305
	local flag
306
	for flag; {
307
		# A numerical parameter is the PID.
308
		if [ "$flag" -eq  "$flag" ] 2> /dev/null; then
309
			pid="${flag}"
310
			continue
311
		fi
312
	
313
		# Activate verbose mode for -v.
314
		case "$flag" in
315
			-v | --verbose)
316
				trap 'verbose 1>&2' EXIT
317
				verbose=1
318
				continue
319
			;;
320
			-h | --help)
321
				printHelp
322
				continue
323
			;;
324
			-? | --*)
325
				errno=$((1 << $ERR_ARG))
326
				exit $errno
327
			;;
328
			-*)
329
				# Split parameters.
330
				readParams "${flag%${flag#-?}}" "-${flag#-?}"
331
				continue
332
			;;
333
		esac
334
335
		# If the variable is not predefined, the command is unknown.
336
		if eval "test -n \"\${cmd_$flag=1}\""; then
337
			errno=$((1 << $ERR_ARG))
338
			exit $errno
339
		fi
340
		setvar "cmd_$flag" 1
341
	}
342
}
343
344
pid="$$"
345
cmd_lock=
346
cmd_unlock=
347
cmd_secure=
348
cmd_env=
349
cmd_fetch=
350
cmd_extract=
351
cmd_update=
352
cmd_ports=
353
cmd_audit=
354
cmd_ftpindex=
355
readParams "$@"
356
357
#
358
# Exclusive commands that will cause all others to be ignored, in order
359
# of priority.
360
#
361
362
if [ -n "$cmd_unlock" ]; then
363
	unlock
364
	return $?
365
fi
366
367
if [ -n "$cmd_secure" ]; then
368
	secureLock
369
	return $?
370
fi
371
372
if [ -n "$cmd_lock" ]; then
373
	lock
374
	return $?
375
fi
376
377
#
378
# Non-exclusive commands that do not require a lock.
379
#
380
381
if [ -n "$cmd_env" ]; then
382
	echo "ARCH='$ARCH'"
383
	echo "BRANCH='$BRANCH'"
384
	echo "FTP_TIMEOUT='$FTP_TIMEOUT'"
385
	echo "PACKAGEROOT='$PACKAGEROOT'"
386
	echo "PACKAGESITE='$PACKAGESITE'"
387
	echo "PKG_INDEX='$PKG_INDEX'"
388
	echo "PACKAGEROOT_MIRRORS='$PACKAGEROOT_MIRRORS'"
389
	echo "PACKAGESITE_MIRRORS='$PACKAGESITE_MIRRORS'"
390
fi
391
392
# Create a local lock if need be.
393
localLock=
394
if ! hasLock; then
395
	localLock=1
396
	lock || return $?
397
fi
398
399
# Ports tree commands.
400
if [ -n "$cmd_ports" ]; then
401
	if [ -n "$cmd_fetch" ]; then
402
		portsnap fetch || errno="$((1 << $ERR_FETCH_PORTS | $errno))"
403
	fi
404
	if [ -n "$cmd_extract" ]; then
405
		portsnap extract || errno=$((1 << $ERR_EXTRACT_PORTS | $errno))
406
	fi
407
	if [ -n "$cmd_update" ]; then
408
		portsnap update || errno=$((1 << $ERR_UPDATE_PORTS | $errno))
409
	fi
410
fi
411
412
# Portaudit commands.
413
if [ -n "$cmd_audit" ]; then
414
	if [ -n "$cmd_fetch" ]; then
415
		portaudit -F || errno=$((1 << $ERR_FETCH_VULNDB | $errno))
416
	fi
417
fi
418
419
# Package index commands.
420
if [ -n "$cmd_ftpindex" ]; then
421
	if ! mkdir -p "${PKG_INDEX%/*}" 2> /dev/null; then
422
		test -n "$verbose" \
423
			&& echo "The directory ${PKG_INDEX%/*} does not exist and cannot be created!"
424
		errno=$((1 << $ERR_FETCH_INDEX | $errno))
425
	elif [ -n "$cmd_fetch" ]; then
426
		fetch -mo "$PKG_INDEX" "$packagetree/INDEX" \
427
			|| errno=$((1 << $ERR_FETCH_INDEX | $errno))
428
	fi
429
fi
430
431
432
# Free a local lock.
433
test -n "$localLock" && unlock
434
435
return $errno
436

Return to bug 193003