#!/usr/bin/perl use strict; use warnings; use feature 'say'; use IPC::Run3; use Path::Tiny; use Getopt::Long qw/ GetOptions /; my %options = ( encrypt => $ENV{LEO_ENCRYPT}, sign => $ENV{LEO_SIGN}, delete => $ENV{LEO_DELETE}, ); GetOptions( \%options, qw{ verbose encrypt sign delete help } ) or die "Error in command line arguments\n"; my $ymd = ymd(); # YYYY-MM-DD. my $backup_dir = "/tmp/backups/$ymd"; path($backup_dir)->mkpath; # Create backup directory. my $prof; # Config file for leo. my $config_file = $ENV{XDG_CONFIG_HOME} || "$ENV{HOME}/.config"; $config_file .= "/leo.pl"; require "$config_file"; my %profile = get_profile(); my $gpg_fingerprint = get_gpg_fingerprint(); my $gpg_bin = get_gpg_bin(); HelpMessage() and exit 0 if scalar @ARGV == 0 or $options{help}; foreach my $arg ( @ARGV ) { $prof = $arg; # Set $prof. if ( $profile{ $arg } ) { say "++++++++********++++++++"; # No encryption for journal profile. my $tmp = $options{encrypt} and undef $options{encrypt} if $prof eq "journal" and $options{encrypt}; # Deref the array here because we want flattened list. backup("$backup_dir/${arg}.tar", $profile{$arg}->@*); $options{encrypt} = $tmp if $prof eq "journal"; } elsif ( -e $arg ) { # If the file/directory exist then create a new profile & run # backup. say "++++++++********++++++++"; backup("$backup_dir/${arg}.tar", # backup() is expecting path relative to $ENV{HOME}. path($arg)->relative($ENV{HOME})); } else { warn "[WARN] leo: no such profile :: `$arg' \n"; } } # User must pass $tar_file first. sub backup { my $tar_file = shift @_; my @backup_paths = @_; say "Backup: $tar_file"; warn "[WARN] $tar_file exists, might overwrite.\n" if -e $tar_file; print "\n"; # All paths should be relative to $ENV{HOME}. tar_create($tar_file, "-C", $ENV{HOME}, @_); $? # tar returns 1 on errors. ? die "Backup creation failed :: $?\n" # Print absolute paths for all backup files/directories. : say path($_)->absolute($ENV{HOME}), " backed up." foreach @backup_paths; print "\n" and tar_list($tar_file) if $options{verbose}; encrypt_sign($tar_file) if $options{encrypt} or $options{sign}; } # Encrypt, Sign backups. sub encrypt_sign() { my $file = shift @_; my @options = (); push @options, "--recipient", $gpg_fingerprint, "--encrypt" if $options{encrypt}; push @options, "--sign" if $options{sign}; push @options, "--verbose" if $options{verbose}; say "\nEncrypt/Sign: $file"; warn "[WARN] $file.gpg exists, might overwrite.\n" if -e "$file.gpg"; run3 [$gpg_bin, "--yes", "-o", "$file.gpg", @options, $file]; $? # We assume non-zero is an error. ? die "Encrypt/Sign failed :: $?\n" : print "\nOutput: $file.gpg"; print " [Encrypted]" if $options{encrypt}; print " [Signed]" if $options{sign}; print "\n"; unlink $file and say "$file deleted." or warn "[WARN] Could not delete $file: $!\n" if $options{delete}; } sub HelpMessage { say qq{Backup files to $backup_dir. Profile:}; foreach my $prof (sort keys %profile) { next if substr($prof, 0, 1) eq "."; # Profiles starting with a # dot will have alias. print " $prof\n"; print " $_\n" foreach $profile{$prof}->@*; } say qq{ Options: --encrypt Encrypt files with $gpg_fingerprint --sign Sign files with $gpg_fingerprint --delete Delete the tar file after running $gpg_bin --verbose --help}; } sub tar_create { run3 ["/bin/tar", "cf", @_]; } sub tar_list { run3 ["/bin/tar", "tvf", @_]; } sub ymd { my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); $year += 1900; # $year contains the number of years since 1900. # $mon the month in the range 0..11 , with 0 indicating January # and 11 indicating December. my @months = qw( 01 02 03 04 05 06 07 08 09 10 11 12 ); my $month = $months[$mon]; return "$year-$month-$mday"; }