#
# BackFire's core  ... a script which performs the nightly backup
source Database.TCL
source System.TCL

#
# create a bkp namespace so as not to pollute ...
namespace eval bkp {

  #
  #  Return today as YYYYMMDD ...
  proc YYYYMMDD { } {
    return [ clock format [clock seconds] -format "%Y%m%d" ]
  }
  
  #
  #  Return Target File name ...
  proc target_File { target } {
    return [ format "bkp_%s_%s.tgz" [YYYYMMDD] $target ]
  }

  #
  #  Return Target Path ...
  proc target_Path { target } {
    return [ file join $::X(archive_path) Data $target ]
  }

  #
  #  Return fully qualified Target name ...
  proc fq_Target { target } {
	return [ file join [ target_Path $target ] [ target_File $target ] ]
  }

  #
  # Backup a mounted file system or directory ...
  proc do_unix { ix } {
    array set t [ sql::get_tbl_Row $ix ]
    foreach v [ array names t ] {
    	eval [ format "set %s {%s}" $v $t($v) ]
    }
    set target [ fq_Target $name ]
    set source $share
    if [ string length $path ] {
	set source [ file join $share $path ]
    } 
    set cmd [ format "%s -zcf %s %s" \
	$::X(tar) $target $source ]
    puts " -- backing $source"
    puts " -- creating $target"
    set elapsed [ sys::do_Timer $cmd ]
    puts " -- $name backup required $elapsed seconds. "

    return [ file size $target ]
  }

  #
  # Backup a Windows/Samba share ...
  proc do_smb { ix } {
    array set t [ sql::get_tbl_Row $ix ]
    foreach v [ array names t ] {
    	eval [ format "set %s {%s}" $v $t($v) ]
    }
    set target [ fq_Target $name ]
    set temp [ file join [target_Path $name] {tmp.tar} ]
    set source [ format "//%s/%s/%s" $host $share $path ]
    puts " -- backing $source"
    puts " -- creating $target."
    set cmd [ format "%s -s %s -x %s -d '%s' -u %s -p %s -t %s *.*" \
	$::X(smbtar) $host $share $path $user $passwd $temp ]
    set elapsed [ sys::do_Timer $cmd ]

    # smbtar does not support the -z compression option
    # so we add a manual compression step for orthagonality.
    set elapsed [ expr $elapsed + [ sys::file_Compress $temp $target ] ]
    file delete $temp 

    puts " -- $name backup required $elapsed seconds. "
    return [ file size $target ]
  }

  #
  # Backup an NFS mount.  This assumes that
  # the target is already mounted, but one
  # could easily scan the /etc/fstab file 
  # for NFS mounts, and process accordingly.
  proc do_nfs { ix } {
    return [ do_unix $ix ]
  }

  #
  # Implement the file Retention policy ...
  proc retention_Policy { n path } {
    while { [llength [glob -nocomplain $path ]] > $n } {
      set delendum [lindex [lsort [glob $path]] 0 ]
      puts " -- deleting expired archive $delendum."
      file delete $delendum
    }
    set n_files [llength [glob -nocomplain $path ]]
    puts " -- retaining $n_files files of $n total."
  }

  #
  # Process each "target" record in the database ...
  proc backup_Target { ix } {
    array set t [ sql::get_tbl_Row $ix ]
    foreach v [ array names t ] {
    	eval [ format "set %s {%s}" $v $t($v) ]
    }

    puts [format "\n== Processing Archive %s." $name]
    set pth [ target_Path $name ]
    if { ! [ file isdirectory $pth ] } {
      puts " -- creating directory $pth for $name."
      file mkdir $pth
    } else {
      puts " -- using pre-existing directory $pth."
    }
    set n_Bytes 0 

    switch -exact $type {
      Unix {
        set n_Bytes [ do_unix $ix ]
      }
      NFS {
        set n_Bytes [ do_nfs $ix ]
      }
      Samba {
        set n_Bytes [ do_smb $ix ]
      }
    }
    set iso_dir [file join $::X(archive_path) Nightly]
    set linkname [ file join $iso_dir [ target_File $name ] ]
    file link -symbolic $linkname [ fq_Target $name ] 
    retention_Policy $::X(retention) $pth/bkp_*
    return $n_Bytes
  }

  #
  # main's a hard habit to break ... 
  proc main { } {

    # Get the resources and cache the Backup Targets ...
    sql::openDBMS 
    set N_Res [ sql::readResources ]
    set N_Targets [ sql::cache_tbl_Data target ]
    sql::closeDBMS 
    set iso_dir [file join $::X(archive_path) Nightly]
    set iso_img [file join $::X(archive_path) Nightly.iso]

    sys::new_Log
    file delete -force $iso_dir
    file delete -force $iso_img
    file mkdir $iso_dir
    set start [ sys::startup Backup ]

    set n_Bytes 0 
    set n_Total 0 
    for { set i 0 } { $i < $N_Targets } { incr i } {
      array set t [ sql::get_tbl_Row $i ]
      set n_Bytes [ backup_Target $i ] 
      puts " -- Archived $n_Bytes bytes."
      sys::sys_Error_Report $t(name)
      set n_Total [expr $n_Total + $n_Bytes ]
      sys::reset_Net
    }

    set m_Bytes [ expr $n_Total / [ expr 1024 * 1024 ] ]
    set end [ sys::finish Backup ]
    puts " -- Total Bytes $n_Total (about $m_Bytes Meg)."
    puts " -- Elapsed Time: [ sys::elapsed [ expr $end - $start ] ]."
		
    sys::burn_DIR $iso_dir
    sys::mount_cd9660 /cdrom
    sys::do_SysCmd "/bin/ls -lh /cdrom"
    puts $sys::sys_result
    sys::umount_cd9660 /cdrom
    sys::close_Log
  }

}
bkp::main
