blob: e014c54acb4442a34a089df5f667cb34b92b6000 [file] [log] [blame]
#!/bin/bash
# Copyright 1999-2006 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Id$
# Author: Karl Trygve Kalleberg <karltk@gentoo.org>
# Rewritten from the old, Perl-based emerge-webrsync script
# Author: Alon Bar-Lev <alon.barlev@gmail.com>
# Major rewrite from Karl's scripts.
#
# gpg key import
# KEY_ID=0x7DDAD20D
# gpg --homedir /etc/portage/gnupg --keyserver subkeys.pgp.net --recv-keys $KEY_ID
# gpg --homedir /etc/portage/gnupg --edit-key $KEY_ID trust
#
type portageq > /dev/null || exit $?
eval $(portageq envvar -v FEATURES FETCHCOMMAND GENTOO_MIRRORS \
PORTAGE_BIN_PATH PORTAGE_GPG_DIR PORTAGE_INST_UID PORTAGE_INST_GID \
PORTAGE_NICENESS PORTAGE_RSYNC_EXTRA_OPTS PORTAGE_TMPDIR PORTDIR \
http_proxy ftp_proxy)
DISTDIR="${PORTAGE_TMPDIR}/emerge-webrsync"
export http_proxy ftp_proxy
# If PORTAGE_NICENESS is overriden via the env then it will
# still pass through the portageq call and override properly.
if [ -n "${PORTAGE_NICENESS}" ]; then
renice $PORTAGE_NICENESS $$ > /dev/null
fi
source "${PORTAGE_BIN_PATH}"/isolated-functions.sh || exit 1
do_verbose=0
if hasq webrsync-gpg ${FEATURES} ; then
WEBSYNC_VERIFY_SIGNATURE=1
else
WEBSYNC_VERIFY_SIGNATURE=0
fi
if [ ${WEBSYNC_VERIFY_SIGNATURE} != 0 -a -z "${PORTAGE_GPG_DIR}" ]; then
echo "Error: Please set PORTAGE_GPG_DIR in make.conf"
exit 1
fi
get_utc_date_in_seconds() {
date -u +"%s"
}
get_date_part() {
local utc_time_in_secs="$1"
local part="$2"
if [[ ${USERLAND} == BSD ]] ; then
date -r ${utc_time_in_secs} -u +"${part}"
else
date -d @${utc_time_in_secs} -u +"${part}"
fi
}
get_utc_second_from_string() {
local s="$1"
date -d "${s:0:4}-${s:4:2}-${s:6:2}" -u +"%s"
}
get_portage_timestamp() {
local portage_current_timestamp=0
if [ -f "${PORTDIR}/metadata/timestamp.x" ]; then
portage_current_timestamp=$(cut -f 1 -d " " "${PORTDIR}/metadata/timestamp.x" )
fi
echo "${portage_current_timestamp}"
}
fetch_file() {
local URI="$1"
local FILE="$2"
local opts
if [ "${FETCHCOMMAND/wget/}" != "${FETCHCOMMAND}" ]; then
opts="--continue"
[ "${do_verbose}" == 0 ] && opts="$opts -q"
elif [ "${FETCHCOMMAND/curl/}" != "${FETCHCOMMAND}" ]; then
opts="--continue-at -"
[ "${do_verbose}" == 0 ] && opts="$opts -s -f"
else
rm -f "${FILE}"
fi
echo "Fetching file ${FILE}..."
#already set DISTDIR=
if [ "${do_verbose}" == 0 ] ; then
eval "${FETCHCOMMAND}" ${opts} > /dev/null && [ -s "${FILE}" ]
else
eval "${FETCHCOMMAND}" ${opts} && [ -s "${FILE}" ]
fi
}
check_file_digest() {
local digest="$1"
local file="$2"
local r=1
echo "Checking digest..."
if type -P md5sum > /dev/null; then
md5sum -c $digest && r=0
elif type -P md5 > /dev/null; then
[ "$(md5 -q $file)" == "$(cut -d \ -f 1 \"$digest\")" ] && r=0
else
echo "Error: Cannot check digest"
echo "No suitable md5/md5sum binaries found"
fi
return "${r}"
}
check_file_signature() {
local signature="$1"
local file="$2"
local r=1
if [ ${WEBSYNC_VERIFY_SIGNATURE} != 0 ]; then
echo "Checking signature..."
if type -p gpg > /dev/null; then
gpg --homedir "${PORTAGE_GPG_DIR}" --verify "$signature" "$file" && r=0
else
echo "Error: Cannot check signature"
echo "gpg binary not found"
fi
else
r=0
fi
return "${r}"
}
get_snapshot_timestamp() {
local file="$1"
tar --to-stdout -xf "${file}" portage/metadata/timestamp.x | cut -f 1 -d " "
}
sync_local() {
local file="$1"
echo "Syncing local tree..."
if type -P tarsync &> /dev/null; then
if [ "${do_verbose}" != 0 ] ; then
tarsync_verbose=-v
fi
if ! tarsync $tarsync_verbose -s 1 -o portage -g portage -e /distfiles -e /packages -e /local "${file}" "${PORTDIR}"; then
echo "Error: tarsync failed; tarball is corrupt? (${file})"
return 1
fi
else
echo "Note: tarsync was not found, you may consider emerge it..."
if ! tar jxf "${file}"; then
echo "Error: tar failed to extract the image. tarball is corrupt? (${file})"
rm -fr portage
return 1
fi
# Free disk space
rm -f "${file}"
# Make sure user and group file ownership is ${PORTAGE_INST_UID}:${PORTAGE_INST_GID}
chown -R ${PORTAGE_INST_UID:-0}:${PORTAGE_INST_GID:-0} portage
cd portage
rsync -av --progress --stats --delete --delete-after \
--exclude='/distfiles' --exclude='/packages' \
--exclude='/local' ${PORTAGE_RSYNC_EXTRA_OPTS} . "${PORTDIR%%/}"
cd ..
echo "Cleaning up..."
rm -fr portage
fi
if hasq metadata-transfer ${FEATURES} ; then
echo "Updating cache..."
emerge --metadata
fi
[ -x /etc/portage/bin/post_sync ] && /etc/portage/bin/post_sync
return 0
}
do_snapshot() {
local ignore_timestamp="$1"
local date="$2"
local r=1
local file="portage-${date}.tar.bz2"
local digest="${file}.md5sum"
local signature="${file}.gpgsig"
local have_files=0
local mirror
echo "Trying to retrieve ${date} snapshot..."
for mirror in ${GENTOO_MIRRORS} ; do
[ -s "${file}" -a -s "${digest}" -a -s "${signature}" ] && \
check_file_digest "${digest}" "${file}" && \
check_file_signature "${signature}" "${file}" && \
have_files=1
[ ${have_files} == 0 ] && \
fetch_file "${mirror}/snapshots/${digest}" "${digest}" && \
fetch_file "${mirror}/snapshots/${signature}" "${signature}" && \
fetch_file "${mirror}/snapshots/${file}" "${file}" && \
check_file_digest "${digest}" "${file}" && \
check_file_signature "${signature}" "${file}" && \
have_files=1
#
# If timestamp is invalid
# we want to try and retieve
# from a different mirror
#
if [ ${have_files} != 0 ]; then
echo "Getting snapshot timetasmp..."
local snapshot_timestamp=$(get_snapshot_timestamp "${file}")
if [ ${ignore_timestamp} == 0 ]; then
if [ ${snapshot_timestamp} -lt $(get_portage_timestamp) ]; then
echo "Warning: Portage is newer than snapshot"
have_files=0
fi
else
local utc_seconds=$(get_utc_second_from_string "${date}")
#
# Check that this snapshot
# is what it claims to be...
#
if [ ${snapshot_timestamp} -lt ${utc_seconds} ] || \
[ ${snapshot_timestamp} -gt $((${utc_seconds}+ 2*86400)) ]; then
echo "Warning: Snapshot timestamp is not in acceptable period."
have_files=0
fi
fi
fi
if [ ${have_files} != 0 ]; then
break;
else
#
# Remove files and use
# a diffeernt mirror
#
rm -f "${file}" "${digest}" "${signature}"
fi
done
if [ ${have_files} != 0 ]; then
sync_local "${file}" && r=0
else
echo "Warning: ${date} snapshot was not found."
fi
rm -f "${file}" "${digest}" "${signature}"
return "${r}"
}
do_latest_snapshot() {
local attempts=-1
local r=1
echo "Fetching most recent snapshot..."
while (( ${attempts} < 40 )) ; do
local day
local month
local year
local seconds
attempts=$(( ${attempts} + 1 ))
utc_attempt=$(expr $(get_utc_date_in_seconds) - 86400 \* ${attempts})
day=$(get_date_part ${utc_attempt} "%d")
month=$(get_date_part ${utc_attempt} "%m")
year=$(get_date_part ${utc_attempt} "%Y")
utc_midnight=$(get_date_part $(expr ${utc_attempt} - ${utc_attempt} % 86400) "%s")
if [ ${utc_midnight} -lt $(($(get_portage_timestamp)-86400)) ]; then
echo "Note: Portage content is newer than available snapshots"
echo "use --revert option to overide."
r=0
break;
fi
if do_snapshot 0 "${year}${month}${day}"; then
r=0
break;
fi
done
return "${r}"
}
main() {
local arg
local do_revert=0
local revert_date
[ ! -d "${DISTDIR}" ] && mkdir -p "${DISTDIR}"
cd "${DISTDIR}"
for arg in $*; do
local v=${arg#*=}
case ${arg} in
--help)
echo "usage: $0 [options]"
echo " --verbose (-v) - verbose"
echo " --revert=yyyymmdd - revert to snapshot"
exit 0
;;
--verbose|-v)
do_verbose=1
;;
--revert=*)
do_revert=1
revert_date=${v}
;;
*)
echo "Error: Invalid arguments"
exit 1
;;
esac
done
if [ ${do_revert} != 0 ]; then
do_snapshot 1 "${revert_date}"
else
do_latest_snapshot
fi
}
main $*