can't delete older file/directory links on another local partition after `snapshot' type backup script

Dalton Harvie daltonh at ualberta.ca
Wed Mar 12 18:09:42 EST 2003


Thanks for looking at this, and developing rsync.  Really useful program that 
I rely on.  Bit of a newbie but I couldn't find anything on this in these 
archives.  Hopefully it's a really stupid question!


I'm trying to backup using cp -al and then rsync -auR --delete backup idea 
basically as per 
http://www.mikerubel.org/computers/rsync_snapshots/#Incremental.


I have a separate partition which I remount as rw, then cp -al yesterday's 
tree to a new one, say /todays/backup/directory.  Then

rsync -auR --delete --delete-excluded --ignore-errors --force 
--include-from=$includedfiles / /todays/backup/directory

to copy over any new files from the master (/) and delete any links to files 
that are no longer on the master.  This puts the root of master at 
/todays/backup/directory/ because of -R.


The problem: the links to old files and directories aren't getting deleted.  
As I understand --force shouldn't be needed, and I can't 
see why --ignore-errors would be necessary either in this case, but they 
don't make any difference.


It's all in a perl script (given below) run by cron.  Makes no difference 
whether run manually by root though.  I can remove directories or files from 
within the script using rm -r, so I don't think it is a permission or 
mounting problem?  I have it set up to use ssh by default (relevant?), but -e 
rsh doesn't make any difference.  I have tried doing this problem with small 
test directory trees on a single partition under a single user using the 
above command and that works fine.  Are there any file/directory deletion 
errors that could cause the deletion process to stop, even with 
--ignore-errors on?


rsync version 2.5.5, mandrake 8.2
Partition line from /etc/fstab: /dev/hdb1 /old ext3 defaults,ro 1 2


Any help appreciated --- I'm running out of disk space!

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SCRIPT: relevant part is after 'now do rsync for real'



#!/usr/bin/perl -w
#
# ARCHIVE: script written to backup all info specified in archive.files
# Dalton Harvie, 24/2/03
#
# version 2: 26/2/03: include ls -l infor in archive.trans listing
#
# version 3: 10/3/03: including --force in rsync command to hopefully remove 
old directories
#
# wanted:
# 1) don't die without remounting /old as ro
# 2) gzip everthing and don't transfer unnecessary stuff if already there but 
zipped
#
#---------------------------------------------------------------------
# definitions

$version=3;

# define strings to define platform dependent functions
$CP='/bin/cp';
$MV='/bin/mv';
$LN='/bin/ln';
$LS='/bin/ls';
$RSYNC='/usr/bin/rsync';
$MOUNT='/bin/mount';

# $archivepart is a string specifying the partition which contains $archivedir
$archivepart='/old';

# $archivedir is the absolute path to archive structure
#$archivedir='/home/daltonh/tmp/old';  # defined globally
$archivedir='/old';  # so structure will be /old/old2003
 
# $log is a directory where the logfile archive.log should be stored
$log='/var/log';
#$log='/home/daltonh/tmp';

# $includedfiles is a filename which specifies in rsync format what files to 
transfer
#$includedfiles='/home/daltonh/perl/archive/archive.include';
$includedfiles='/root/archive/archive.include';

#---------------------------------------------------------------------
# open logfile in $log directory and append new info

open(LOG, ">>$log/archive.log");

print LOG "archive script version $version called at ".(scalar 
localtime)."\n";

#---------------------------------------------------------------------
# remount partition where the archive is in in rw mode
 
$systemcall="$MOUNT -w -o remount $archivepart";
(!(system($systemcall))) or do {print LOG "could not $systemcall\n"; die;};
 
#---------------------------------------------------------------------
# create backup directory if one hasn't already been specified

createdir($dir);  # call subroutine createdir to create the directory and 
possibly the tree too
  
print LOG "created directory for archive $dir\n";

#---------------------------------------------------------------------
# copy (hard link) files to directory from recent which has the previous tree 
(if it exists)

$recent="$archivedir/recent";

if (-e $recent and (-d $recent or -l $recent)) {  # have established that 
recent exists and that it's a link or directory

# copy (actually hard link) contents of $recent to new $dir, recursively, 
preserving atributes and copying but not following soft links
 
  $systemcall="$CP -al $recent/* $dir";  
  (!(system($systemcall))) or do {print LOG "could not $systemcall\n"; die;};

# now remove link ready for new one to be put in place

  unlink $recent or do {print LOG "could not unlink $recent\n"; die;};

}

# remove old archive.trans file if possible

if (-e "$dir/archive.trans") {unlink "$dir/archive.trans" or print LOG "could 
not unlink $dir/archive.trans\n";}
 
#---------------------------------------------------------------------
# rsync files to the new directory
# options: -a = -r (recursive) l (recreate symbolic links) ptgo (preserve 
permissions, time, group, ownership) D (copy devices)
#          -u = update
#          -R = relative filenames (eg /home/joeblogg -> old/home/joeblogg)
#          --delete = remove files from destination that aren't in source
#          --delete-excluded = remove files from destination that aren't 
included in transfer either
#          --include-from=$includedfiles = specify what to copy

# first check that $includedfiles exists

if (!(-f $includedfiles)) {print LOG "$includedfiles file does not exist\n"; 
die;}

