131 lines
3.9 KiB
Plaintext
131 lines
3.9 KiB
Plaintext
|
#!/usr/bin/perl
|
||
|
|
||
|
use strict;
|
||
|
use warnings;
|
||
|
use POSIX qw(strftime);
|
||
|
use File::Path;
|
||
|
use File::Basename;
|
||
|
use esmith::ConfigDB;
|
||
|
use esmith::AccountsDB;
|
||
|
|
||
|
# Routines taken from powershift of rlbackup
|
||
|
sub stagger;
|
||
|
sub powershift;
|
||
|
sub shadowdir;
|
||
|
sub rmshadow;
|
||
|
|
||
|
my $cdb = esmith::ConfigDB->open_ro;
|
||
|
my $adb = esmith::AccountsDB->open_ro();
|
||
|
|
||
|
my $smb = $cdb->get('smb') or die "No smb db entry found\n";
|
||
|
my $shadowdir = $smb->prop('ShadowDir') || '/home/e-smith/files/.shadow';
|
||
|
my $shadowcopy = $smb->prop('ShadowCopy') || 'disabled';
|
||
|
my $offset = ($smb->prop('ShadowCount') || 2) - 2;
|
||
|
$offset = 0 if $offset < 0;
|
||
|
|
||
|
exit unless -d $shadowdir;
|
||
|
exit if $shadowcopy eq 'disabled';
|
||
|
|
||
|
my $filesdir = '/home/e-smith/files';
|
||
|
my $snapfmt = '@GMT-%Y.%m.%d-%H.%M.%S';
|
||
|
|
||
|
# Switch old shadow directories to new format
|
||
|
opendir(SHADOW, $shadowdir);
|
||
|
foreach my $s ( grep { /^\d/ && ! -l "$shadowdir/$_" && -d "$shadowdir/$_" } readdir SHADOW ) {
|
||
|
my @stat = stat("$shadowdir/$s");
|
||
|
rename "$shadowdir/$s", "$shadowdir/".strftime($snapfmt, gmtime($stat[9]));
|
||
|
symlink strftime($snapfmt, gmtime($stat[9])), "$shadowdir/$s";
|
||
|
}
|
||
|
closedir(SHADOW);
|
||
|
|
||
|
# remove old symlinks in ibays
|
||
|
foreach my $ibay ($adb->ibays()) {
|
||
|
my $ibaydir = 'ibays/' . $ibay->key . ( $ibay->prop('PublicAccess') eq 'none' ? '/files' : '' );
|
||
|
|
||
|
opendir(IBAY, "$filesdir/$ibaydir") || next;
|
||
|
unlink "$filesdir/$ibaydir/$_" foreach (grep /^\@GMT-/, readdir(IBAY));
|
||
|
closedir(IBAY);
|
||
|
}
|
||
|
|
||
|
# remove old symlinks in ibays
|
||
|
foreach my $user ($adb->users()) {
|
||
|
my $userdir = 'users/' . $user->key . '/home';
|
||
|
|
||
|
opendir(USER, "$filesdir/$userdir") || next;
|
||
|
unlink "$filesdir/$userdir/$_" foreach (grep /^\@GMT-/, readdir(USER));
|
||
|
closedir(USER);
|
||
|
}
|
||
|
|
||
|
# Create sync point if it doesn't already exist
|
||
|
my $snapdir = strftime($snapfmt, gmtime(time));
|
||
|
if ( -d "$shadowdir/0" ) {
|
||
|
rename "$shadowdir/".readlink("$shadowdir/0"), "$shadowdir/$snapdir";
|
||
|
unlink "$shadowdir/0";
|
||
|
} else {
|
||
|
mkdir "$shadowdir/$snapdir";
|
||
|
}
|
||
|
symlink "$snapdir", "$shadowdir/0";
|
||
|
|
||
|
# Create list of ibays and users to shadow
|
||
|
my ($ibays, $users, $link) = ('','','');
|
||
|
my @ibays = grep { ($_->prop('ShadowCopy') || 'enabled') ne 'disabled' } $adb->ibays();
|
||
|
$ibays = "$filesdir/./ibays/{" . join(',', map { $_->key } @ibays) . "}/" if scalar @ibays > 1;
|
||
|
$ibays = "$filesdir/./ibays/" . $ibays[0]->key . "/" if scalar @ibays == 1;
|
||
|
my @users = grep { ($_->prop('ShadowCopy') || 'enabled') ne 'disabled' } $adb->users();
|
||
|
$users = "$filesdir/./users/{" . join(',', map { $_->key } @users) . "}/home/" if scalar @users > 1;
|
||
|
$users = "$filesdir/./users/" . $users[0]->key . "/home/" if scalar @users == 1;
|
||
|
$link = "--link-dest ../1" if -d "$shadowdir/1";
|
||
|
|
||
|
# Sync directories to shadow directory
|
||
|
if ( $ibays || $users) {
|
||
|
system("rsync -aHmR --partial --delete --delete-excluded --exclude 'aquota.*' $link $ibays $users $shadowdir/0/") == 0
|
||
|
or die "Couldn't sync directories";
|
||
|
}
|
||
|
|
||
|
# Shift directories using geometric roll-off (only if different)
|
||
|
if ( -d "$shadowdir/1" ) {
|
||
|
if (system("diff -qr $shadowdir/0 $shadowdir/1 &> /dev/null") == 0) {
|
||
|
rmshadow("$shadowdir/0");
|
||
|
} else {
|
||
|
powershift(2) if -d shadowdir(-$offset);
|
||
|
for (my $i=2; $i >= -$offset; $i--) {
|
||
|
rename shadowdir($i), shadowdir($i+1)
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
rename "$shadowdir/0", "$shadowdir/1";
|
||
|
}
|
||
|
|
||
|
sub rmshadow {
|
||
|
my $d = shift;
|
||
|
if ( -l "$d" ) {
|
||
|
rmtree dirname($d)."/".readlink($d);
|
||
|
unlink "$d";
|
||
|
} elsif ( -d "$d" ) {
|
||
|
rmtree "$d"
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sub shadowdir {
|
||
|
my $i = shift;
|
||
|
return "$shadowdir/".($i+$offset);
|
||
|
}
|
||
|
|
||
|
sub stagger {
|
||
|
my $i = shift;
|
||
|
return $i + ($i >> 1);
|
||
|
}
|
||
|
|
||
|
sub powershift {
|
||
|
my $i = shift;
|
||
|
if ( -d shadowdir(stagger($i)) ) {
|
||
|
my $n = powershift($i << 1);
|
||
|
$i = $n >> 1;
|
||
|
rename shadowdir(stagger($i)), shadowdir($n) if -d shadowdir(stagger($i));
|
||
|
rmshadow(shadowdir($i));
|
||
|
} else {
|
||
|
rename shadowdir($i), shadowdir(stagger($i)) if -d shadowdir($i);
|
||
|
}
|
||
|
return $i;
|
||
|
}
|