Files

1783 lines
62 KiB
Perl

#!/usr/bin/perl -wT
#----------------------------------------------------------------------
# heading : Administration
# description : Rsync
# navigation : 4000 4863
#
# Author Stephen Noble dungog.net
#
#----------------------------------------------------------------------
package esmith;
use strict;
use CGI ':all';
use CGI::Carp qw(fatalsToBrowser);
use esmith::cgi;
use esmith::config;
use esmith::util;
use esmith::db;
sub showInitial ($$); # main form
sub showHelp ($);
sub modifyRsync ($$); # secure form
sub performModifyRsync ($); # secure action
sub showAnon ($$); # anon form
sub performShowAnon ($); # anon action
sub showIbay ($$); # ibay form
sub performAnon ($); # start stop anon rsync
sub modifyIbay ($); # toggle ibay public access
sub deleteRsync ($);
sub deleteItem ($);
sub performRsyncNow ($); # run backup now
sub rsyncNowResults ($); # view logs
sub recentRsync ($);
BEGIN
{
# Clear PATH and related environment variables so that calls to
# external programs do not cause results to be tainted. See
# "perlsec" manual page for details.
$ENV {'PATH'} = '';
$ENV {'SHELL'} = '/bin/bash';
delete $ENV {'ENV'};
}
esmith::util::setRealToEffective ();
$CGI::POST_MAX=1024 * 100; # max 100K posts
$CGI::DISABLE_UPLOADS = 1; # no uploads
my %conf;
tie %conf, 'esmith::config';
my %dungog;
tie %dungog, 'esmith::config', '/home/e-smith/db/dungog';
my %accounts;
tie %accounts, 'esmith::config', '/home/e-smith/db/accounts';
my %Labels = ('*' => 'Daily',
'1-5' => 'Week days',
'0,6' => 'Week ends',
'sun' => 'Sunday',
'1' => 'Monday',
'2' => 'Tuesday',
'3' => 'Wednesday',
'4' => 'Thursday',
'5' => 'Friday',
'6' => 'Saturday');
my %Labels2 = ('senddirs' => 'send one or more directories to another server',
'senddirs2self' => 'save directories to self. eg 2nd hardrive',
'sendservers' => 'send one directory to many servers',
'receivedirs' => 'receive one or more directories from one server',
'receiveservers' => 'receive one directory from many servers');
my %Labels5 = ('test' => 'Test. Only displays what rsync would do and does no actual copying',
'verbose' => 'Copies but still gives a verbose display of what it is doing',
'stats' => 'Copies and just displays statistics',
'quiet' => 'Copies and does no display at all');
my %Labels4 = ('none' => 'no limit',
'10' => '10 kb/s',
'25' => '25 kb/s',
'50' => '50 kb/s',
'100' => '100 kb/s',
'500' => '500 kb/s',
'1000' => '1 mb/s',
'2000' => '2 mb/s',
'4000' => '4 mb/s',
'6000' => '6 mb/s',
'10000' => '10 mb/s',
'20000' => '20 mb/s');
my %Labels3 = ('*/2' => 'Each 2 hours',
'*/4' => 'Each 4 hours',
'*/8' => 'Each 8 hours',
'*/12' => 'Each 12 hours',
'9-17' => '9am-5pm',
'8-18' => '8am-6pm',
'1' => '1 am',
'2' => '2 am',
'3' => '3 am',
'4' => '4 am',
'5' => '5 am',
'6' => '6 am',
'7' => '7 am',
'8' => '8 am',
'9' => '9 am',
'10' => '10 am',
'11' => '11 am',
'12' => 'noon',
'13' => '1 pm',
'14' => '2 pm',
'15' => '3 pm',
'16' => '4 pm',
'17' => '5 pm',
'18' => '6 pm',
'19' => '7 pm',
'20' => '8 pm',
'21' => '9 pm',
'22' => '10 pm',
'23' => '11 pm');
#------------------------------------------------------------
# examine state parameter and display the appropriate form
#------------------------------------------------------------
my $q = new CGI;
if (! grep (/^state$/, $q->param))
{
showInitial ($q, '');
}
elsif ($q->param ('state') eq "choosesub")
{
if ($q->param ('action') eq "Save Settings")
{
performModifyRsync ($q);
}
if ($q->param ('action') eq "Save Job")
{
performShowAnon ($q);
}
elsif ($q->param ('action') eq "Run this rsync job now")
{
performRsyncNow ($q);
}
}
elsif ($q->param ('state') eq "help")
{
showHelp ($q);
}
#secure form
elsif ($q->param ('state') eq "modifyrsync")
{
modifyRsync ($q, '');
}
elsif ($q->param ('state') eq "performmodify")
{
performModifyRsync ($q);
}
#tasks
elsif ($q->param ('state') eq "deletersync")
{
deleteRsync ($q);
}
elsif ($q->param ('state') eq "deleteitem")
{
deleteItem ($q);
}
#show results
elsif ($q->param ('state') eq "rsyncNowResults")
{
rsyncNowResults ($q);
}
elsif ($q->param ('state') eq "recentRsync")
{
recentRsync ($q);
}
#ibay setup form
elsif ($q->param ('state') eq "showibay")
{
showIbay ($q, '');
}
elsif ($q->param ('state') eq "performAnon")
{
performAnon ($q);
}
elsif ($q->param ('state') eq "modifyibay")
{
modifyIbay ($q);
}
#anon form
elsif ($q->param ('state') eq "showAnon")
{
showAnon ($q, '');
}
elsif ($q->param ('state') eq "performShowAnon")
{
performShowAnon ($q);
}
else
{
esmith::cgi::genStateError ($q, \%conf);
}
exit (0);
#########################################################################
sub showInitial ($$)
{
my ($q, $msg) = @_;
if ($msg eq '')
{
esmith::cgi::genHeaderNonCacheable
($q, \%conf, 'Rsync file transfer');
}
else
{
esmith::cgi::genHeaderNonCacheable
($q, \%conf, 'Rsync file transfer');
print $q->h4 ('Operation status report');
print $q->p ($msg);
print $q->hr;
}
print $q->startform (-method => 'POST', -action => $q->url (-absolute => 1));
#short intro
print $q->Tr (esmith::cgi::genTextRow ($q, $q->p ('Automatically mirror your data to another server.
Use either secure rsync using ssh keys, or anonymous rsync.
Transfers have been scheduled for sets highlighted in red.
You also have a transfer now option for each set')));
#check to see if cron is running
unless ( -e "/var/run/crond.pid" )
{
print $q->p (esmith::cgi::genSmallRedCell ($q, "NOTE: cron is not ".
"running. It really should be, besides not automating our backups, lots of system tasks are not ".
"performed. As root, on the command line, type 'service crond start' then 'ps -A' to check."));
}
#configure and select set
print $q->h4 ('Transfer Sets Summary - Send and Retrieve files via rsync using SSH');
print $q->p ($q->a ({href => $q->url (-absolute => 1) . "?state=modifyrsync&&rsync=new"},
'Click here'),
'to add a transfer set.');
print "<table border=1 cellspacing=1 cellpadding=4>";
#header
print $q->Tr (esmith::cgi::genSmallCell ($q, $q->b ('Description')),
esmith::cgi::genSmallCell ($q, $q->b ('Frequency')),
esmith::cgi::genSmallCell ($q, $q->b ('Time')),
$q->td ('&nbsp;'),
$q->td ('&nbsp;'));
#get rsyncs/shares
my @rsyncs = ();
foreach (sort keys %dungog)
{
push (@rsyncs, $_)
if (db_get_type(\%dungog, $_) eq "rsync");
}
my $rsync = '';
foreach $rsync (sort @rsyncs)
{
my $desc = db_get_prop(\%dungog, $rsync, "desc") || '';
my $freq = db_get_prop(\%dungog, $rsync, "freq") || '';
my $day = db_get_prop(\%dungog, $rsync, "day") || '';
my $hour = db_get_prop(\%dungog, $rsync, "hour") || '';
my $min = db_get_prop(\%dungog, $rsync, "min") || '';
#modify frequency value for display
my $daylabel = ($Labels{$day});
if ($freq eq 'hourly')
{
$hour = '*';
}
elsif ($freq eq 'on')
{
$freq = $daylabel;
}
if ($freq eq 'off')
{
print $q->Tr (esmith::cgi::genSmallCell ($q, $desc),
esmith::cgi::genSmallCell ($q, $freq),
esmith::cgi::genSmallCell ($q, ''),
esmith::cgi::genSmallCell ($q,
$q->a ({href => $q->url (-absolute => 1)
. "?state=modifyrsync&&rsync="
. $rsync}, 'Modify/Run...')),
esmith::cgi::genSmallCell ($q,
$q->a ({href => $q->url (-absolute => 1)
. "?state=deletersync&&rsync="
. $rsync}, 'Remove...')));
}
else
{
print $q->Tr (esmith::cgi::genSmallCell ($q, $desc),
esmith::cgi::genSmallRedCell ($q, $freq),
esmith::cgi::genSmallRedCell ($q, $hour.':'.$min),
esmith::cgi::genSmallCell ($q,
$q->a ({href => $q->url (-absolute => 1)
. "?state=modifyrsync&&rsync="
. $rsync}, 'Modify/Run...')),
esmith::cgi::genSmallCell ($q,
$q->a ({href => $q->url (-absolute => 1)
. "?state=deletersync&&rsync="
. $rsync}, 'Remove...')));
}
}
print '</table>';
print '<br />';
#configure and select set
print $q->h4 ('Transfer Sets Summary - Anonymous rsync retrieve from remote');
print $q->p ($q->a ({href => $q->url (-absolute => 1) . "?state=showAnon&&rsync=new"},
'Click here'),
'to add a transfer set.');
print "<table border=1 cellspacing=1 cellpadding=4>";
#header
print $q->Tr (esmith::cgi::genSmallCell ($q, $q->b ('Description')),
esmith::cgi::genSmallCell ($q, $q->b ('Frequency')),
esmith::cgi::genSmallCell ($q, $q->b ('Time')),
$q->td ('&nbsp;'),
$q->td ('&nbsp;'));
#get rsyncs/shares
my @rsyncAnon = ();
foreach (sort keys %dungog)
{
push (@rsyncAnon, $_)
if (db_get_type(\%dungog, $_) eq "rsyncAnon");
}
$rsync = '';
foreach $rsync (sort @rsyncAnon)
{
my $desc = db_get_prop(\%dungog, $rsync, "desc") || '';
my $freq = db_get_prop(\%dungog, $rsync, "freq") || '';
my $day = db_get_prop(\%dungog, $rsync, "day") || '';
my $hour = db_get_prop(\%dungog, $rsync, "hour") || '';
my $min = db_get_prop(\%dungog, $rsync, "min") || '';
#modify frequency value for display
my $daylabel = ($Labels{$day});
if ($freq eq 'hourly')
{
$hour = '*';
}
elsif ($freq eq 'on')
{
$freq = $daylabel;
}
if ($freq eq 'off')
{
print $q->Tr (esmith::cgi::genSmallCell ($q, $desc),
esmith::cgi::genSmallCell ($q, $freq),
esmith::cgi::genSmallCell ($q, ''),
esmith::cgi::genSmallCell ($q,
$q->a ({href => $q->url (-absolute => 1)
. "?state=showAnon&&rsync="
. $rsync}, 'Modify/Run...')),
esmith::cgi::genSmallCell ($q,
$q->a ({href => $q->url (-absolute => 1)
. "?state=deletersync&&rsync="
. $rsync}, 'Remove...')));
}
else
{
print $q->Tr (esmith::cgi::genSmallCell ($q, $desc),
esmith::cgi::genSmallRedCell ($q, $freq),
esmith::cgi::genSmallRedCell ($q, $hour.':'.$min),
esmith::cgi::genSmallCell ($q,
$q->a ({href => $q->url (-absolute => 1)
. "?state=showAnon&&rsync="
. $rsync}, 'Modify/Run...')),
esmith::cgi::genSmallCell ($q,
$q->a ({href => $q->url (-absolute => 1)
. "?state=deletersync&&rsync="
. $rsync}, 'Remove...')));
}
}
print '</table>';
print '<br />';
#configure and select set
print $q->h4 ('Configure your server as an Anonymous Rsync server');
# check to see if e-smith-rsyncd is installed
# old code - unless ( -e "/etc/e-smith/events/actions/conf-rsyncd" )
# use existing rsync key to decide whether the following section can be configured
# test for rsyncd property
my $rsyncd_status = db_get(\%conf, "rsyncd");
unless ($rsyncd_status ne '')
{
print $q->p (esmith::cgi::genSmallCell ($q, 'To make files available for download by
Anonymous Rsync to you need to install
smeserver-shared-folders, see help below'));
}
else
{
print $q->p ($q->a ({href => $q->url (-absolute => 1) . "?state=showibay"},
'Click here'),
'to view which ibays are setup to allow anonymous rsync
downloads. You can also enable or disable anonymous rsync to your server');
}
print $q->endform;
print $q->p ($q->hr, $q->font ({size => "-1"}, "Copyright dungog.net",
$q->a ({href => $q->url (-absolute => 1) . "?state=help"}, 'Rsync help'), " ..."));
print '</FONT>';
print '</DIV>';
print $q->end_html;
}
# -------------********* secure Sets ***********---------------------------
sub modifyRsync ($$)
{
my ($q, $msg) = @_;
my $rsync = $q->param ('rsync') ||'';
my $editlocaldir = $q->param ('editlocaldir') ||'';
my $editremoteserver = $q->param ('editremoteserver') ||'';
my $editremotedir = $q->param ('editremotedir') ||'';
if ($msg eq '')
{
esmith::cgi::genHeaderNonCacheable
($q, \%conf, 'Modify the selected rsync job.');
}
else
{
esmith::cgi::genHeaderNonCacheable
($q, \%conf, 'Modify the selected rsync job.');
print $q->p ($msg);
print $q->hr;
}
if ($rsync eq 'new')
{
my $random = int(rand(999999));
$rsync = 'rsync'.$random;
}
# find system users
my @userlist = ('');
foreach (keys %accounts)
{
push (@userlist, $_)
if (db_get_type(\%accounts, $_) eq 'user');
}
my $localdirlist = db_get_prop(\%dungog, "$rsync", "localdirlist") || 'none';
my @localdirlist = split(/,/, $localdirlist);
my $remoteserverlist = db_get_prop(\%dungog, "$rsync", "remoteserverlist") || 'none';
my @remoteserverlist = split(/,/, $remoteserverlist);
my $remotedirlist = db_get_prop(\%dungog, "$rsync", "remotedirlist") || 'none';
my @remotedirlist = split(/,/, $remotedirlist);
print $q->startform (-method => 'POST', -action => $q->url (-absolute => 1));
print $q->table ({border => 0, cellspacing => 0, cellpadding => 4},
esmith::cgi::genTextRow ($q, $q->p ($q->a ({href => $q->url (-absolute => 1) . "?state=help"},
'Please review'),
"the help page for explanations and suggestions on how to setup.")),
esmith::cgi::genNameValueRow ($q,
"Description",
"desc",
db_get_prop(\%dungog, $rsync, "desc") || '',),
esmith::cgi::genWidgetRow ($q, "Select a user for rsync to run as",
$q->popup_menu (-name => "user",
-values => [ sort @userlist , 'root' ],
-default => db_get_prop(\%dungog, $rsync, "user") || '')),
esmith::cgi::genWidgetRow ($q, "Method",
$q->popup_menu (-name => "method",
-values => ['senddirs','sendservers','receivedirs','receiveservers','senddirs2self'],
-default => db_get_prop(\%dungog, $rsync, "method") || '',
-labels => \%Labels2)),
esmith::cgi::genWidgetRow ($q, "Options",
$q->popup_menu (-name => "options",
-values => ['test','verbose','stats','quiet'],
-default => db_get_prop(\%dungog, $rsync, "options") || 'test',
-labels => \%Labels5)));
my $delete = db_get_prop(\%dungog, $rsync, "delete") || 'no';
my $tick = '';
if ($delete eq 'on')
{
$tick = "checked";
}
print $q->Tr ($q->td ("<input type=\"checkbox\" name=\"delete\" $tick>"),
esmith::cgi::genTextRow ($q, ('Delete files that do not exist on the sending side. <font color="red">Always use Testing option first.</font>')));
my $compress = db_get_prop(\%dungog, $rsync, "compress") || 'no';
$tick = '';
if ($compress eq 'on')
{
$tick = "checked";
}
print $q->Tr ($q->br);
print $q->Tr ($q->td ("<input type=\"checkbox\" name=\"compress\" $tick>"),
esmith::cgi::genTextRow ($q, ('Compress file data. This option is useful on slow links.')));
my $mail = db_get_prop(\%dungog, $rsync, "mail") || '';
$tick = '';
if ($mail eq 'on')
{
$tick = "checked";
}
print $q->Tr ($q->br);
print $q->Tr ($q->td ("<input type=\"checkbox\" name=\"mail\" $tick>"),
esmith::cgi::genTextRow ($q, ('If automating, email any output to admin.')));
my $dbdump = db_get_prop(\%dungog, $rsync, "dbdump") || '';
$tick = '';
if ($dbdump eq 'on')
{
$tick = "checked";
}
print $q->Tr ($q->br);
print $q->Tr ($q->td ("<input type=\"checkbox\" name=\"dbdump\" $tick>"),
esmith::cgi::genTextRow ($q, ('Include mysql tables in your transfer -
requires you to send the dir /home/e-smith/db/mysql or a parent dir.')));
print $q->p (esmith::cgi::genWidgetRow ($q, "Limit I/O bandwidth, KBytes per second",
$q->popup_menu (-name => 'bwlimit',
-values => ['none','10','25','50','100','500','1000','2000','4000','6000','10000','20000'],
-default => db_get_prop(\%dungog, $rsync, "bwlimit") || 'none',
-labels => \%Labels4)));
print $q->table ({border => 0, cellspacing => 0, cellpadding => 4},
esmith::cgi::genTextRow ($q, ("Create /opt/$rsync.ex and/or /opt/$rsync.in
to exclude or include directories or files from this rsync job,
see help below. If either file exists the options are added into the script below after a panel save.")),
esmith::cgi::genTextRow ($q, ('To run a command or shell script before or after the
rsync job enter the command below. Leave blank for no command.')),
esmith::cgi::genNameValueRow ($q,
"Pre rsync command, eg, /usr/bin/moveaway",
"pre",
db_get_prop(\%dungog, $rsync, "pre") || '',),
esmith::cgi::genNameValueRow ($q,
"Post rsync command, eg, /usr/bin/moveback",
"post",
db_get_prop(\%dungog, $rsync, "post") || '',),
esmith::cgi::genTextRow ($q, $q->p ("<b>Local server - $conf{SystemName}.$conf{DomainName}</b>")),
#local directory
esmith::cgi::genTextRow ($q, $q->p ("<b>Local directory</b>")));
print "<table border=1 cellspacing=1 cellpadding=4>";
foreach (sort @localdirlist)
{
print $q->Tr (esmith::cgi::genSmallCell ($q, $_),
esmith::cgi::genSmallCell ($q,
$q->a ({href => $q->url (-absolute => 1)
. "?state=modifyrsync&&rsync=$rsync&&editlocaldir="
. $_}, 'Copy & Edit... ')),
esmith::cgi::genSmallCell ($q,
$q->a ({href => $q->url (-absolute => 1)
. "?state=deleteitem&&type=localdir&&rsync=$rsync&&item="
. $_}, 'Remove...')));
}
print '</table>';
print $q->table ({border => 0, cellspacing => 0, cellpadding => 4},
esmith::cgi::genNameValueRow ($q,
"add directory, eg,/home/e-smith/files/ibays/vital",
"localdir",
"$editlocaldir",),
#remote servers
esmith::cgi::genTextRow ($q, $q->p ('<b>Remote user@server</b> user is required. Can be different to local user<br />
See Help - Changing the port for using different ports')));
print $q->table ({border => 1, cellspacing => 1, cellpadding => 4});
foreach (sort @remoteserverlist)
{
print $q->Tr (esmith::cgi::genSmallCell ($q, $_),
esmith::cgi::genSmallCell ($q,
$q->a ({href => $q->url (-absolute => 1)
. "?state=modifyrsync&&rsync=$rsync&&editremoteserver="
. $_}, 'Copy & Edit... ')),
esmith::cgi::genSmallCell ($q,
$q->a ({href => $q->url (-absolute => 1)
. "?state=deleteitem&&type=remoteserver&&rsync=$rsync&&item="
. $_}, 'Remove...')));
}
print '</table>';
print $q->table ({border => 0, cellspacing => 0, cellpadding => 4},
esmith::cgi::genNameValueRow ($q,
"add server",
"remoteserver",
"$editremoteserver",),
#remote directory
esmith::cgi::genTextRow ($q, $q->p ('<b>Remote directory</b>')));
print $q->table ({border => 1, cellspacing => 1, cellpadding => 4});
foreach (sort @remotedirlist)
{
print $q->Tr (esmith::cgi::genSmallCell ($q, $_),
esmith::cgi::genSmallCell ($q,
$q->a ({href => $q->url (-absolute => 1)
. "?state=modifyrsync&&rsync=$rsync&&editremotedir="
. $_}, 'Copy & Edit... ')),
esmith::cgi::genSmallCell ($q,
$q->a ({href => $q->url (-absolute => 1)
. "?state=deleteitem&&type=remotedir&&rsync=$rsync&&item="
. $_}, 'Remove...')));
}
print '</table>';
print $q->table ({border => 0, cellspacing => 0, cellpadding => 4},
esmith::cgi::genNameValueRow ($q,
"add directory",
"remotedir",
"$editremotedir",));
#extra table just to align fields better
print '</table>';
print $q->table ({border => 0, cellspacing => 0, cellpadding => 4},
#time for automation
#esmith::cgi::genTextRow ($q, $q->p ('<b>Timing</b>')),
esmith::cgi::genTextRow ($q, $q->p ('Select the time and enable to automate<br>
Alternatively add this job to cron using the Cron panel, the command to give is <br>
'."/usr/bin/dungogrsync-$rsync")),
esmith::cgi::genWidgetRow ($q, "Automatic backups",
$q->popup_menu (-name => 'freq',
-values => ['off','on','hourly'] ,
-default => db_get_prop(\%dungog, $rsync, "freq") || 'off',)),
esmith::cgi::genWidgetRow ($q, "Backup time, minute",
$q->popup_menu (-name => 'min',
-values => ['1','4','7','10','13','16','19','22','25','28','31','33','36','39','42','45','48','51','54','57','59'] ,
-default => db_get_prop(\%dungog, $rsync, "min") || '16',)),
esmith::cgi::genWidgetRow ($q, "Backup time, 24 hour",
$q->popup_menu (-name => 'hour',
-values => ['*/2','*/4','*/8','*/12','8-18','9-17','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22','23'] ,
-default => db_get_prop(\%dungog, $rsync, "hour") || '3',
-labels => \%Labels3)),
esmith::cgi::genWidgetRow ($q, "Backup time, day of week",
$q->popup_menu (-name => 'day',
-values => ['*','1-5','0,6','sun','1','2','3','4','5','6'] ,
-default => db_get_prop(\%dungog, $rsync, "day") || '4',
-labels => \%Labels)));
print $q->Tr (esmith::cgi::genButtonRow ($q,
$q->submit (-name => 'action', -value => 'Save Settings')));
print $q->Tr (esmith::cgi::genTextRow ($q, $q->p ('After saving your settings
you can run the backup immediately by clicking below.
You should also save after creating or deleting includes or excludes
or relevant db commands eg override allow')));
print $q->Tr (esmith::cgi::genButtonRow ($q,
$q->submit (-name => 'action', -value => 'Run this rsync job now')));
if ( -e "/usr/bin/dungogrsync-$rsync" )
{
print $q->h4 ("Current rsync script file - /usr/bin/dungogrsync-$rsync");
print "<table border=1 cellspacing=1 cellpadding=4>";
print '<font color = "green">';
print "<pre>";
open (INF,"/usr/bin/dungogrsync-$rsync")
or die ("can't open rsync script: $1");
while (<INF>)
{
print "$_";
}
close INF;
print "</pre>\n";
}
print '</font>';
print '<font color = "black">';
print $q->hidden (-name => 'state', -override => 1, -default => 'choosesub');
print $q->hidden (-name => 'rsync', -override => 1, -default => $rsync);
print $q->endform;
print $q->p ($q->hr, $q->font ({size => "-1"}, "Copyright dungog.net",
$q->a ({href => $q->url (-absolute => 1) . "?state=help"}, 'Rsync help'), " ..."));
print '</FONT>';
print '</DIV>';
print $q->end_html;
}
sub performModifyRsync ($)
{
my ($q) = @_;
my $rsync = $q->param ('rsync');
my $desc = $q->param ('desc') || '';
my $method = $q->param ('method') || '';
my $options = $q->param ('options') || '';
my $delete = $q->param ('delete') || '';
my $compress = $q->param ('compress') || '';
my $mail = $q->param ('mail') || '';
my $dbdump = $q->param ('dbdump') || '';
my $pre = $q->param ('pre') || '';
my $post = $q->param ('post') || '';
my $user = $q->param ('user') || '';
my $localdir = $q->param ('localdir') || '';
my $remoteserver = $q->param ('remoteserver')|| '';
my $remotedir = $q->param ('remotedir') || '';
my $freq = $q->param ('freq') || '';
my $hour = $q->param ('hour') || '';
my $min = $q->param ('min') || '';
my $day = $q->param ('day') || '';
my $bwlimit = $q->param ('bwlimit') || '';
if ($rsync =~ /^([a-z][\-\_\.a-z0-9]*)$/)
{
$rsync = $1;
}
#check for invalid characters
foreach ($localdir, $remoteserver, $remotedir)
{
if ($_ =~ /^([\/\-\_\.\ \"\@A-Za-z0-9]*)$/)
{
$_ = $1;
}
else
{
modifyRsync ($q, "Error: You have invalid characters [$_], use only /\-\_\.A-Za-z0-9");
return;
}
}
#test that non blank entries are directories or files, then add to $localdirlist
if ( $localdir ne '' )
{
my $test = $localdir;
$test =~ s/"//g;
unless ( -e $test )
{
modifyRsync ($q, "Error, local server directory or file does not exist. [$test]");
return;
}
else
{
my $localdirlist = db_get_prop(\%dungog, $rsync, "localdirlist");
db_set_prop(\%dungog, $rsync, "localdirlist", "$localdir,$localdirlist");
}
}
#add non blank entries to $remoteserverlist
if ( $remoteserver ne '' )
{
my $remoteserverlist = db_get_prop(\%dungog, $rsync, "remoteserverlist");
db_set_prop(\%dungog, $rsync, "remoteserverlist", "$remoteserver,$remoteserverlist");
}
#add non blank entries to $remotedirlist
if ( $remotedir ne '' )
{
my $remotedirlist = db_get_prop(\%dungog, $rsync, "remotedirlist");
db_set_prop(\%dungog, $rsync, "remotedirlist", "$remotedir,$remotedirlist");
}
unless (exists $dungog {$rsync})
{
db_set(\%dungog, $rsync, 'rsync');
}
db_set_prop(\%dungog, $rsync, "desc", $desc);
db_set_prop(\%dungog, $rsync, "method", $method);
db_set_prop(\%dungog, $rsync, "options", $options);
db_set_prop(\%dungog, $rsync, "delete", $delete);
db_set_prop(\%dungog, $rsync, "compress", $compress);
db_set_prop(\%dungog, $rsync, "user", $user);
db_set_prop(\%dungog, $rsync, "mail", $mail);
db_set_prop(\%dungog, $rsync, "dbdump", $dbdump);
db_set_prop(\%dungog, $rsync, "pre", $pre);
db_set_prop(\%dungog, $rsync, "post", $post);
db_set_prop(\%dungog, $rsync, "freq", $freq);
db_set_prop(\%dungog, $rsync, "day", $day);
db_set_prop(\%dungog, $rsync, "hour", $hour);
db_set_prop(\%dungog, $rsync, "min", $min);
db_set_prop(\%dungog, $rsync, "bwlimit", $bwlimit);
system ("/sbin/e-smith/signal-event conf-dungogrsync $rsync") == 0
or die ("Error occurred while updating system configuration.\n");
system ("/sbin/e-smith/expand-template /etc/crontab") == 0
or die ("Error occurred expanding crontab.\n");
modifyRsync ($q, 'settings saved');
return;
}
# -------------********* secure Sets ***********---------------------------
sub showAnon ($$)
{
my ($q, $msg) = @_;
my $rsync = $q->param ('rsync') ||'';
if ($msg eq '')
{
esmith::cgi::genHeaderNonCacheable
($q, \%conf, 'Modify the selected rsync job.');
}
else
{
esmith::cgi::genHeaderNonCacheable
($q, \%conf, 'Modify the selected rsync job.');
print $q->p ($msg);
print $q->hr;
}
if ($rsync eq 'new')
{
my $random = int(rand(999999));
$rsync = 'rsync'.$random;
}
print $q->startform (-method => 'POST', -action => $q->url (-absolute => 1));
print $q->table ({border => 0, cellspacing => 0, cellpadding => 4},
esmith::cgi::genTextRow ($q, $q->p ('<b>General</b>')),
esmith::cgi::genTextRow ($q, $q->p ('This form allows you to mirror a set of files from a remote
server to your local server, when the remote files are being made
available with a rsync server.')),
esmith::cgi::genNameValueRow ($q,
"Description",
"desc",
db_get_prop(\%dungog, $rsync, "desc") || '',),
esmith::cgi::genWidgetRow ($q, "Options",
$q->popup_menu (-name => "options",
-values => ['test','verbose','stats','quiet'],
-default => db_get_prop(\%dungog, $rsync, "options") || 'stats',
-labels => \%Labels5)));
my $compress = db_get_prop(\%dungog, $rsync, "compress") || 'no';
my $tick = '';
if ($compress eq 'on')
{
$tick = "checked";
}
print $q->Tr ($q->br);
print $q->Tr ($q->td ("<input type=\"checkbox\" name=\"compress\" $tick>"),
esmith::cgi::genTextRow ($q, ('Compress file data, This option is useful on slow links.')));
my $mail = db_get_prop(\%dungog, $rsync, "mail") || '';
$tick = '';
if ($mail eq 'on')
{
$tick = "checked";
}
print $q->Tr ($q->br);
print $q->Tr ($q->td ("<input type=\"checkbox\" name=\"mail\" $tick>"),
esmith::cgi::genTextRow ($q, ('If automating, email any output to admin.')));
print $q->p (esmith::cgi::genWidgetRow ($q, "limit I/O bandwidth, KBytes per second",
$q->popup_menu (-name => 'bwlimit',
-values => ['none','1','2.5','5','10','25','50','100','1000'],
-default => db_get_prop(\%dungog, $rsync, "bwlimit") || 'none',
-labels => \%Labels4)));
print $q->Tr ($q->br);
print $q->Tr (esmith::cgi::genTextRow ($q, $q->p ('<b>Locations</b>')));
#remote server
print $q->Tr (esmith::cgi::genTextRow ($q, $q->p ('The remote server is the source you will be mirroring,
it will be in the form domain.dom::directory')));
print $q->Tr (esmith::cgi::genNameValueRow ($q,
"Remote server and directory",
"remoteserver",
db_get_prop(\%dungog, $rsync, "remoteserver") || '',));
print $q->Tr (esmith::cgi::genTextRow ($q, $q->p ('The local directory is the destination for the copy
enter an existing directory on your local server,
eg. /home/e-smith/files/ibays/anibay/files/data')));
#local directory
print $q->Tr (esmith::cgi::genNameValueRow ($q,
"Local directory",
"localdir",
db_get_prop(\%dungog, $rsync, "localdir") || '',));
#extra table just to align fields better
print '</table>';
print $q->table ({border => 0, cellspacing => 0, cellpadding => 4},
#time for automation
#esmith::cgi::genTextRow ($q, $q->p ('<b>Timing</b>')),
esmith::cgi::genTextRow ($q, $q->p ('Select the time, and day or days to run.
Hourly runs each hour at the nominated minutes past the hour.
Enabling automatic backups by selecting on,
allows you to choose which days to run.')),
esmith::cgi::genWidgetRow ($q, "Automatic backups",
$q->popup_menu (-name => 'freq',
-values => ['off','on','hourly'] ,
-default => db_get_prop(\%dungog, $rsync, "freq") || 'off',)),
esmith::cgi::genWidgetRow ($q, "Backup time, minute",
$q->popup_menu (-name => 'min',
-values => ['1','4','7','10','13','16','19','22','25','28','31','33','36','39','42','45','48','51','54','57','59'] ,
-default => db_get_prop(\%dungog, $rsync, "min") || '16',)),
esmith::cgi::genWidgetRow ($q, "Backup time, 24 hour",
$q->popup_menu (-name => 'hour',
-values => ['1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22','23'] ,
-default => db_get_prop(\%dungog, $rsync, "hour") || '3',
-labels => \%Labels3)),
esmith::cgi::genWidgetRow ($q, "Backup time, day of week",
$q->popup_menu (-name => 'day',
-values => ['*','1-5','0,6','sun','1','2','3','4','5','6'] ,
-default => db_get_prop(\%dungog, $rsync, "day") || '4',
-labels => \%Labels)),
esmith::cgi::genTextRow ($q, $q->p ('Click Save to enable the above settings')));
print $q->Tr (esmith::cgi::genButtonRow ($q,
$q->submit (-name => 'action', -value => 'Save Job')));
print $q->Tr (esmith::cgi::genTextRow ($q, $q->p ('After saving your settings
you can run the backup immediately by clicking below.')));
print $q->Tr (esmith::cgi::genButtonRow ($q,
$q->submit (-name => 'action', -value => 'Run this rsync job now')));
print $q->h4 ('Current rsync script file');
if ( -e "/usr/bin/dungogrsync-$rsync" )
{
print "<table border=1 cellspacing=1 cellpadding=4>";
print '<font color = "green">';
print "<pre>";
open (INF,"/usr/bin/dungogrsync-$rsync")
or die ("can't open rsync script: $1");
while (<INF>)
{
print "$_";
}
close INF;
print "</pre>\n";
}
print '</font>';
print '<font color = "black">';
print $q->hidden (-name => 'state', -override => 1, -default => 'choosesub');
print $q->hidden (-name => 'rsync', -override => 1, -default => $rsync);
print $q->endform;
print $q->p ($q->hr, $q->font ({size => "-1"}, "Copyright dungog.net",
$q->a ({href => $q->url (-absolute => 1) . "?state=help"}, 'Rsync help'), " ..."));
print '</FONT>';
print '</DIV>';
print $q->end_html;
}
sub performShowAnon ($)
{
my ($q) = @_;
my $rsync = $q->param ('rsync');
my $desc = $q->param ('desc') || '';
my $options = $q->param ('options') || '';
my $compress = $q->param ('compress') || '';
my $mail = $q->param ('mail') || '';
my $localdir = $q->param ('localdir') || '';
my $remoteserver = $q->param ('remoteserver')|| '';
my $freq = $q->param ('freq') || '';
my $hour = $q->param ('hour') || '';
my $min = $q->param ('min') || '';
my $day = $q->param ('day') || '';
my $bwlimit = $q->param ('bwlimit') || '';
if ($rsync =~ /^([a-z][\-\_\.a-z0-9]*)$/)
{
$rsync = $1;
}
if ($desc =~ /^([a-z][\-\_\.a-z0-9]*)$/)
{
$desc = $1;
}
unless (exists $dungog {$rsync})
{
db_set(\%dungog, $rsync, 'rsyncAnon');
}
db_set_prop(\%dungog, $rsync, "desc", $desc);
db_set_prop(\%dungog, $rsync, "options", $options);
db_set_prop(\%dungog, $rsync, "compress", $compress);
db_set_prop(\%dungog, $rsync, "mail", $mail);
db_set_prop(\%dungog, $rsync, "freq", $freq);
db_set_prop(\%dungog, $rsync, "day", $day);
db_set_prop(\%dungog, $rsync, "hour", $hour);
db_set_prop(\%dungog, $rsync, "min", $min);
db_set_prop(\%dungog, $rsync, "bwlimit", $bwlimit);
#check for invalid characters
if ($remoteserver =~ /^([\/\-\_\.A-Za-z0-9]*::[\/\-\_\.A-Za-z0-9]*)$/)
{
$_ = $1;
}
else
{
showAnon ($q, "Error: You have invalid characters for the remote server [$remoteserver], ".
"use only /\-\_\.A-Za-z0-9 with the domain and directory separated by ::");
return;
}
db_set_prop(\%dungog, $rsync, "remoteserver", $remoteserver);
if ($localdir =~ /^([\/\-\_\.A-Za-z0-9]*)$/)
{
$_ = $1;
}
else
{
showAnon ($q, "Error: You have invalid characters in the local directory [$localdir], use only /\-\_\.A-Za-z0-9");
return;
}
#test that local directory exists
unless ( -e "$localdir" )
{
showAnon ($q, "Error, local server directory does not exist. [$localdir]");
return;
}
db_set_prop(\%dungog, $rsync, "localdir", $localdir);
system ("/sbin/e-smith/signal-event conf-dungogrsyncanon $rsync") == 0
or die ("Error occurred while updating system configuration.\n");
system ("/sbin/e-smith/expand-template /etc/crontab") == 0
or die ("Error occurred expanding crontab.\n");
showAnon ($q, 'settings saved');
return;}
# ------------- ibay anon setup ------------------------
sub showIbay ($$)
{
my ($q, $msg) = @_;
if ($msg eq '')
{
esmith::cgi::genHeaderNonCacheable
($q, \%conf, 'Anonymous Rsync');
}
else
{
esmith::cgi::genHeaderNonCacheable
($q, \%conf, 'Anonymous Rsync');
print $q->h4 ('Operation status report');
print $q->p ($msg);
print $q->hr;
}
print $q->startform (-method => 'POST', -action => $q->url (-absolute => 1));
#configure and select set
print $q->h4 ('Shared Folders');
# setup ibays to be used for anonymous ibay
my @ibayAccounts = ();
foreach (sort keys %accounts)
{
push (@ibayAccounts, $_)
if (db_get_type(\%accounts, $_) eq "share");
}
unless (scalar @ibayAccounts)
{
print $q->p ($q->b ('There are no shared folders in the system.'));
}
else
{
#short intro
print $q->p ($q->p ('<font style color="red">This is not fully functioning currently.</font></br>
Shared Folders shown in red have Global Access set to <br />
<p>Use the <a href=shares>Shared Folders</a> panel for finer control</P>'));
unless ( -e '/etc/rsyncd.conf')
{
print $q->p ($q->p ('This is not fully functioning currently.<br>
It requires smeserver-shared-folders to enable rsyncd<br>
Work still required.'
));
}
print $q->p ($q->a ({href => $q->url (-absolute => 1) . "?state=recentRsync"},
'Click here'),
'to view logs of recent access to your rsync server.');
print "<table border=1 cellspacing=1 cellpadding=4>";
print $q->Tr (esmith::cgi::genSmallCell ($q, $q->b ('Name')),
esmith::cgi::genSmallCell ($q, $q->b ('Description')),
esmith::cgi::genSmallCell ($q, $q->b ('Status')),
esmith::cgi::genSmallCell ($q, $q->b ('Modify'))
);
my $ibay = '';
foreach $ibay (sort @ibayAccounts)
{
unless ($ibay eq 'Primary')
{
my $name = db_get_prop(\%accounts, "$ibay", 'Name') || '';
my $rsyncAccess = db_get_prop(\%accounts, "$ibay", "rsyncAccess") || '';
# vvv This whole section can probably go unless we want to set perms on a shared folder
# my $PublicAccess = db_get_prop(\%accounts, "$ibay", "PublicAccess") || '';
# my $Group = db_get_prop(\%accounts, "$ibay", "Group") || '';
# my $UserAccess = db_get_prop(\%accounts, "$ibay", "UserAccess") || '';
# my $perms ='check';
# if ($UserAccess eq 'wr-group-rd-everyone')
# {
# $perms = 'ok';
# }
# elsif ($Group eq 'shared')
# {
# $perms = 'ok';
# }
# ^^^ To here
# Not sure about this - we should be able to toggle access for each share
print "<br />";
unless ($rsyncAccess eq 'global')
{
print $q->Tr (esmith::cgi::genSmallCell ($q, $ibay),
esmith::cgi::genSmallCell ($q, $name),
esmith::cgi::genSmallCell ($q, $rsyncAccess),
esmith::cgi::genSmallCell ($q,
$q->a ({href => $q->url (-absolute => 1)
. "?state=modifyibay&&rsyncAccess=global&share="
. $ibay}, 'Set Global...')));
}
else
{
print $q->Tr (esmith::cgi::genSmallRedCell ($q, $ibay),
esmith::cgi::genSmallRedCell ($q, $name),
esmith::cgi::genSmallRedCell ($q, $rsyncAccess),
esmith::cgi::genSmallCell ($q,
$q->a ({href => $q->url (-absolute => 1)
. "?state=modifyibay&&rsyncAccess=local&share="
. $ibay}, 'Set Local...')));
}
}
}
print '</table>';
}
# enable/disable rsyncd
print $q->h4 ('Status');
print $q->p ($q->p ('Disable or enable access to files on your server via Anonymous Rsync'));
print $q->p (esmith::cgi::genWidgetRow ($q, "Anonymous Rsyncd",
$q->popup_menu (-name => 'status',
-values => ['enabled','disabled'],
-default => db_get_prop(\%conf, 'rsyncd', 'status') || 'disabled')));
print $q->p (esmith::cgi::genButtonRow ($q,
$q->submit (-name => 'action',
-value => 'Save')));
print $q->hidden (-name => 'state',
-override => 1,
-default => 'performAnon');
print $q->endform;
print $q->p ($q->hr, $q->font ({size => "-1"}, "Copyright dungog.net",
$q->a ({href => $q->url (-absolute => 1) . "?state=help"}, 'Rsync help'), " ..."));
print '</FONT>';
print '</DIV>';
print $q->end_html;
}
sub modifyIbay ($)
{
my ($q) = @_;
my $ibay = $q->param ('share') ||'';
my $rsyncAccess = $q->param ('rsyncAccess') ||'local';
if ($ibay =~ /^([a-z][\-\_\.a-z0-9]*)$/)
{
$ibay = $1;
}
db_set_prop(\%accounts, $ibay, "rsyncAccess", $rsyncAccess);
system ("/sbin/e-smith/signal-event share-modify $ibay") == 0
or die ("Error occurred :signal-event share-modify.\n");
showIbay ($q, "Successfully modified Shared Folder.");
}
#ibay anon
sub performAnon ($)
{
my ($q) = @_;
my $status = $q->param ('status') ||'';
if ($status =~ /^([a-z][\-\_\.a-z0-9]*)$/)
{
$status = $1;
}
unless (exists $conf {'rsyncd'})
{
db_set(\%conf, 'rsyncd', 'service');
}
db_set_prop(\%conf, 'rsyncd', 'status', $status);
if ($status eq'enabled') {
db_set_prop(\%conf, 'rsyncd', 'access', 'public');
}
else {
db_set_prop(\%conf, 'rsyncd', 'access', 'private');
}
system ("/sbin/e-smith/expand-template /etc/rsyncd.conf") == 0
or die ("Error occurred :expand-template /etc/rsyncd.conf.\n");
system ("/sbin/e-smith/signal-event remoteaccess-update") == 0
or die ("Error occurred :signal-event remoteaccess-update.\n");
showIbay ($q, "Successfully altered status.");
}
sub deleteRsync ($)
{
my ($q) = @_;
my $rsync = $q->param ('rsync') ||'';
if ($rsync =~ /^([a-z][\-\_\.a-z0-9]*)$/)
{
$rsync = $1;
}
db_delete(\%dungog, "$rsync");
system ("/sbin/e-smith/signal-event conf-dungogrsync $rsync") == 0
or die ("Error occurred :conf-dungogrsync $rsync.\n");
system ("/bin/rm /usr/bin/dungogrsync-$rsync") == 0
or die ("Error occurred :rm /usr/bin/dungogrsync.\n");
showInitial ($q, "Successfully removed rsync job.");
}
sub deleteItem ($)
{
my ($q) = @_;
my $type = $q->param ('type') ||'';
my $item = $q->param ('item') ||'';
my $rsync = $q->param ('rsync') ||'';
my @add = ();
my @list = ();
if ($rsync =~ /^([a-z][\-\_\.a-z0-9]*)$/)
{
$rsync = $1;
}
if ($type eq 'localdir')
{
my $localdirlist = db_get_prop(\%dungog, "$rsync", "localdirlist") || 'none';
my @localdirlist = split(/,/, $localdirlist);
foreach (@localdirlist)
{
unless ($_ eq $item) { push(@add, "$_") }
@list = join(',', @add);
}
db_set_prop(\%dungog, $rsync, "localdirlist", "@list");
}
if ($type eq 'remoteserver')
{
my $remoteserverlist = db_get_prop(\%dungog, "$rsync", "remoteserverlist") || 'none';
my @remoteserverlist = split(/,/, $remoteserverlist);
foreach (@remoteserverlist)
{
unless ($_ eq $item) { push(@add, "$_") }
@list = join(',', @add);
}
db_set_prop(\%dungog, $rsync, "remoteserverlist", "@list");
}
if ($type eq 'remotedir')
{
my $remotedirlist = db_get_prop(\%dungog, "$rsync", "remotedirlist") || 'none';
my @remotedirlist = split(/,/, $remotedirlist);
foreach (@remotedirlist)
{
unless ($_ eq $item) { push(@add, "$_") }
@list = join(',', @add);
}
db_set_prop(\%dungog, $rsync, "remotedirlist", "@list");
}
system ("/sbin/e-smith/signal-event conf-dungogrsync $rsync") == 0
or die ("Error occurred while updating system configuration.\n");
system ("/sbin/e-smith/expand-template /etc/crontab") == 0
or die ("Error occurred expanding crontab.\n");
modifyRsync ($q, "Settings saved, $item removed");
}
#backup now any backupset
sub performRsyncNow ($)
{
my ($q) = @_;
my $rsync = $q->param ('rsync');
my $user = $q->param ('user');
if ($rsync =~ /^([a-z][\-\_\.a-z0-9]*)$/)
{
$rsync = $1;
}
if ($user =~ /^([a-z][\-\_\.a-z0-9]*)$/)
{
$user = $1;
}
esmith::util::backgroundCommand (1, "/sbin/e-smith/signal-event", "run-rsync", "$rsync", "$user");
esmith::cgi::genHeaderNonCacheable
($q, \%conf, "Backup request initiated.");
print $q->p ($q->a ({href => $q->url (-absolute => 1) . "?state=rsyncNowResults"},
'Click here'),
'for progressive information on the transfer.');
print $q->endform;
print $q->p ($q->hr, $q->font ({size => "-1"}, "Copyright dungog.net",
$q->a ({href => $q->url (-absolute => 1) . "?state=help"}, 'Rsync help'), " ..."));
print '</FONT>';
print '</DIV>';
print $q->end_html;
}
sub rsyncNowResults ($)
{
my ($q) = @_;
esmith::cgi::genHeaderNonCacheable
($q, \%conf, "Backup request initiated.");
print $q->startform (-method => 'POST', -action => $q->url (-absolute => 1));
print $q->h4 ('Current rsync activity file');
print $q->p ($q->a ({href => $q->url (-absolute => 1) . "?state=rsyncNowResults"},
'Click here'),
'to refresh this page for progessive information.');
if ( -e "/var/log/dungogrsyncnow" )
{
print "<table border=1 cellspacing=1 cellpadding=4>";
print '<font color = "green">';
print "<pre>";
open (INF,"/var/log/dungogrsyncnow")
or die ("can't open rsync log file: $1");
while (<INF>)
{
print "$_";
}
close INF;
print "</pre>\n";
}
print '</font>';
print '<font color = "black">';
print $q->endform;
print $q->p ($q->hr, $q->font ({size => "-1"}, "Copyright dungog.net",
$q->a ({href => $q->url (-absolute => 1) . "?state=help"}, 'Rsync help'), " ..."));
print '</FONT>';
print '</DIV>';
print $q->end_html;
}
sub recentRsync ($)
{
my ($q) = @_;
esmith::cgi::genHeaderNonCacheable
($q, \%conf, "Recent rsync activity");
system ("/bin/cat /var/log/messages |/bin/grep rsyncd > /tmp/recentrsync") == 0
or die ("Error occurred viewing usage.\n");
print $q->startform (-method => 'POST', -action => $q->url (-absolute => 1));
if ( -e "/tmp/recentrsync" )
{
print "<table border=1 cellspacing=1 cellpadding=4>";
print '<font color = "green">';
print "<pre>";
open (INF,"/tmp/recentrsync")
or die ("can't open rsync log file: $1");
while (<INF>)
{
print "$_";
}
close INF;
print "</pre>\n";
}
print '</font>';
print '<font color = "black">';
print $q->endform;
print $q->p ($q->hr, $q->font ({size => "-1"}, "Copyright dungog.net",
$q->a ({href => $q->url (-absolute => 1) . "?state=help"}, 'Rsync help'), " ..."));
print '</FONT>';
print '</DIV>';
print $q->end_html;
}
sub showHelp ($)
{
my ($q) = @_;
esmith::cgi::genHeaderNonCacheable
($q, \%conf, 'Rsync Help');
print $q->startform (-method => 'POST',
-action => $q->url (-absolute => 1));
print $q->table ({border => 0, cellspacing => 0, cellpadding => 4},
esmith::cgi::genTextRow ($q, $q->p ('<pre>
* <a href="#1">General</a>
* <a href="#2">Secure rsync</a>
* <a href="#2s">SSH keys</a>
* <a href="#3port">Changing the port</a>
* <a href="#3">Rsync Anonymous server</a>
* <a href="#4">Rsync Anonymous client</a>
* <a href="#5">Exclude / Include syntax</a>
* <a href="#6">Advanced</a>
<a name="1"><h3>General</h3></a>
Transfer files between your sme server and other servers with ssh and rsync installed.
Automate the process using a secure ssh connection.
Distribute to or collect data from other servers automatically.
<a name="2"><h3>Secure rsync</h3></a>
<b>Safeguards</b>
To prevent server resources being overused only one rsync job is
permitted to run at once, this can be overridden with the db command
db dungog setprop rsync overlap allow
Emails to admin warn of this and other errors, and advise of success, please check for them.
<b>Method</b>
For multiple directory or server transfers it could get very confusing,
so only enter multiple entries for one catagory, if you enter extra entries
only one is used. See the advanced section below for workarounds
<b>Notes</b>
You can transfer a single file instead of a directory.
Enclose directories or filenames that include spaces with a double quote
Save the panel settings in stages, it is frustrating to have to re-enter data
when you get an error becasue your local path/filename is wrong
Remember to remove the extra server or directory record after using the copy&Edit... link
Rsync will attempt to transfer data at the I/O bandwith rate,
the actual rate depends on network traffic and hardware
<a name="2s"><h3>SSH Keys</h3></a>
To automate the transfer you need to establish a secure connection
without being prompted for a password. To connect with ssh to the user
on a remote server you need to place the public key of whichever user
you are using on this server into ~/.ssh/authorized_keys on the remote user/server.
cd /home/e-smith/files/users/dummy/.ssh
ssh-keygen -t rsa [accept file name id_rsa][don\'t enter a passphrase]
ssh dummy@remote-server.net mkdir .ssh
scp id_rsa.pub dummy@remote-server.net:.ssh/dummy.localserver.pub
ssh dummy@remote-server.net
cd .ssh
cat dummy.localserver.pub >> authorized_keys
[or for the first key
scp id_rsa.pub dummy@remote-server.net:.ssh/authorized_keys ]
now you should be able to "ssh dummy@remote-server.net" without a passord prompt
<a name="3port"><h3>Changing the port</h3></a> to connect to a remote server
dungog-rsync and dungog-backup
can use a db setting to find the ssh port of your remote servers
set the port for any server with the following commands
run this once
# /sbin/e-smith/db dungog set remoteport setting
then for each server add a matching server entry
# /sbin/e-smith/db dungog setprop remoteport root@mail.server2.com 2211
verify
# /sbin/e-smith/db dungog show remoteport
remoteport=setting
root@mail.server2.com=2211
root@www.server3.com=2212
<a name="3"><h3>Rsync Anonymous server TODO</h3></a>
Highly experimental - do not use
This used to require e-smith-rsyncd but you can now get rsyncd
functionality via the smeserver-shared-folders contrib
To make files available for download by Anonymous Rsync you place them
in the files directory of an ibay and make it globally accesable.
The panel shows which servers have the correct settings and warns of
possible errors in permissions. It has an option to enable or disable
anonymous rsync access.
<a name="4"><h3>Rsync Anonymous client</h3></a>
Used to pull files from an anonymous rsync server
<a name="5"><h3>Exclude / Include syntax</h3></a>
here is a simple example
# cat /opt/rsync55622.ex
/home/e-smith/files/ibays/backup/
*.bak
Note. the exlude file is matched first
From man rsync
--exclude-from=FILE
This option allows you to selectively exclude cer-
tain files from the list of files to be trans-
ferred. This is most useful in combination with a
recursive transfer.
This option adds all exclude patterns listed in the
file FILE to the exclude list. Blank lines in FILE
and lines starting with ";" or "#" are ignored. If
FILE is - the list will be read from standard
input.
EXCLUDE PATTERNS
The exclude and include patterns specified to rsync allow
for flexible selection of which files to transfer and
which files to skip.
rsync builds an ordered list of include/exclude options as
specified on the command line. When a filename is encoun-
tered, rsync checks the name against each exclude/include
pattern in turn. The first matching pattern is acted on.
If it is an exclude pattern, then that file is skipped. If
it is an include pattern then that filename is not
skipped. If no matching include/exclude pattern is found
then the filename is not skipped.
Note that when used with -r (which is implied by -a),
every subcomponent of every path is visited from top down,
so include/exclude patterns get applied recursively to
each subcomponent.
The patterns can take several forms. The rules are:
o if the pattern starts with a / then it is matched
against the start of the filename, otherwise it is
matched against the end of the filename. Thus
"/foo" would match a file called "foo" at the base
of the tree. On the other hand, "foo" would match
any file called "foo" anywhere in the tree because
the algorithm is applied recursively from top down;
it behaves as if each path component gets a turn at
being the end of the file name.
o if the pattern ends with a / then it will only
match a directory, not a file, link or device.
o if the pattern contains a wildcard character from
the set *?[ then expression matching is applied
using the shell filename matching rules. Otherwise
a simple string match is used.
o if the pattern includes a double asterisk "**" then
all wildcards in the pattern will match slashes,
otherwise they will stop at slashes.
o if the pattern contains a / (not counting a trail-
ing /) then it is matched against the full file-
name, including any leading directory. If the pat-
tern does not contain a / then it is matched only
against the final component of the filename.
Again, remember that the algorithm is applied
recursively so "full filename" can actually be any
portion of a path.
o if the pattern starts with "+ " (a plus followed by
a space) then it is always considered an include
pattern, even if specified as part of an exclude
option. The "+ " part is discarded before matching.
o if the pattern starts with "- " (a minus followed
by a space) then it is always considered an exclude
pattern, even if specified as part of an include
option. The "- " part is discarded before matching.
o if the pattern is a single exclamation mark ! then
the current include/exclude list is reset, removing
all previously defined patterns.
The +/- rules are most useful in exclude lists, allowing
you to have a single exclude list that contains both
include and exclude options.
If you end an exclude list with --exclude "*", note that
since the algorithm is applied recursively that unless you
explicitly include parent directories of files you want to
include then the algorithm will stop at the parent direc
tories and never see the files below them. To include all
directories, use --include "*/" before the --exclude "*".
Here are some exclude/include examples:
o *.o would exclude all filenames
matching *.o
o /foo would exclude a file in the base
directory called foo
o "foo/" would exclude any directory called
foo
o /foo/*/bar would exclude any file
called bar two levels below a base directory called
foo
o /foo/**/bar would exclude any file
called bar two or more levels below a base direc-
tory called foo
o */
*.c
* would
include all directories and C source files
o foo/
foo/bar.c
* would include only foo/bar.c (the foo/ direc-
tory must be explicitly included or it would be
excluded by the "*")
<a name="6"><h3>Advanced</h3></a>
Not all rsync options can be applied with the panel, if you have
a need to further refine your script you can
1.
the panel creates shell scripts in /usr/bin/ called dungogrsync-rsync*
eg.
-rwxr-xr-x 1 cathie admin 467 Sep 30 21:34 /usr/bin/dungogrsync-rsync55622
-rwxr-xr-x 1 stephen admin 593 Oct 1 01:28 /usr/bin/dungogrsync-rsync608624
2.
if automated, these are called from cron
3.
you can take these files,
copy and/or combine them into a new files so they are not overwritten
then add the new file into cron, eg with dungog-cron.
* combining the files will let one job finish before a new one starts
* you can add other options,
either generate a dummy script with the panel to check syntax,
or read the manual, man rsync or google
</pre> ')));
print $q->endform;
print $q->p ($q->hr, $q->font ({size => "-1"}, "Copyright dungog.net",
$q->a ({href => $q->url (-absolute => 1) . ""}, 'Return to main'), " ..."));
return;
}