# this bit modified for version 2
# open TEMP file and write out to this the transfer listing and some other 
info

open(TEMP, ">$dir.temp") or do {print LOG "could not open $dir.temp\n"; die;};

# assemble systemcall to run rsync for output purposes
 
$systemcall="$RSYNC -auRn --delete --delete-excluded 
--include-from=$includedfiles / $dir";  

print TEMP "archive script version $version called at ".(scalar 
localtime)."\n";
print TEMP "rsync command: $systemcall\n";
print TEMP "archive directory $dir\n";
print TEMP "this file contains a listing of files that were transferred for 
this backup\n";
print TEMP ('_'x120)."\n";
print TEMP `$systemcall`;
print TEMP ('_'x120)."\n";

close TEMP;

# now, open TEMP again, this time for reading
 
open(TEMP, "<$dir.temp") or do {print LOG "could not open $dir.temp\n"; die;};
 
# open TRAN, the destination file for this info, for writing

open(TRAN, ">$dir.trans") or do {print LOG "could not open $dir.trans\n"; 
die;};

# loop through initial lines, reading from TEMP and writing to TRAN

while (<TEMP>) {
  print TRAN $_;
  if (/^building file list/) {last;}  # this indicates the next line will be 
file listings
}

# now loop through file names, using ls -l to give file specifics

while (<TEMP>) {
  if (/^wrote/) {print TRAN $_; last;}  # this indicates that we have 
finished the file listings
  print TRAN `$LS -l $_` or print TRAN "problem listing $_";
}

# write out final lines
while (<TEMP>) {
  print TRAN $_;
}

close TRAN;
close TEMP;

# get rid of TEMP

unlink "$dir.temp" or print LOG "could not unlink $dir.temp\n";

#**********************
# now do rsync for real

# trying to work out why directories aren't deleted --- maybe permission 
problem? --- nah don't think so as rm -r works 
# shouldn't need --force or --ignore-errors according to me
$systemcall="$RSYNC -auR --delete --delete-excluded --ignore-errors --force 
--include-from=$includedfiles / $dir";  
(!(system($systemcall))) or do {print LOG "could not $systemcall\n"; die;};

# temp old
#$systemcall="$RSYNC -auR --delete --delete-excluded --force 
--include-from=$includedfiles / $dir";  
#(!(system($systemcall))) or do {print LOG "could not $systemcall\n"; die;};
 
# temp try just deleting something using this script --- works
#$systemcall="rm -r $dir/home/daltonh/balls/herbo/ir1";
#(!(system($systemcall))) or do {print LOG "could not $systemcall\n"; die;};

#**********************

#---------------------------------------------------------------------
# if possible move transfer file to directory

if (!(-e "$dir/archive.trans")) {    # this is an unlikely possibility if 
archive.trans already exists
  $systemcall="$MV $dir.trans $dir/archive.trans";
  (!(system($systemcall))) or print LOG "could not $systemcall\n";
}

#---------------------------------------------------------------------
# create a new soft link from the new directory to $recent

if (!(-e $recent))  # true if $recent doesn't exist
{
  $systemcall="$LN -s $dir $recent";  
  (!(system($systemcall))) or do {print LOG "could not $systemcall\n"; die;};
}
else
{
  print LOG "$recent link cannot be made because of existing file\n";
}

#---------------------------------------------------------------------
# remount partition where the archive is in in ro mode
 
$systemcall="$MOUNT -r -o remount $archivepart";
(!(system($systemcall))) or do {print LOG "could not $systemcall\n"; die;};
 
print LOG "archive finished\n".('_'x80)."\n";

#*******************************************************************************
# subroutine to check and create backup directory tree
# new directory (complete path from root) is given by $dir

sub createdir
{

# set date variables
 
  $year=(localtime)[5]+1900;        # portable date functions
  
$month=('jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec')[(localtime)[4]];
  $day=(localtime)[3];

  $diryear=$archivedir.'/old'.$year;
  $dirmonth=$diryear.'/old'.$month.$year;
  $dirday=$dirmonth.'/old'.$day.$month.$year;

# loop through all required directories up to final checking and creating if 
necessary
# change directory permissions
   
  if (!(-d $archivedir)) {print LOG "archivedir $archivedir does not 
exist\n"; die;}

  foreach $dirc ($diryear,$dirmonth)
  {
    if (!(-d $dirc)) {mkdir ($dirc, 0755) or do {print LOG "can't make $dirc: 
$! \n"; die;};}
  }

# now loop through possible directory suffixes finding a directory that 
hasn't been created yet
   
  foreach $diradd ('','a'..'z','A'..'Z')
  {

    $dirtry=$dirday.$diradd;              # add a suffix to the default day 
string

    if (!(-d $dirtry))                    # test if that directory exists
    {
      mkdir ($dirtry, 0755) or do {print LOG "can't make $dirtry: $!\n"; 
die;};
      $dir=$dirtry;                       # must have made directory if we 
reach here
    }

    if ($dir) {last;}             # if $dir has been set then a directory has 
been creted

  }

# check that a directory actually was created
 
  if (!($dir))
  {
    print LOG "ran out of directory suffixes when attempting to create 
directory\n";
    die;
  }

}

#*******************************************************************************


More information about the rsync mailing list