X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;ds=sidebyside;f=update-smart-drivedb.in;h=4b23c7f05bbfe8df938cdcb9acd5cb7fd21999f4;hb=HEAD;hp=ca728e170820abe70e27f4ec56fab2d8c02c38cf;hpb=4d561bdbb71727621a1890b24b1ec50e21da1fe9;p=mirror_smartmontools-debian.git diff --git a/update-smart-drivedb.in b/update-smart-drivedb.in index ca728e1..4b23c7f 100644 --- a/update-smart-drivedb.in +++ b/update-smart-drivedb.in @@ -2,22 +2,19 @@ # # smartmontools drive database update script # -# Copyright (C) 2010-11 Christian Franke +# Home page of code is: http://www.smartmontools.org # -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. +# Copyright (C) 2010-18 Christian Franke # -# You should have received a copy of the GNU General Public License -# (for example COPYING); If not, see . +# SPDX-License-Identifier: GPL-2.0-or-later # -# $Id: update-smart-drivedb.in 3294 2011-03-16 21:36:58Z chrfranke $ +# $Id: update-smart-drivedb.in 4879 2018-12-28 22:05:12Z chrfranke $ # set -e # Set by config.status +@ENABLE_SCRIPTPATH_TRUE@export PATH="@scriptpath@" PACKAGE="@PACKAGE@" VERSION="@VERSION@" prefix="@prefix@" @@ -34,117 +31,521 @@ os_dltools="@os_dltools@" BRANCH="@DRIVEDB_BRANCH@" # Default drivedb location -DEST="$drivedbdir/drivedb.h" +DRIVEDB="$drivedbdir/drivedb.h" + +# GnuPG used to verify signature (disabled if empty) +GPG="@gnupg@" # Smartctl used for syntax check SMARTCTL="$sbindir/smartctl" -# Trac repository browser (does not return HTTP 404 errors) -#SRCEXPR='http://sourceforge.net/apps/trac/smartmontools/export/HEAD/$location/smartmontools/drivedb.h' - -# ViewVC repository browser -SRCEXPR='http://smartmontools.svn.sourceforge.net/viewvc/smartmontools/$location/smartmontools/drivedb.h?revision=HEAD' - +# PATH information for help and error messages +@ENABLE_SCRIPTPATH_FALSE@pathinfo='$PATH' +@ENABLE_SCRIPTPATH_TRUE@pathinfo="'$PATH'" -# Parse options -q="-q " -case "$1" in - -v) q=; shift ;; -esac +myname=$0 -case "$*" in - -*|*\ *) - cat <&2 + exit 1 +} + +err_notfound() +{ + case $1 in + */*) error "$1: not found $2" ;; + *) error "$1: not found in $pathinfo $2" ;; + esac +} + +warning() +{ + echo "$myname: (Warning) $*" >&2 +} -# Abort if 'which' is not available -which which >/dev/null || exit 1 - -# Find download tool -DOWNLOAD= -for t in $os_dltools; do - if which $t >/dev/null 2>/dev/null; then - case $t in - curl) DOWNLOAD="curl ${q:+-s }"'-f -o "$DEST.new" "$SRC"' ;; - lynx) DOWNLOAD='lynx -source "$SRC" >"$DEST.new"' ;; - wget) DOWNLOAD="wget $q"'-O "$DEST.new" "$SRC"' ;; - fetch) DOWNLOAD='fetch -o "$DEST.new" "$SRC"' ;; # FreeBSD - ftp) DOWNLOAD='ftp -o "$DEST.new" "$SRC"' ;; # OpenBSD - esac +selecturl() +{ + case $1 in + github) # https://github.com/smartmontools/smartmontools/raw/origin/$BRANCH/smartmontools/drivedb.h + # https://github.com/smartmontools/smartmontools/raw/master/smartmontools/drivedb.h + # redirected to: + url='https://raw.githubusercontent.com/smartmontools/smartmontools/master/smartmontools/drivedb.h' ;; + sf) url='https://sourceforge.net/p/smartmontools/code/HEAD/tree/trunk/smartmontools/drivedb.h?format=raw' ;; + svn) url='https://svn.code.sf.net/p/smartmontools/code/trunk/smartmontools/drivedb.h' ;; + svni) url='http://svn.code.sf.net/p/smartmontools/code/trunk/smartmontools/drivedb.h' ;; + trac) url='https://www.smartmontools.org/export/HEAD/trunk/smartmontools/drivedb.h' ;; + *) usage ;; + esac +} + +inpath() +{ + local d rc save + rc=1 + save=$IFS + IFS=':' + for d in $PATH; do + test -f "$d/$1" || continue + test -x "$d/$1" || continue + rc=0 break + done + IFS=$save + return $rc +} + +vecho() +{ + test -n "$q" || echo "$*" +} + +# vrun COMMAND ARGS... +vrun() +{ + if [ -n "$dryrun" ]; then + echo "$*" + elif [ -n "$q" ]; then + "$@" 2>/dev/null + else + echo "$*" + "$@" fi -done -if [ -z "$DOWNLOAD" ]; then - echo "$0: found none of: $os_dltools" >&2; exit 1 -fi +} -# Try possible branch first, then trunk -for location in "branches/$BRANCH" "trunk"; do - test -n "$q" || echo "Download from $location" +# vrun2 OUTFILE COMMAND ARGS... +vrun2() +{ + local f err rc + f=$1; shift + rc=0 + if [ -n "$dryrun" ]; then + echo "$* > $f" + else + vecho "$* > $f" + err=`"$@" 2>&1 > $f` || rc=$? + if [ -n "$err" ]; then + vecho "$err" >&2 + test $rc != 0 || rc=42 + fi + fi + return $rc +} - errmsg= - rm -f "$DEST.new" - SRC="`eval echo "$SRCEXPR"`" +# download URL FILE +download() +{ + local f u rc + u=$1; f=$2 + rc=0 + + case $tool in + curl) + vrun curl ${q:+-s} -f --max-redirs 0 \ + ${cacert:+--cacert "$cacert"} \ + ${capath:+--capath "$capath"} \ + ${insecure:+--insecure} \ + -o "$f" "$u" || rc=$? + ;; + + wget) + vrun wget $q --max-redirect=0 \ + ${cacert:+--ca-certificate="$cacert"} \ + ${capath:+--ca-directory="$capath"} \ + ${insecure:+--no-check-certificate} \ + -O "$f" "$u" || rc=$? + ;; + + lynx) + test -z "$cacert" || vrun export SSL_CERT_FILE="$cacert" + test -z "$capath" || vrun export SSL_CERT_DIR="$capath" + # Check also stderr as lynx does not return != 0 on HTTP error + vrun2 "$f" lynx -stderr -noredir -source "$u" || rc=$? + ;; + + svn) + vrun svn $q export \ + --non-interactive --no-auth-cache \ + ${cacert:+--config-option "servers:global:ssl-trust-default-ca=no"} \ + ${cacert:+--config-option "servers:global:ssl-authority-files=$cacert"} \ + ${insecure:+--trust-server-cert} \ + "$u" "$f" || rc=$? + ;; + + fetch) # FreeBSD + vrun fetch $q --no-redirect \ + ${cacert:+--ca-cert "$cacert"} \ + ${capath:+--ca-path "$capath"} \ + ${insecure:+--no-verify-hostname} \ + -o "$f" "$u" || rc=$? + ;; - if (eval $DOWNLOAD); then :; else - errmsg="download from $location failed (HTTP error)" - continue + ftp) # OpenBSD + vrun ftp \ + ${cacert:+-S cafile="$cacert"} \ + ${capath:+-S capath="$capath"} \ + ${insecure:+-S dont} \ + -o "$f" "$u" || rc=$? + ;; + + *) error "$tool: unknown (internal error)" ;; + esac + return $rc +} + +# check_file FILE FIRST_CHAR MIN_SIZE MAX_SIZE +check_file() +{ + local firstchar f maxsize minsize size + test -z "$dryrun" || return 0 + f=$1; firstchar=$2; minsize=$3; maxsize=$4 + + # Check first chars + case `dd if="$f" bs=1 count=1 2>/dev/null` in + $firstchar) ;; + \<) echo "HTML error message"; return 1 ;; + *) echo "unknown file contents"; return 1 ;; + esac + + # Check file size + size=`wc -c < "$f"` + if test "$size" -lt $minsize; then + echo "too small file size $size bytes" + return 1 fi - if grep -i 'ViewVC Exception' "$DEST.new" >/dev/null; then - errmsg="download from $location failed (ViewVC error)" - continue + if test "$size" -gt $maxsize; then + echo "too large file size $size bytes" + return 1 fi + return 0 +} - break -done +# unexpand_svn_id < INFILE > OUTFILE +unexpand_svn_id() +{ + sed 's,\$''Id'': drivedb\.h [0-9][0-9]* 2[-0-9]* [012][:0-9]*Z [a-z][a-z0-9]* \$,$''Id''$,' +} -if [ -n "$errmsg" ]; then - rm -f "$DEST.new" - echo "$0: $errmsg" >&2 - exit 1 +# Smartmontools Signing Key (through 2020) +# +# Key ID 721042C5 +public_key="\ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +=0uFV +-----END PGP PUBLIC KEY BLOCK----- +" + +# gpg_verify FILE.asc FILE +gpg_verify() +{ + local gnupgtmp opts out rc + opts="--quiet ${q:+--no-secmem-warnin} --batch --no-tty" + + # Create temp home dir + gnupgtmp="$tmpdir/.gnupg.$$.tmp" + rm -f -r "$gnupgtmp" + mkdir "$gnupgtmp" || exit 1 + chmod 0700 "$gnupgtmp" + + # Import public key + "$GPG" $opts --homedir="$gnupgtmp" --import <&1` || rc=1 + vecho "$out" + + rm -f -r "$gnupgtmp" + return $rc +} + +# mv_all PREFIX OLD NEW +mv_all() +{ + mv "${1}${2}" "${1}${3}" + mv "${1}${2}.raw" "${1}${3}.raw" + mv "${1}${2}.raw.asc" "${1}${3}.raw.asc" +} + +# Parse options +smtctl=$SMARTCTL +tool= +url= +q="-q" +dryrun= +trunk= +cacert= +capath= +insecure= +no_verify= + +while true; do case $1 in + -s) + shift; test -n "$1" || usage + smtctl=$1 ;; + + -t) + shift + case $1 in *\ *) usage ;; esac + case " $os_dltools " in *\ $1\ *) ;; *) usage ;; esac + tool=$1 ;; + + -u) + shift; selecturl "$1" ;; + + -v) + q= ;; + + --dryrun) + dryrun=t ;; + + --trunk) + trunk=trunk ;; + + --cacert) + shift; test -n "$1" || usage + cacert=$1 ;; + + --capath) + shift; test -n "$1" || usage + capath=$1 ;; + + --insecure) + insecure=t ;; + + --no-verify) + no_verify=t ;; + + --export-key) + cat </dev/null 2>&1 \ + || err_notfound "$smtctl" "('-s -' to ignore)" fi -# Adjust timestamp and permissions -touch "$DEST.new" -chmod 0644 "$DEST.new" +# Check for GnuPG +if [ -z "$no_verify" ]; then + test -n "$GPG" \ + || error "GnuPG is not available ('--no-verify' to ignore)" + "$GPG" --version >/dev/null 2>&1 \ + || err_notfound "$GPG" "('--no-verify' to ignore)" +fi + +# Use destination directory as temp directory for gpg +tmpdir=`dirname "$DEST"` + +# Adjust URLs +src=`echo "$url" | sed -e "s,/trunk/,/branches/$BRANCH/," \ + -e "s,/master/,/origin/$BRANCH/,"` +src_asc=`echo "$src" | sed "s,/drivedb\.h,/drivedb.h.raw.asc,"` +test -z "$trunk" || src=$url -# Check syntax -rm -f "$DEST.error" -if $SMARTCTL -B "$DEST.new" -P showall >/dev/null; then :; else +# Download +test -n "$dryrun" || rm -f "$DEST.new" "$DEST.new.raw" "$DEST.new.raw.asc" + +vecho "Download ${trunk:-branches/$BRANCH}/drivedb.h with $tool" +rc=0 +download "$src" "$DEST.new" || rc=$? +if [ $rc != 0 ]; then + rm -f "$DEST.new" + error "${trunk:-$BRANCH}/drivedb.h: download failed ($tool: exit $rc)" +fi +if ! errmsg=`check_file "$DEST.new" '/' 10000 1000000`; then mv "$DEST.new" "$DEST.error" - echo "$DEST.error: rejected by $SMARTCTL, probably no longer compatible" >&2 - exit 1 + error "$DEST.error: $errmsg" +fi + +vecho "Download branches/$BRANCH/drivedb.h.raw.asc with $tool" +rc=0 +download "$src_asc" "$DEST.new.raw.asc" || rc=$? +if [ $rc != 0 ]; then + rm -f "$DEST.new" "$DEST.new.raw.asc" + error "$BRANCH/drivedb.h.raw.asc: download failed ($tool: exit $rc)" +fi +if ! errmsg=`check_file "$DEST.new.raw.asc" '-' 200 2000`; then + rm -f "$DEST.new" + mv "$DEST.new.raw.asc" "$DEST.error.raw.asc" + error "$DEST.error.raw.asc: $errmsg" fi -# Keep old file if identical, ignore differences in Id string +test -z "$dryrun" || exit 0 + +# Create raw file with unexpanded SVN Id +# (This assumes newlines are LF and not CR/LF) +unexpand_svn_id < "$DEST.new" > "$DEST.new.raw" + +# Adjust timestamps and permissions +touch "$DEST.new" "$DEST.new.raw" "$DEST.new.raw.asc" +chmod 0644 "$DEST.new" "$DEST.new.raw" "$DEST.new.raw.asc" + +if [ -z "$no_verify" ]; then + # Verify raw file + if ! gpg_verify "$DEST.new.raw.asc" "$DEST.new.raw"; then + mv_all "$DEST" ".new" ".error" + test -n "$trunk" || error "$DEST.error.raw: *** BAD signature ***" + error "$DEST.error.raw: signature from branch no longer valid ('--no-verify' to ignore)" + fi +fi + +if [ "$smtctl" != "-" ]; then + # Check syntax + if ! "$smtctl" -B "$DEST.new" -P showall >/dev/null; then + mv_all "$DEST" ".new" ".error" + error "$DEST.error: rejected by $smtctl, probably no longer compatible" + fi + vecho "$smtctl: syntax OK" +fi + +# Keep old file if identical, ignore missing Id keyword expansion in new file rm -f "$DEST.lastcheck" if [ -f "$DEST" ]; then - if cat "$DEST" | sed 's|\$''Id''[^$]*\$|$''Id''$|' | cmp - "$DEST.new" >/dev/null; then - rm -f "$DEST.new" - touch "$DEST.lastcheck" - echo "$DEST is already up to date" - exit 0 + if [ -f "$DEST.raw" ] && [ -f "$DEST.raw.asc" ]; then + if cmp "$DEST.raw" "$DEST.new.raw" >/dev/null 2>&1 \ + && cmp "$DEST.raw.asc" "$DEST.new.raw.asc" >/dev/null 2>&1 \ + && { cmp "$DEST" "$DEST.new" >/dev/null 2>&1 \ + || cmp "$DEST.raw" "$DEST.new" >/dev/null 2>&1; } + then + rm -f "$DEST.new" "$DEST.new.raw" "$DEST.new.raw.asc" + touch "$DEST.lastcheck" + echo "$DEST is already up to date" + exit 0 + fi + mv_all "$DEST" "" ".old" + else + mv "$DEST" "$DEST.old" fi - mv "$DEST" "$DEST.old" fi -mv "$DEST.new" "$DEST" - -echo "$DEST updated from $location" +mv_all "$DEST" ".new" "" +echo "$DEST updated from ${trunk:-branches/$BRANCH}${no_verify:+ (NOT VERIFIED)}"