#!/usr/bin/perl
#: dump all the contents of all your at(1) jobs, for backup
my $VERSION = "0.90"; # late beta
# Time-stamp: "2009-01-11 20:39:08 AKST sburke@cpan.org"
use constant DEBUG => 0; use strict; use warnings; $| = 1;
my $Default_Dir = "./at_jobs_bu";

sub Usage { die
"Usage:
  atsave ~/.atbu  = dumps your at(1) jobs into directory ~/.atbu
                      (or whatever directory you specify)

  atsave          = dumps your at(1) jobs into the default dir,
                      which is $Default_Dir

(The destination directory must already exist.)

                                               [sburke\@cpan.org, v$VERSION]
"}
#======================================================================
#
# atsave - dump the source of all our at(1) jobs to a particular directory
#
#======================================================================
#
# The problem that this program is meant to solve:
#
# I have a backup system that backs up everything under my home
# directory.  But there's two things that I consider important, and as
# part of my account, but which aren't in my home directory: my cron
# file, and my at(1) jobs.  Now, my cron file is easily back-uppable
# by either just always having its source file be somewhere under my
# home directory, or by just running the command:
#        crontab -l > ~/.crontab_backup
# ...a command that, appropriately, is probably something you'd put in
# your cron file.
#
#
# But there's no similarly easy way to dump all your at(1) jobs.
#
# But that's what atsave does.
#
# Atsave calls "atq" to get the numbers of each of the current user's
# jobs (and saves the atq output to atq.txt, incidentally, so you can
# see when each job is scheduled to run, etc); and then, for each job,
# atsave writes out a atNNN.dat file, where NNN is the job number, as
# in "at721.dat".  (Atsave also deletes any atNNN.dat files that have
# a job number that /isn't/ in the output from "atq", otherwise the
# directory would fill up with sources for already-done at(1) jobs.)
#
# Atsave does all this saving (and that bit of deleting) into a
# directory that you specify, or into the default directory ./at_jobs_bu
# Whatever directory atsave is meant to dump into, must already exist.
#
# You might like to specify an absolute path, as in:
#   atsave ~/.at_backups
# or
#   atsave /media/backupdrive/atjob_backups
#
# And you might want to cron this, as in:
#   50 5 * * *      atsave ~/.at_backups
#
#======================================================================
# Author: Sean M. Burke, sburke@cpan.org
#======================================================================

Usage if @ARGV > 1 or ($ARGV[0] && $ARGV[0] =~ m<^->);
{
  my $dir = $ARGV[0] || $Default_Dir;
  unless( -e $dir ) {
    Usage() unless @ARGV;
      # That's so that just running this command with no parameters
      # will be nice to users who don't know what they're doing, as is
      # revealed by $Default_Dir not existing.

    # Otherwise the user has specified a dir (and thus isn't a
    # novice), but that specified directory doesn't exist, so we die
    # this way:
    die "$dir doesn't exist";
  }
  chdir $dir or die "Can't chdir into $dir: $!";
}
my $Extension_For_Job_Files = ".atj";
my @Job_Numbers;
umask 0077;
main();
exit;

#======================================================================

sub main {
  purge_heres();
  read_job_numbers();
  write_them();
  return;
}

#======================================================================

sub purge_heres {
  my @here = sort glob "at*$Extension_For_Job_Files";
  for (@here) {
    next unless m/^at\d+\Q$Extension_For_Job_Files\E$/;
    unless( -f $_ ) { warn "But $_ isn't a file!!\n"; next }
    unlink $_ or warn "Couldn't rm $_ -- $!\n";
  }
  return;
}

#======================================================================

sub read_job_numbers {
  my $atq_out = qx[atq];

  # We assume that atq output is formatted like:
  # 912	Mon Aug 25 07:01:00 2008 a sean
  # ^^^ i.e., job number being the very first thing on the line

  {
    my $fs = "atq.txt";
    open my $ATQ, ">", $fs or die "Couldn't write-open $fs: $!";
    print $ATQ $atq_out;
    close($ATQ);
  }
  my @lines = split m/[\n\r]/, $atq_out;
  for (@lines) {
    push @Job_Numbers, $1 if m/^(\d+)\s/;
  }
  return;
}

#======================================================================

sub write_them {
  DEBUG and print "Job numbers: @Job_Numbers\n";
  unless(@Job_Numbers) {
    DEBUG and print "No jobs, according to atq.\n";
    return;
  }
  for(@Job_Numbers) {
    my $cmd =  "at -c $_ > at$_$Extension_For_Job_Files";
    if( DEBUG > 15 ) {
      print "Would run: $cmd\n";
      next;
    }
    0==system($cmd) or warn "Couldn't run command \"$cmd\" $!";
  }
  return;
}


#======================================================================

__END__
