Index: head/usr.sbin/portsnap/portsnap/portsnap.8 =================================================================== --- head/usr.sbin/portsnap/portsnap/portsnap.8 (revision 149026) +++ head/usr.sbin/portsnap/portsnap/portsnap.8 (revision 149027) @@ -1,208 +1,208 @@ \.\"- .\" Copyright 2004-2005 Colin Percival .\" All rights reserved .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted providing that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, .\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING .\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd January 30, 2005 .Dt PORTSNAP 8 .Os FreeBSD .Sh NAME .Nm portsnap .Nd fetch and extract compressed snapshots of the ports tree .Sh SYNOPSIS .Nm .Op Fl I .Op Fl d Ar workdir .Op Fl f Ar conffile .Op Fl k Ar KEY .Op Fl p Ar portsdir .Op Fl s Ar server -.Cm command +.Cm command ... .Op Ar path .Sh DESCRIPTION The .Nm tool is used to fetch and update compressed snapshots of the FreeBSD ports tree, and extract and update an uncompressed ports tree. .Sh OPTIONS The following options are supported: .Bl -tag -width "-f conffile" .It Fl d Ar workdir Store working files (e.g. downloaded updates) in .Ar workdir . (default: .Pa /var/db/portsnap , or as given in the configuration file.) .It Fl f Ar conffile Read the configuration from from .Ar conffile . (default: .Pa /etc/portsnap.conf ) .It Fl I For the .Cm update command, update INDEX files, but not the rest of the ports tree. .It Fl k Ar KEY Expect a public key with given SHA256 hash. (default: read value from configuration file.) .It Fl p Ar portsdir When extracting or updating an uncompressed snapshot, operate on the directory .Ar portsdir . (default: .Pa /usr/ports/ , or as given in the configuration file.) .It Fl s Ar server Fetch files from the specified server or server pool. (default: portsnap.FreeBSD.org , or as given in the configuration file.) .It path For .Cm extract command only, operate only on parts of the ports tree starting with .Ar path . (e.g. .Nm .cm extract .Ar sysutils/port would extract sysutils/portsman, sysutils/portsnap, sysutils/portupgrade, etc.) .El .Sh COMMANDS The .Cm command can be any one of the following: .Pp .Bl -tag -width "-f conffile" .It fetch Fetch a compressed snapshot of the ports tree, or update the existing snapshot. This command should only be used interactively; for non-interactive use, you should use the .Cm cron command. .It cron Sleep a random amount of time, then operate as if the .Cm fetch command was specified. As the name suggests, this command is designed for running from .Xr cron 8 ; the random delay serves to minimize the probability that a large number of machines will simultaneously attempt to fetch updates. .It extract Extract a ports tree, replacing existing files and directories. NOTE: This will remove anything occupying the location where files or directories are being extracted; in particular, any changes made locally to the ports tree (for example, adding new patches) will be silently obliterated. .Pp Only run this command to initialize your portsnap-maintained ports tree for the first time, if you wish to start over with a clean, completely unmodified tree, or if you wish to extract a specific part of the tree (using the .Ar path option). .It update Update a ports tree extracted using the .Cm extract command. You must run this command to apply changes to your ports tree after downloading updates via the .Cm fetch or .Cm cron commands. Again, note that in the parts of the ports tree which are being updated, any local changes or additions will be removed. .El .Sh TIPS .Bl -bullet .It If your clock is set to local time, adding the line .Pp .Dl 0 3 * * * root /usr/sbin/portsnap cron .Pp to /etc/crontab is a good way to make sure you always have an up-to-date snapshot of the ports tree available which can quickly be extracted into .Pa /usr/ports . If your clock is set to UTC, please pick a random time other than 3AM, to avoid overly imposing an uneven load on the server(s) hosting the snapshots. .It Running .Nm .Cm update from .Xr cron 8 is a bad idea -- if you're ever installing or updating a port at the time the cron job runs, you'll probably end up in a mess when .Cm updates or removes files which are being used by the port build. However, running .Nm .Fl I .Cm update is probably safe, and can be used together with .Xr portversion 1 to identify installed software which is out of date. .It If you wish to use .Nm to keep a large number of machines up to date, you may wish to set up a caching HTTP proxy. Since .Nm uses .Xr fetch 1 to download updates, setting the .Ev HTTP_PROXY environment variable will direct it to fetch updates from the given proxy. This is much more efficient than .Em mirroring the files on the portsnap server, since the vast majority of files are not needed by any particular client. .El .Sh FILES .Bl -tag -width "/etc/portsnap.conf" .It /etc/portsnap.conf Default location of the portsnap configuration file. .It /var/db/portsnap Default location where compressed snapshots are stored. .It /usr/ports Default location where the ports tree is extracted. .El .Sh SEE ALSO .Xr fetch 1 .Xr fetch 3 .Xr portsnap.conf 5 .Xr sha256 8 .Sh AUTHORS .An Colin Percival Aq cperciva@FreeBSD.org Index: head/usr.sbin/portsnap/portsnap/portsnap.sh =================================================================== --- head/usr.sbin/portsnap/portsnap/portsnap.sh (revision 149026) +++ head/usr.sbin/portsnap/portsnap/portsnap.sh (revision 149027) @@ -1,909 +1,913 @@ #!/bin/sh #- # Copyright 2004-2005 Colin Percival # All rights reserved # # Redistribution and use in source and binary forms, with or without # modification, are permitted providing that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # $FreeBSD$ #### Usage function -- called from command-line handling code. # Usage instructions. Options not listed: # --debug -- don't filter output from utilities # --no-stats -- don't show progress statistics while fetching files usage() { cat < serverlist # If no records, give up -- we'll just use the server name we were given. if [ `wc -l < serverlist` -eq 0 ]; then echo " none found." return fi # Find the highest priority level (lowest numeric value). SRV_PRIORITY=`cut -f 1 -d ' ' serverlist | sort -n | head -1` # Add up the weights of the response lines at that priority level. SRV_WSUM=0; while read X; do case "$X" in ${SRV_PRIORITY}\ *) SRV_W=`echo $X | cut -f 2 -d ' '` SRV_WSUM=$(($SRV_WSUM + $SRV_W)) ;; esac done < serverlist # If all the weights are 0, pretend that they are all 1 instead. if [ ${SRV_WSUM} -eq 0 ]; then SRV_WSUM=`grep -E "^${SRV_PRIORITY} " serverlist | wc -l` SRV_W_ADD=1 else SRV_W_ADD=0 fi # Pick a random value between 1 and the sum of the weights SRV_RND=`jot -r 1 1 ${SRV_WSUM}` # Read through the list of mirrors and set SERVERNAME while read X; do case "$X" in ${SRV_PRIORITY}\ *) SRV_W=`echo $X | cut -f 2 -d ' '` SRV_W=$(($SRV_W + $SRV_W_ADD)) if [ $SRV_RND -le $SRV_W ]; then SERVERNAME=`echo $X | cut -f 3 -d ' '` break else SRV_RND=$(($SRV_RND - $SRV_W)) fi ;; esac done < serverlist echo " using ${SERVERNAME}" } # Check that we have a public key with an appropriate hash, or # fetch the key if it doesn't exist. fetch_key() { if [ -r pub.ssl ] && [ `${SHA256} -q pub.ssl` = ${KEYPRINT} ]; then return fi echo -n "Fetching public key... " rm -f pub.ssl fetch ${QUIETFLAG} http://${SERVERNAME}/pub.ssl \ 2>${QUIETREDIR} || true if ! [ -r pub.ssl ]; then echo "failed." return 1 fi if ! [ `${SHA256} -q pub.ssl` = ${KEYPRINT} ]; then echo "key has incorrect hash." rm -f pub.ssl return 1 fi echo "done." } # Fetch a snapshot tag fetch_tag() { rm -f snapshot.ssl tag.new echo ${NDEBUG} "Fetching snapshot tag... " fetch ${QUIETFLAG} http://${SERVERNAME}/$1.ssl 2>${QUIETREDIR} || true if ! [ -r $1.ssl ]; then echo "failed." return 1 fi openssl rsautl -pubin -inkey pub.ssl -verify \ < $1.ssl > tag.new 2>${QUIETREDIR} || true rm $1.ssl if ! [ `wc -l < tag.new` = 1 ] || ! grep -qE "^portsnap\|[0-9]{10}\|[0-9a-f]{64}" tag.new; then echo "invalid snapshot tag." return 1 fi echo "done." SNAPSHOTDATE=`cut -f 2 -d '|' < tag.new` SNAPSHOTHASH=`cut -f 3 -d '|' < tag.new` } # Sanity-check the date on a snapshot tag fetch_snapshot_tagsanity() { if [ `date "+%s"` -gt `expr ${SNAPSHOTDATE} + 31536000` ]; then echo "Snapshot appears to be more than a year old!" echo "(Is the system clock correct?)" echo "Cowarly refusing to proceed any further." return 1 fi if [ `date "+%s"` -lt `expr ${SNAPSHOTDATE} - 86400` ]; then echo -n "Snapshot appears to have been created more than " echo "one day into the future!" echo "(Is the system clock correct?)" echo "Cowardly refusing to proceed any further." return 1 fi } # Sanity-check the date on a snapshot update tag fetch_update_tagsanity() { fetch_snapshot_tagsanity || return 1 if [ ${OLDSNAPSHOTDATE} -gt ${SNAPSHOTDATE} ]; then echo -n "Latest snapshot on server is " echo "older than what we already have!" echo -n "Cowardly refusing to downgrade from " date -r ${OLDSNAPSHOTDATE} echo "to `date -r ${SNAPSHOTDATE}`." return 1 fi } # Compare old and new tags; return 1 if update is unnecessary fetch_update_neededp() { if [ ${OLDSNAPSHOTDATE} -eq ${SNAPSHOTDATE} ]; then echo -n "Latest snapshot on server matches " echo "what we already have." echo "No updates needed." rm tag.new return 1 fi if [ ${OLDSNAPSHOTHASH} = ${SNAPSHOTHASH} ]; then echo -n "Ports tree hasn't changed since " echo "last snapshot." echo "No updates needed." rm tag.new return 1 fi return 0 } # Fetch snapshot metadata file fetch_metadata() { rm -f ${SNAPSHOTHASH} tINDEX.new echo ${NDEBUG} "Fetching snapshot metadata... " fetch ${QUIETFLAG} http://${SERVERNAME}/t/${SNAPSHOTHASH} 2>${QUIETREDIR} || return if [ `${SHA256} -q ${SNAPSHOTHASH}` != ${SNAPSHOTHASH} ]; then echo "snapshot metadata corrupt." return 1 fi mv ${SNAPSHOTHASH} tINDEX.new echo "done." } # Warn user about bogus metadata fetch_metadata_freakout() { echo echo "Portsnap metadata is correctly signed, but contains" echo "at least one line which appears bogus." echo "Cowardly refusing to proceed any further." } # Sanity-check a snapshot metadata file fetch_metadata_sanity() { if grep -qvE "^[0-9A-Z.]+\|[0-9a-f]{64}$" tINDEX.new; then fetch_metadata_freakout return 1 fi if [ `look INDEX tINDEX.new | wc -l` != 1 ]; then echo echo "Portsnap metadata appears bogus." echo "Cowardly refusing to proceed any further." return 1 fi } # Take a list of ${oldhash}|${newhash} and output a list of needed patches fetch_make_patchlist() { grep -vE "^([0-9a-f]{64})\|\1$" | while read LINE; do X=`echo ${LINE} | cut -f 1 -d '|'` Y=`echo ${LINE} | cut -f 2 -d '|'` if [ -f "files/${Y}.gz" ]; then continue; fi if [ ! -f "files/${X}.gz" ]; then continue; fi echo "${LINE}" done } # Print user-friendly progress statistics fetch_progress() { LNC=0 while read x; do LNC=$(($LNC + 1)) if [ $(($LNC % 10)) = 0 ]; then echo -n $LNC elif [ $(($LNC % 2)) = 0 ]; then echo -n . fi done echo -n " " } # Sanity-check an index file fetch_index_sanity() { if grep -qvE "^[-_+./@0-9A-Za-z]+\|[0-9a-f]{64}$" INDEX.new || fgrep -q "./" INDEX.new; then fetch_metadata_freakout return 1 fi } # Verify a list of files fetch_snapshot_verify() { while read F; do if [ `gunzip -c snap/${F} | ${SHA256} -q` != ${F} ]; then echo "snapshot corrupt." return 1 fi done return 0 } # Fetch a snapshot tarball, extract, and verify. fetch_snapshot() { fetch_tag snapshot || return 1 fetch_snapshot_tagsanity || return 1 fetch_metadata || return 1 fetch_metadata_sanity || return 1 rm -f ${SNAPSHOTHASH}.tgz rm -rf snap/ # Don't ask fetch(1) to be quiet -- downloading a snapshot of ~ 35MB will # probably take a while, so the progrees reports that fetch(1) generates # will be useful for keeping the users' attention from drifting. echo "Fetching snapshot generated at `date -r ${SNAPSHOTDATE}`:" fetch http://${SERVERNAME}/s/${SNAPSHOTHASH}.tgz || return 1 echo -n "Extracting snapshot... " tar -xzf ${SNAPSHOTHASH}.tgz snap/ || return 1 rm ${SNAPSHOTHASH}.tgz echo "done." echo -n "Verifying snapshot integrity... " # Verify the metadata files cut -f 2 -d '|' tINDEX.new | fetch_snapshot_verify || return 1 # Extract the index rm -f INDEX.new gunzip -c snap/`look INDEX tINDEX.new | cut -f 2 -d '|'`.gz > INDEX.new fetch_index_sanity || return 1 # Verify the snapshot contents cut -f 2 -d '|' INDEX.new | fetch_snapshot_verify || return 1 echo "done." # Move files into their proper locations rm -f tag INDEX tINDEX rm -rf files mv tag.new tag mv tINDEX.new tINDEX mv INDEX.new INDEX mv snap/ files/ return 0 } # Update a compressed snapshot fetch_update() { rm -f patchlist diff OLD NEW filelist INDEX.new OLDSNAPSHOTDATE=`cut -f 2 -d '|' < tag` OLDSNAPSHOTHASH=`cut -f 3 -d '|' < tag` fetch_tag latest || return 1 fetch_update_tagsanity || return 1 fetch_update_neededp || return 0 fetch_metadata || return 1 fetch_metadata_sanity || return 1 echo -n "Updating from `date -r ${OLDSNAPSHOTDATE}` " echo "to `date -r ${SNAPSHOTDATE}`." # Generate a list of wanted metadata patches join -t '|' -o 1.2,2.2 tINDEX tINDEX.new | fetch_make_patchlist > patchlist # Attempt to fetch metadata patches echo -n "Fetching `wc -l < patchlist | tr -d ' '` " echo ${NDEBUG} "metadata patches.${DDSTATS}" tr '|' '-' < patchlist | lam -s "tp/" - -s ".gz" | xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \ 2>${STATSREDIR} | fetch_progress echo "done." # Attempt to apply metadata patches echo -n "Applying metadata patches... " while read LINE; do X=`echo ${LINE} | cut -f 1 -d '|'` Y=`echo ${LINE} | cut -f 2 -d '|'` if [ ! -f "${X}-${Y}.gz" ]; then continue; fi gunzip -c < ${X}-${Y}.gz > diff gunzip -c < files/${X}.gz > OLD cut -c 2- diff | join -t '|' -v 2 - OLD > ptmp grep '^\+' diff | cut -c 2- | sort -k 1,1 -t '|' -m - ptmp > NEW if [ `${SHA256} -q NEW` = ${Y} ]; then mv NEW files/${Y} gzip -n files/${Y} fi rm -f diff OLD NEW ${X}-${Y}.gz ptmp done < patchlist 2>${QUIETREDIR} echo "done." # Update metadata without patches join -t '|' -v 2 tINDEX tINDEX.new | cut -f 2 -d '|' /dev/stdin patchlist | while read Y; do if [ ! -f "files/${Y}.gz" ]; then echo ${Y}; fi done > filelist echo -n "Fetching `wc -l < filelist | tr -d ' '` " echo ${NDEBUG} "metadata files... " lam -s "f/" - -s ".gz" < filelist | xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \ 2>${QUIETREDIR} while read Y; do if [ `gunzip -c < ${Y}.gz | ${SHA256} -q` = ${Y} ]; then mv ${Y}.gz files/${Y}.gz else echo "metadata is corrupt." return 1 fi done < filelist echo "done." # Extract the index gunzip -c files/`look INDEX tINDEX.new | cut -f 2 -d '|'`.gz > INDEX.new fetch_index_sanity || return 1 # Generate a list of wanted ports patches join -t '|' -o 1.2,2.2 INDEX INDEX.new | fetch_make_patchlist > patchlist # Attempt to fetch ports patches echo -n "Fetching `wc -l < patchlist | tr -d ' '` " echo ${NDEBUG} "patches.${DDSTATS}" tr '|' '-' < patchlist | lam -s "bp/" - | xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \ 2>${STATSREDIR} | fetch_progress echo "done." # Attempt to apply ports patches echo -n "Applying patches... " while read LINE; do X=`echo ${LINE} | cut -f 1 -d '|'` Y=`echo ${LINE} | cut -f 2 -d '|'` if [ ! -f "${X}-${Y}" ]; then continue; fi gunzip -c < files/${X}.gz > OLD ${BSPATCH} OLD NEW ${X}-${Y} if [ `${SHA256} -q NEW` = ${Y} ]; then mv NEW files/${Y} gzip -n files/${Y} fi rm -f diff OLD NEW ${X}-${Y} done < patchlist 2>${QUIETREDIR} echo "done." # Update ports without patches join -t '|' -v 2 INDEX INDEX.new | cut -f 2 -d '|' /dev/stdin patchlist | while read Y; do if [ ! -f "files/${Y}.gz" ]; then echo ${Y}; fi done > filelist echo -n "Fetching `wc -l < filelist | tr -d ' '` " echo ${NDEBUG} "new ports or files... " lam -s "f/" - -s ".gz" < filelist | xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \ 2>${QUIETREDIR} while read Y; do if [ `gunzip -c < ${Y}.gz | ${SHA256} -q` = ${Y} ]; then mv ${Y}.gz files/${Y}.gz else echo "snapshot is corrupt." return 1 fi done < filelist echo "done." # Remove files which are no longer needed cut -f 2 -d '|' tINDEX INDEX | sort > oldfiles cut -f 2 -d '|' tINDEX.new INDEX.new | sort | comm -13 - oldfiles | lam -s "files/" - -s ".gz" | xargs rm -f rm patchlist filelist oldfiles # We're done! mv INDEX.new INDEX mv tINDEX.new tINDEX mv tag.new tag return 0 } # Do the actual work involved in "fetch" / "cron". fetch_run() { fetch_pick_server fetch_key || return 1 if ! [ -d files -a -r tag -a -r INDEX -a -r tINDEX ]; then fetch_snapshot || return 1 fi fetch_update || return 1 } # Build a ports INDEX file extract_make_index() { gunzip -c "${WORKDIR}/files/`look $1 ${WORKDIR}/tINDEX | cut -f 2 -d '|'`.gz" | ${MKINDEX} /dev/stdin > ${PORTSDIR}/$2 } # Create INDEX, INDEX-5, INDEX-6 extract_indices() { echo -n "Building new INDEX files... " extract_make_index DESCRIBE.4 INDEX || return 1 extract_make_index DESCRIBE.5 INDEX-5 || return 1 extract_make_index DESCRIBE.6 INDEX-6 || return 1 echo "done." } # Create .portsnap.INDEX extract_metadata() { sort ${WORKDIR}/INDEX > ${PORTSDIR}/.portsnap.INDEX } # Do the actual work involved in "extract" extract_run() { grep "^${EXTRACTPATH}" ${WORKDIR}/INDEX | while read LINE; do FILE=`echo ${LINE} | cut -f 1 -d '|'` HASH=`echo ${LINE} | cut -f 2 -d '|'` echo ${PORTSDIR}/${FILE} if ! [ -r "${WORKDIR}/files/${HASH}.gz" ]; then echo "files/${HASH}.gz not found -- snapshot corrupt." return 1 fi case ${FILE} in */) rm -rf ${PORTSDIR}/${FILE} mkdir -p ${PORTSDIR}/${FILE} tar -xzf ${WORKDIR}/files/${HASH}.gz \ -C ${PORTSDIR}/${FILE} ;; *) rm -f ${PORTSDIR}/${FILE} tar -xzf ${WORKDIR}/files/${HASH}.gz \ -C ${PORTSDIR} ${FILE} ;; esac done if [ ! -z "${EXTRACTPATH}" ]; then return 0; fi extract_metadata extract_indices } # Do the actual work involved in "update" update_run() { if ! [ -z "${INDEXONLY}" ]; then extract_indices >/dev/null || return 1 return 0 fi if sort ${WORKDIR}/INDEX | cmp ${PORTSDIR}/.portsnap.INDEX - >/dev/null; then echo "Ports tree is already up to date." return 0 fi echo -n "Removing old files and directories... " sort ${WORKDIR}/INDEX | comm -23 ${PORTSDIR}/.portsnap.INDEX - | cut -f 1 -d '|' | lam -s "${PORTSDIR}/" - | xargs rm -rf echo "done." # Install new files echo "Extracting new files:" sort ${WORKDIR}/INDEX | comm -13 ${PORTSDIR}/.portsnap.INDEX - | while read LINE; do FILE=`echo ${LINE} | cut -f 1 -d '|'` HASH=`echo ${LINE} | cut -f 2 -d '|'` echo ${PORTSDIR}/${FILE} if ! [ -r "${WORKDIR}/files/${HASH}.gz" ]; then echo "files/${HASH}.gz not found -- snapshot corrupt." return 1 fi case ${FILE} in */) mkdir -p ${PORTSDIR}/${FILE} tar -xzf ${WORKDIR}/files/${HASH}.gz \ -C ${PORTSDIR}/${FILE} ;; *) tar -xzf ${WORKDIR}/files/${HASH}.gz \ -C ${PORTSDIR} ${FILE} ;; esac done extract_metadata extract_indices } #### Main functions -- call parameter-handling and core functions # Using the command line, configuration file, and defaults, # set all the parameters which are needed later. get_params() { init_params parse_cmdline $@ sanity_conffile default_conffile parse_conffile default_params } # Fetch command. Make sure that we're being called # interactively, then run fetch_check_params and fetch_run cmd_fetch() { if [ ! -t 0 ]; then echo -n "`basename $0` fetch should not " echo "be run non-interactively." echo "Run `basename $0` cron instead." exit 1 fi fetch_check_params fetch_run || exit 1 } # Cron command. Make sure the parameters are sensible; wait # rand(3600) seconds; then fetch updates. While fetching updates, # send output to a temporary file; only print that file if the # fetching failed. cmd_cron() { fetch_check_params sleep `jot -r 1 0 3600` TMPFILE=`mktemp /tmp/portsnap.XXXXXX` || exit 1 if ! fetch_run >> ${TMPFILE}; then cat ${TMPFILE} rm ${TMPFILE} exit 1 fi rm ${TMPFILE} } # Extract command. Make sure the parameters are sensible, # then extract the ports tree (or part thereof). cmd_extract() { extract_check_params extract_run || exit 1 } # Update command. Make sure the parameters are sensible, # then update the ports tree. cmd_update() { update_check_params update_run || exit 1 } #### Entry point # Make sure we find utilities from the base system export PATH=/sbin:/bin:/usr/sbin:/usr/bin:${PATH} get_params $@ -cmd_${COMMAND} +for COMMAND in ${COMMANDS}; do + cmd_${COMMAND} +done