#!/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 ""; #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 (' '), $q->td (' ')); #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 '
'; print '
'; #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 ""; #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 (' '), $q->td (' ')); #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 '
'; print '
'; #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 ''; print ''; 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 (""), esmith::cgi::genTextRow ($q, ('Delete files that do not exist on the sending side. Always use Testing option first.'))); 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 (""), 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 (""), 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 (""), 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 ("Local server - $conf{SystemName}.$conf{DomainName}")), #local directory esmith::cgi::genTextRow ($q, $q->p ("Local directory"))); print ""; 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 '
'; 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 ('Remote user@server user is required. Can be different to local user
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 ''; 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 ('Remote directory'))); 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 ''; 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 ''; print $q->table ({border => 0, cellspacing => 0, cellpadding => 4}, #time for automation #esmith::cgi::genTextRow ($q, $q->p ('Timing')), esmith::cgi::genTextRow ($q, $q->p ('Select the time and enable to automate
Alternatively add this job to cron using the Cron panel, the command to give is
'."/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 ""; print ''; print "
";
      open (INF,"/usr/bin/dungogrsync-$rsync")
      or die ("can't open rsync script: $1");

      while ()
      {
          print "$_";
      }

      close INF;
      print "
\n"; } print '
'; print ''; 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 ''; print ''; 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 ('General')), 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 (""), 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 (""), 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 ('Locations'))); #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 '
'; print $q->table ({border => 0, cellspacing => 0, cellpadding => 4}, #time for automation #esmith::cgi::genTextRow ($q, $q->p ('Timing')), 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 ""; print ''; print "
";
      open (INF,"/usr/bin/dungogrsync-$rsync")
      or die ("can't open rsync script: $1");

      while ()
      {
          print "$_";
      }

      close INF;
      print "
\n"; } print '
'; print ''; 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 ''; print ''; 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 ('This is not fully functioning currently.
Shared Folders shown in red have Global Access set to

Use the Shared Folders panel for finer control

')); unless ( -e '/etc/rsyncd.conf') { print $q->p ($q->p ('This is not fully functioning currently.
It requires smeserver-shared-folders to enable rsyncd
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 "
"; 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 "
"; 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 '
'; } # 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 ''; print ''; 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 ''; print ''; 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 ""; print ''; print "
";
      open (INF,"/var/log/dungogrsyncnow")
      or die ("can't open rsync log file: $1");

      while ()
      {
          print "$_";
      }

      close INF;
      print "
\n"; } print '
'; print ''; 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 ''; print ''; 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 "
"; print ''; print "
";
      open (INF,"/tmp/recentrsync")
      or die ("can't open rsync log file: $1");

      while ()
      {
          print "$_";
      }

      close INF;
      print "
\n"; } print '
'; print ''; 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 ''; print ''; 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 ('
* General
* Secure rsync
* SSH keys
* Changing the port
* Rsync Anonymous server
* Rsync Anonymous client
* Exclude / Include syntax
* Advanced

General

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.

Secure rsync

Safeguards 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. Method 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 Notes 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

SSH Keys

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

Changing the port

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

Rsync Anonymous server TODO

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.

Rsync Anonymous client

Used to pull files from an anonymous rsync server

Exclude / Include syntax

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 "*")

Advanced

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
'))); 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; }