chiark / gitweb /
Merge branch 'master' of git.distorted.org.uk:~mdw/publish/public-git/dvdrip
[dvdrip] / dvdrip
1 #! /bin/bash -e
2
3 prog=${0##*/}
4 dev=${DVDRIP_DEVICE-/dev/dvd}
5 tmp=${DVDRIP_TMPDIR-${HOME?}/tmp/dvdrip}
6 archive=${DVDRIP_ARCHIVE-jem.distorted.org.uk:/mnt/dvd/archive}
7 : ${DVD_SECTOR_COPY=dvd-sector-copy}
8 : ${DVD_ID=dvd-id}
9 : ${DVDRIP_UPLOAD=dvdrip-upload}
10 backup=nil ding=nil eject=nil force=nil retry=nil verbose=nil bogus=nil
11 unset params
12 usage () {
13   cat <<EOF
14 usage: $prog [-defrv] [-D DEV] [-a ARCH] [-t TMP] TITLE
15 EOF
16 }
17 while getopts "hB:D:a:defrt:v" opt; do
18   case $opt in
19     h) usage; exit 0 ;;
20     B) params=${params+$params,}$OPTARG ;;
21     D) dev=$OPTARG ;;
22     a) archive=$OPTARG ;;
23     d) ding=t ;;
24     e) eject=t ;;
25     f) force=t ;;
26     r) retry=t ;;
27     t) tmp=$OPTARG ;;
28     v) verbose=t ;;
29     *) bogus=t ;;
30   esac
31 done
32 shift $(( $OPTIND - 1 ))
33 case $# in 1) title=$1 ;; *) bogus=t ;; esac
34 case $bogus in t) usage >&2; exit 2 ;; esac
35 case $verbose in t) set -x ;; esac
36 case $archive in
37   *:*) archhost=${archive%%:*} archpath=${archive#*:} ;;
38   *) unset archhost; archpath=$archive ;;
39 esac
40
41 notify () {
42   colour=$1 message=$2
43   echo "$(tput bold; tput setaf $colour)$message$(tput sgr0; tput op)"
44 }
45 fail () { notify 1 "!!! $*"; exit 2; }
46 warn () { notify 5 "??? $*"; }
47 info () { notify 6 "--- $*"; }
48 run_setrc () {
49   notify 2 "+++ $*";
50   set +e; nice "$@"; rc=$?; set -e
51 }
52 run () { run_setrc "$@"; case $rc in 0) ;; *) fail "$1: exit $rc" ;; esac; }
53
54 archdo () {
55   op=$1; shift
56   case ${archhost+t} in
57     t)
58       qq=
59       for a in "$@"; do
60         qq="${qq:+$qq }'${a//\'/"'\\''"}'" #" # emacs is confused
61       done
62       "$op" ssh "$archhost" "$qq"
63       ;;
64     *)
65       "$op" "$@"
66       ;;
67   esac
68 }
69 archrun () { archdo run "$@"; }
70
71 tag=${title//\//_}
72
73 archdo run_setrc test -f "$archpath/$title.iso"
74 case $rc,$force in
75   0,nil) fail "output file already exists" ;;
76   0,t) warn "output file already exists; will overwrite" ;;
77 esac
78
79 mkdir -p "$tmp/$tag"
80
81 discid=$("$DVD_ID" -I "$dev")
82 if [ -f "$tmp/$tag/discid" ]; then
83   read oldid <"$tmp/$tag/discid"
84   case $force,$oldid in
85     t,"$discid" | nil,"$discid")
86       ;;
87     nil,*)
88       fail "discid mismatch: expected \`$oldid' but drive has \`$discid'"
89       ;;
90     t,*)
91       warn "discid mismatch: expected \`$oldid' but drive has \`$discid'; continuing anway"
92       ;;
93   esac
94 fi
95 info "copying \`$discid'"
96 echo "$discid" >"$tmp/$tag/discid.new"
97 mv "$tmp/$tag/discid.new" "$tmp/$tag/discid"
98
99 if [ -b "$dev" ]; then msz=$(blockdev --getsize64 "$dev")
100 else msz=nil; fi
101
102 echo "$dev" >"$tmp/$tag/device.new"
103 mv "$tmp/$tag/device.new" "$tmp/$tag/device"
104
105 accumulate_badblocks () {
106   if [ -f "$tmp/$tag/badblocks.new" ]; then
107     if [ ! -f "$tmp/$tag/badblocks" ]; then
108       { echo "## bad-blocks region map"; echo; } >"$tmp/$tag/badblocks"
109     fi
110     sed -n "/^[^#]/p" "$tmp/$tag/badblocks.new" >>"$tmp/$tag/badblocks"
111     rm "$tmp/$tag/badblocks.new"
112   fi
113 }
114
115 set --
116 any=nil
117 for i in "$tmp/$tag/dest.new" "$tmp/$tag/dest" "$tmp/$tag/dest.seen"; do
118   if [ -f "$tmp/$tag/dest.new" ]; then any=t; fi
119 done
120 case $any in
121   nil) printf "%s\n" "$title.iso" >"$tmp/$tag/dest.new" ;;
122 esac
123 case $eject in
124   t) touch "$tmp/$tag/eject" ;;
125   nil) rm -f "$tmp/$tag/eject" ;;
126 esac
127 case $ding in
128   t) touch "$tmp/$tag/ding" ;;
129   nil) rm -f "$tmp/$tag/ding" ;;
130 esac
131
132 accumulate_badblocks
133 case $retry in
134   t)
135     if [ -f "$tmp/$tag/badblocks.retry" ]; then
136       :
137     elif [ -f "$tmp/$tag/badblocks" ]; then
138       run mv "$tmp/$tag/badblocks" "$tmp/$tag/badblocks.retry"
139     else
140       fail "no blocks to retry"
141     fi
142     set -- "$@" -R"$tmp/$tag/badblocks.retry"
143     if [ -f "$tmp/$tag/iso" ]; then
144       mv "$tmp/$tag/iso" "$tmp/$tag/iso.new"
145     fi
146     ;;
147 esac
148 if [ ! -f "$tmp/$tag/iso" ]; then
149   run "$DVD_SECTOR_COPY" -cs ${params+"-B$params"} \
150       -b"$tmp/$tag/badblocks.new" "$@" "$dev" "$tmp/$tag/iso.new"
151   run mv "$tmp/$tag/iso.new" "$tmp/$tag/iso"
152   accumulate_badblocks
153   rm -f "$tmp/$tag/device"
154   case $retry in t) rm -f "$tmp/$tag/badblocks.retry" ;; esac
155   if [ -f "$tmp/$tag/badblocks" ]; then
156     fail "bad sectors found: check \`$tmp/$tag/iso', run again if ok"
157   fi
158   case $msz in
159     nil) ;;
160     *)
161       newmsz=$(blockdev --getsize64 "$dev")
162       case $newmsz in
163         $msz) ;;
164         *) fail "medium size changed ($msz -> $newmsz): try again" ;;
165       esac
166       ;;
167   esac
168 fi
169
170 rm -f "$tmp/$tag/device"
171 run mv "$tmp/$tag/dest.new" "$tmp/$tag/dest"
172 if [ -f "$tmp/$tag/eject" ]; then eject=t; else eject=nil; fi
173 if [ -f "$tmp/$tag/ding" ]; then ding=t; else ding=nil; fi
174 run "$DVDRIP_UPLOAD"
175 case $eject in t) run eject "$dev" ;; esac
176 case $ding in
177   t)
178     if [ -t 1 ]; then exec 3>&1
179     elif [ -t 2 ]; then exec 3>&2
180     else exec 3>/dev/tty
181     fi
182     printf "\a" >&3
183     exec 3>&-
184     ;;
185 esac