]> git.proxmox.com Git - mirror_smartmontools-debian.git/blame - update-smart-drivedb.in
New upstream version 6.6
[mirror_smartmontools-debian.git] / update-smart-drivedb.in
CommitLineData
7f0798ef
GI
1#! /bin/sh
2#
3# smartmontools drive database update script
4#
f9e10201
JD
5# Home page of code is: http://www.smartmontools.org
6#
7# Copyright (C) 2010-17 Christian Franke
7f0798ef
GI
8#
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation; either version 2, or (at your option)
12# any later version.
13#
14# You should have received a copy of the GNU General Public License
15# (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
16#
f9e10201 17# $Id: update-smart-drivedb.in 4584 2017-11-03 22:43:32Z chrfranke $
7f0798ef
GI
18#
19
20set -e
21
22# Set by config.status
f9e10201 23@ENABLE_SCRIPTPATH_TRUE@export PATH="@scriptpath@"
7f0798ef
GI
24PACKAGE="@PACKAGE@"
25VERSION="@VERSION@"
26prefix="@prefix@"
27exec_prefix="@exec_prefix@"
28sbindir="@sbindir@"
29datarootdir="@datarootdir@"
30datadir="@datadir@"
31drivedbdir="@drivedbdir@"
32
cfbba5b9
GI
33# Download tools
34os_dltools="@os_dltools@"
35
36# drivedb.h update branch
37BRANCH="@DRIVEDB_BRANCH@"
38
7f0798ef 39# Default drivedb location
a86ec89e 40DRIVEDB="$drivedbdir/drivedb.h"
7f0798ef 41
f9e10201
JD
42# GnuPG used to verify signature (disabled if empty)
43GPG="@gnupg@"
44
7f0798ef
GI
45# Smartctl used for syntax check
46SMARTCTL="$sbindir/smartctl"
47
a86ec89e 48myname=$0
7f0798ef 49
a86ec89e
GI
50usage()
51{
52 cat <<EOF
7f0798ef
GI
53smartmontools $VERSION drive database update script
54
a86ec89e 55Usage: $myname [OPTIONS] [DESTFILE]
7f0798ef 56
a86ec89e
GI
57 -s SMARTCTL Use SMARTCTL for syntax check ('-s -' to disable)
58 [default: $SMARTCTL]
59 -t TOOL Use TOOL for download: $os_dltools
60 [default: first one found in PATH]
61 -u LOCATION Use URL of LOCATION for download:
62 sf (Sourceforge code browser via HTTPS)
63 svn (SVN repository via HTTPS) [default]
64 svni (SVN repository via HTTP)
65 trac (Trac code browser via HTTPS)
f9e10201 66 --trunk Download from SVN trunk (may require '--no-verify')
a86ec89e
GI
67 --cacert FILE Use CA certificates from FILE to verify the peer
68 --capath DIR Use CA certificate files from DIR to verify the peer
69 --insecure Don't abort download if certificate verification fails
f9e10201
JD
70 --no-verify Don't verify signature
71 --export-key Print the OpenPGP/GPG public key block
a86ec89e
GI
72 --dryrun Print download commands only
73 -v Verbose output
7f0798ef 74
a86ec89e 75Updates $DRIVEDB
f9e10201
JD
76or DESTFILE from branches/$BRANCH of smartmontools
77SVN repository.
7f0798ef 78EOF
a86ec89e
GI
79 exit 1
80}
7f0798ef 81
a86ec89e
GI
82error()
83{
84 echo "$myname: $*" >&2
85 exit 1
86}
7f0798ef 87
a86ec89e
GI
88warning()
89{
90 echo "$myname: (Warning) $*" >&2
91}
92
93selecturl()
94{
95 case $1 in
96 sf) url='https://sourceforge.net/p/smartmontools/code/HEAD/tree/trunk/smartmontools/drivedb.h?format=raw' ;;
97 svn) url='https://svn.code.sf.net/p/smartmontools/code/trunk/smartmontools/drivedb.h' ;;
98 svni) url='http://svn.code.sf.net/p/smartmontools/code/trunk/smartmontools/drivedb.h' ;;
99 trac) url='https://www.smartmontools.org/export/HEAD/trunk/smartmontools/drivedb.h' ;;
100 *) usage ;;
101 esac
102}
103
104inpath()
105{
106 local d rc save
107 rc=1
108 save=$IFS
109 IFS=':'
110 for d in $PATH; do
111 test -f "$d/$1" || continue
112 test -x "$d/$1" || continue
113 rc=0
cfbba5b9 114 break
a86ec89e
GI
115 done
116 IFS=$save
117 return $rc
118}
119
120vecho()
121{
122 test -n "$q" || echo "$*"
123}
124
125# vrun COMMAND ARGS...
126vrun()
127{
128 if [ -n "$dryrun" ]; then
129 echo "$*"
130 elif [ -n "$q" ]; then
131 "$@" 2>/dev/null
132 else
133 echo "$*"
134 "$@"
cfbba5b9 135 fi
a86ec89e
GI
136}
137
138# vrun2 OUTFILE COMMAND ARGS...
139vrun2()
140{
141 local f err rc
142 f=$1; shift
143 rc=0
144 if [ -n "$dryrun" ]; then
145 echo "$* > $f"
146 else
147 vecho "$* > $f"
148 err=`"$@" 2>&1 > $f` || rc=$?
149 if [ -n "$err" ]; then
150 vecho "$err" >&2
151 test $rc != 0 || rc=42
152 fi
153 fi
154 return $rc
155}
156
157# download URL FILE
158download()
159{
f9e10201 160 local f u rc
a86ec89e
GI
161 u=$1; f=$2
162 rc=0
163
164 case $tool in
165 curl)
166 vrun curl ${q:+-s} -f --max-redirs 0 \
167 ${cacert:+--cacert "$cacert"} \
168 ${capath:+--capath "$capath"} \
169 ${insecure:+--insecure} \
170 -o "$f" "$u" || rc=$?
171 ;;
172
173 wget)
174 vrun wget $q --max-redirect=0 \
175 ${cacert:+--ca-certificate="$cacert"} \
176 ${capath:+--ca-directory="$capath"} \
177 ${insecure:+--no-check-certificate} \
178 -O "$f" "$u" || rc=$?
179 ;;
180
181 lynx)
182 test -z "$cacert" || vrun export SSL_CERT_FILE="$cacert"
183 test -z "$capath" || vrun export SSL_CERT_DIR="$capath"
184 # Check also stderr as lynx does not return != 0 on HTTP error
185 vrun2 "$f" lynx -stderr -noredir -source "$u" || rc=$?
186 ;;
187
188 svn)
189 vrun svn $q export \
190 --non-interactive --no-auth-cache \
191 ${cacert:+--config-option "servers:global:ssl-trust-default-ca=no"} \
192 ${cacert:+--config-option "servers:global:ssl-authority-files=$cacert"} \
193 ${insecure:+--trust-server-cert} \
194 "$u" "$f" || rc=$?
195 ;;
196
197 fetch) # FreeBSD
198 vrun fetch $q --no-redirect \
199 ${cacert:+--ca-cert "$cacert"} \
200 ${capath:+--ca-path "$capath"} \
201 ${insecure:+--no-verify-hostname} \
202 -o "$f" "$u" || rc=$?
203 ;;
204
205 ftp) # OpenBSD
206 vrun ftp \
207 ${cacert:+-S cafile="$cacert"} \
208 ${capath:+-S capath="$capath"} \
209 ${insecure:+-S dont} \
210 -o "$f" "$u" || rc=$?
211 ;;
212
213 *) error "$tool: unknown (internal error)" ;;
214 esac
215 return $rc
216}
217
f9e10201
JD
218# check_file FILE FIRST_CHAR MIN_SIZE MAX_SIZE
219check_file()
220{
221 local firstchar f maxsize minsize size
222 test -z "$dryrun" || return 0
223 f=$1; firstchar=$2; minsize=$3; maxsize=$4
224
225 # Check first chars
226 case `dd if="$f" bs=1 count=1 2>/dev/null` in
227 $firstchar) ;;
228 \<) echo "HTML error message"; return 1 ;;
229 *) echo "unknown file contents"; return 1 ;;
230 esac
231
232 # Check file size
233 size=`wc -c < "$f"`
234 if test "$size" -lt $minsize; then
235 echo "too small file size $size bytes"
236 return 1
237 fi
238 if test "$size" -gt $maxsize; then
239 echo "too large file size $size bytes"
240 return 1
241 fi
242 return 0
243}
244
245# unexpand_svn_id < INFILE > OUTFILE
246unexpand_svn_id()
247{
248 sed 's,\$''Id'': drivedb\.h [0-9][0-9]* 2[-0-9]* [012][:0-9]*Z [a-z][a-z]* \$,$''Id''$,'
249}
250
251# Smartmontools Signing Key (through 2018)
252# <smartmontools-database@listi.jpberlin.de>
253# Key ID DFD22559
254public_key="\
255-----BEGIN PGP PUBLIC KEY BLOCK-----
256
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
298=CNK4
299-----END PGP PUBLIC KEY BLOCK-----
300"
301
302# gpg_verify FILE.asc FILE
303gpg_verify()
304{
305 local gnupgtmp opts out rc
306 opts="--quiet ${q:+--no-secmem-warnin} --batch --no-tty"
307
308 # Create temp home dir
309 gnupgtmp="$tmpdir/.gnupg.$$.tmp"
310 rm -f -r "$gnupgtmp"
311 mkdir "$gnupgtmp" || exit 1
312 chmod 0700 "$gnupgtmp"
313
314 # Import public key
315 "$GPG" $opts --homedir="$gnupgtmp" --import <<EOF
316$public_key
317EOF
318 test $? = 0 || exit 1
319
320 # Verify
321 rc=0
322 out=`"$GPG" $opts --homedir="$gnupgtmp" --verify "$1" "$2" </dev/null 2>&1` || rc=1
323 vecho "$out"
324
325 rm -f -r "$gnupgtmp"
326 return $rc
327}
328
329# mv_all PREFIX OLD NEW
330mv_all()
331{
332 mv "${1}${2}" "${1}${3}"
333 mv "${1}${2}.raw" "${1}${3}.raw"
334 mv "${1}${2}.raw.asc" "${1}${3}.raw.asc"
335}
336
a86ec89e
GI
337# Parse options
338smtctl=$SMARTCTL
339tool=
340url=
341q="-q"
342dryrun=
f9e10201 343trunk=
a86ec89e
GI
344cacert=
345capath=
346insecure=
f9e10201 347no_verify=
a86ec89e
GI
348
349while true; do case $1 in
350 -s)
351 shift; test -n "$1" || usage
352 smtctl=$1 ;;
353
354 -t)
355 shift
356 case $1 in *\ *) usage ;; esac
357 case " $os_dltools " in *\ $1\ *) ;; *) usage ;; esac
358 tool=$1 ;;
359
360 -u)
361 shift; selecturl "$1" ;;
362
363 -v)
364 q= ;;
365
366 --dryrun)
367 dryrun=t ;;
368
f9e10201
JD
369 --trunk)
370 trunk=trunk ;;
371
a86ec89e
GI
372 --cacert)
373 shift; test -n "$1" || usage
374 cacert=$1 ;;
375
376 --capath)
377 shift; test -n "$1" || usage
378 capath=$1 ;;
379
380 --insecure)
381 insecure=t ;;
382
f9e10201
JD
383 --no-verify)
384 no_verify=t ;;
385
386 --export-key)
387 cat <<EOF
388$public_key
389EOF
390 exit 0 ;;
391
a86ec89e
GI
392 -*)
393 usage ;;
394
395 *)
396 break ;;
397esac; shift; done
398
399case $# in
400 0) DEST=$DRIVEDB ;;
401 1) DEST=$1 ;;
402 *) usage ;;
403esac
404
405if [ -z "$tool" ]; then
406 # Find download tool in PATH
407 for t in $os_dltools; do
408 if inpath "$t"; then
409 tool=$t
410 break
411 fi
412 done
413 test -n "$tool" || error "found none of: $os_dltools"
7f0798ef
GI
414fi
415
a86ec89e
GI
416test -n "$url" || selecturl "svn"
417
418# Check option compatibility
419case "$tool:$url" in
420 svn:http*://svn.code.sf.net*) ;;
421 svn:*) error "'-t svn' requires '-u svn' or '-u svni'" ;;
422esac
423case "$tool:${capath:+set}" in
424 svn:set) warning "'--capath' is ignored if '-t svn' is used" ;;
425esac
426case "${insecure:-f}:$url" in
427 t:http:*) insecure= ;;
428 ?:https:*) ;;
429 *) error "'-u svni' requires '--insecure'" ;;
430esac
431case "$tool:$insecure" in
432 lynx:t) warning "'--insecure' is ignored if '-t lynx' is used" ;;
433esac
434
f9e10201
JD
435# Check for smartctl
436if [ "$smtctl" != "-" ]; then
437 "$smtctl" -V >/dev/null 2>&1 \
438 || error "$smtctl: not found ('-s -' to ignore)"
439fi
7f0798ef 440
f9e10201
JD
441# Check for GnuPG
442if [ -z "$no_verify" ]; then
443 test -n "$GPG" \
444 || error "GnuPG is not available ('--no-verify' to ignore)"
445 "$GPG" --version >/dev/null 2>&1 \
446 || error "$GPG: not found ('--no-verify' to ignore)"
447fi
a86ec89e 448
f9e10201
JD
449# Use destination directory as temp directory for gpg
450tmpdir=`dirname "$DEST"`
a86ec89e 451
f9e10201
JD
452# Adjust URLs
453src=`echo "$url" | sed "s,/trunk/,/branches/$BRANCH/,"`
454src_asc=`echo "$src" | sed "s,/drivedb\.h,/drivedb.h.raw.asc,"`
455test -z "$trunk" || src=$url
7f0798ef 456
f9e10201
JD
457# Download
458test -n "$dryrun" || rm -f "$DEST.new" "$DEST.new.raw" "$DEST.new.raw.asc"
7f0798ef 459
f9e10201
JD
460vecho "Download ${trunk:-branches/$BRANCH}/drivedb.h with $tool"
461rc=0
462download "$src" "$DEST.new" || rc=$?
463if [ $rc != 0 ]; then
464 rm -f "$DEST.new"
465 error "${trunk:-$BRANCH}/drivedb.h: download failed ($tool: exit $rc)"
466fi
467if ! errmsg=`check_file "$DEST.new" '/' 10000 1000000`; then
468 mv "$DEST.new" "$DEST.error"
469 error "$DEST.error: $errmsg"
470fi
a86ec89e 471
f9e10201
JD
472vecho "Download branches/$BRANCH/drivedb.h.raw.asc with $tool"
473rc=0
474download "$src_asc" "$DEST.new.raw.asc" || rc=$?
475if [ $rc != 0 ]; then
476 rm -f "$DEST.new" "$DEST.new.raw.asc"
477 error "$BRANCH/drivedb.h.raw.asc: download failed ($tool: exit $rc)"
478fi
479if ! errmsg=`check_file "$DEST.new.raw.asc" '-' 200 2000`; then
7f0798ef 480 rm -f "$DEST.new"
f9e10201
JD
481 mv "$DEST.new.raw.asc" "$DEST.error.raw.asc"
482 error "$DEST.error.raw.asc: $errmsg"
7f0798ef
GI
483fi
484
f9e10201
JD
485test -z "$dryrun" || exit 0
486
487# Create raw file with unexpanded SVN Id
488# (This assumes newlines are LF and not CR/LF)
489unexpand_svn_id < "$DEST.new" > "$DEST.new.raw"
490
491# Adjust timestamps and permissions
492touch "$DEST.new" "$DEST.new.raw" "$DEST.new.raw.asc"
493chmod 0644 "$DEST.new" "$DEST.new.raw" "$DEST.new.raw.asc"
494
495if [ -z "$no_verify" ]; then
496 # Verify raw file
497 if ! gpg_verify "$DEST.new.raw.asc" "$DEST.new.raw"; then
498 mv_all "$DEST" ".new" ".error"
499 test -n "$trunk" || error "$DEST.error.raw: *** BAD signature ***"
500 error "$DEST.error.raw: signature from branch no longer valid ('--no-verify' to ignore)"
501 fi
502fi
7f0798ef 503
a86ec89e
GI
504if [ "$smtctl" != "-" ]; then
505 # Check syntax
f9e10201
JD
506 if ! "$smtctl" -B "$DEST.new" -P showall >/dev/null; then
507 mv_all "$DEST" ".new" ".error"
508 error "$DEST.error: rejected by $smtctl, probably no longer compatible"
a86ec89e 509 fi
f9e10201 510 vecho "$smtctl: syntax OK"
7f0798ef
GI
511fi
512
a86ec89e 513# Keep old file if identical, ignore missing Id keyword expansion in new file
7f0798ef
GI
514rm -f "$DEST.lastcheck"
515if [ -f "$DEST" ]; then
f9e10201
JD
516 if [ -f "$DEST.raw" ] && [ -f "$DEST.raw.asc" ]; then
517 if cmp "$DEST.raw" "$DEST.new.raw" >/dev/null 2>&1 \
518 && cmp "$DEST.raw.asc" "$DEST.new.raw.asc" >/dev/null 2>&1 \
519 && { cmp "$DEST" "$DEST.new" >/dev/null 2>&1 \
520 || cmp "$DEST.raw" "$DEST.new" >/dev/null 2>&1; }
521 then
522 rm -f "$DEST.new" "$DEST.new.raw" "$DEST.new.raw.asc"
523 touch "$DEST.lastcheck"
524 echo "$DEST is already up to date"
525 exit 0
526 fi
527 mv_all "$DEST" "" ".old"
528 else
529 mv "$DEST" "$DEST.old"
7f0798ef 530 fi
7f0798ef
GI
531fi
532
f9e10201 533mv_all "$DEST" ".new" ""
7f0798ef 534
f9e10201 535echo "$DEST updated from ${trunk:-branches/$BRANCH}${no_verify:+ (NOT VERIFIED)}"