1148871Scperciva#!/bin/sh 2148871Scperciva 3148871Scperciva#- 4148871Scperciva# Copyright 2004-2005 Colin Percival 5148871Scperciva# All rights reserved 6148871Scperciva# 7148871Scperciva# Redistribution and use in source and binary forms, with or without 8148871Scperciva# modification, are permitted providing that the following conditions 9148871Scperciva# are met: 10148871Scperciva# 1. Redistributions of source code must retain the above copyright 11148871Scperciva# notice, this list of conditions and the following disclaimer. 12148871Scperciva# 2. Redistributions in binary form must reproduce the above copyright 13148871Scperciva# notice, this list of conditions and the following disclaimer in the 14148871Scperciva# documentation and/or other materials provided with the distribution. 15148871Scperciva# 16148871Scperciva# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17148871Scperciva# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18148871Scperciva# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19148871Scperciva# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20148871Scperciva# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21148871Scperciva# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22148871Scperciva# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23148871Scperciva# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24148871Scperciva# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25148871Scperciva# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26148871Scperciva# POSSIBILITY OF SUCH DAMAGE. 27148871Scperciva 28148871Scperciva# $FreeBSD: releng/9.3/usr.sbin/portsnap/portsnap/portsnap.sh 306942 2016-10-10 07:19:16Z delphij $ 29148871Scperciva 30148871Scperciva#### Usage function -- called from command-line handling code. 31148871Scperciva 32148871Scperciva# Usage instructions. Options not listed: 33148871Scperciva# --debug -- don't filter output from utilities 34148871Scperciva# --no-stats -- don't show progress statistics while fetching files 35148871Scpercivausage() { 36148871Scperciva cat <<EOF 37149027Scpercivausage: `basename $0` [options] command ... [path] 38148871Scperciva 39148871ScpercivaOptions: 40148871Scperciva -d workdir -- Store working files in workdir 41148871Scperciva (default: /var/db/portsnap/) 42148871Scperciva -f conffile -- Read configuration options from conffile 43148871Scperciva (default: /etc/portsnap.conf) 44148871Scperciva -I -- Update INDEX only. (update command only) 45148871Scperciva -k KEY -- Trust an RSA key with SHA256 hash of KEY 46158523Scperciva -l descfile -- Merge the specified local describes file into the INDEX. 47148871Scperciva -p portsdir -- Location of uncompressed ports tree 48148871Scperciva (default: /usr/ports/) 49148871Scperciva -s server -- Server from which to fetch updates. 50148871Scperciva (default: portsnap.FreeBSD.org) 51148871Scperciva path -- Extract only parts of the tree starting with the given 52148871Scperciva string. (extract command only) 53148871ScpercivaCommands: 54148871Scperciva fetch -- Fetch a compressed snapshot of the ports tree, 55148871Scperciva or update an existing snapshot. 56148871Scperciva cron -- Sleep rand(3600) seconds, and then fetch updates. 57148871Scperciva extract -- Extract snapshot of ports tree, replacing existing 58148871Scperciva files and directories. 59148871Scperciva update -- Update ports tree to match current snapshot, replacing 60148871Scperciva files and directories which have changed. 61148871ScpercivaEOF 62148871Scperciva exit 0 63148871Scperciva} 64148871Scperciva 65148871Scperciva#### Parameter handling functions. 66148871Scperciva 67148871Scperciva# Initialize parameters to null, just in case they're 68148871Scperciva# set in the environment. 69148871Scpercivainit_params() { 70148871Scperciva KEYPRINT="" 71148871Scperciva EXTRACTPATH="" 72148871Scperciva WORKDIR="" 73148871Scperciva PORTSDIR="" 74148871Scperciva CONFFILE="" 75148871Scperciva COMMAND="" 76149027Scperciva COMMANDS="" 77148871Scperciva QUIETREDIR="" 78148871Scperciva QUIETFLAG="" 79148871Scperciva STATSREDIR="" 80148879Scperciva XARGST="" 81148871Scperciva NDEBUG="" 82148871Scperciva DDSTATS="" 83148871Scperciva INDEXONLY="" 84148871Scperciva SERVERNAME="" 85149824Scperciva REFUSE="" 86158523Scperciva LOCALDESC="" 87148871Scperciva} 88148871Scperciva 89148871Scperciva# Parse the command line 90148871Scpercivaparse_cmdline() { 91148871Scperciva while [ $# -gt 0 ]; do 92148871Scperciva case "$1" in 93148871Scperciva -d) 94148871Scperciva if [ $# -eq 1 ]; then usage; fi 95148871Scperciva if [ ! -z "${WORKDIR}" ]; then usage; fi 96148871Scperciva shift; WORKDIR="$1" 97148871Scperciva ;; 98148871Scperciva --debug) 99148871Scperciva QUIETREDIR="/dev/stderr" 100148871Scperciva STATSREDIR="/dev/stderr" 101148871Scperciva QUIETFLAG=" " 102148871Scperciva NDEBUG=" " 103148879Scperciva XARGST="-t" 104148871Scperciva DDSTATS=".." 105148871Scperciva ;; 106148871Scperciva -f) 107148871Scperciva if [ $# -eq 1 ]; then usage; fi 108148871Scperciva if [ ! -z "${CONFFILE}" ]; then usage; fi 109148871Scperciva shift; CONFFILE="$1" 110148871Scperciva ;; 111148871Scperciva -h | --help | help) 112148871Scperciva usage 113148871Scperciva ;; 114148871Scperciva -I) 115148871Scperciva INDEXONLY="YES" 116148871Scperciva ;; 117148871Scperciva -k) 118148871Scperciva if [ $# -eq 1 ]; then usage; fi 119148871Scperciva if [ ! -z "${KEYPRINT}" ]; then usage; fi 120148871Scperciva shift; KEYPRINT="$1" 121148871Scperciva ;; 122158523Scperciva -l) 123158523Scperciva if [ $# -eq 1 ]; then usage; fi 124158523Scperciva if [ ! -z "${LOCALDESC}" ]; then usage; fi 125158523Scperciva shift; LOCALDESC="$1" 126158523Scperciva ;; 127148871Scperciva --no-stats) 128148871Scperciva if [ -z "${STATSREDIR}" ]; then 129148871Scperciva STATSREDIR="/dev/null" 130148871Scperciva DDSTATS=".. " 131148871Scperciva fi 132148871Scperciva ;; 133148871Scperciva -p) 134148871Scperciva if [ $# -eq 1 ]; then usage; fi 135148871Scperciva if [ ! -z "${PORTSDIR}" ]; then usage; fi 136148871Scperciva shift; PORTSDIR="$1" 137148871Scperciva ;; 138148871Scperciva -s) 139148871Scperciva if [ $# -eq 1 ]; then usage; fi 140148871Scperciva if [ ! -z "${SERVERNAME}" ]; then usage; fi 141148871Scperciva shift; SERVERNAME="$1" 142148871Scperciva ;; 143201251Scperciva cron | extract | fetch | update | alfred) 144149027Scperciva COMMANDS="${COMMANDS} $1" 145148871Scperciva ;; 146235310Seadler up) 147235310Seadler COMMANDS="${COMMANDS} update" 148235310Seadler ;; 149148871Scperciva *) 150148871Scperciva if [ $# -gt 1 ]; then usage; fi 151149027Scperciva if echo ${COMMANDS} | grep -vq extract; then 152149027Scperciva usage 153149027Scperciva fi 154148871Scperciva EXTRACTPATH="$1" 155148871Scperciva ;; 156148871Scperciva esac 157148871Scperciva shift 158148871Scperciva done 159148871Scperciva 160149027Scperciva if [ -z "${COMMANDS}" ]; then 161148871Scperciva usage 162148871Scperciva fi 163148871Scperciva} 164148871Scperciva 165148871Scperciva# If CONFFILE was specified at the command-line, make 166148871Scperciva# sure that it exists and is readable. 167148871Scpercivasanity_conffile() { 168148871Scperciva if [ ! -z "${CONFFILE}" ] && [ ! -r "${CONFFILE}" ]; then 169148871Scperciva echo -n "File does not exist " 170148871Scperciva echo -n "or is not readable: " 171148871Scperciva echo ${CONFFILE} 172148871Scperciva exit 1 173148871Scperciva fi 174148871Scperciva} 175148871Scperciva 176148871Scperciva# If a configuration file hasn't been specified, use 177148871Scperciva# the default value (/etc/portsnap.conf) 178148871Scpercivadefault_conffile() { 179148871Scperciva if [ -z "${CONFFILE}" ]; then 180148871Scperciva CONFFILE="/etc/portsnap.conf" 181148871Scperciva fi 182148871Scperciva} 183148871Scperciva 184148871Scperciva# Read {KEYPRINT, SERVERNAME, WORKDIR, PORTSDIR} from the configuration 185148871Scperciva# file if they haven't already been set. If the configuration 186148871Scperciva# file doesn't exist, do nothing. 187149824Scperciva# Also read REFUSE (which cannot be set via the command line) if it is 188149824Scperciva# present in the configuration file. 189148871Scpercivaparse_conffile() { 190148871Scperciva if [ -r "${CONFFILE}" ]; then 191148871Scperciva for X in KEYPRINT WORKDIR PORTSDIR SERVERNAME; do 192148871Scperciva eval _=\$${X} 193148871Scperciva if [ -z "${_}" ]; then 194148871Scperciva eval ${X}=`grep "^${X}=" "${CONFFILE}" | 195148871Scperciva cut -f 2- -d '=' | tail -1` 196148871Scperciva fi 197148871Scperciva done 198149824Scperciva 199149824Scperciva if grep -qE "^REFUSE[[:space:]]" ${CONFFILE}; then 200149824Scperciva REFUSE="^(` 201149824Scperciva grep -E "^REFUSE[[:space:]]" "${CONFFILE}" | 202149824Scperciva cut -c 7- | xargs echo | tr ' ' '|' 203149824Scperciva `)" 204149824Scperciva fi 205179073Scperciva 206179073Scperciva if grep -qE "^INDEX[[:space:]]" ${CONFFILE}; then 207179073Scperciva INDEXPAIRS="` 208179073Scperciva grep -E "^INDEX[[:space:]]" "${CONFFILE}" | 209179073Scperciva cut -c 7- | tr ' ' '|' | xargs echo`" 210179073Scperciva fi 211148871Scperciva fi 212148871Scperciva} 213148871Scperciva 214148871Scperciva# If parameters have not been set, use default values 215148871Scpercivadefault_params() { 216148871Scperciva _QUIETREDIR="/dev/null" 217148871Scperciva _QUIETFLAG="-q" 218148871Scperciva _STATSREDIR="/dev/stdout" 219148871Scperciva _WORKDIR="/var/db/portsnap" 220148871Scperciva _PORTSDIR="/usr/ports" 221148871Scperciva _NDEBUG="-n" 222158523Scperciva _LOCALDESC="/dev/null" 223158523Scperciva for X in QUIETREDIR QUIETFLAG STATSREDIR WORKDIR PORTSDIR \ 224158523Scperciva NDEBUG LOCALDESC; do 225148871Scperciva eval _=\$${X} 226148871Scperciva eval __=\$_${X} 227148871Scperciva if [ -z "${_}" ]; then 228148871Scperciva eval ${X}=${__} 229148871Scperciva fi 230148871Scperciva done 231148871Scperciva} 232148871Scperciva 233148871Scperciva# Perform sanity checks and set some final parameters 234148871Scperciva# in preparation for fetching files. Also chdir into 235148871Scperciva# the working directory. 236148871Scpercivafetch_check_params() { 237148871Scperciva export HTTP_USER_AGENT="portsnap (${COMMAND}, `uname -r`)" 238148871Scperciva 239148871Scperciva _SERVERNAME_z=\ 240148871Scperciva"SERVERNAME must be given via command line or configuration file." 241148871Scperciva _KEYPRINT_z="Key must be given via -k option or configuration file." 242148871Scperciva _KEYPRINT_bad="Invalid key fingerprint: " 243148871Scperciva _WORKDIR_bad="Directory does not exist or is not writable: " 244148871Scperciva 245148871Scperciva if [ -z "${SERVERNAME}" ]; then 246148871Scperciva echo -n "`basename $0`: " 247148871Scperciva echo "${_SERVERNAME_z}" 248148871Scperciva exit 1 249148871Scperciva fi 250148871Scperciva if [ -z "${KEYPRINT}" ]; then 251148871Scperciva echo -n "`basename $0`: " 252148871Scperciva echo "${_KEYPRINT_z}" 253148871Scperciva exit 1 254148871Scperciva fi 255148871Scperciva if ! echo "${KEYPRINT}" | grep -qE "^[0-9a-f]{64}$"; then 256148871Scperciva echo -n "`basename $0`: " 257148871Scperciva echo -n "${_KEYPRINT_bad}" 258148871Scperciva echo ${KEYPRINT} 259148871Scperciva exit 1 260148871Scperciva fi 261148871Scperciva if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then 262148871Scperciva echo -n "`basename $0`: " 263148871Scperciva echo -n "${_WORKDIR_bad}" 264148871Scperciva echo ${WORKDIR} 265148871Scperciva exit 1 266148871Scperciva fi 267148871Scperciva cd ${WORKDIR} || exit 1 268148871Scperciva 269148871Scperciva BSPATCH=/usr/bin/bspatch 270148871Scperciva SHA256=/sbin/sha256 271148871Scperciva PHTTPGET=/usr/libexec/phttpget 272148871Scperciva} 273148871Scperciva 274148871Scperciva# Perform sanity checks and set some final parameters 275148871Scperciva# in preparation for extracting or updating ${PORTSDIR} 276154088Scperciva# Complain if ${PORTSDIR} exists but is not writable, 277154088Scperciva# but don't complain if ${PORTSDIR} doesn't exist. 278148871Scpercivaextract_check_params() { 279148871Scperciva _WORKDIR_bad="Directory does not exist: " 280154088Scperciva _PORTSDIR_bad="Directory is not writable: " 281148871Scperciva 282148871Scperciva if ! [ -d "${WORKDIR}" ]; then 283148871Scperciva echo -n "`basename $0`: " 284148871Scperciva echo -n "${_WORKDIR_bad}" 285148871Scperciva echo ${WORKDIR} 286148871Scperciva exit 1 287148871Scperciva fi 288154088Scperciva if [ -d "${PORTSDIR}" ] && ! [ -w "${PORTSDIR}" ]; then 289148871Scperciva echo -n "`basename $0`: " 290148871Scperciva echo -n "${_PORTSDIR_bad}" 291148871Scperciva echo ${PORTSDIR} 292148871Scperciva exit 1 293148871Scperciva fi 294148871Scperciva 295148871Scperciva if ! [ -d "${WORKDIR}/files" -a -r "${WORKDIR}/tag" \ 296148871Scperciva -a -r "${WORKDIR}/INDEX" -a -r "${WORKDIR}/tINDEX" ]; then 297148871Scperciva echo "No snapshot available. Try running" 298148871Scperciva echo "# `basename $0` fetch" 299148871Scperciva exit 1 300148871Scperciva fi 301148871Scperciva 302148871Scperciva MKINDEX=/usr/libexec/make_index 303148871Scperciva} 304148871Scperciva 305148871Scperciva# Perform sanity checks and set some final parameters 306148871Scperciva# in preparation for updating ${PORTSDIR} 307148871Scpercivaupdate_check_params() { 308148871Scperciva extract_check_params 309148871Scperciva 310148871Scperciva if ! [ -r ${PORTSDIR}/.portsnap.INDEX ]; then 311148871Scperciva echo "${PORTSDIR} was not created by portsnap." 312148871Scperciva echo -n "You must run '`basename $0` extract' before " 313148871Scperciva echo "running '`basename $0` update'." 314148871Scperciva exit 1 315148871Scperciva fi 316148871Scperciva 317148871Scperciva} 318148871Scperciva 319148871Scperciva#### Core functionality -- the actual work gets done here 320148871Scperciva 321148871Scperciva# Use an SRV query to pick a server. If the SRV query doesn't provide 322148871Scperciva# a useful answer, use the server name specified by the user. 323148871Scperciva# Put another way... look up _http._tcp.${SERVERNAME} and pick a server 324148871Scperciva# from that; or if no servers are returned, use ${SERVERNAME}. 325148871Scperciva# This allows a user to specify "portsnap.freebsd.org" (in which case 326148871Scperciva# portsnap will select one of the mirrors) or "portsnap5.tld.freebsd.org" 327148871Scperciva# (in which case portsnap will use that particular server, since there 328148871Scperciva# won't be an SRV entry for that name). 329148871Scperciva# 330158273Scperciva# We ignore the Port field, since we are always going to use port 80. 331158273Scperciva 332158273Scperciva# Fetch the mirror list, but do not pick a mirror yet. Returns 1 if 333158273Scperciva# no mirrors are available for any reason. 334158273Scpercivafetch_pick_server_init() { 335158273Scperciva : > serverlist_tried 336158273Scperciva 337150159Scperciva# Check that host(1) exists (i.e., that the system wasn't built with the 338156813Sru# WITHOUT_BIND set) and don't try to find a mirror if it doesn't exist. 339150159Scperciva if ! which -s host; then 340158273Scperciva : > serverlist_full 341158273Scperciva return 1 342150159Scperciva fi 343150159Scperciva 344158273Scperciva echo -n "Looking up ${SERVERNAME} mirrors... " 345148871Scperciva 346148871Scperciva# Issue the SRV query and pull out the Priority, Weight, and Target fields. 347158245Scperciva# BIND 9 prints "$name has SRV record ..." while BIND 8 prints 348158245Scperciva# "$name server selection ..."; we allow either format. 349158245Scperciva MLIST="_http._tcp.${SERVERNAME}" 350158245Scperciva host -t srv "${MLIST}" | 351265753Sdelphij sed -nE "s/${MLIST} (has SRV record|server selection) //Ip" | 352158245Scperciva cut -f 1,2,4 -d ' ' | 353158273Scperciva sed -e 's/\.$//' | 354158273Scperciva sort > serverlist_full 355148871Scperciva 356148871Scperciva# If no records, give up -- we'll just use the server name we were given. 357158273Scperciva if [ `wc -l < serverlist_full` -eq 0 ]; then 358158273Scperciva echo "none found." 359158273Scperciva return 1 360158273Scperciva fi 361158273Scperciva 362158273Scperciva# Report how many mirrors we found. 363158273Scperciva echo `wc -l < serverlist_full` "mirrors found." 364158274Scperciva 365158274Scperciva# Generate a random seed for use in picking mirrors. If HTTP_PROXY 366158274Scperciva# is set, this will be used to generate the seed; otherwise, the seed 367158274Scperciva# will be random. 368158301Scperciva if [ -n "${HTTP_PROXY}${http_proxy}" ]; then 369158301Scperciva RANDVALUE=`sha256 -qs "${HTTP_PROXY}${http_proxy}" | 370158274Scperciva tr -d 'a-f' | 371158274Scperciva cut -c 1-9` 372158274Scperciva else 373158274Scperciva RANDVALUE=`jot -r 1 0 999999999` 374158274Scperciva fi 375158273Scperciva} 376158273Scperciva 377158273Scperciva# Pick a mirror. Returns 1 if we have run out of mirrors to try. 378158273Scpercivafetch_pick_server() { 379158273Scperciva# Generate a list of not-yet-tried mirrors 380158273Scperciva sort serverlist_tried | 381158273Scperciva comm -23 serverlist_full - > serverlist 382158273Scperciva 383158273Scperciva# Have we run out of mirrors? 384148871Scperciva if [ `wc -l < serverlist` -eq 0 ]; then 385158273Scperciva echo "No mirrors remaining, giving up." 386158273Scperciva return 1 387148871Scperciva fi 388148871Scperciva 389148871Scperciva# Find the highest priority level (lowest numeric value). 390148871Scperciva SRV_PRIORITY=`cut -f 1 -d ' ' serverlist | sort -n | head -1` 391148871Scperciva 392148871Scperciva# Add up the weights of the response lines at that priority level. 393148871Scperciva SRV_WSUM=0; 394148871Scperciva while read X; do 395148871Scperciva case "$X" in 396148871Scperciva ${SRV_PRIORITY}\ *) 397148871Scperciva SRV_W=`echo $X | cut -f 2 -d ' '` 398148871Scperciva SRV_WSUM=$(($SRV_WSUM + $SRV_W)) 399148871Scperciva ;; 400148871Scperciva esac 401148871Scperciva done < serverlist 402148871Scperciva 403148871Scperciva# If all the weights are 0, pretend that they are all 1 instead. 404148871Scperciva if [ ${SRV_WSUM} -eq 0 ]; then 405148871Scperciva SRV_WSUM=`grep -E "^${SRV_PRIORITY} " serverlist | wc -l` 406148871Scperciva SRV_W_ADD=1 407148871Scperciva else 408148871Scperciva SRV_W_ADD=0 409148871Scperciva fi 410148871Scperciva 411158274Scperciva# Pick a value between 0 and the sum of the weights - 1 412158274Scperciva SRV_RND=`expr ${RANDVALUE} % ${SRV_WSUM}` 413148871Scperciva 414158273Scperciva# Read through the list of mirrors and set SERVERNAME. Write the line 415158273Scperciva# corresponding to the mirror we selected into serverlist_tried so that 416158273Scperciva# we won't try it again. 417148871Scperciva while read X; do 418148871Scperciva case "$X" in 419148871Scperciva ${SRV_PRIORITY}\ *) 420148871Scperciva SRV_W=`echo $X | cut -f 2 -d ' '` 421148871Scperciva SRV_W=$(($SRV_W + $SRV_W_ADD)) 422158274Scperciva if [ $SRV_RND -lt $SRV_W ]; then 423148871Scperciva SERVERNAME=`echo $X | cut -f 3 -d ' '` 424158273Scperciva echo "$X" >> serverlist_tried 425148871Scperciva break 426148871Scperciva else 427148871Scperciva SRV_RND=$(($SRV_RND - $SRV_W)) 428148871Scperciva fi 429148871Scperciva ;; 430148871Scperciva esac 431148871Scperciva done < serverlist 432148871Scperciva} 433148871Scperciva 434148871Scperciva# Check that we have a public key with an appropriate hash, or 435158273Scperciva# fetch the key if it doesn't exist. Returns 1 if the key has 436158273Scperciva# not yet been fetched. 437148871Scpercivafetch_key() { 438148871Scperciva if [ -r pub.ssl ] && [ `${SHA256} -q pub.ssl` = ${KEYPRINT} ]; then 439158273Scperciva return 0 440148871Scperciva fi 441148871Scperciva 442158273Scperciva echo -n "Fetching public key from ${SERVERNAME}... " 443148871Scperciva rm -f pub.ssl 444148871Scperciva fetch ${QUIETFLAG} http://${SERVERNAME}/pub.ssl \ 445148871Scperciva 2>${QUIETREDIR} || true 446148871Scperciva if ! [ -r pub.ssl ]; then 447148871Scperciva echo "failed." 448148871Scperciva return 1 449148871Scperciva fi 450148871Scperciva if ! [ `${SHA256} -q pub.ssl` = ${KEYPRINT} ]; then 451148871Scperciva echo "key has incorrect hash." 452148871Scperciva rm -f pub.ssl 453148871Scperciva return 1 454148871Scperciva fi 455148871Scperciva echo "done." 456148871Scperciva} 457148871Scperciva 458148871Scperciva# Fetch a snapshot tag 459148871Scpercivafetch_tag() { 460148871Scperciva rm -f snapshot.ssl tag.new 461148871Scperciva 462158273Scperciva echo ${NDEBUG} "Fetching snapshot tag from ${SERVERNAME}... " 463158273Scperciva fetch ${QUIETFLAG} http://${SERVERNAME}/$1.ssl \ 464148871Scperciva 2>${QUIETREDIR} || true 465148871Scperciva if ! [ -r $1.ssl ]; then 466148871Scperciva echo "failed." 467148871Scperciva return 1 468148871Scperciva fi 469148871Scperciva 470148871Scperciva openssl rsautl -pubin -inkey pub.ssl -verify \ 471148871Scperciva < $1.ssl > tag.new 2>${QUIETREDIR} || true 472148871Scperciva rm $1.ssl 473148871Scperciva 474148871Scperciva if ! [ `wc -l < tag.new` = 1 ] || 475148871Scperciva ! grep -qE "^portsnap\|[0-9]{10}\|[0-9a-f]{64}" tag.new; then 476148871Scperciva echo "invalid snapshot tag." 477148871Scperciva return 1 478148871Scperciva fi 479148871Scperciva 480148871Scperciva echo "done." 481148871Scperciva 482148871Scperciva SNAPSHOTDATE=`cut -f 2 -d '|' < tag.new` 483148871Scperciva SNAPSHOTHASH=`cut -f 3 -d '|' < tag.new` 484148871Scperciva} 485148871Scperciva 486148871Scperciva# Sanity-check the date on a snapshot tag 487148871Scpercivafetch_snapshot_tagsanity() { 488148871Scperciva if [ `date "+%s"` -gt `expr ${SNAPSHOTDATE} + 31536000` ]; then 489148871Scperciva echo "Snapshot appears to be more than a year old!" 490148871Scperciva echo "(Is the system clock correct?)" 491149868Scperciva echo "Cowardly refusing to proceed any further." 492148871Scperciva return 1 493148871Scperciva fi 494148871Scperciva if [ `date "+%s"` -lt `expr ${SNAPSHOTDATE} - 86400` ]; then 495148871Scperciva echo -n "Snapshot appears to have been created more than " 496148871Scperciva echo "one day into the future!" 497148871Scperciva echo "(Is the system clock correct?)" 498148871Scperciva echo "Cowardly refusing to proceed any further." 499148871Scperciva return 1 500148871Scperciva fi 501148871Scperciva} 502148871Scperciva 503148871Scperciva# Sanity-check the date on a snapshot update tag 504148871Scpercivafetch_update_tagsanity() { 505148871Scperciva fetch_snapshot_tagsanity || return 1 506148871Scperciva 507148871Scperciva if [ ${OLDSNAPSHOTDATE} -gt ${SNAPSHOTDATE} ]; then 508148871Scperciva echo -n "Latest snapshot on server is " 509148871Scperciva echo "older than what we already have!" 510148871Scperciva echo -n "Cowardly refusing to downgrade from " 511148871Scperciva date -r ${OLDSNAPSHOTDATE} 512148879Scperciva echo "to `date -r ${SNAPSHOTDATE}`." 513148871Scperciva return 1 514148871Scperciva fi 515148871Scperciva} 516148871Scperciva 517148871Scperciva# Compare old and new tags; return 1 if update is unnecessary 518148871Scpercivafetch_update_neededp() { 519148871Scperciva if [ ${OLDSNAPSHOTDATE} -eq ${SNAPSHOTDATE} ]; then 520148871Scperciva echo -n "Latest snapshot on server matches " 521148871Scperciva echo "what we already have." 522148871Scperciva echo "No updates needed." 523148871Scperciva rm tag.new 524148871Scperciva return 1 525148871Scperciva fi 526148871Scperciva if [ ${OLDSNAPSHOTHASH} = ${SNAPSHOTHASH} ]; then 527148871Scperciva echo -n "Ports tree hasn't changed since " 528148871Scperciva echo "last snapshot." 529148871Scperciva echo "No updates needed." 530148871Scperciva rm tag.new 531148871Scperciva return 1 532148871Scperciva fi 533148871Scperciva 534148871Scperciva return 0 535148871Scperciva} 536148871Scperciva 537148871Scperciva# Fetch snapshot metadata file 538148871Scpercivafetch_metadata() { 539148871Scperciva rm -f ${SNAPSHOTHASH} tINDEX.new 540148871Scperciva 541148871Scperciva echo ${NDEBUG} "Fetching snapshot metadata... " 542226312Sjilles fetch ${QUIETFLAG} http://${SERVERNAME}/t/${SNAPSHOTHASH} \ 543148871Scperciva 2>${QUIETREDIR} || return 544226312Sjilles if [ "`${SHA256} -q ${SNAPSHOTHASH}`" != ${SNAPSHOTHASH} ]; then 545148871Scperciva echo "snapshot metadata corrupt." 546148871Scperciva return 1 547148871Scperciva fi 548148871Scperciva mv ${SNAPSHOTHASH} tINDEX.new 549148871Scperciva echo "done." 550148871Scperciva} 551148871Scperciva 552148871Scperciva# Warn user about bogus metadata 553148871Scpercivafetch_metadata_freakout() { 554148871Scperciva echo 555148871Scperciva echo "Portsnap metadata is correctly signed, but contains" 556148871Scperciva echo "at least one line which appears bogus." 557148871Scperciva echo "Cowardly refusing to proceed any further." 558148871Scperciva} 559148871Scperciva 560148871Scperciva# Sanity-check a snapshot metadata file 561148871Scpercivafetch_metadata_sanity() { 562148871Scperciva if grep -qvE "^[0-9A-Z.]+\|[0-9a-f]{64}$" tINDEX.new; then 563148871Scperciva fetch_metadata_freakout 564148871Scperciva return 1 565148871Scperciva fi 566148871Scperciva if [ `look INDEX tINDEX.new | wc -l` != 1 ]; then 567148871Scperciva echo 568148871Scperciva echo "Portsnap metadata appears bogus." 569148871Scperciva echo "Cowardly refusing to proceed any further." 570148871Scperciva return 1 571148871Scperciva fi 572148871Scperciva} 573148871Scperciva 574148871Scperciva# Take a list of ${oldhash}|${newhash} and output a list of needed patches 575148871Scpercivafetch_make_patchlist() { 576148871Scperciva grep -vE "^([0-9a-f]{64})\|\1$" | 577148871Scperciva while read LINE; do 578148871Scperciva X=`echo ${LINE} | cut -f 1 -d '|'` 579148871Scperciva Y=`echo ${LINE} | cut -f 2 -d '|'` 580148871Scperciva if [ -f "files/${Y}.gz" ]; then continue; fi 581148871Scperciva if [ ! -f "files/${X}.gz" ]; then continue; fi 582148871Scperciva echo "${LINE}" 583148871Scperciva done 584148871Scperciva} 585148871Scperciva 586148871Scperciva# Print user-friendly progress statistics 587148871Scpercivafetch_progress() { 588148871Scperciva LNC=0 589148871Scperciva while read x; do 590148871Scperciva LNC=$(($LNC + 1)) 591148871Scperciva if [ $(($LNC % 10)) = 0 ]; then 592149023Scperciva echo -n $LNC 593148871Scperciva elif [ $(($LNC % 2)) = 0 ]; then 594148871Scperciva echo -n . 595148871Scperciva fi 596148871Scperciva done 597148871Scperciva echo -n " " 598148871Scperciva} 599148871Scperciva 600148871Scperciva# Sanity-check an index file 601148871Scpercivafetch_index_sanity() { 602148871Scperciva if grep -qvE "^[-_+./@0-9A-Za-z]+\|[0-9a-f]{64}$" INDEX.new || 603148871Scperciva fgrep -q "./" INDEX.new; then 604148871Scperciva fetch_metadata_freakout 605148871Scperciva return 1 606148871Scperciva fi 607148871Scperciva} 608148871Scperciva 609148871Scperciva# Verify a list of files 610148871Scpercivafetch_snapshot_verify() { 611148871Scperciva while read F; do 612306942Sdelphij if [ "`gunzip -c < snap/${F}.gz | ${SHA256} -q`" != ${F} ]; then 613148871Scperciva echo "snapshot corrupt." 614148871Scperciva return 1 615148871Scperciva fi 616148871Scperciva done 617148871Scperciva return 0 618148871Scperciva} 619148871Scperciva 620148871Scperciva# Fetch a snapshot tarball, extract, and verify. 621148871Scpercivafetch_snapshot() { 622158273Scperciva while ! fetch_tag snapshot; do 623158273Scperciva fetch_pick_server || return 1 624158273Scperciva done 625148871Scperciva fetch_snapshot_tagsanity || return 1 626148871Scperciva fetch_metadata || return 1 627148871Scperciva fetch_metadata_sanity || return 1 628148871Scperciva 629148871Scperciva rm -rf snap/ 630148871Scperciva 631148871Scperciva# Don't ask fetch(1) to be quiet -- downloading a snapshot of ~ 35MB will 632148871Scperciva# probably take a while, so the progrees reports that fetch(1) generates 633148871Scperciva# will be useful for keeping the users' attention from drifting. 634148871Scperciva echo "Fetching snapshot generated at `date -r ${SNAPSHOTDATE}`:" 635154693Scperciva fetch -r http://${SERVERNAME}/s/${SNAPSHOTHASH}.tgz || return 1 636148871Scperciva 637148871Scperciva echo -n "Extracting snapshot... " 638216575Ssimon tar -xz --numeric-owner -f ${SNAPSHOTHASH}.tgz snap/ || return 1 639148871Scperciva rm ${SNAPSHOTHASH}.tgz 640148871Scperciva echo "done." 641148871Scperciva 642148871Scperciva echo -n "Verifying snapshot integrity... " 643148871Scperciva# Verify the metadata files 644148871Scperciva cut -f 2 -d '|' tINDEX.new | fetch_snapshot_verify || return 1 645148871Scperciva# Extract the index 646148871Scperciva rm -f INDEX.new 647306942Sdelphij gunzip -c < snap/`look INDEX tINDEX.new | 648148871Scperciva cut -f 2 -d '|'`.gz > INDEX.new 649148871Scperciva fetch_index_sanity || return 1 650148871Scperciva# Verify the snapshot contents 651148871Scperciva cut -f 2 -d '|' INDEX.new | fetch_snapshot_verify || return 1 652306942Sdelphij cut -f 2 -d '|' tINDEX.new INDEX.new | sort -u > files.expected 653306942Sdelphij find snap -mindepth 1 | sed -E 's^snap/(.*)\.gz^\1^' | sort > files.snap 654306942Sdelphij if ! cmp -s files.expected files.snap; then 655306942Sdelphij echo "unexpected files in snapshot." 656306942Sdelphij return 1 657306942Sdelphij fi 658306942Sdelphij rm files.expected files.snap 659148871Scperciva echo "done." 660148871Scperciva 661148871Scperciva# Move files into their proper locations 662148871Scperciva rm -f tag INDEX tINDEX 663148871Scperciva rm -rf files 664148871Scperciva mv tag.new tag 665148871Scperciva mv tINDEX.new tINDEX 666148871Scperciva mv INDEX.new INDEX 667148871Scperciva mv snap/ files/ 668148871Scperciva 669148871Scperciva return 0 670148871Scperciva} 671148871Scperciva 672148871Scperciva# Update a compressed snapshot 673148871Scpercivafetch_update() { 674148871Scperciva rm -f patchlist diff OLD NEW filelist INDEX.new 675148871Scperciva 676148871Scperciva OLDSNAPSHOTDATE=`cut -f 2 -d '|' < tag` 677148871Scperciva OLDSNAPSHOTHASH=`cut -f 3 -d '|' < tag` 678148871Scperciva 679158273Scperciva while ! fetch_tag latest; do 680158273Scperciva fetch_pick_server || return 1 681158273Scperciva done 682148871Scperciva fetch_update_tagsanity || return 1 683148871Scperciva fetch_update_neededp || return 0 684148871Scperciva fetch_metadata || return 1 685148871Scperciva fetch_metadata_sanity || return 1 686148871Scperciva 687148871Scperciva echo -n "Updating from `date -r ${OLDSNAPSHOTDATE}` " 688148871Scperciva echo "to `date -r ${SNAPSHOTDATE}`." 689148871Scperciva 690148871Scperciva# Generate a list of wanted metadata patches 691148871Scperciva join -t '|' -o 1.2,2.2 tINDEX tINDEX.new | 692148871Scperciva fetch_make_patchlist > patchlist 693148871Scperciva 694148871Scperciva# Attempt to fetch metadata patches 695148871Scperciva echo -n "Fetching `wc -l < patchlist | tr -d ' '` " 696148871Scperciva echo ${NDEBUG} "metadata patches.${DDSTATS}" 697148871Scperciva tr '|' '-' < patchlist | 698148871Scperciva lam -s "tp/" - -s ".gz" | 699148879Scperciva xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \ 700148871Scperciva 2>${STATSREDIR} | fetch_progress 701148871Scperciva echo "done." 702148871Scperciva 703148871Scperciva# Attempt to apply metadata patches 704148871Scperciva echo -n "Applying metadata patches... " 705148871Scperciva while read LINE; do 706148871Scperciva X=`echo ${LINE} | cut -f 1 -d '|'` 707148871Scperciva Y=`echo ${LINE} | cut -f 2 -d '|'` 708148871Scperciva if [ ! -f "${X}-${Y}.gz" ]; then continue; fi 709148871Scperciva gunzip -c < ${X}-${Y}.gz > diff 710148871Scperciva gunzip -c < files/${X}.gz > OLD 711148871Scperciva cut -c 2- diff | join -t '|' -v 2 - OLD > ptmp 712148871Scperciva grep '^\+' diff | cut -c 2- | 713148871Scperciva sort -k 1,1 -t '|' -m - ptmp > NEW 714148871Scperciva if [ `${SHA256} -q NEW` = ${Y} ]; then 715148871Scperciva mv NEW files/${Y} 716148871Scperciva gzip -n files/${Y} 717148871Scperciva fi 718148871Scperciva rm -f diff OLD NEW ${X}-${Y}.gz ptmp 719148871Scperciva done < patchlist 2>${QUIETREDIR} 720148871Scperciva echo "done." 721148871Scperciva 722148871Scperciva# Update metadata without patches 723148871Scperciva join -t '|' -v 2 tINDEX tINDEX.new | 724148871Scperciva cut -f 2 -d '|' /dev/stdin patchlist | 725148871Scperciva while read Y; do 726148871Scperciva if [ ! -f "files/${Y}.gz" ]; then 727148871Scperciva echo ${Y}; 728148871Scperciva fi 729148871Scperciva done > filelist 730148871Scperciva echo -n "Fetching `wc -l < filelist | tr -d ' '` " 731148871Scperciva echo ${NDEBUG} "metadata files... " 732148871Scperciva lam -s "f/" - -s ".gz" < filelist | 733148879Scperciva xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \ 734148871Scperciva 2>${QUIETREDIR} 735148871Scperciva 736148871Scperciva while read Y; do 737148871Scperciva if [ `gunzip -c < ${Y}.gz | ${SHA256} -q` = ${Y} ]; then 738148871Scperciva mv ${Y}.gz files/${Y}.gz 739148871Scperciva else 740148871Scperciva echo "metadata is corrupt." 741148871Scperciva return 1 742148871Scperciva fi 743148871Scperciva done < filelist 744148871Scperciva echo "done." 745148871Scperciva 746148871Scperciva# Extract the index 747306942Sdelphij gunzip -c < files/`look INDEX tINDEX.new | 748148871Scperciva cut -f 2 -d '|'`.gz > INDEX.new 749148871Scperciva fetch_index_sanity || return 1 750148871Scperciva 751149824Scperciva# If we have decided to refuse certain updates, construct a hybrid index which 752149824Scperciva# is equal to the old index for parts of the tree which we don't want to 753149824Scperciva# update, and equal to the new index for parts of the tree which gets updates. 754149824Scperciva# This means that we should always have a "complete snapshot" of the ports 755149824Scperciva# tree -- with the caveat that it isn't actually a snapshot. 756149824Scperciva if [ ! -z "${REFUSE}" ]; then 757149824Scperciva echo "Refusing to download updates for ${REFUSE}" \ 758149824Scperciva >${QUIETREDIR} 759149824Scperciva 760149824Scperciva grep -Ev "${REFUSE}" INDEX.new > INDEX.tmp 761149824Scperciva grep -E "${REFUSE}" INDEX | 762149824Scperciva sort -m -k 1,1 -t '|' - INDEX.tmp > INDEX.new 763149824Scperciva rm -f INDEX.tmp 764149824Scperciva fi 765149824Scperciva 766148871Scperciva# Generate a list of wanted ports patches 767148871Scperciva join -t '|' -o 1.2,2.2 INDEX INDEX.new | 768148871Scperciva fetch_make_patchlist > patchlist 769148871Scperciva 770148871Scperciva# Attempt to fetch ports patches 771148871Scperciva echo -n "Fetching `wc -l < patchlist | tr -d ' '` " 772148871Scperciva echo ${NDEBUG} "patches.${DDSTATS}" 773148871Scperciva tr '|' '-' < patchlist | lam -s "bp/" - | 774148879Scperciva xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \ 775148871Scperciva 2>${STATSREDIR} | fetch_progress 776148871Scperciva echo "done." 777148871Scperciva 778148871Scperciva# Attempt to apply ports patches 779148871Scperciva echo -n "Applying patches... " 780148871Scperciva while read LINE; do 781148871Scperciva X=`echo ${LINE} | cut -f 1 -d '|'` 782148871Scperciva Y=`echo ${LINE} | cut -f 2 -d '|'` 783148871Scperciva if [ ! -f "${X}-${Y}" ]; then continue; fi 784148871Scperciva gunzip -c < files/${X}.gz > OLD 785148871Scperciva ${BSPATCH} OLD NEW ${X}-${Y} 786148871Scperciva if [ `${SHA256} -q NEW` = ${Y} ]; then 787148871Scperciva mv NEW files/${Y} 788148871Scperciva gzip -n files/${Y} 789148871Scperciva fi 790148871Scperciva rm -f diff OLD NEW ${X}-${Y} 791148871Scperciva done < patchlist 2>${QUIETREDIR} 792148871Scperciva echo "done." 793148871Scperciva 794148871Scperciva# Update ports without patches 795148871Scperciva join -t '|' -v 2 INDEX INDEX.new | 796148871Scperciva cut -f 2 -d '|' /dev/stdin patchlist | 797148871Scperciva while read Y; do 798148871Scperciva if [ ! -f "files/${Y}.gz" ]; then 799148871Scperciva echo ${Y}; 800148871Scperciva fi 801148871Scperciva done > filelist 802148871Scperciva echo -n "Fetching `wc -l < filelist | tr -d ' '` " 803148871Scperciva echo ${NDEBUG} "new ports or files... " 804148871Scperciva lam -s "f/" - -s ".gz" < filelist | 805148879Scperciva xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \ 806148871Scperciva 2>${QUIETREDIR} 807148871Scperciva 808148871Scperciva while read Y; do 809148871Scperciva if [ `gunzip -c < ${Y}.gz | ${SHA256} -q` = ${Y} ]; then 810148871Scperciva mv ${Y}.gz files/${Y}.gz 811148871Scperciva else 812148871Scperciva echo "snapshot is corrupt." 813148871Scperciva return 1 814148871Scperciva fi 815148871Scperciva done < filelist 816148871Scperciva echo "done." 817148871Scperciva 818148871Scperciva# Remove files which are no longer needed 819253337Scperciva cut -f 2 -d '|' tINDEX INDEX | sort -u > oldfiles 820253337Scperciva cut -f 2 -d '|' tINDEX.new INDEX.new | sort -u | comm -13 - oldfiles | 821148871Scperciva lam -s "files/" - -s ".gz" | xargs rm -f 822148871Scperciva rm patchlist filelist oldfiles 823148871Scperciva 824148871Scperciva# We're done! 825148871Scperciva mv INDEX.new INDEX 826148871Scperciva mv tINDEX.new tINDEX 827148871Scperciva mv tag.new tag 828148871Scperciva 829148871Scperciva return 0 830148871Scperciva} 831148871Scperciva 832148871Scperciva# Do the actual work involved in "fetch" / "cron". 833148871Scpercivafetch_run() { 834158273Scperciva fetch_pick_server_init && fetch_pick_server 835148871Scperciva 836158273Scperciva while ! fetch_key; do 837158273Scperciva fetch_pick_server || return 1 838158273Scperciva done 839148871Scperciva 840148871Scperciva if ! [ -d files -a -r tag -a -r INDEX -a -r tINDEX ]; then 841148871Scperciva fetch_snapshot || return 1 842148871Scperciva fi 843148871Scperciva fetch_update || return 1 844148871Scperciva} 845148871Scperciva 846148871Scperciva# Build a ports INDEX file 847148871Scpercivaextract_make_index() { 848179073Scperciva if ! look $1 ${WORKDIR}/tINDEX > /dev/null; then 849179073Scperciva echo -n "$1 not provided by portsnap server; " 850179073Scperciva echo "$2 not being generated." 851179073Scperciva else 852306942Sdelphij gunzip -c < "${WORKDIR}/files/`look $1 ${WORKDIR}/tINDEX | 853158523Scperciva cut -f 2 -d '|'`.gz" | 854158523Scperciva cat - ${LOCALDESC} | 855158523Scperciva ${MKINDEX} /dev/stdin > ${PORTSDIR}/$2 856179073Scperciva fi 857148871Scperciva} 858148871Scperciva 859148871Scperciva# Create INDEX, INDEX-5, INDEX-6 860148871Scpercivaextract_indices() { 861148871Scperciva echo -n "Building new INDEX files... " 862179073Scperciva for PAIR in ${INDEXPAIRS}; do 863179073Scperciva INDEXFILE=`echo ${PAIR} | cut -f 1 -d '|'` 864179073Scperciva DESCRIBEFILE=`echo ${PAIR} | cut -f 2 -d '|'` 865179073Scperciva extract_make_index ${DESCRIBEFILE} ${INDEXFILE} || return 1 866179073Scperciva done 867148871Scperciva echo "done." 868148871Scperciva} 869148871Scperciva 870149824Scperciva# Create .portsnap.INDEX; if we are REFUSEing to touch certain directories, 871149824Scperciva# merge the values from any exiting .portsnap.INDEX file. 872148871Scpercivaextract_metadata() { 873149824Scperciva if [ -z "${REFUSE}" ]; then 874149984Scperciva sort ${WORKDIR}/INDEX > ${PORTSDIR}/.portsnap.INDEX 875149824Scperciva elif [ -f ${PORTSDIR}/.portsnap.INDEX ]; then 876149824Scperciva grep -E "${REFUSE}" ${PORTSDIR}/.portsnap.INDEX \ 877149824Scperciva > ${PORTSDIR}/.portsnap.INDEX.tmp 878149824Scperciva grep -vE "${REFUSE}" ${WORKDIR}/INDEX | sort | 879149824Scperciva sort -m - ${PORTSDIR}/.portsnap.INDEX.tmp \ 880149824Scperciva > ${PORTSDIR}/.portsnap.INDEX 881149824Scperciva rm -f ${PORTSDIR}/.portsnap.INDEX.tmp 882149824Scperciva else 883149824Scperciva grep -vE "${REFUSE}" ${WORKDIR}/INDEX | sort \ 884149824Scperciva > ${PORTSDIR}/.portsnap.INDEX 885149824Scperciva fi 886148871Scperciva} 887148871Scperciva 888148871Scperciva# Do the actual work involved in "extract" 889148871Scpercivaextract_run() { 890154088Scperciva mkdir -p ${PORTSDIR} || return 1 891154088Scperciva 892149824Scperciva if ! 893149824Scperciva if ! [ -z "${EXTRACTPATH}" ]; then 894149824Scperciva grep "^${EXTRACTPATH}" ${WORKDIR}/INDEX 895149824Scperciva elif ! [ -z "${REFUSE}" ]; then 896149824Scperciva grep -vE "${REFUSE}" ${WORKDIR}/INDEX 897149824Scperciva else 898149824Scperciva cat ${WORKDIR}/INDEX 899159062Scperciva fi | tr '|' ' ' | while read FILE HASH; do 900148871Scperciva echo ${PORTSDIR}/${FILE} 901148871Scperciva if ! [ -r "${WORKDIR}/files/${HASH}.gz" ]; then 902148871Scperciva echo "files/${HASH}.gz not found -- snapshot corrupt." 903148871Scperciva return 1 904148871Scperciva fi 905148871Scperciva case ${FILE} in 906148871Scperciva */) 907159062Scperciva rm -rf ${PORTSDIR}/${FILE%/} 908148871Scperciva mkdir -p ${PORTSDIR}/${FILE} 909216575Ssimon tar -xz --numeric-owner -f ${WORKDIR}/files/${HASH}.gz \ 910148871Scperciva -C ${PORTSDIR}/${FILE} 911148871Scperciva ;; 912148871Scperciva *) 913148871Scperciva rm -f ${PORTSDIR}/${FILE} 914216575Ssimon tar -xz --numeric-owner -f ${WORKDIR}/files/${HASH}.gz \ 915148871Scperciva -C ${PORTSDIR} ${FILE} 916148871Scperciva ;; 917148871Scperciva esac 918149041Scperciva done; then 919149041Scperciva return 1 920149041Scperciva fi 921148871Scperciva if [ ! -z "${EXTRACTPATH}" ]; then 922148871Scperciva return 0; 923148871Scperciva fi 924148871Scperciva 925148871Scperciva extract_metadata 926148871Scperciva extract_indices 927148871Scperciva} 928148871Scperciva 929148871Scperciva# Do the actual work involved in "update" 930148871Scpercivaupdate_run() { 931148871Scperciva if ! [ -z "${INDEXONLY}" ]; then 932148871Scperciva extract_indices >/dev/null || return 1 933148871Scperciva return 0 934148871Scperciva fi 935148871Scperciva 936148981Scperciva if sort ${WORKDIR}/INDEX | 937149042Scperciva cmp -s ${PORTSDIR}/.portsnap.INDEX -; then 938148958Scperciva echo "Ports tree is already up to date." 939148958Scperciva return 0 940148958Scperciva fi 941148958Scperciva 942149824Scperciva# If we are REFUSEing to touch certain directories, don't remove files 943149824Scperciva# from those directories (even if they are out of date) 944148871Scperciva echo -n "Removing old files and directories... " 945149824Scperciva if ! [ -z "${REFUSE}" ]; then 946149824Scperciva sort ${WORKDIR}/INDEX | 947149824Scperciva comm -23 ${PORTSDIR}/.portsnap.INDEX - | cut -f 1 -d '|' | 948149824Scperciva grep -vE "${REFUSE}" | 949158473Scperciva lam -s "${PORTSDIR}/" - | 950158473Scperciva sed -e 's|/$||' | xargs rm -rf 951149824Scperciva else 952149824Scperciva sort ${WORKDIR}/INDEX | 953149824Scperciva comm -23 ${PORTSDIR}/.portsnap.INDEX - | cut -f 1 -d '|' | 954158473Scperciva lam -s "${PORTSDIR}/" - | 955158473Scperciva sed -e 's|/$||' | xargs rm -rf 956149824Scperciva fi 957148871Scperciva echo "done." 958148871Scperciva 959148871Scperciva# Install new files 960148871Scperciva echo "Extracting new files:" 961149824Scperciva if ! 962149824Scperciva if ! [ -z "${REFUSE}" ]; then 963149824Scperciva grep -vE "${REFUSE}" ${WORKDIR}/INDEX | sort 964149824Scperciva else 965149824Scperciva sort ${WORKDIR}/INDEX 966149824Scperciva fi | 967149041Scperciva comm -13 ${PORTSDIR}/.portsnap.INDEX - | 968148871Scperciva while read LINE; do 969148871Scperciva FILE=`echo ${LINE} | cut -f 1 -d '|'` 970148871Scperciva HASH=`echo ${LINE} | cut -f 2 -d '|'` 971148871Scperciva echo ${PORTSDIR}/${FILE} 972148871Scperciva if ! [ -r "${WORKDIR}/files/${HASH}.gz" ]; then 973148871Scperciva echo "files/${HASH}.gz not found -- snapshot corrupt." 974148871Scperciva return 1 975148871Scperciva fi 976148871Scperciva case ${FILE} in 977148871Scperciva */) 978148871Scperciva mkdir -p ${PORTSDIR}/${FILE} 979216575Ssimon tar -xz --numeric-owner -f ${WORKDIR}/files/${HASH}.gz \ 980148871Scperciva -C ${PORTSDIR}/${FILE} 981148871Scperciva ;; 982148871Scperciva *) 983216575Ssimon tar -xz --numeric-owner -f ${WORKDIR}/files/${HASH}.gz \ 984148871Scperciva -C ${PORTSDIR} ${FILE} 985148871Scperciva ;; 986148871Scperciva esac 987149041Scperciva done; then 988149041Scperciva return 1 989149041Scperciva fi 990148871Scperciva 991148871Scperciva extract_metadata 992148871Scperciva extract_indices 993148871Scperciva} 994148871Scperciva 995148871Scperciva#### Main functions -- call parameter-handling and core functions 996148871Scperciva 997148871Scperciva# Using the command line, configuration file, and defaults, 998148871Scperciva# set all the parameters which are needed later. 999148871Scpercivaget_params() { 1000148871Scperciva init_params 1001148871Scperciva parse_cmdline $@ 1002148871Scperciva sanity_conffile 1003148871Scperciva default_conffile 1004148871Scperciva parse_conffile 1005148871Scperciva default_params 1006148871Scperciva} 1007148871Scperciva 1008148871Scperciva# Fetch command. Make sure that we're being called 1009148871Scperciva# interactively, then run fetch_check_params and fetch_run 1010148871Scpercivacmd_fetch() { 1011148871Scperciva if [ ! -t 0 ]; then 1012148871Scperciva echo -n "`basename $0` fetch should not " 1013148871Scperciva echo "be run non-interactively." 1014148871Scperciva echo "Run `basename $0` cron instead." 1015148871Scperciva exit 1 1016148871Scperciva fi 1017148871Scperciva fetch_check_params 1018148871Scperciva fetch_run || exit 1 1019148871Scperciva} 1020148871Scperciva 1021148871Scperciva# Cron command. Make sure the parameters are sensible; wait 1022148871Scperciva# rand(3600) seconds; then fetch updates. While fetching updates, 1023148871Scperciva# send output to a temporary file; only print that file if the 1024148871Scperciva# fetching failed. 1025148871Scpercivacmd_cron() { 1026148871Scperciva fetch_check_params 1027148871Scperciva sleep `jot -r 1 0 3600` 1028148871Scperciva 1029148871Scperciva TMPFILE=`mktemp /tmp/portsnap.XXXXXX` || exit 1 1030148871Scperciva if ! fetch_run >> ${TMPFILE}; then 1031148871Scperciva cat ${TMPFILE} 1032148871Scperciva rm ${TMPFILE} 1033148871Scperciva exit 1 1034148871Scperciva fi 1035148871Scperciva 1036148871Scperciva rm ${TMPFILE} 1037148871Scperciva} 1038148871Scperciva 1039148871Scperciva# Extract command. Make sure the parameters are sensible, 1040148871Scperciva# then extract the ports tree (or part thereof). 1041148871Scpercivacmd_extract() { 1042148871Scperciva extract_check_params 1043148871Scperciva extract_run || exit 1 1044148871Scperciva} 1045148871Scperciva 1046148871Scperciva# Update command. Make sure the parameters are sensible, 1047148871Scperciva# then update the ports tree. 1048148871Scpercivacmd_update() { 1049148871Scperciva update_check_params 1050148871Scperciva update_run || exit 1 1051148871Scperciva} 1052148871Scperciva 1053201251Scperciva# Alfred command. Run 'fetch' or 'cron' depending on 1054201251Scperciva# whether stdin is a terminal; then run 'update' or 1055201251Scperciva# 'extract' depending on whether ${PORTSDIR} exists. 1056201251Scpercivacmd_alfred() { 1057201251Scperciva if [ -t 0 ]; then 1058201251Scperciva cmd_fetch 1059201251Scperciva else 1060201251Scperciva cmd_cron 1061201251Scperciva fi 1062201251Scperciva if [ -d ${PORTSDIR} ]; then 1063201251Scperciva cmd_update 1064201251Scperciva else 1065201251Scperciva cmd_extract 1066201251Scperciva fi 1067201251Scperciva} 1068201251Scperciva 1069148871Scperciva#### Entry point 1070148871Scperciva 1071148871Scperciva# Make sure we find utilities from the base system 1072148871Scpercivaexport PATH=/sbin:/bin:/usr/sbin:/usr/bin:${PATH} 1073148871Scperciva 1074163564Scperciva# Set LC_ALL in order to avoid problems with character ranges like [A-Z]. 1075163564Scpercivaexport LC_ALL=C 1076163564Scperciva 1077148871Scpercivaget_params $@ 1078149027Scpercivafor COMMAND in ${COMMANDS}; do 1079149027Scperciva cmd_${COMMAND} 1080149027Scpercivadone 1081