#! /bin/csh -f
#
#	Utility for burning x-ray data sets onto DVD-R
#
#
if($#argv == 0) then
    set BAD
    goto Help
endif

goto Setup
############################################################################
Help:
cat << EOF

usage: backup.com directory [otherdirectory] -not junk -only good -since timefile -nolabel -noimage

where:
directory  - is the directory you want to back up onto a DVD-R
junk       - are files/subdirectories you want to leave out
good	   - is a string that the back-ed up filenames must contain
timefile   - no files as old or older than timefile will be included
-nolabel   - don't generate labels
-noimage   - don't generate an intermediate disk image (fast and dangerous)
-noverify  - don't check the written files match the originals

example:

backup.com /data/mcfuser/whatever -not '_0_'
will back up everything but screening shots

backup.com /data/mcfuser/whatever -only img -only scan -not '_0_'
will back up every *.img or *.scan file but no screening shots

backup.com /data/mcfuser -since /data/mcfuser/blah/firstrun_1_100.img
will back up everything collected AFTER firstrun_1_100.img

EOF

if($?BAD) exit 9
############################################################################
Return_from_Setup:

echo "media:     ${media}-R ($mediasize bytes)"
echo "recorders: $recorders"
echo "drives:    $drives"
echo "program:   $dvdrecord"
echo "cache:     ${localdisk}"
echo "temp:      ${tempfile}*"
echo "image:     $?USE_IMAGE"
echo "verify:    $?VERIFY"
echo "dirs:      $dirs"
echo "onlyfind:  $onlyfind"
echo "not:       $not"

startover:
echo "examining files..."
rm -f ${tempfile}* >& /dev/null
echo -n "" >! ${tempfile}filenames
if( "$dirs" != "") then
    find $dirs -type f -print >> ${tempfile}filenames
endif
if( "$lists" != "") then
    awk '{print $NF}' $lists >> ${tempfile}filenames
endif

# filter and get dates
# find $dirs -type f -printf "%T@ %s %t %p\n" | sort -n
cat ${tempfile}filenames |\
egrep "$onlyfind" |\
egrep -v "$not" |\
awk '{print "puts \"[file mtime", $1 "] [file size", $1 "] [clock format [file mtime", $1 "]] "$1"\""}' |\
tclsh |\
sort -n |\
cat >! ${tempfile}dated

cat ${tempfile}dated |\
awk -v lastarchive=$lastarchive '$1>lastarchive' |\
awk -v mediasize=$mediasize '{pattern=$NF;n=""} \
  /[0-9][0-9][0-9]\.img$/{n=split($NF,a,"\."); ext=a[n];\
      pattern=substr($NF,1,length($NF)-length(ext)-4) "%03d." ext;\
      n=substr($NF,length($NF)-length(ext)-3)+0;}\
  {++files[pattern];file[pattern,files[pattern]]=$1" "$2" "$NF;\
      size[pattern]+=int($2/2048+2)*2048;date[pattern]=$1;num[pattern]=num[pattern]" "n;\
      if(low[pattern]==""){low[pattern]=n}}\
  n<low[pattern]{low[pattern]=n}  n>=high[pattern]{high[pattern]=n}\
    END{for(pattern in size) {\
   if(size[pattern]>mediasize){for(i=1;i<=files[pattern];++i)print file[pattern,i]; continue}\
   printf "%10s %10.0f %-70s %3s\n", date[pattern], size[pattern], pattern, num[pattern]}}' |\
sort -n >! ${tempfile}groups.txt

rm -f ${tempfile}dvd????.list >& /dev/null
cat ${tempfile}groups.txt |\
awk -v mediasize=$mediasize -v tempfile=$tempfile '{size[dvd]+=$2}\
  NR==1 || size[dvd]>=mediasize{size[dvd]-=$2;\
    printf "%s %d%% %s ...\n", dvd, size[dvd]/mediasize*100, $3;\
    dvd=sprintf("%04d",dvd+1);size[dvd]=$2}\
  NF==3{print $3 >> tempfile"dvd"dvd".list"}\
   NF>3{for(i=4;i<=NF;++i) printf $3"\n",$i >> tempfile"dvd"dvd".list"} \
END{printf "%s %d%% %s ...\n", dvd, size[dvd]/mediasize*100, $3}' |\
awk 'NR!=1'

if(! $?APPROVED) then
    # explain the filename patterns here
    foreach dvd ( ${tempfile}dvd????.list )
        set dvdnum = `basename $dvd | awk '{print substr($1,match($1,"[0-9]"))}' | awk '{print substr($1,1,match($1,"[^0-9\/]")-1)}'`
        echo ""
        echo "$media #$dvdnum"
        if (! $?FAST) sumarize.com $dvd
    end
    
    set dvds = `ls -1 ${tempfile}dvd????.list | wc -l`
    set s = "s"
    if($dvds == 1) set s = ""
    echo "this will take $dvds ${media}-R pair${s}"
    echo "Okay? [Yes]"
    echo -n "-> "
    if (! $?AUTO) then
	set in = ( $< )
    endif
    if("$in" =~ [Nn]*) exit
    set APPROVED
endif

# print out nice labels
#if(! $?NOLABEL) then
#    # first, kill any old label generation proceses
#    set others = `ps -fea | awk '$NF~/^autolabel/{print $3}'`
#    if("$others" != "") then
#	( kill -9 $others )
#    endif
#endif

set dvdnum = 0
set last_dvdnum = 0
set IMAGE = ""
foreach drive ( $drives )
    ( eject $drive & ) >& /dev/null
end
echo 'please insert a blank pair of '${media}'-Rs and press "Enter"'
set temp = ""
if (! $?AUTO) then
    set temp = ( $< )
else
    annoy.wish "please insert a blank pair of ${media}-Rs in `hostname -s`"
    if ($status) exit 9
endif
if("$temp" == "skip") then
    set SKIP
endif
set disk = blank
wait

foreach drive ( $drives )
    ( eject -t $drive & ) >& /dev/null
end

set second_to_last = `ls -1 ${tempfile}dvd????.list | tail -2 | head -1`
foreach dvd ( ${tempfile}dvd????.list )

if ($?REALTIME) then
    # fast-forward to the "current" dvd number
    if("$REALTIME" != "" && "$REALTIME" != $dvd) continue
endif

increment:
    set dvdnum = `basename $dvd | awk '{print substr($1,match($1,"[0-9]"))}' | awk '{print substr($1,1,match($1,"[^0-9\/]")-1)}'`
    
if ($?REALTIME) set REALTIME = "$dvd"

image:
    if ($?SKIP) goto try_again
    ls ${localdisk}/dvd.image >& /dev/null
    if ( ! $status && "$IMAGE" == "$dvdnum") goto burn
    if(! $?NOLABEL) then
	echo "printing label $dvdnum in the background..."
	( autolabel.com $media double $dvd >! ${tempfile}autolabel.log & )
    endif
    if ( ! $?USE_IMAGE ) then
	set IMAGE = $dvdnum
	goto burn
    endif
    echo "making disk $dvdnum image..."
    rm -f ${localdisk}/dvd.image >& /dev/null
    awk '{gsub("[=]","\\="); print $1"="$1}' $dvd |\
    sh -c "mkisofs -r -J -D -graft-points -o ${localdisk}/dvd.image -path-list - "
    set IMAGE = $dvdnum
    if("$disk" == "blank") goto burn

try_again:
    if(! $?SKIP) then
    	if("$last_dvdnum" != "") then
	    echo 'dvd# '$last_dvdnum' is ready'
	    if ($?alert_email) then
        	echo "alerting $alert_email"
        	echo "DVD $last_dvdnum is ready" | mail -s "DVD $last_dvdnum is ready" "$alert_email" 
	    endif
	endif
	foreach drive ( $drives )
	    ( eject $drive & ) >& /dev/null
	end
    endif
    unset SKIP
    echo 'please insert a blank pair of '${media}'-Rs for '$dvdnum' and press "Enter"'
    set temp = ""
    if(! $?AUTO) then
	set temp = ( $< )
    else
	annoy.wish "please insert a blank pair of ${media}-Rs in `hostname -s`"
	if($status) exit 9
    endif
    if("$temp" == "skip") then
	set SKIP
	continue
    endif
    if(! $?SKIP) then
	foreach drive ( $drives )
	    ( eject -t $drive & ) >& /dev/null
	end
	set disk = blank
    endif

burn:
    wait
    if("$disk" != "blank") goto try_again
    if(! $?USE_IMAGE ) then
	# burn directly to the drives!
	set extents = `awk '{gsub("[=]","\\="); print $1"="$1}' $dvd | sh -c "mkisofs -r -J -D -graft-points -path-list - -q -print-size"`
	
	set n = 0
	foreach recorder ( $recorders )
	    @ n = ( $n + 1)
	    awk '{gsub("[=]","\\="); print $1"="$1}' $dvd |\
	    mkisofs -r -J -D -graft-points -path-list - |\
	    $dvdrecord dev=$recorder -v -tsize ${extents}s -data - ; echo $status >! ${tempfile}$n &
	end
	wait
	goto checkstatus
    endif

    if("$IMAGE" != "$dvdnum") then
	echo "disk image is not up to date: IMAGE=$IMAGE dvdnum=$dvdnum "
	goto image
    endif
    ls ${localdisk}/dvd.image > /dev/null
    if( $status ) then
	echo "disk image does not exist! "
	goto image
    endif

    # burn it direct
    set n = 0
    foreach recorder ( $recorders )
	@ n = ( $n + 1)
	$dvdrecord dev=$recorder -v -data ${localdisk}/dvd.image |& tee ${tempfile}$n ; echo $status >! ${tempfile}$n &
	sleep 10
    end
    wait
    goto checkstatus

checkstatus:
    wait
    # now check and see if the burn worked
    set n = 0
    foreach drive ( $drives )
	@ n = ( $n + 1)
	set Status = `cat ${tempfile}$n`
        rm -f ${tempfile}$n >& /dev/null
	if("$Status" != "0") then
	    echo "disk write in recorder $recorder did not work! "
#	    ( eject $drive & ) >& /dev/null
	endif
    end

verify:
    if (! $?VERIFY) goto eject

    # get the filesystem mounted up
    foreach drive ( $drives )
	eject $drive
	sleep 1
	mount $drive
	if ($status) then
	    # try one more time
	    eject $drive
	    sleep 10
	    mount $drive
	endif
    end

    set n = 0
    foreach drive ( $drives )
	@ n = ( $n + 1)
	verify.com $drive ; echo $status >! ${tempfile}$n &
    end
    wait
    set n = 0
    foreach drive ( $drives )
	@ n = ( $n + 1)
	set Status = `cat ${tempfile}$n`
        rm -f ${tempfile}$n >& /dev/null
	if("$Status" != "0") then
	    echo "disk in $drive failed verification! "
	    annoy.wish "ERROR: DVD in $drive on `hostname -s` is BAD! "
	    ( eject $drive & ) >& /dev/null
	endif
    end

eject:
    # eject the disks wether they were good or not
    foreach drive ( $drives )
	( eject $drive & ) >& /dev/null
    end
    set disk = $dvdnum

    if($Status != 0) then
	echo "write failed!  Sorry."
	wait
	goto try_again
    endif
    
    # the write for "$dvdnum" succeeded
    set last_dvdnum = "$dvdnum"

    if($?REALTIME && "$dvd" == "$second_to_last") goto startover
end

goto exit

exit:
exit

Setup:
set USE_IMAGE
set VERIFY
set media = DVD
#set noglob
set dirs
set lists
set not
set onlyfind
set dummy
set lastarchive = 0
set tempfile = /dvd_temp/tempfile

if($#argv == 0) then
    set BAD
    goto Help
endif

set i = 0
while($i < $#argv)

    @ i = ( $i + 1 )
    @ j = ( $i + 1 )
    set arg = "$argv[$i]"
    set ARG = `echo "$arg" | awk '{print toupper($1)}'`

    if("$arg" =~ *@*) then
	set alert_email = "$arg"
	echo "will alert $alert_email when each DVD is ready."
    endif

    if(-e "$arg") then
	test -d $arg
	if((! $status) && ($arg !~ */)) then
	    set arg = "${arg}/"
	endif
	test -d $arg
	if($status) then
	    set lists = ( $lists $arg )
	    continue
	endif
	if(! $?NO) then
	    set dirs = ( $dirs $arg )
	else
	    set not  = ( $not $arg )
	endif
	continue
    endif

    # wether or not to use an intermediate disk image
    if("$arg" == "-image") then
	if(! $?NO) then
	    set USE_IMAGE
	else
	    unset USE_IMAGE
	endif
    endif
    if("$arg" == "-fast") then
	if(! $?NO) then
	    set FAST
	else
	    unset FAST
	endif
    endif
    # only back up certain patterns
    if("$arg" == "-only" && $j <= $#argv) then
	set noglob
	set onlyfind = ( $onlyfind $argv[$j] )
	unset noglob
	# skip two this time
        @ i = ( $i + 1 )
	continue
    endif
    # only back up new fies
    if("$arg" == "-since" && $j <= $#argv) then
	set lastarchive = "$argv[$j]"
	if (-e "$argv[$j]" ) then
	    # must be a file
	    set lastarchive = `echo "puts [file mtime $argv[$j]]" | tclsh`
	endif
	# skip two this time
        @ i = ( $i + 1 )
	continue
    endif
    if("$arg" == "-noimage") then
	unset USE_IMAGE
	continue
    endif
    if("$arg" == "-noverify") then
	unset VERIFY
	continue
    endif
    if("$arg" == "-fake") then
	set dummy = "-dummy"
	continue
    endif
    if("$arg" == "-dummy") then
	set dummy = "-dummy"
	continue
    endif
    if("$arg" == "-nolabel") then
	set NOLABEL
	continue
    endif
    if("$arg" == "-realtime") then
	set REALTIME
	continue
    endif
    if("$arg" =~ *dpi) then
	set dpi = `echo $arg | awk '{print $1+0}'`
	continue
    endif
    if("$arg" == "CD") then
	set media = "CD"
	continue
    endif
    if("$arg" == "DVD") then
	set media = "DVD"
	continue
    endif

    if($?NO) set not = ( $not $arg )

    if(("$ARG" =~ NO*) || ("$ARG" =~ "-NO"*)) then
	set NO
	continue
    endif
    unset NO
end

# figure out fastest storage
set fileserver = `df $dirs | awk '/^\/dev\//{print "localhost"} $1~/[:]/{print substr($1,1,index($1,":")-1)}' | head -1`
foreach localdisk ( /dvd_temp/ /tmp/$USER /tmp )
    df $localdisk |& egrep -q "^/dev"
    if(! $status) then
	rm -f ${localdisk}/this >& /dev/null
	touch ${localdisk}/this >& /dev/null
	if (! $status) then
	    # this is a local filesystem we can write to...
	    break
	endif
    endif
end
rm -f ${localdisk}/this >& /dev/null
set tempfile = ${localdisk}/tempfile
if($?CCP4_SCR) then
    set tempfile = ${CCP4_SCR}/tempfile
endif

# select an executable; count the DVD recorders
foreach dvdrecord ( dvdrecord cdrecord cdrecord-dvd )
    $dvdrecord -scanbus >& ${tempfile}
    if(! $status) break
end
set recorders = `awk '/D-R/{print $1}' ${tempfile}`
rm -f ${tempfile}
if ("$dvdrecord" == "dvdrecord") set dvdrecord = "dvdrecord -dao"
if ("$dvdrecord" == "cdrecord-dvd") set dvdrecord = "dvdrecord -packet"

# drives seem to be listed as /dev/scd* in the same order
set drives = `awk '/^\/dev/{printf "%s ",$2; system("ls -ld "$1)}' /etc/fstab | awk '$NF ~ /^\/dev\/scd/{print substr($NF,9)+0,$1}' | sort -n | awk '{print $NF}'`
#set drives = ( /dvdr-1 /dvdr-2 )

# create exclusion definitions
set not = `echo " $not " | awk 'BEGIN{RS=" "} NF==1{printf "%s|", $1}'`
set not = `echo $not | awk '{print substr($1,1,length($1)-1)}'`

set onlyfind = `echo " $onlyfind " | awk 'BEGIN{RS=" "} NF==1{printf "%s|", $1}'`
set onlyfind = `echo $onlyfind | awk '{print substr($1,1,length($1)-1)}'`

# default to excluding raw images
if("$not" == "") set not = "\.imx_|\.dkx_|mtz2various_TMP|\adxv_beam_center|tempfile|sent_home"
if("$onlyfind" == "") set onlyfind = "[.]"

set mediasize = 4700000000
if ("$media" == "CD") set mediasize = 683483136

# now look for problems
if("$recorders" == "") then
    echo "ERROR: cannot find a CD/DVD-R recorder! "
    goto Help
endif

goto Return_from_Setup