Thu Dec 16 14:10:46 2021 UTC ()
The non-writability check for DISTDIR is intended to prevent wasting
resources when fetchers wouldn't be able to save what they download. On
my build farm with pkgsrc (and pkgsrc/distfiles) mounted over NFS,
however, the check gives false positives for NetBSD 9.2 and -current.
Downgrade it to a warning so that these fetches can succeed, while
leaving a breadcrumb in case someone encounters a true positive.

It would of course be interesting to sort out why, in my environment, a
wide variety of other OSes get 1 for "${TEST} ! -w $fetchdir" while
NetBSD gets 0. In the meantime, joerg@ suggested this workaround and
gdt@ agrees it's reasonable to try.


(schmonz)
diff -r1.20 -r1.21 pkgsrc/mk/fetch/fetch

cvs diff -r1.20 -r1.21 pkgsrc/mk/fetch/fetch (switch to unified diff)

--- pkgsrc/mk/fetch/fetch 2020/08/27 11:45:45 1.20
+++ pkgsrc/mk/fetch/fetch 2021/12/16 14:10:46 1.21
@@ -1,311 +1,309 @@ @@ -1,311 +1,309 @@
1#!/bin/sh 1#!/bin/sh
2# 2#
3# $NetBSD: fetch,v 1.20 2020/08/27 11:45:45 jperkin Exp $ 3# $NetBSD: fetch,v 1.21 2021/12/16 14:10:46 schmonz Exp $
4# 4#
5# Copyright (c) 2006, 2015 The NetBSD Foundation, Inc. 5# Copyright (c) 2006, 2015 The NetBSD Foundation, Inc.
6# All rights reserved. 6# All rights reserved.
7# 7#
8# This code is derived from software contributed to The NetBSD Foundation 8# This code is derived from software contributed to The NetBSD Foundation
9# by Johnny C. Lam. 9# by Johnny C. Lam.
10# 10#
11# Redistribution and use in source and binary forms, with or without 11# Redistribution and use in source and binary forms, with or without
12# modification, are permitted provided that the following conditions 12# modification, are permitted provided that the following conditions
13# are met: 13# are met:
14# 1. Redistributions of source code must retain the above copyright 14# 1. Redistributions of source code must retain the above copyright
15# notice, this list of conditions and the following disclaimer. 15# notice, this list of conditions and the following disclaimer.
16# 2. Redistributions in binary form must reproduce the above copyright 16# 2. Redistributions in binary form must reproduce the above copyright
17# notice, this list of conditions and the following disclaimer in the 17# notice, this list of conditions and the following disclaimer in the
18# documentation and/or other materials provided with the distribution. 18# documentation and/or other materials provided with the distribution.
19# 19#
20# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30# POSSIBILITY OF SUCH DAMAGE. 30# POSSIBILITY OF SUCH DAMAGE.
31# 31#
32 32
33###################################################################### 33######################################################################
34# 34#
35# NAME 35# NAME
36# fetch -- fetch files via URLs 36# fetch -- fetch files via URLs
37# 37#
38# SYNOPSIS 38# SYNOPSIS
39# fetch [-c] [-d dir] [-f distinfo] [-p hook] [-r] [-v] file [site ...] 39# fetch [-c] [-d dir] [-f distinfo] [-p hook] [-r] [-v] file [site ...]
40# 40#
41# DESCRIPTION 41# DESCRIPTION
42# fetch will attempt to fetch the file from the list of specified 42# fetch will attempt to fetch the file from the list of specified
43# sites in the order given. The complete URL to the file on each 43# sites in the order given. The complete URL to the file on each
44# site should be the concatenation of the specified site and file. 44# site should be the concatenation of the specified site and file.
45# If the file cannot be fetched successfully, then we try the next 45# If the file cannot be fetched successfully, then we try the next
46# listed site. 46# listed site.
47# 47#
48# If the file already exists on the disk and is verified, then 48# If the file already exists on the disk and is verified, then
49# no fetch action is taken. 49# no fetch action is taken.
50# 50#
51# OPTIONS 51# OPTIONS
52# -c Verify the checksum for the file. If the checksum 52# -c Verify the checksum for the file. If the checksum
53# does not match, then the fetch is determined to be 53# does not match, then the fetch is determined to be
54# not successful. 54# not successful.
55# 55#
56# -d dir Fetch the files into the specified directory. 56# -d dir Fetch the files into the specified directory.
57# 57#
58# -f distinfo 58# -f distinfo
59# The path to the distinfo file containing the checksums 59# The path to the distinfo file containing the checksums
60# for the file. The file format should match what is 60# for the file. The file format should match what is
61# needed by the pkgsrc/mk/checksum/checksum script. 61# needed by the pkgsrc/mk/checksum/checksum script.
62# 62#
63# -p hook 63# -p hook
64# After a successful fetch, run hook. The first argument is 64# After a successful fetch, run hook. The first argument is
65# the relative path of the distfile and the second argument 65# the relative path of the distfile and the second argument
66# the full URL the file was obtained from. 66# the full URL the file was obtained from.
67# 67#
68# -r Resume a previous fetch for the file. In this case, 68# -r Resume a previous fetch for the file. In this case,
69# the file is first saved to a ".pkgsrc.resume" file, 69# the file is first saved to a ".pkgsrc.resume" file,
70# and is later renamed to the final file name if the 70# and is later renamed to the final file name if the
71# complete file has been sucessfully fetched. 71# complete file has been sucessfully fetched.
72# 72#
73# -v Show the actual command line used to fetch the file 73# -v Show the actual command line used to fetch the file
74# from each site. 74# from each site.
75# 75#
76# ENVIRONMENT 76# ENVIRONMENT
77# PKGSRCDIR This is a hint to help locate the default 77# PKGSRCDIR This is a hint to help locate the default
78# checksum script. 78# checksum script.
79# 79#
80# CHECKSUM This is the path to the checksum script used 80# CHECKSUM This is the path to the checksum script used
81# when "-c" is specified. 81# when "-c" is specified.
82# 82#
83# FETCH_CMD This is the actual command used for transferring 83# FETCH_CMD This is the actual command used for transferring
84# files from the various sites. 84# files from the various sites.
85# 85#
86# The following are lists of options to pass to ${FETCH_CMD}: 86# The following are lists of options to pass to ${FETCH_CMD}:
87# 87#
88# FETCH_BEFORE_ARGS 88# FETCH_BEFORE_ARGS
89# These options appear before all other options. 89# These options appear before all other options.
90# 90#
91# FETCH_AFTER_ARGS 91# FETCH_AFTER_ARGS
92# These options appear after all other options. 92# These options appear after all other options.
93# 93#
94# FETCH_RESUME_ARGS 94# FETCH_RESUME_ARGS
95# These options appear just after FETCH_BEFORE_ARGS 95# These options appear just after FETCH_BEFORE_ARGS
96# options and cause ${FETCH_CMD} to resume a 96# options and cause ${FETCH_CMD} to resume a
97# previous file transfer. 97# previous file transfer.
98# 98#
99# FETCH_OUTPUT_ARGS 99# FETCH_OUTPUT_ARGS
100# These options specify the name of the local file 100# These options specify the name of the local file
101# that will hold the contents of the fetched file. 101# that will hold the contents of the fetched file.
102# 102#
103###################################################################### 103######################################################################
104 104
105: ${PKGSRCDIR:=/usr/pkgsrc} 105: ${PKGSRCDIR:=/usr/pkgsrc}
106: ${CHECKSUM:=false} 106: ${CHECKSUM:=false}
107: ${CP:=cp} 107: ${CP:=cp}
108: ${ECHO:=echo} 108: ${ECHO:=echo}
109: ${FETCH_CMD:=ftp} 109: ${FETCH_CMD:=ftp}
110: ${MKDIR:=mkdir} 110: ${MKDIR:=mkdir}
111: ${MV:=mv} 111: ${MV:=mv}
112: ${TEST:=test} 112: ${TEST:=test}
113: ${TOUCH:=touch} 113: ${TOUCH:=touch}
114: ${WC:=wc} 114: ${WC:=wc}
115 115
116self="${0##*/}" 116self="${0##*/}"
117 117
118usage() { 118usage() {
119 ${ECHO} 1>&2 "usage: $self [-c] [-d dir] [-f distinfo] [-p hook] [-r] [-v] file [site ...]" 119 ${ECHO} 1>&2 "usage: $self [-c] [-d dir] [-f distinfo] [-p hook] [-r] [-v] file [site ...]"
120} 120}
121 121
122# Process optional arguments 122# Process optional arguments
123checksum= 123checksum=
124distinfo= 124distinfo=
125fetchdir=. # A relative directory or "." 125fetchdir=. # A relative directory or "."
126post_fetch= 126post_fetch=
127resume= 127resume=
128verbose= 128verbose=
129while ${TEST} $# -gt 0; do 129while ${TEST} $# -gt 0; do
130 case "$1" in 130 case "$1" in
131 -c) checksum=yes; shift ;; 131 -c) checksum=yes; shift ;;
132 -d) fetchdir="$2"; shift 2 ;; 132 -d) fetchdir="$2"; shift 2 ;;
133 -f) distinfo="$2"; shift 2 ;; 133 -f) distinfo="$2"; shift 2 ;;
134 -p) post_fetch="$2"; shift 2 ;; 134 -p) post_fetch="$2"; shift 2 ;;
135 -r) resume=yes; shift ;; 135 -r) resume=yes; shift ;;
136 -v) verbose=yes; shift ;; 136 -v) verbose=yes; shift ;;
137 --) shift; break ;; 137 --) shift; break ;;
138 -*) ${ECHO} 1>&2 "$self: unknown option -- ${1#-}" 138 -*) ${ECHO} 1>&2 "$self: unknown option -- ${1#-}"
139 usage 139 usage
140 exit 1 140 exit 1
141 ;; 141 ;;
142 *) break ;; 142 *) break ;;
143 esac 143 esac
144done 144done
145if ${TEST} -n "$checksum" -a -z "$distinfo"; then 145if ${TEST} -n "$checksum" -a -z "$distinfo"; then
146 ${ECHO} 1>&2 "$self: \`\`-c'' requires \`\`-f distinfo''." 146 ${ECHO} 1>&2 "$self: \`\`-c'' requires \`\`-f distinfo''."
147 exit 1 147 exit 1
148fi 148fi
149if ${TEST} -n "$resume"; then 149if ${TEST} -n "$resume"; then
150 if ${TEST} -z "$distinfo"; then 150 if ${TEST} -z "$distinfo"; then
151 ${ECHO} 1>&2 "$self: \`\`-r'' requires \`\`-f distinfo''." 151 ${ECHO} 1>&2 "$self: \`\`-r'' requires \`\`-f distinfo''."
152 resume= 152 resume=
153 elif ${TEST} "x${FETCH_RESUME_ARGS}" = "x"; then 153 elif ${TEST} "x${FETCH_RESUME_ARGS}" = "x"; then
154 ${ECHO} 1>&2 "$self: \`\`-r'' requires FETCH_RESUME_ARGS to be non-empty." 154 ${ECHO} 1>&2 "$self: \`\`-r'' requires FETCH_RESUME_ARGS to be non-empty."
155 resume= 155 resume=
156 fi 156 fi
157 ${TEST} -n "$resume" || 157 ${TEST} -n "$resume" ||
158 ${ECHO} 1>&2 "$self: Falling back to non-resume fetch." 158 ${ECHO} 1>&2 "$self: Falling back to non-resume fetch."
159fi 159fi
160 160
161# Process required arguments 161# Process required arguments
162if ${TEST} $# -lt 1; then 162if ${TEST} $# -lt 1; then
163 usage 163 usage
164 exit 1 164 exit 1
165fi 165fi
166file="$1"; shift 166file="$1"; shift
167path="$fetchdir/$file" 167path="$fetchdir/$file"
168 168
169if ${TEST} -n "$distinfo" && ${TEST} ! -f "$distinfo"; then 169if ${TEST} -n "$distinfo" && ${TEST} ! -f "$distinfo"; then
170 ${ECHO} 1>&2 "$self: distinfo file missing: $distinfo" 170 ${ECHO} 1>&2 "$self: distinfo file missing: $distinfo"
171 exit 1 171 exit 1
172fi 172fi
173 173
174# Compute the expected size of the fetched file. 174# Compute the expected size of the fetched file.
175distsize= 175distsize=
176distunits= 176distunits=
177if ${TEST} -n "$distinfo"; then 177if ${TEST} -n "$distinfo"; then
178 while read d_type d_file d_equals d_size d_units; do 178 while read d_type d_file d_equals d_size d_units; do
179 case "$d_type" in 179 case "$d_type" in
180 Size) ;; # only handle "Size" lines 180 Size) ;; # only handle "Size" lines
181 *) continue ;; 181 *) continue ;;
182 esac 182 esac
183 case "$fetchdir" in 183 case "$fetchdir" in
184 ".") ${TEST} "$d_file" = "($file)" || continue ;; 184 ".") ${TEST} "$d_file" = "($file)" || continue ;;
185 *) ${TEST} "$d_file" = "($path)" || continue ;; 185 *) ${TEST} "$d_file" = "($path)" || continue ;;
186 esac 186 esac
187 distsize="$d_size"; distunits="$d_units" 187 distsize="$d_size"; distunits="$d_units"
188 break 188 break
189 done < $distinfo 189 done < $distinfo
190fi 190fi
191 191
192# verify_file [-v] $file 192# verify_file [-v] $file
193# If we can checksum the file, then see if it matches the listed 193# If we can checksum the file, then see if it matches the listed
194# checksums in the distinfo file. If we can check the size, then 194# checksums in the distinfo file. If we can check the size, then
195# check that instead. We strip off ".pkgsrc.resume" from the 195# check that instead. We strip off ".pkgsrc.resume" from the
196# filename so that we can verify the checksum for the temporary 196# filename so that we can verify the checksum for the temporary
197# fetch file as well. 197# fetch file as well.
198# 198#
199verify_file() { 199verify_file() {
200 _if_verbose=:; if [ "x$1" = "x-v" ]; then shift; _if_verbose=; fi 200 _if_verbose=:; if [ "x$1" = "x-v" ]; then shift; _if_verbose=; fi
201 _file="${1#./}" 201 _file="${1#./}"
202 ${TEST} -f $_file || { 202 ${TEST} -f $_file || {
203 $_if_verbose ${ECHO} 1>&2 "$self: File $_file does not exist." 203 $_if_verbose ${ECHO} 1>&2 "$self: File $_file does not exist."
204 return 1 204 return 1
205 } 205 }
206 if ${TEST} -n "$checksum"; then 206 if ${TEST} -n "$checksum"; then
207 ${CHECKSUM} -s ".pkgsrc.resume" $distinfo ${_file} || { 207 ${CHECKSUM} -s ".pkgsrc.resume" $distinfo ${_file} || {
208 $_if_verbose ${ECHO} 1>&2 "$self: Checksum of the file $_file doesn't match." 208 $_if_verbose ${ECHO} 1>&2 "$self: Checksum of the file $_file doesn't match."
209 return 1 209 return 1
210 } 210 }
211 return 0 211 return 0
212 elif ${TEST} -n "$distsize"; then 212 elif ${TEST} -n "$distsize"; then
213 _size=`${WC} -c < $_file` 213 _size=`${WC} -c < $_file`
214 ${TEST} "$_size" -eq "$distsize" || { 214 ${TEST} "$_size" -eq "$distsize" || {
215 $_if_verbose ${ECHO} 1>&2 "$self: Size of the file $_file doesn't match." 215 $_if_verbose ${ECHO} 1>&2 "$self: Size of the file $_file doesn't match."
216 return 1 216 return 1
217 } 217 }
218 return 0 218 return 0
219 fi 219 fi
220 return 0; 220 return 0;
221} 221}
222 222
223# If the file already exists and it verifies, then we don't need to fetch 223# If the file already exists and it verifies, then we don't need to fetch
224# it again. 224# it again.
225# 225#
226if verify_file $path; then 226if verify_file $path; then
227 exit 0 227 exit 0
228fi 228fi
229 229
230${TEST} -d $fetchdir || ${MKDIR} -p $fetchdir 2>/dev/null 230${TEST} -d $fetchdir || ${MKDIR} -p $fetchdir 2>/dev/null
231if ${TEST} ! -w $fetchdir; then 231
232 ${ECHO} 1>&2 "$self: Cannot write to `cd $fetchdir && pwd`" 232${TEST} -w $fetchdir || ${ECHO} 1>&2 "$self: WARNING: DISTDIR `cd $fetchdir && pwd` looks non-writable."
233 exit 1 
234fi 
235 233
236# Set the name of the output file. In the "resume" case, we initialize 234# Set the name of the output file. In the "resume" case, we initialize
237# the fetch loop by ensuring that the temporary output file already 235# the fetch loop by ensuring that the temporary output file already
238# exists. 236# exists.
239# 237#
240outputfile="$file" 238outputfile="$file"
241outputpath="$fetchdir/$outputfile" 239outputpath="$fetchdir/$outputfile"
242if ${TEST} -n "$resume"; then 240if ${TEST} -n "$resume"; then
243 outputfile="${file}.pkgsrc.resume" 241 outputfile="${file}.pkgsrc.resume"
244 outputpath="$fetchdir/$outputfile" 242 outputpath="$fetchdir/$outputfile"
245 if ${TEST} ! -f $outputpath; then 243 if ${TEST} ! -f $outputpath; then
246 if ${TEST} -f $path; then 244 if ${TEST} -f $path; then
247 ${CP} -f $path $outputpath 245 ${CP} -f $path $outputpath
248 else 246 else
249 ${RM} -f $outputpath 247 ${RM} -f $outputpath
250 ${TOUCH} $outputpath 248 ${TOUCH} $outputpath
251 fi 249 fi
252 fi 250 fi
253 # 251 #
254 # If the temporary file verifies, then we don't need to resume 252 # If the temporary file verifies, then we don't need to resume
255 # fetching it. 253 # fetching it.
256 # 254 #
257 if verify_file $outputpath; then 255 if verify_file $outputpath; then
258 ${MV} -f $outputpath $path 256 ${MV} -f $outputpath $path
259 exit 0 257 exit 0
260 fi 258 fi
261 size=`${WC} -c < $outputpath` 259 size=`${WC} -c < $outputpath`
262 ${ECHO} "=> Downloaded size: $size bytes" 260 ${ECHO} "=> Downloaded size: $size bytes"
263fi 261fi
264${TEST} -z "$distsize" || ${ECHO} "=> Total size: $distsize $distunits" 262${TEST} -z "$distsize" || ${ECHO} "=> Total size: $distsize $distunits"
265 263
266# Iterate over each site and try to fetch the file. We verify the fetched 264# Iterate over each site and try to fetch the file. We verify the fetched
267# file to see if we need to try fetching from the next site. 265# file to see if we need to try fetching from the next site.
268# 266#
269while ${TEST} $# -gt 0; do 267while ${TEST} $# -gt 0; do
270 site="$1"; shift 268 site="$1"; shift
271 case "$site" in 269 case "$site" in
272 -*) 270 -*)
273 url=${site#-} 271 url=${site#-}
274 ;; 272 ;;
275 *) 273 *)
276 url=$site$file 274 url=$site$file
277 ;; 275 ;;
278 esac 276 esac
279 277
280 ( cd $fetchdir 278 ( cd $fetchdir
281 if ${TEST} -n "$resume"; then 279 if ${TEST} -n "$resume"; then
282 fetch_cmd="${FETCH_CMD} ${FETCH_BEFORE_ARGS} ${FETCH_RESUME_ARGS} ${FETCH_OUTPUT_ARGS} $outputfile $url" 280 fetch_cmd="${FETCH_CMD} ${FETCH_BEFORE_ARGS} ${FETCH_RESUME_ARGS} ${FETCH_OUTPUT_ARGS} $outputfile $url"
283 else 281 else
284 fetch_cmd="${FETCH_CMD} ${FETCH_BEFORE_ARGS} ${FETCH_OUTPUT_ARGS} $outputfile $url ${FETCH_AFTER_ARGS}" 282 fetch_cmd="${FETCH_CMD} ${FETCH_BEFORE_ARGS} ${FETCH_OUTPUT_ARGS} $outputfile $url ${FETCH_AFTER_ARGS}"
285 fi 283 fi
286 ${TEST} -z "$verbose" || ${ECHO} "$fetch_cmd" 284 ${TEST} -z "$verbose" || ${ECHO} "$fetch_cmd"
287 $fetch_cmd ) 285 $fetch_cmd )
288 if ${TEST} $? -ne 0; then 286 if ${TEST} $? -ne 0; then
289 ${ECHO} 1>&2 "$self: Unable to fetch expected file $file" 287 ${ECHO} 1>&2 "$self: Unable to fetch expected file $file"
290 continue 288 continue
291 fi 289 fi
292 if verify_file -v $outputpath; then 290 if verify_file -v $outputpath; then
293 ${TEST} -z "$resume" || ${MV} -f $outputpath $path 291 ${TEST} -z "$resume" || ${MV} -f $outputpath $path
294 break 292 break
295 fi 293 fi
296 if ${TEST} -n "$resume"; then 294 if ${TEST} -n "$resume"; then
297 if ${TEST} -f $path; then 295 if ${TEST} -f $path; then
298 ${CP} -f $path $outputpath 296 ${CP} -f $path $outputpath
299 else 297 else
300 ${TOUCH} $outputpath 298 ${TOUCH} $outputpath
301 fi 299 fi
302 fi 300 fi
303done 301done
304if ${TEST} -f $path && ${TEST} -n "$post_fetch"; then 302if ${TEST} -f $path && ${TEST} -n "$post_fetch"; then
305 "$post_fetch" $path "$url" 303 "$post_fetch" $path "$url"
306fi 304fi
307if ${TEST} -f $path; then 305if ${TEST} -f $path; then
308 exit 0 306 exit 0
309else 307else
310 exit 1 308 exit 1
311fi 309fi