#! /bin/sh # # smartmontools drive database update script # # Copyright (C) 2010-16 Christian Franke # # 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. # # You should have received a copy of the GNU General Public License # (for example COPYING); If not, see . # # $Id: update-smart-drivedb.in 4224 2016-02-26 20:29:24Z chrfranke $ # set -e # Set by config.status PACKAGE="@PACKAGE@" VERSION="@VERSION@" prefix="@prefix@" exec_prefix="@exec_prefix@" sbindir="@sbindir@" datarootdir="@datarootdir@" datadir="@datadir@" drivedbdir="@drivedbdir@" # Download tools os_dltools="@os_dltools@" # drivedb.h update branch BRANCH="@DRIVEDB_BRANCH@" # Default drivedb location DRIVEDB="$drivedbdir/drivedb.h" # Smartctl used for syntax check SMARTCTL="$sbindir/smartctl" myname=$0 usage() { cat <&2 exit 1 } warning() { echo "$myname: (Warning) $*" >&2 } selecturl() { case $1 in 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 } # 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 } # download URL FILE download() { local f u se 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=$? ;; 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 } # Parse options smtctl=$SMARTCTL tool= url= q="-q" dryrun= cacert= capath= insecure= 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 ;; --cacert) shift; test -n "$1" || usage cacert=$1 ;; --capath) shift; test -n "$1" || usage capath=$1 ;; --insecure) insecure=t ;; -*) usage ;; *) break ;; esac; shift; done case $# in 0) DEST=$DRIVEDB ;; 1) DEST=$1 ;; *) usage ;; esac if [ -z "$tool" ]; then # Find download tool in PATH for t in $os_dltools; do if inpath "$t"; then tool=$t break fi done test -n "$tool" || error "found none of: $os_dltools" fi test -n "$url" || selecturl "svn" # Check option compatibility case "$tool:$url" in svn:http*://svn.code.sf.net*) ;; svn:*) error "'-t svn' requires '-u svn' or '-u svni'" ;; esac case "$tool:${capath:+set}" in svn:set) warning "'--capath' is ignored if '-t svn' is used" ;; esac case "${insecure:-f}:$url" in t:http:*) insecure= ;; ?:https:*) ;; *) error "'-u svni' requires '--insecure'" ;; esac case "$tool:$insecure" in lynx:t) warning "'--insecure' is ignored if '-t lynx' is used" ;; esac # Try possible branch first, then trunk errmsg= errmsg2= for location in "branches/$BRANCH" "trunk"; do test -z "$errmsg" || errmsg2=$errmsg vecho "Download from $location with $tool" # Adjust URL case $location in trunk) src=$url ;; *) src=`echo "$url" | sed "s,/trunk/,/$location/,"` ;; esac # Download test -n "$dryrun" || rm -f "$DEST.new" || exit 1 rc=0 download "$src" "$DEST.new" || rc=$? test -z "$dryrun" || continue errmsg= if [ $rc != 0 ]; then errmsg="download from $location failed ($tool: exit $rc)" continue fi # Check file contents case `sed 1q "$DEST.new"` in /*) ;; \<*) errmsg="download from $location failed (HTML error message)" continue ;; *) errmsg="download from $location failed (Unknown file contents)" continue ;; esac # Check file size size=`wc -c < "$DEST.new"` if [ "$size" -lt 10000 ]; then errmsg="download from $location failed (too small file size $size bytes)" continue fi if [ "$size" -gt 1000000 ]; then errmsg="download from $location failed (too large file size $size bytes)" break fi break done test -z "$dryrun" || exit 0 if [ -n "$errmsg" ]; then rm -f "$DEST.new" test -z "$errmsg2" || echo "$myname: $errmsg2" >&2 error "$errmsg" fi # Adjust timestamp and permissions touch "$DEST.new" chmod 0644 "$DEST.new" if [ "$smtctl" != "-" ]; then # Check syntax rm -f "$DEST.error" if "$smtctl" -B "$DEST.new" -P showall >/dev/null; then test -n "$q" || echo "$smtctl: syntax OK" else mv "$DEST.new" "$DEST.error" echo "$DEST.error: rejected by $smtctl, probably no longer compatible" >&2 exit 1 fi fi # Keep old file if identical, ignore missing Id keyword expansion in new file rm -f "$DEST.lastcheck" if [ -f "$DEST" ]; then if cmp "$DEST" "$DEST.new" >/dev/null 2>/dev/null \ || cat "$DEST" | sed 's|\$''Id''[^$]*\$|$''Id''$|' \ | cmp - "$DEST.new" >/dev/null 2>/dev/null; then rm -f "$DEST.new" touch "$DEST.lastcheck" echo "$DEST is already up to date" exit 0 fi mv "$DEST" "$DEST.old" fi mv "$DEST.new" "$DEST" echo "$DEST updated from $location"