Rsync.pm 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912
  1. # -*- perl -*-
  2. # vim:ft=perl foldlevel=1
  3. # __
  4. # /\ \ From the mind of
  5. # / \ \
  6. # / /\ \ \_____ Lee Eakin ( Leakin at dfw dot Nostrum dot com )
  7. # / \ \ \______\ or ( Leakin at cpan dot org )
  8. # / /\ \ \/____ / or ( Leakin at japh dot net )
  9. # \ \ \ \____\/ / or ( Lee at Eakin dot Org )
  10. # \ \ \/____ / Wrapper module for the rsync program
  11. # \ \____\/ / rsync can be found at http://rsync.samba.org/rsync/
  12. # \/______/
  13. package File::Rsync;
  14. require 5.004; # it might work with older versions of 5 but not tested
  15. use FileHandle;
  16. use IPC::Open3 qw(open3);
  17. use IO::Select;
  18. use POSIX ":sys_wait_h";
  19. use Carp 'carp';
  20. use File::Rsync::Config;
  21. use Scalar::Util qw(blessed);
  22. use strict;
  23. use vars qw($VERSION);
  24. $VERSION = '0.43';
  25. =head1 NAME
  26. File::Rsync - perl module interface to rsync(1) F<http://rsync.samba.org/rsync/>
  27. =head1 SYNOPSIS
  28. use File::Rsync;
  29. $obj = File::Rsync->new( { archive => 1, compress => 1,
  30. rsh => '/usr/local/bin/ssh',
  31. 'rsync-path' => '/usr/local/bin/rsync' } );
  32. $obj->exec( { src => 'localdir', dest => 'rhost:remdir' } )
  33. or warn "rsync failed\n";
  34. =head1 DESCRIPTION
  35. Perl Convenience wrapper for the rsync(1) program. Written for I<rsync-2.3.2>
  36. and updated for I<rsync-2.6.0> but should perform properly with most recent
  37. versions.
  38. =over 4
  39. =item File::Rsync::new
  40. $obj = I<new> File::Rsync;
  41. or
  42. $obj = File::Rsync->I<new>;
  43. or
  44. $obj = File::Rsync->new(@options);
  45. or
  46. $obj = File::Rsync->new(\%options);
  47. Create a I<File::Rsync> object. Any options passed at creation are stored
  48. in the object as defaults for all future I<exec> calls on that object.
  49. Options may be passed in the form of a hash and are the same as the long
  50. options in I<rsync(1)> with the leading double-dash removed. An additional
  51. option of B<path-to-rsync> also exists which can be used to override the
  52. hardcoded path to the rsync binary that is defined when the module is
  53. installed, and B<debug> which causes the module methods to print some
  54. debugging information to STDERR. There are also 2 options to wrap the
  55. source and/or destination paths in double-quotes. They are B<quote-src>
  56. and B<quote-dst>, and may be useful in protecting the paths from shell
  57. expansion (particularly useful for paths containing spaces). The
  58. B<outfun> and B<errfun> options take a function reference. The function
  59. is called once for each line of output from the I<rsync> program with the
  60. output line passed in as the first argument, the second arg is either
  61. 'out' or 'err' depending on the source. This makes it possible to use the
  62. same function for both and still determine where the output came from.
  63. Options may also be passed as a reference to a hash. The B<exclude>
  64. option needs an array reference as its value, since there cannot be
  65. duplicate keys in a hash. There is an equivalent B<include> option. Only
  66. an B<exclude> or B<include> option should be used, not both. Use the '+ '
  67. or '- ' prefix trick to put includes in an B<exclude> array, or to put
  68. excludes in an B<include> array (see I<rsync(1)> for details).
  69. Include/exclude options form an ordered list. The order must be retained
  70. for proper execution. There are also B<source> and B<dest> keys. The key
  71. B<src> is also accepted as an equivalent to B<source>, and B<dst> or
  72. B<destination> may be used as equivalents to B<dest>. The B<source>
  73. option may take a scalar or an array reference. If the source is the
  74. local system then multiple B<source> paths are allowed. In this case an
  75. array reference should be used. There is also a method for passing
  76. multiple source paths to a remote system. This method may be triggered in
  77. this module by passing the remote hostname to the B<srchost> key and
  78. passing an array reference to the B<source> key. If the source host is
  79. being accessed via an Rsync server, the remote hostname should have a
  80. single trailing colon on the name. When rsync is called, the B<srchost>
  81. value and the values in the B<source> array will be joined with a colon
  82. resulting in the double-colon required for server access. The B<dest> key
  83. only takes a scalar since I<rsync> only accepts a single destination path.
  84. Version 2.6.0 of I<rsync(1)> provides a new B<files-from> option along with
  85. a few other supporting options (B<from0>, B<no-relative>, and
  86. B<no-implied-dirs>). To support this wonderful new option at the level it
  87. deserves, this module now has an additional parameter. If B<files-from> is
  88. set to '-' (meaning read from stdin) you can define B<infun> to be a
  89. reference to a function that prints your file list to the default file handle.
  90. The output from the function is attached to stdin of the rsync call during
  91. exec. If B<infun> is defined it will be called regardless of the value of
  92. B<files-from>, so it can provide any data expected on stdin, but keep in mind
  93. that stdin will not be attached to a tty so it is not very useful for sending
  94. passwords (see the I<rsync(1)> and I<ssh(1)> man pages for ways to handle
  95. authentication). The I<rsync(1)> man page has a more complete description of
  96. B<files-from>. Also see L<File::Find> for ideas to use with B<files-from>
  97. and B<infun>. The B<infun> option may also be used with the B<include-from>
  98. or B<exclude-from> settings, but this is generally more clumsy than using the
  99. B<include> or B<exclude> arrays.
  100. Version 2.6.3 of I<rsync(1)> provides new options B<partial-dir>,
  101. B<checksum-seed>, B<keep-dirlinks>, B<inplace>, B<ipv4>, and B<ipv6>.
  102. Version 2.6.4 of I<rsync(1)> provides new options B<del>, B<delete-before>
  103. B<delete-during>, B<delay-updates>, B<dirs>, B<filter>, B<fuzzy>,
  104. B<itemize-changes>, B<list-only>, B<omit-dir-times>, B<remove-sent-files>,
  105. B<max-size>, and B<protocol>.
  106. Version 0.38 of this module also adds support for the B<acls> option that
  107. is not part of I<rsync(1)> unless the patch has been applied, but people do
  108. use it. It also includes a new B<literal> option that takes an array reference
  109. similar to B<include>, B<exclude>, and B<filter>. Any arguments in the array
  110. are passed as literal arguments to rsync, and are passed first. They should
  111. have the proper single or double hyphen prefixes and the elements should be
  112. split up the way you want them passed to exec. The purpose of this option
  113. is to allow the use of arbitrary options added by patches, and/or to allow
  114. the use of new options in rsync without needing an imediate update to the
  115. module in addtition to I<rsync(1)> itself.
  116. =back
  117. =cut
  118. sub new {
  119. my $class = shift;
  120. # seed the options hash, booleans, scalars, excludes, source, dest, data,
  121. # status, stderr/stdout storage for last exec
  122. my $self = {
  123. # the full path name to the rsync binary
  124. 'path-to-rsync' => $RsyncConfig{rsync_path},
  125. # these are the boolean flags to rsync, all default off, including them
  126. # in the args list turns them on
  127. 'flag' => {qw(
  128. 8-bit-output 0 fuzzy 0 no-specials 0
  129. acls 0 group 0 no-super 0
  130. append 0 hard-links 0 no-times 0
  131. archive 0 help 0 no-whole-file 0
  132. backup 0 ignore-errors 0 numeric-ids 0
  133. blocking-io 0 ignore-existing 0 omit-dir-times 0
  134. checksum 0 ignore-non-existing 0 one-file-system 0
  135. compress 0 ignore-times 0 whole-file 0
  136. copy-dirlinks 0 inplace 0 owner 0
  137. copy-links 0 ipv4 0 partial 0
  138. copy-unsafe-links 0 ipv6 0 perms 0
  139. cvs-exclude 0 keep-dirlinks 0 progress 0
  140. daemon 0 links 0 prune-empty-dirs 0
  141. del 0 list-only 0 recursive 0
  142. delay-updates 0 no-blocking-io 0 relative 0
  143. delete 0 no-detach 0 remove-sent-files 0
  144. delete-after 0 no-devices 0 safe-links 0
  145. delete-before 0 no-dirs 0 size-only 0
  146. delete-during 0 no-groups 0 sparse 0
  147. delete-excluded 0 no-implied-dirs 0 specials 0
  148. devices 0 no-links 0 stats 0
  149. dirs 0 no-owner 0 super 0
  150. dry-run 0 no-partial 0 times 0
  151. executability 0 no-perms 0 update 0
  152. existing 0 no-progress 0 version 0
  153. force 0 no-recursive 0 xattrs 0
  154. from0 0 no-relative 0
  155. )},
  156. # these have simple scalar args we cannot easily check
  157. 'scalar' => {qw(
  158. address 0 log-format 0 protocol 0
  159. backup-dir 0 max-delete 0 read-batch 0
  160. block-size 0 max-size 0 rsh 0
  161. bwlimit 0 min-size 0 rsync-path 0
  162. checksum-seed 0 modify-window 0 sockopts 0
  163. compress-level 0 only-write-batch 0 suffix 0
  164. config 0 partial-dir 0 temp-dir 0
  165. csum-length 0 password-file 0 timeout 0
  166. files-from 0 port 0 write-batch 0
  167. )},
  168. # these are not flags but counters, each time they appear it raises the
  169. # count, so we keep track and pass them the same number of times
  170. 'counter' => {qw(
  171. human-readable 0 one-file-system 0 verbose 0
  172. itemize-changes 0 quiet 0
  173. )},
  174. # these can be specified multiple times and are additive, the doc also
  175. # specifies that it is an ordered list so we must preserve that order
  176. 'chmod' => [],
  177. 'compare-dest' => [],
  178. 'copy-dest' => [],
  179. 'exclude' => [],
  180. 'exclude-from' => [],
  181. 'filter' => [],
  182. 'include' => [],
  183. 'include-from' => [],
  184. 'link-dest' => [],
  185. 'literal' => [],
  186. # hostname of source, used if 'source' is an array reference
  187. 'srchost' => '',
  188. # source host and/or path names
  189. 'source' => '',
  190. # destination host and/or path
  191. 'dest' => '',
  192. # return status from last exec
  193. 'status' => 0,
  194. 'realstatus' => 0,
  195. # last rsync command-line executed
  196. 'lastcmd' => undef,
  197. # whether or not to print debug statements
  198. 'debug' => 0,
  199. # double-quote source and/or destination paths
  200. 'quote-src' => 0,
  201. 'quote-dst' => 0,
  202. # stderr from last exec in array format (messages from remote rsync proc)
  203. 'err' => 0,
  204. 'errfun' => undef,
  205. # stdout from last exec in array format (messages from local rsync proc)
  206. 'out' => 0,
  207. 'outfun' => undef,
  208. # function to prvide --*-from=- data via pipe
  209. 'infun' => undef,
  210. # this flag changes error checking in 'exec' when called by 'list'
  211. 'list' => 0,
  212. };
  213. bless $self, $class; # bless it first so defopts can find out the class
  214. if (@_) {
  215. &defopts($self,@_) or return;
  216. }
  217. return $self;
  218. }
  219. =over 4
  220. =item File::Rsync::defopts
  221. $obj->defopts(@options);
  222. or
  223. $obj->defopts(\%options);
  224. Set default options for future exec calls for the object. See I<rsync(1)>
  225. for a complete list of valid options. This is really the internal
  226. method that I<new> calls but you can use it too. The B<verbose> and B<quiet>
  227. options to rsync are actually counters. When assigning the perl hash-style
  228. options you may specify the counter value directly and the module will pass
  229. the proper number of options to rsync.
  230. =back
  231. =cut
  232. sub defopts {
  233. # this method has now been split into 2 sub methods (parse and save)
  234. # _saveopts and _parseopts should only be used via defopts or exec
  235. my $self = shift;
  236. &_saveopts($self,&_parseopts($self,@_));
  237. }
  238. sub _parseopts {
  239. # this method checks and converts it's args into a reference to a hash
  240. # of valid options and returns it to the caller
  241. my $self = shift;
  242. my $pkgname = ref $self;
  243. my @opts = @_;
  244. my $opt;
  245. my %OPT = (); # this is the hash we will return a ref to
  246. # make sure we are passed the proper number of args
  247. if (@opts == 1) {
  248. $opt = shift;
  249. if (my $reftype = ref $opt) {
  250. unless ($reftype eq 'HASH') {
  251. carp "$pkgname: invalid reference type ($reftype) in options";
  252. return;
  253. }
  254. } else {
  255. carp "$pkgname: invalid option ($opt)";
  256. return;
  257. }
  258. } elsif (@opts % 2) {
  259. carp "$pkgname: invalid number of options passed (must be key/value pairs)";
  260. return;
  261. } else {
  262. $opt = {@opts};
  263. }
  264. # now process the options given, we handle debug first since hashes do not
  265. # have a specific order, and it would not be set first even if we sorted
  266. if (exists $opt->{'debug'}) {
  267. $OPT{'debug'} = $opt->{'debug'};
  268. print(STDERR "setting debug flag\n") if $OPT{'debug'};
  269. }
  270. foreach my $hashopt (keys %$opt) {
  271. my $savopt = $hashopt;
  272. $savopt =~ tr/_/-/;
  273. next if $hashopt eq 'debug'; # we did this one first (above)
  274. print STDERR "processing option: $hashopt\n"
  275. if $OPT{'debug'} or $self->{'debug'};
  276. if (exists $self->{'flag'}{$savopt}
  277. or exists $self->{'scalar'}{$savopt}
  278. or exists $self->{'counter'}{$savopt}) {
  279. $OPT{$savopt} = $opt->{$hashopt};
  280. } else {
  281. my $tag = '';
  282. if ( $hashopt eq 'chmod'
  283. or $hashopt eq 'compare-dest'
  284. or $hashopt eq 'copy-dest'
  285. or $hashopt eq 'exclude'
  286. or $hashopt eq 'exclude-from'
  287. or $hashopt eq 'filter'
  288. or $hashopt eq 'include'
  289. or $hashopt eq 'include-from'
  290. or $hashopt eq 'link-dest'
  291. or $hashopt eq 'literal') {
  292. $tag = $hashopt;
  293. } elsif ($hashopt eq 'source'
  294. or $hashopt eq 'src') {
  295. $tag = 'source';
  296. }
  297. if ($tag) {
  298. if (my $reftype = ref $opt->{$hashopt}) {
  299. if ($reftype eq 'ARRAY') {
  300. $OPT{$tag} = $opt->{$hashopt};
  301. } elsif ($tag eq 'source' && blessed $opt->{$hashopt}) {
  302. $OPT{$tag} = [ $opt->{$hashopt} ];
  303. } else {
  304. carp "$pkgname: invalid reference type for $hashopt option";
  305. return;
  306. }
  307. } elsif ($tag eq 'source') {
  308. $OPT{$tag} = [ $opt->{$hashopt} ];
  309. } else {
  310. carp "$pkgname: $hashopt is not a reference";
  311. return;
  312. }
  313. } elsif ($hashopt eq 'dest'
  314. or $hashopt eq 'destination'
  315. or $hashopt eq 'dst') {
  316. $OPT{'dest'} = $opt->{$hashopt};
  317. } elsif ($savopt eq 'path-to-rsync'
  318. or $savopt eq 'srchost'
  319. or $savopt eq 'quote-dst'
  320. or $savopt eq 'quote-src') {
  321. $OPT{$savopt} = $opt->{$hashopt};
  322. } elsif ($hashopt eq 'outfun' or $hashopt eq 'errfun'
  323. or $hashopt eq 'infun') {
  324. if (ref $opt->{$hashopt} eq 'CODE') {
  325. $OPT{$hashopt} = $opt->{$hashopt};
  326. } else {
  327. carp "$pkgname: $hashopt option is not a function reference";
  328. return;
  329. }
  330. } else {
  331. carp "$pkgname: $hashopt - unknown option";
  332. return;
  333. }
  334. }
  335. }
  336. return \%OPT;
  337. }
  338. sub _saveopts {
  339. # this method saves the data from the hash passed to it in the object's
  340. # hash
  341. my $self = shift;
  342. my $pkgname = ref $self;
  343. my $opts = shift;
  344. return unless ref $opts eq 'HASH';
  345. foreach my $opt (keys %$opts) {
  346. if (exists $self->{'flag'}{$opt}) {
  347. $self->{'flag'}{$opt} = $opts->{$opt};
  348. } elsif (exists $self->{'scalar'}{$opt}) {
  349. $self->{'scalar'}{$opt} = $opts->{$opt};
  350. } elsif (exists $self->{'counter'}{$opt}) {
  351. $self->{'counter'}{$opt} = $opts->{$opt};
  352. } elsif ($opt eq 'chmod' or $opt eq 'compare-dest'
  353. or $opt eq 'copy-dest' or $opt eq 'link-dest'
  354. or $opt eq 'exclude' or $opt eq 'exclude-from'
  355. or $opt eq 'include' or $opt eq 'include-from'
  356. or $opt eq 'filter' or $opt eq 'source' or $opt eq 'dest'
  357. or $opt eq 'debug' or $opt eq 'outfun' or $opt eq 'errfun'
  358. or $opt eq 'infun' or $opt eq 'path-to-rsync'
  359. or $opt eq 'srchost' or $opt eq 'quote-dst'
  360. or $opt eq 'quote-src' or $opt eq 'literal') {
  361. $self->{$opt} = $opts->{$opt};
  362. } else {
  363. carp "$pkgname: unknown option: $opt";
  364. return;
  365. }
  366. }
  367. return 1;
  368. }
  369. =over 4
  370. =item File::Rsync::getcmd
  371. my $cmd = $obj->getcmd(@options);
  372. or
  373. my $cmd = $obj->getcmd(\%options);
  374. or
  375. my ($cmd, $infun, $outfun, $errfun, $debug) = $obj->getcmd(\%options);
  376. I<getcmd> returns a reference to an array containing the real rsync command
  377. that would be called if the exec function were called. The last example above
  378. includes a reference to the optional stdin function, stdout function, stderr
  379. function, and the debug setting. This is the form used by the I<exec> method
  380. to get the extra parameters it needs to do its job. The function is exposed
  381. to allow a user-defined exec function to be used, or for debugging purposes.
  382. =back
  383. =cut
  384. sub getcmd {
  385. my $self = shift;
  386. my $pkgname = ref $self;
  387. my $merged = $self;
  388. my $list = $self->{list};
  389. $self->{list} = 0 if $self->{list};
  390. if (@_) { # If args are passed to exec then we have to merge the saved
  391. # (default) options with those passed, for any conflicts those passed
  392. # directly to exec take precidence
  393. my $execopts = &_parseopts($self,@_);
  394. return unless ref $execopts eq 'HASH';
  395. my %runopts = ();
  396. # first copy the default info from $self
  397. foreach my $type (qw(flag scalar counter)) {
  398. foreach my $opt (keys %{$self->{$type}}) {
  399. $runopts{$type}{$opt} = $self->{$type}{$opt};
  400. }
  401. }
  402. foreach my $opt (qw(path-to-rsync chmod compare-dest copy-dest
  403. exclude exclude-from filter include include-from
  404. link-dest source srchost debug dest outfun
  405. errfun infun quote-dst quote-src literal)) {
  406. $runopts{$opt} = $self->{$opt};
  407. }
  408. # now allow any args passed directly to exec to override
  409. foreach my $opt (keys %$execopts) {
  410. if (exists $runopts{'flag'}{$opt}) {
  411. $runopts{'flag'}{$opt} = $execopts->{$opt};
  412. } elsif (exists $runopts{'scalar'}{$opt}) {
  413. $runopts{'scalar'}{$opt} = $execopts->{$opt};
  414. } elsif (exists $runopts{'counter'}{$opt}) {
  415. $runopts{'counter'}{$opt} = $execopts->{$opt};
  416. } elsif ($opt eq 'chmod' or $opt eq 'compare-dest'
  417. or $opt eq 'copy-dest' or $opt eq 'link-dest'
  418. or $opt eq 'exclude' or $opt eq 'exclude-from'
  419. or $opt eq 'include' or $opt eq 'include-from'
  420. or $opt eq 'filter' or $opt eq 'source' or $opt eq 'dest'
  421. or $opt eq 'debug' or $opt eq 'outfun' or $opt eq 'errfun'
  422. or $opt eq 'infun' or $opt eq 'path-to-rsync'
  423. or $opt eq 'srchost' or $opt eq 'quote-dst'
  424. or $opt eq 'quote-src' or $opt eq 'literal') {
  425. $runopts{$opt} = $execopts->{$opt};
  426. } else {
  427. carp "$pkgname: unknown option: $opt";
  428. return;
  429. }
  430. }
  431. $merged = \%runopts;
  432. }
  433. my @cmd = ($merged->{'path-to-rsync'});
  434. # put any literal options first
  435. push @cmd,@{$merged->{'literal'}} if @{$merged->{'literal'}};
  436. foreach my $opt (sort keys %{$merged->{'flag'}}) {
  437. push @cmd,"--$opt" if $merged->{'flag'}{$opt};
  438. }
  439. foreach my $opt (sort keys %{$merged->{'scalar'}}) {
  440. push @cmd,"--$opt=$merged->{'scalar'}{$opt}" if $merged->{'scalar'}{$opt};
  441. }
  442. foreach my $opt (sort keys %{$merged->{'counter'}}) {
  443. for (my $i = 0;$i<$merged->{'counter'}{$opt};$i++) {
  444. push @cmd,"--$opt";
  445. }
  446. }
  447. if ((@{$merged->{'exclude'}} != 0) + (@{$merged->{'include'}} != 0)
  448. + (@{$merged->{'filter'}} != 0) > 1) {
  449. carp "$pkgname: 'exclude' and/or 'include' and/or 'filter' options specified, only one allowed";
  450. return;
  451. }
  452. foreach my $opt (@{$merged->{'chmod'}}) {
  453. push @cmd,"--chmod=$opt";
  454. }
  455. foreach my $opt (@{$merged->{'compare-dest'}}) {
  456. push @cmd,"--compare-dest=$opt";
  457. }
  458. foreach my $opt (@{$merged->{'copy-dest'}}) {
  459. push @cmd,"--copy-dest=$opt";
  460. }
  461. foreach my $opt (@{$merged->{'exclude'}}) {
  462. push @cmd,"--exclude=$opt";
  463. }
  464. foreach my $opt (@{$merged->{'exclude-from'}}) {
  465. push @cmd,"--exclude-from=$opt";
  466. }
  467. foreach my $opt (@{$merged->{'filter'}}) {
  468. push @cmd,"--filter=$opt";
  469. }
  470. foreach my $opt (@{$merged->{'include'}}) {
  471. push @cmd,"--include=$opt";
  472. }
  473. foreach my $opt (@{$merged->{'include-from'}}) {
  474. push @cmd,"--include-from=$opt";
  475. }
  476. foreach my $opt (@{$merged->{'link-dest'}}) {
  477. push @cmd,"--link-dest=$opt";
  478. }
  479. if ($merged->{'source'}) {
  480. if ($merged->{'srchost'}) {
  481. push @cmd, "$merged->{'srchost'}:" . join ' ',
  482. $merged->{'quote-src'} ? map { "\"$_\"" } @{$merged->{'source'}}
  483. : @{$merged->{'source'}};
  484. } else {
  485. push @cmd,
  486. $merged->{'quote-src'} ? map { "\"$_\"" } @{$merged->{'source'}}
  487. : @{$merged->{'source'}};
  488. }
  489. } elsif ($merged->{'srchost'} and $list) {
  490. push @cmd, "$merged->{'srchost'}:";
  491. } else {
  492. if ($list) {
  493. carp "$pkgname: no 'source' specified";
  494. return;
  495. } elsif ($merged->{'dest'}) {
  496. carp "$pkgname: option 'dest' specified without 'source' option";
  497. return;
  498. } else {
  499. carp "$pkgname: no source or destination specified";
  500. return;
  501. }
  502. }
  503. unless ($list) {
  504. if ($merged->{'dest'}) {
  505. push @cmd,
  506. $merged->{'quote-dst'} ? "\"$merged->{'dest'}\""
  507. : $merged->{'dest'};
  508. } else {
  509. carp "$pkgname: option 'source' specified without 'dest' option";
  510. return;
  511. }
  512. }
  513. return(wantarray
  514. ? (\@cmd,
  515. $merged->{'infun'},
  516. $merged->{'outfun'},
  517. $merged->{'errfun'},
  518. $merged->{'debug'})
  519. : \@cmd);
  520. }
  521. =over 4
  522. =item File::Rsync::exec
  523. $obj->exec(@options) or warn "rsync failed\n";
  524. or
  525. $obj->exec(\%options) or warn "rsync failed\n";
  526. This is the method that does the real work. Any options passed to this
  527. routine are appended to any pre-set options and are not saved. They effect
  528. the current execution of I<rsync> only. In the case of conflicts, the options
  529. passed directly to I<exec> take precedence. It returns B<1> if the return
  530. status was zero (or true), if the I<rsync> return status was non-zero it
  531. returns B<0> and stores the return status. You can examine the return status
  532. from I<rsync> and any output to stdout and stderr with the methods listed below.
  533. =back
  534. =cut
  535. sub exec {
  536. my $self = shift;
  537. my ($cmd, $infun, $outfun, $errfun, $debug) = $self->getcmd(@_);
  538. return unless $cmd;
  539. print STDERR "exec: @$cmd\n" if $debug;
  540. my $out = FileHandle->new; my $err = FileHandle->new;
  541. $err->autoflush(1);
  542. $out->autoflush(1);
  543. local $SIG{CHLD}='DEFAULT';
  544. my $pid;
  545. {
  546. my $in = FileHandle->new;
  547. $in->autoflush(1);
  548. $pid = eval{ open3 $in,$out,$err,@$cmd };
  549. $self->{lastcmd} = $cmd;
  550. if ($@) {
  551. $self->{'realstatus'} = 0;
  552. $self->{'status'} = 255;
  553. $self->{'err'} = [$@,"Execution of rsync failed.\n"];
  554. return 0;
  555. }
  556. if ($infun) {
  557. select((select($in),&{$infun})[0]);
  558. }
  559. $in->close;
  560. }
  561. my $odata = my $edata = '';
  562. my $stream = {
  563. $out->fileno => {
  564. name => 'out',
  565. data => \$odata,
  566. buffer_tail => '',
  567. block_size => ($out->stat)[11] || 1024,
  568. handler => $outfun
  569. },
  570. $err->fileno => {
  571. name => 'err',
  572. data => \$edata,
  573. buffer_tail => '',
  574. block_size => ($err->stat)[11] || 1024,
  575. handler => $errfun
  576. }
  577. };
  578. my $select = IO::Select->new;
  579. $select->add($out,$err);
  580. while ($out->opened or $err->opened) {
  581. foreach my $fd ( $select->can_read(1) ) {
  582. my $str = $stream->{$fd->fileno};
  583. warn("stream not found") unless $str;
  584. my $buffer;
  585. if ( $fd->sysread($buffer, $str->{block_size}) ) {
  586. ${$str->{data}} .= $buffer;
  587. if ( $str->{handler} ) {
  588. my $tail = '';
  589. $tail = $1 if $buffer =~ s/([^\n]+)\z//s;
  590. foreach my $line ( split /^/m, $str->{buffer_tail}.$buffer ) {
  591. &{$str->{handler}}($line, $str->{name});
  592. }
  593. $str->{buffer_tail} = $tail;
  594. }
  595. } else {
  596. $select->remove($fd);
  597. $fd->close;
  598. }
  599. }
  600. }
  601. $self->{'out'} = $odata ? [ split /^/m,$odata ] : '';
  602. $self->{'err'} = $edata ? [ split /^/m,$edata ] : '';
  603. $out->close;
  604. $err->close;
  605. waitpid $pid,0;
  606. $self->{'realstatus'} = $?;
  607. $self->{'status'} = $?>>8;
  608. return($self->{'status'} ? 0 : 1);
  609. }
  610. =over 4
  611. =item File::Rsync::list
  612. $out = $obj->list(@options);
  613. or
  614. $out = $obj->list(\%options);
  615. or
  616. @out = $obj->list(\%options);
  617. This is a wrapper for I<exec> called without a destination to get a listing.
  618. It returns the output of stdout like the I<out> function below. When
  619. no destination is given rsync returns the equivalent of 'ls -l' or 'ls -lr'
  620. modified by any include/exclude/filter parameters you specify. This is useful
  621. for manual comparison without actual changes to the destination or for
  622. comparing against another listing taken at a different point in time.
  623. (As of rsync version 2.6.4-pre1 this can also be accomplished with the
  624. 'list-only' option regardless of whether a destination is given.)
  625. =back
  626. =cut
  627. sub list {
  628. my $self = shift;
  629. $self->{list}++;
  630. $self->exec(@_);
  631. if ($self->{'out'}) {
  632. return(wantarray ? @{$self->{'out'}} : $self->{'out'});
  633. } else {
  634. return;
  635. }
  636. }
  637. =over 4
  638. =item File::Rsync::status
  639. $rval = $obj->I<status>;
  640. Returns the status from last I<exec> call right shifted 8 bits.
  641. =back
  642. =cut
  643. sub status {
  644. my $self = shift;
  645. return $self->{'status'};
  646. }
  647. =over 4
  648. =item File::Rsync::realstatus
  649. $rval = $obj->I<realstatus>;
  650. Returns the real status from last I<exec> call (not right shifted).
  651. =back
  652. =cut
  653. sub realstatus {
  654. my $self = shift;
  655. return $self->{'realstatus'};
  656. }
  657. =over 4
  658. =item File::Rsync::err
  659. $aref = $obj->I<err>;
  660. In a scalar context this method will return a reference to an array containing
  661. all output to stderr from the last I<exec> call, or zero (false) if there
  662. was no output. In an array context it will return an array of all output to
  663. stderr or an empty list. The scalar context can be used to efficiently test
  664. for the existance of output. I<rsync> sends all messages from the remote
  665. I<rsync> process and any error messages to stderr. This method's purpose is
  666. to make it easier for you to parse that output for appropriate information.
  667. =back
  668. =cut
  669. sub err {
  670. my $self = shift;
  671. if ($self->{'err'}) {
  672. return(wantarray ? @{$self->{'err'}} : $self->{'err'});
  673. } else {
  674. return;
  675. }
  676. }
  677. =over 4
  678. =item File::Rsync::out
  679. $aref = $obj->I<out>;
  680. Similar to the I<err> method, in a scalar context it returns a reference to an
  681. array containing all output to stdout from the last I<exec> call, or zero
  682. (false) if there was no output. In an array context it returns an array of all
  683. output to stdout or an empty list. I<rsync> sends all informational messages
  684. (B<verbose> option) from the local I<rsync> process to stdout.
  685. =back
  686. =cut
  687. sub out {
  688. my $self = shift;
  689. if ($self->{'out'}) {
  690. return(wantarray ? @{$self->{'out'}} : $self->{'out'});
  691. } else {
  692. return;
  693. }
  694. }
  695. =over 4
  696. =item File::Rsync::lastcmd
  697. $aref = $obj->I<lastcmd>;
  698. Returns the actual system command used by the last I<exec> call, or '' before
  699. any calls to I<exec> for the object. This can be useful in the case of an
  700. error condition to give a more informative message or for debugging purposes.
  701. In an array context it return an array of args as passed to the system, in
  702. a scalar context it returns a space-seperated string. See I<getcmd> for access
  703. to the command before execution.
  704. =back
  705. =cut
  706. sub lastcmd {
  707. my $self = shift;
  708. if ($self->{lastcmd}) {
  709. return wantarray ? @{$self->{lastcmd}} : join ' ',@{$self->{lastcmd}};
  710. } else {
  711. return;
  712. }
  713. }
  714. =head1 Author
  715. Lee Eakin E<lt>[email protected]<gt>
  716. =head1 Credits
  717. The following people have contributed ideas, bug fixes, code or helped out
  718. by reporting or tracking down bugs in order to improve this module since
  719. it's initial release. See the Changelog for details:
  720. Greg Ward
  721. Boris Goldowsky
  722. James Mello
  723. Andreas Koenig
  724. Joe Smith
  725. Jonathan Pelletier
  726. Heiko Jansen
  727. Tong Zhu
  728. Paul Egan
  729. Ronald J Kimball
  730. James CE Johnson
  731. Bill Uhl
  732. Peter teStrake
  733. Harald Flaucher
  734. Simon Myers
  735. Gavin Carr
  736. Petya Kohts
  737. =head1 Inspiration and Assistance
  738. Gerard Hickey C<PGP::Pipe>
  739. Russ Allbery C<PGP::Sign>
  740. Graham Barr C<Net::*>
  741. Andrew Tridgell and Paul Mackerras rsync(1)
  742. John Steele E<lt>[email protected]<gt>
  743. Philip Kizer E<lt>[email protected]<gt>
  744. Larry Wall perl(1)
  745. I borrowed many clues on wrapping an external program from the PGP modules,
  746. and I would not have had such a useful tool to wrap except for the great work
  747. of the B<rsync> authors. Thanks also to Graham Barr, the author of the libnet
  748. modules and many others, for looking over this code. Of course I must mention
  749. the other half of my brain, John Steele, and his good friend Philip Kizer for
  750. finding B<rsync> and bringing it to my attention. And I would not have been
  751. able to enjoy writing useful tools if not for the creator of the B<perl>
  752. language.
  753. =head1 Copyrights
  754. Copyright (c) 1999-2005 Lee Eakin. All rights reserved.
  755. This program is free software; you can redistribute it and/or modify
  756. it under the same terms as Perl itself.
  757. =cut
  758. 1;