Compare commits

...

985 Commits

Author SHA1 Message Date
Martin Pool
5c6e0ee27c Signedness security patch from Sebastian Krahmer <krahmer@suse.de> --
in some cases we were not sufficiently careful about reading integers
from the network.
2002-01-25 00:56:35 +00:00
Martin Pool
0d95824995 Verbose messages for spoof check... doesn't work on old linux libc? 2002-01-24 09:42:52 +00:00
Martin Pool
bbc09ffba9 When doing a name->addr translation to check for spoofing, give the
resolver the address family of the original address as a hint, so that
we're more likely to find the correct A or AAAA record.,
2002-01-24 08:52:28 +00:00
Martin Pool
a4677968cf Message on successful configuration. 2002-01-24 08:50:35 +00:00
Martin Pool
03b1cddc31 Fix comment.
Bump version to 2.5.2pre3
2002-01-24 08:42:21 +00:00
Martin Pool
9c2dd04993 Name resolution on machines supporting IPv6 is improved. 2002-01-24 08:20:51 +00:00
Martin Pool
a84a93fafe ignore gmon.out 2002-01-24 08:19:28 +00:00
Martin Pool
5fdcc397b1 Fix getpeername call. 2002-01-24 08:16:27 +00:00
Martin Pool
5664871e5f size_t fix. 2002-01-24 08:09:46 +00:00
Martin Pool
55d9e0fada write_batch_csums_file: Opaque IO buffers should be void*. 2002-01-24 08:08:56 +00:00
Martin Pool
929e3011c6 Fix cast that was breaking HP/UX. 2002-01-24 08:07:35 +00:00
Martin Pool
07d70ff560 Move both calls to getpeername into a common wrapper function that
handles IPV4_MAPPED addresses.
2002-01-24 08:05:22 +00:00
Martin Pool
58c2960960 Must get declarations from addrinfo.h before prototypes. 2002-01-24 07:22:38 +00:00
Martin Pool
00d943d513 Another size_t warning 2002-01-24 05:57:49 +00:00
Martin Pool
71c780da06 check_name: Print out name *before* clobbering it. 2002-01-24 05:57:22 +00:00
Martin Pool
3b18cba889 Try to fix error on Solaris:
+ [ -f /export/home/build/build_farm/rsync/testtmp.symlink-ignore/to/referent ]
+ [ -d /export/home/build/build_farm/rsync/testtmp.symlink-ignore/to/from ]
+ [ -L /export/home/build/build_farm/rsync/testtmp.symlink-ignore/to/dangling ]
./testsuite/symlink-ignore.test: test: argument expected

Solaris says it supports -L, so I'm not sure what's happening...
2002-01-24 05:54:47 +00:00
Martin Pool
2974e20550 If name lookup fails, then show the relevant IP address in the error message. 2002-01-24 05:41:46 +00:00
Martin Pool
430d841a2c At the connections that just get a list of modules are not logged,
but they should be.
2002-01-24 04:49:07 +00:00
Martin Pool
31ec50d7da rsync_module: If host-based access fails, show the exact name/address
used for the check in the error message.  (Just in case...)
2002-01-24 04:41:09 +00:00
Martin Pool
5ad0e46f08 Show command used to start connection child. 2002-01-24 04:36:00 +00:00
Martin Pool
1b5814e338 indent -kr -i8 2002-01-24 04:26:55 +00:00
Martin Pool
255810c0d6 Doc.
Oops, connection program message was in the wrong place.
2002-01-24 04:24:12 +00:00
Martin Pool
5d2640376e Show helper program with -v when opening connection.
Doc.
2002-01-24 04:21:42 +00:00
Martin Pool
d02984bbb7 Doc. 2002-01-24 04:19:41 +00:00
Martin Pool
0f9555207a Fix const 2002-01-24 04:07:07 +00:00
Martin Pool
885448d74c Unbreak the old behavior of using UNKNOWN as a hostname if any of the
addr->name->addr translations fail, because people might count on this
in "hosts deny" lines.
2002-01-24 04:03:06 +00:00
Martin Pool
b14545b3ff Fix inverted sense of error check. 2002-01-24 03:31:28 +00:00
Martin Pool
9a5a86734f Refactor client_name() into smaller functions.
Better messages for DNS failure.

If we can get a reverse name for an IP address, but not confirm that
it is correct using a forward lookup then we still proceed to use the
name, but also emit a warning.
2002-01-24 03:28:20 +00:00
Martin Pool
d1d1505045 Doc. 2002-01-24 03:03:20 +00:00
Martin Pool
144ce1dc21 Bump version to 2.5.2pre2. 2002-01-24 03:01:42 +00:00
Martin Pool
aa126974ba log_formatted: Fill the log buffer with nuls to make sure we cannot
accidentally leave the string unterminated.
2002-01-24 02:41:38 +00:00
Martin Pool
707de53457 Another harmless size_t warning. 2002-01-24 02:33:45 +00:00
Martin Pool
10f83cf43d Doc. 2002-01-23 08:08:48 +00:00
Martin Pool
59ee743c5f More size_t fixes. 2002-01-23 08:04:54 +00:00
Martin Pool
d54765c442 Just for variety we have some socklen_t fixes too. 2002-01-23 07:57:43 +00:00
Martin Pool
91262d5d3e Refactor code in send_sums to remove repeated ternaries. 2002-01-23 07:54:13 +00:00
Martin Pool
1c09c743b1 indent -kr -i8 2002-01-23 07:52:52 +00:00
Martin Pool
06ce139fcc Fix more ints that ought to be size_t's. 2002-01-23 07:48:35 +00:00
Martin Pool
fae5bb3183 Doc.
do_hard_links() actually only looks at the global hardlink table, so
it can be a (void) fn.  (Another gcc warning...)
2002-01-23 07:42:30 +00:00
Martin Pool
6fe25398d6 Fix another int that ought to be a size_t. 2002-01-23 07:36:23 +00:00
Martin Pool
909ce14fc4 indent -kr -i8 2002-01-23 07:34:26 +00:00
Martin Pool
935b920120 Another signedness fix to quieten Sun cc warning. 2002-01-23 07:32:29 +00:00
Martin Pool
b31427cd4a Skip this for now; it's a known bug 2002-01-23 07:28:38 +00:00
Martin Pool
e2e3379d79 Bump version to 2.5.2pre1. 2002-01-23 07:22:03 +00:00
Martin Pool
6b1ef85dd8 Note batch-mode changes. 2002-01-23 07:18:58 +00:00
Martin Pool
92325ada0c Note about proxy authentication and SOCKS. 2002-01-23 07:12:57 +00:00
Martin Pool
1707e0f9e2 Indent. 2002-01-23 06:48:13 +00:00
Martin Pool
7ff701e816 Update thankyou list.
Clarify email addresses.
2002-01-23 05:59:10 +00:00
Martin Pool
2e3c141795 Note that batch mode is currently experimental. 2002-01-23 05:53:58 +00:00
Martin Pool
76f79ba748 Patch from Jos Backus -- Fix breakage from dev_t to DEV64_T in batch
mode.

Also, drop -f and -F for batch mode: these should be reserved for
options that are more commonly used.

It also appends a newline to the argvs file and skips adding the
source directory to the command line.
2002-01-23 05:51:06 +00:00
Martin Pool
9dd891bb28 Signedness security patch from Sebastian Krahmer <krahmer@suse.de> --
in some cases we were not sufficiently careful about reading integers
from the network.

Also, make sure log messages are always nul-terminated.
2002-01-23 04:57:18 +00:00
Martin Pool
99f106d1cf If using gcc, then also turn on -W to get even more warnings.
Remove obsolete message.
2002-01-23 03:52:06 +00:00
Martin Pool
3816cae745 Don't need to reread configuration on SIGHUP because we always do that
on new connections.
2002-01-21 01:57:13 +00:00
David Dykstra
759c0627e1 Aack! Since released version 2.5.0, the --whole-file option was accidentally
changed to --whole.  Change it back.  Anybody who wants to use this option
with any version of rsync will have to switch to using -W.
2002-01-15 21:25:55 +00:00
Martin Pool
e03dfae507 Change gratuituous strlcat's into strlcpy, since we already know the
length of the existing string.
2002-01-15 11:50:32 +00:00
Martin Pool
c7677b892a Clearer doc. 2002-01-15 11:32:30 +00:00
Martin Pool
da7b63972d Add --enable-profile to turn on gprof. This is not perfect, because
it seems to only write to ./gmon.out, and that causes trouble when
there are several rsync processes in the same directory.  But you can
make it work.
2002-01-15 11:20:26 +00:00
Martin Pool
499957d9ba Update 2002-01-15 10:47:59 +00:00
Martin Pool
582250008b The Ted T'so school of program optimization: make progress visible and
people will think it's faster.

So now with --progress rsync will show you how many files it has seen
as it builds the file_list.
2002-01-15 10:43:51 +00:00
Martin Pool
a9b31409d5 Remove unused variable. 2002-01-15 10:04:48 +00:00
Martin Pool
98355b8086 Oops, getaddrinfo returns an error code (not -1) for error. -Wall is
good.
2002-01-15 10:04:11 +00:00
Martin Pool
70ed474b38 Define _GNU_SOURCE so that we get all necessary prototypes. 2002-01-15 09:53:27 +00:00
Martin Pool
4775934364 If using GCC, try to turn on -Wall. I want to be clean with respect
to -Wall.
2002-01-15 09:43:21 +00:00
Martin Pool
25f2cb3d6b Fix for <http://rsync.samba.org/cgi-bin/rsync/incoming?id=3750>
temp files must be opened through do_open so that binary modes is used
on cygwin.  (Chris Boucher)
2002-01-14 00:16:51 +00:00
Martin Pool
154f9a3aca Ignore testtmp directories. 2002-01-13 23:57:13 +00:00
Martin Pool
b9df3bf20c DOc. 2002-01-11 08:37:42 +00:00
Martin Pool
6abd193fe3 Always use 64-bit ino_t and dev_t internally, so that we can detect
hardlinks if coming from a larger platform.  Add heaps of comments
explaining why this is so.
2002-01-11 08:25:32 +00:00
Martin Pool
362099a512 More comments about IPv6 stuff.
If a reverse name lookup fails, show the name that we were trying to
look up.
2002-01-11 08:24:34 +00:00
Martin Pool
fdfc3dc9f3 When checking what was copied, use specific -d -f -L flags to test
rather than -e.  (Perhaps Solaris doesn't have test -e?)
2002-01-11 08:08:34 +00:00
Martin Pool
4937459225 The current version of rsync is expected to fail to eliminate all
duplicates from list.
2002-01-11 08:02:43 +00:00
Martin Pool
be2f866b4c Add concept of expected-failure. 2002-01-11 08:01:05 +00:00
Martin Pool
f08aacf7d6 Give cleaner output from "make check" 2002-01-11 07:41:50 +00:00
Martin Pool
4fa6112efe Bump version number.
Now finished merging across work from experimental BK repository.
2002-01-11 07:30:50 +00:00
Martin Pool
1623ba6889 Improved duplicates test: check that each file is
copied once and exactly once.
2002-01-11 07:29:53 +00:00
Martin Pool
766526c791 Check whether code to eliminate duplicate filenames works
(hint: it does not.)
2002-01-11 07:29:02 +00:00
Martin Pool
5c15e29f2b Better mallinfo() output in --stats 2002-01-11 07:26:39 +00:00
Martin Pool
0413e1605f Update copyright 2002-01-11 07:25:54 +00:00
Martin Pool
0e5a1f8352 Doc 2002-01-11 07:24:31 +00:00
Martin Pool
e5a2b8544d Look for mallinfo() and use it to display
heap usage information in --stats
2002-01-11 07:16:11 +00:00
Martin Pool
736a6a291c In protocol version 26, always
send 64-bit ino_t and dev_t.  We also need to try to use 64-bit
ino_t internally *even if* this platform does not have 64-bit
inums itself, because we need to find duplicate inums when
coming from a larger platform with --hardlinks.
2002-01-11 07:15:16 +00:00
Martin Pool
6e69cff118 Autoindent
Add copyright
2002-01-11 07:11:43 +00:00
Martin Pool
cf72f20426 Improved test framework and test for hardlink handling 2002-01-11 07:11:23 +00:00
Martin Pool
d479210cee Bump version 2002-01-11 07:10:25 +00:00
Martin Pool
b781537597 Merge ChangeSet@1.12: Add test case for -H 2002-01-11 07:09:53 +00:00
Martin Pool
ea1438dad8 Merge ChangeSet@1.12: tls now shows number of links to a file to aid in testing -H 2002-01-11 07:09:22 +00:00
Martin Pool
d2e9d069b4 Merge ChangeSet@1.10: Documentation about flist scalabilityTODO 2002-01-11 07:07:49 +00:00
Martin Pool
58379559cc Merge ChangeSet@1.9: Documentation about flist scalability 2002-01-11 07:07:30 +00:00
Martin Pool
b3e6c81565 Merge ChangeSet@1.4: Documentation about flist scalability 2002-01-11 07:05:30 +00:00
Martin Pool
a6a3c3df45 Merge ChangeSet@1.4: Documentation about future development. 2002-01-11 07:04:37 +00:00
Martin Pool
6e3d4c4045 Oops, fix date. 2002-01-03 07:18:17 +00:00
rsync-bugs
ca60b701ee preparing for release of 2.5.1 2002-01-03 07:11:10 +00:00
Martin Pool
e24c0b98d7 Cleanup. 2002-01-03 07:08:35 +00:00
David Dykstra
f389ac80a9 Removed debugging statement that was added to sig_int() by the rsync+ patch
integration.  It was causing the format of the daemon log to be messed up
because of the leading \n.
2001-12-20 15:33:13 +00:00
Martin Pool
50f2f002d9 Suggestion from David Stein
verbose output

  Indicate whether files are new, updated, or deleted
2001-12-20 01:23:28 +00:00
Martin Pool
9ec7528475 Typo 2001-12-18 06:48:56 +00:00
Martin Pool
a8e2a43a09 Get rid of global_opts struct as suggested by Dave -- too many
problems with initialization.
2001-12-18 06:47:40 +00:00
Martin Pool
eb06fa95e4 Documentation fixes based on mail from Edward Welbourne, and an
attempted explanation of rsync's symbolic-link handling.
2001-12-18 06:45:28 +00:00
Martin Pool
1db8b61de7 Add an "unsafe" symlink to the symlink test case so we can see what happens. 2001-12-18 06:26:26 +00:00
Martin Pool
38c66db8d6 Note about hardlink performance. 2001-12-18 06:25:31 +00:00
Martin Pool
f8be7d4219 Refactor code for setting local address on outgoing connections. If a
local address is specified, then try all addrinfo records for it.
2001-12-18 06:21:33 +00:00
Martin Pool
13e29995f5 Get rid of global_opts struct as suggested by Dave -- too many
problems with initialization.

Change the algorithm from trying to open an inbound socket with
getaddrinfo: keep trying suggested addresses until we find one on
which we can both get a socket and bind.  Not convinced this is the
best, but it's probably better.
2001-12-18 05:54:57 +00:00
Martin Pool
7c583c7316 Note rsyncd-over-ssh and documentation TODOs. 2001-12-18 01:33:56 +00:00
Martin Pool
9fecec5e85 Fix from Jeff Garzik for inet_ntop prototype errors on some Linux
distributions: we were failing to define HAVE_INET_NTOP, so our
prototype in rsync.h came through.

Also rerun autoheader, and have comment for HAVE_SOCKADDR_STORAGE.
2001-12-18 01:32:27 +00:00
Martin Pool
9e696bd468 Update README so that Paulus doesn't get bug reports anymore :-)
I think this document needs to be reworked to better explain how to
use rsync, but not right now.
2001-12-18 01:07:20 +00:00
David Dykstra
6ab6d4bfc1 When INET6 is not defined, meaning that IPv6 is not supported, need to
initalize the global_opts.af_hint to AF_INET or systems such as Linux that
have a native getaddrinfo() because they support IPv6 will attempt to
create IPv6 sockets.  This brings up a problem with the new global_opts
structure; in order to initialize them to a value other than 0, we need to
explicitly initialize them all in an order that matches the order in
rsync.h.  I think that's more inconvenient & error prone than keeping
global variables.
2001-12-14 18:25:51 +00:00
David Dykstra
cb1bcc7ebb open_socket_in was attempting to try all the protocols returned from
getaddrinfo(), but only if a corresponding call to socket() returned one of
three *NOSUPPORT errno codes.  A Redhat 6.2 system was observed returning
EINVAL instead so it never went on to try IPv4.  This update adds EINVAL to
the list.  Question: why not always continue through the list regardless of
what errno is?
2001-12-14 18:00:54 +00:00
Martin Pool
19ba7d6318 Verbose. 2001-12-14 05:55:21 +00:00
Martin Pool
7753ca1f49 Only show test output if it failed. 2001-12-14 05:54:24 +00:00
Martin Pool
d52a796c39 Be less verbose. 2001-12-14 05:52:25 +00:00
Martin Pool
60514d457c Fix quoting. 2001-12-14 05:44:04 +00:00
Martin Pool
5bc00efe42 Perhaps Solaris sh wants us to explicitly exit 0, rather than just
using the last return code?
2001-12-14 05:27:42 +00:00
Martin Pool
c45f3133bc More error messages. 2001-12-14 05:19:15 +00:00
Martin Pool
fb47591de0 Typo. 2001-12-14 05:17:52 +00:00
Martin Pool
514d129c49 Make scratch directory properly. 2001-12-14 05:01:48 +00:00
Martin Pool
db843fc12d Doc. 2001-12-14 02:18:31 +00:00
Martin Pool
63787382d8 Clearer error messages. 2001-12-14 02:16:20 +00:00
Martin Pool
85d4d142d8 Clearer error messages. 2001-12-14 02:14:58 +00:00
Martin Pool
3cd2af41e4 Add a test that when none of -l, -L, -a are specified symlinks are not
copied at all.
2001-12-14 02:01:46 +00:00
Martin Pool
b214eda4f0 Clean scratch directory between each test run. 2001-12-14 01:52:43 +00:00
Martin Pool
0771727d41 Readlink(2) does not nul-terminate the output buffer, so we were
getting corrupt output when listing more than one symlink.
2001-12-14 01:48:48 +00:00
Martin Pool
a5d74a1876 Fix contact details. 2001-12-14 01:09:23 +00:00
Martin Pool
23bf32f767 Don't define DEBUG with --enable-debug, because that makes zlib emit strange messages 2001-12-09 21:48:13 +00:00
Martin Pool
87a819edee IRIX cc cares that the operands to the ternary have the same type. 2001-12-05 13:48:41 +00:00
Martin Pool
27a1234874 Be more strict about 'enum logcode' rather than int. IRIX compiler
picked this up -- quite neat.
2001-12-05 13:45:51 +00:00
Martin Pool
51f289d1e6 Some platforms don't have sa_family_t. 2001-12-05 13:44:37 +00:00
Martin Pool
d0d6dc61e8 Bump version 2001-12-05 13:41:38 +00:00
Martin Pool
d91c8c50d2 RFC2553 just says that sockaddr_storage has to have initial fields
isomorphic to sa_family etc from a struct sockaddr, not what they're
called.  On some platforms they seem not to be called ss_family.
Rather than guess, we will try casting to a sockaddr and looking
through that -- I think this is what the RFC intends.
2001-12-05 13:25:29 +00:00
Martin Pool
e20a4f84d6 Some platforms may have getaddrinfo() but not sockaddr_storage. 2001-12-05 13:19:16 +00:00
Martin Pool
bbd6f4ba8e Document --no-detach. 2001-12-05 13:10:24 +00:00
Martin Pool
2a951cd2f9 Fix help message for --address option 2001-12-05 13:06:26 +00:00
Martin Pool
a538066d5a Add --no-detach option for W32, daemontools, etc. 2001-12-05 13:03:16 +00:00
Martin Pool
c10b0bdd50 Doc 2001-12-05 13:02:11 +00:00
Martin Pool
431efc8979 Doc. 2001-12-05 12:56:06 +00:00
Martin Pool
2d6dbe290c Change back to using sockaddr_storage rather than sockaddr_in. If
sockaddr_storage is not defined, then supply our own definition that
will hopefully satisfy RFC2553 but also compile on all supported
platforms.

Thankyou to YOSHIFUJI Hideaki, SUMIKAWA Munechika and Jun-ichiro
"itojun" Hagino.
2001-12-05 12:48:46 +00:00
Martin Pool
c33e3e3967 Suggestions from KAME IPv6 newsletter. 2001-12-05 12:25:36 +00:00
Martin Pool
71b3374bd5 Note from tpot that sighup should have standard behaviour of reinitializing. 2001-12-05 00:58:20 +00:00
David Dykstra
de343e3cce Don't print out the directory name twice in verbose mode; it was being
printed a second time when the modification time of the directory was
being set, and that time around recv_files() calls recv_generator() with
an f_out of -1 so check that before printing the directory name.
2001-12-03 18:37:33 +00:00
Martin Pool
384958ed3d Note about crash from Ayamura KIKUCHI 2001-12-02 22:47:30 +00:00
Martin Pool
1cd5beeb06 batch reindent 2001-12-02 22:28:50 +00:00
Martin Pool
4c70e359d0 Bump version 2001-12-02 22:26:09 +00:00
Martin Pool
f9c3005bff Fix FP usage. 2001-12-02 14:12:03 +00:00
Martin Pool
9147074d8b Oops, units bug. 2001-12-02 13:58:03 +00:00
Martin Pool
7007bddaef Show time-remaining as hh:mm:ss. 2001-12-02 13:45:38 +00:00
Martin Pool
2f8dc29182 Update notes 2001-12-02 13:22:55 +00:00
Martin Pool
6066594bbe Improved estimation algorithm for time-to-complete. 2001-12-02 13:07:07 +00:00
Martin Pool
40c0289176 Typo fix by Tom Schmidt 2001-12-02 13:02:17 +00:00
Martin Pool
acf1af0cd9 const-cast required for silly UNICOS headers 2001-12-02 12:37:48 +00:00
Martin Pool
62791bdfa2 Also estimate time remaining. 2001-12-02 08:56:25 +00:00
Martin Pool
47f1218d69 Progress indicator now shows estimated rate of transfer (e.g. kB/s).
Based on a patch from Rik Faith, but modified to make sure we do only
one rprintf call, and that we never end up with two copies of the line
printed out.
2001-12-02 08:38:51 +00:00
Martin Pool
1179355dab Revert change from 1.39, because it causes a crash because of
attempting to free a static string.  (Thankyou to Paul Mackerras.)
There's still a small leak here.
2001-12-02 08:16:15 +00:00
Martin Pool
3d807132e4 Fix test suite breakage in calling tls.
Clean up test directory on completion.
2001-12-02 07:22:54 +00:00
Martin Pool
42d0b4c280 Bump version 2001-12-02 07:21:55 +00:00
Martin Pool
d313ae7d23 Move old news from release 2.5.0. 2001-12-02 07:17:50 +00:00
Martin Pool
28a69e25ea More notes from email. 2001-12-02 07:07:43 +00:00
Martin Pool
ad911a7ac3 Typo fix from Matt Kraai <kraai@debian.org> 2001-12-02 06:17:33 +00:00
Martin Pool
5575de140d Add note about device major/minor numbers, and about ACLs 2001-12-02 05:12:39 +00:00
David Dykstra
a5ce1eb1af Add "$(OBJS): config.h" so everything will rebuild if config.h changes. 2001-11-30 22:21:20 +00:00
Martin Pool
76a78cd8bc Add message to ignore warnings about mktemp 2001-11-30 22:06:29 +00:00
rsync-bugs
0b25efc12a Modified file stored as well 2001-11-30 00:31:06 +00:00
rsync-bugs
64cae087b6 preparing for release of 2.5.0 2001-11-30 00:29:46 +00:00
Martin Pool
b7cc59c503 Spec file needs to be generated from a template to include the version
number.
2001-11-30 00:29:20 +00:00
rsync-bugs
7eb8d18a99 preparing for release of 2.5.0 2001-11-30 00:23:11 +00:00
Martin Pool
e7bf3e5e87 Last bug fix for 2.5.0? Make the documentation for -a point out that
it does not in fact propagate hardlinsk.
2001-11-30 00:17:53 +00:00
Martin Pool
5aafd07b37 Note error cases that we ought to improve. 2001-11-30 00:16:14 +00:00
Martin Pool
053f3a831d Note other supported platforms 2001-11-30 00:15:32 +00:00
Martin Pool
a2d2e5c047 Add notes on things to do mentioned on the list in the last few months. 2001-11-29 01:31:31 +00:00
Martin Pool
dd3a922035 IPv6 support is now merged. 2001-11-29 00:23:29 +00:00
Martin Pool
0e916c6038 Just include rsync.h rather than all the individual headers.
(Suggestion from Dave Dykstra.)
2001-11-29 00:15:20 +00:00
Martin Pool
87fcb63975 No need to test for memcmp, because even broken ones are good enough
for our purposes.  (Patch from Dave Dykstra.)
2001-11-29 00:08:36 +00:00
Martin Pool
68b2cc5538 Show version when configuring.
If we don't seem to have an ANSI compiler, then omit a warning as soon
as that is discovered, because it is likely to break later configure
tests.  This doesn't seem to catch the particular HP-UX compiler I was
after, which is non-ANSI but only emits a warning on this configure
test.  Nevertheless probably better to have it in.
2001-11-29 00:04:48 +00:00
Martin Pool
4dcf3697ff Add list of platforms that build. 2001-11-28 07:49:32 +00:00
Martin Pool
ea77525546 Note half-baked Darwin IPv6 support. 2001-11-28 07:12:09 +00:00
Martin Pool
17d5a07ec2 Put back the --disable-ipv6 option. This should only be needed if
your platform seems to support ipv6, but actually it breaks.  This
seems to be the case for "powerpc-apple-darwin1.4".
2001-11-28 06:52:04 +00:00
Martin Pool
3966b9c609 Call this 2.4.7pre4 2001-11-28 04:32:33 +00:00
Martin Pool
1c47fbd96b Note on HP-UX's bundled so-called C compiler. 2001-11-28 04:10:39 +00:00
Martin Pool
1691bdcafc HP's cpp apparently can't handle whitespace before #include 2001-11-28 03:12:20 +00:00
Martin Pool
6a5ef41fb3 HP's cpp chokes on preprocessor directives that have whitespace before
the '#'.  Off to the Implant Office with you!
2001-11-28 02:55:20 +00:00
Martin Pool
09b6f4b00d Fix inet_ntop/pton names 2001-11-28 01:29:41 +00:00
Martin Pool
7067b0aa28 Protect AF_INET6 references with #ifdef INET6 2001-11-28 00:36:32 +00:00
Martin Pool
112e731150 Fix sh 2001-11-27 07:59:34 +00:00
Martin Pool
1336e41460 Show symlink targets 2001-11-27 07:56:33 +00:00
Martin Pool
7c1b7890d3 Be a bit more verbose 2001-11-27 07:54:48 +00:00
Martin Pool
dd0700b025 mtime and ownership of symlinks can be random, so don't print them. 2001-11-27 07:54:03 +00:00
Martin Pool
04d8e8b25f Be a bit more verbose 2001-11-27 07:32:42 +00:00
Martin Pool
3723efcb1d Try to fix headers for UNICOS 2001-11-27 07:23:58 +00:00
Martin Pool
054b40b6fa Unbreak recursive ls test 2001-11-27 07:19:37 +00:00
Martin Pool
6773a7798f Oops, fix bash syntax 2001-11-27 07:09:47 +00:00
Martin Pool
2d4c8e5945 The size of anything but a regular file is probably not worth thinking
about.
2001-11-27 07:07:36 +00:00
Martin Pool
087173c887 When producing a ls-style permissions string, also handle
sticky/setuid/setgid bits the same way as GNU ls.
2001-11-27 07:05:33 +00:00
Martin Pool
57835c00ad Use tls rather than the OS's ls(1) so that we have more chance of
reproducible results.
2001-11-27 06:51:51 +00:00
Martin Pool
4ed886ae6e Also list permissions, ownership, size, and mtime. 2001-11-27 06:45:47 +00:00
Martin Pool
740819ef7b Split code to generate "rwx-----" strings into lib/permstring.c so it
can be reused in tls.
2001-11-27 06:43:17 +00:00
Martin Pool
829230689e Build getaddr/nameinfo into lib/. 2001-11-27 06:41:38 +00:00
Martin Pool
77ba4cc2f9 make clean can rm config.cache but not config.h, or it wil jam.
Build getaddr/nameinfo into lib/.

Split code to generate "rwx-----" strings into lib/permstring.c so it
can be reused in tls.
2001-11-27 06:39:02 +00:00
Martin Pool
e94989fe4d Try to fix LIBOBJ detection of ntop/pton. 2001-11-27 06:17:33 +00:00
Martin Pool
c11b88061f Fix missing parameter in log call. 2001-11-27 06:01:05 +00:00
Martin Pool
647c5433f8 Make clean should also remove the autoconf cache etc. 2001-11-27 05:35:14 +00:00
Martin Pool
8f694072a5 Add Paul Vixie's implementation of inet_ntop and inet_pton for
platforms that don't have them.
2001-11-27 05:22:23 +00:00
Martin Pool
9a689986c6 Look in -lresolv for inet_ntop 2001-11-27 04:53:08 +00:00
Martin Pool
3174b31d96 Check for inet_ntop and inet_pton, which may be missing. 2001-11-27 03:49:53 +00:00
Martin Pool
4eb61975b7 Explain IPv6 merge. 2001-11-27 02:28:36 +00:00
David Dykstra
76e26e1042 Better fix for case of excluded symlinks that point nowhere when using
--copy-links.  The readlink_stat() does need to be done in the normal case
before checking the exclude patterns because it needs to know whether or
not a file is a directory in order to properly handle a trailing slash
in an exclude pattern.  This fix makes make_file() go ahead and call
readlink_stat() but then if the latter returns an ENOENT and copy_links is
on then it will only print an error if the path is not excluded.
2001-11-26 19:15:53 +00:00
Martin Pool
9069dfd005 Fix rename of global option 2001-11-26 08:21:30 +00:00
Martin Pool
2be5d2daad Remove kame cruft 2001-11-26 08:21:14 +00:00
Martin Pool
22cd0063e5 Attempted clean up some of the IPv6 tests. 2001-11-26 08:20:13 +00:00
Martin Pool
3d2e458a4d Fix a small memory leak that was causing an Insure warning. 2001-11-26 07:58:47 +00:00
Martin Pool
a57568d716 Oops, no C++ comments. 2001-11-26 07:47:59 +00:00
Martin Pool
61f543cade Kill a function for jra. 2001-11-26 07:11:55 +00:00
Martin Pool
b8771f9615 Try to be better about handling the results of getaddrinfo(): when
opening an inbound socket, we might get several address results,
e.g. for the machine's ipv4 and ipv6 name.

If binding a wildcard, then any one of them should do.  If an address
was specified but it's insufficiently specific then that's not our
fault.

However, some of the advertized addresses may not work because e.g. we
don't have IPv6 support in the kernel.  In that case go on and try all
addresses until one succeeds.
2001-11-26 07:10:06 +00:00
Martin Pool
d5d4b28220 Put the new address family option into an options struct. We have too
many globals already.

Better error messages for network-related failures.
2001-11-26 04:52:19 +00:00
Martin Pool
a037edaccd Silly autoconf 2001-11-26 01:49:33 +00:00
Martin Pool
356bbb8351 Check for -lnsl, -lsocket, etc, *before* looking for getaddrinfo,
because on Solaris (for one) it's not in libc.
2001-11-26 01:15:12 +00:00
Martin Pool
1f0fa9318a Remove highly suspicious redefinition of sockaddr structure -- there
seems no point using anything but the platform's native definition,
and if we can't get that from the system headers we're hosed anyhow.
2001-11-26 00:41:11 +00:00
Martin Pool
15c1707887 Remove check for buggy getaddrinfo for the time being -- it's unclear
how this is supposed to help.

Check for netdb.h
2001-11-26 00:23:29 +00:00
Martin Pool
9dec7aa9c1 Make some of the headers used by the KAME getaddrinfo implementation
be conditional -- they are missing on e.g. Solaris.  Not sure if this
will fix it.
2001-11-25 09:30:36 +00:00
Martin Pool
bc3d7454e0 Fix KAME patch to use proper autoconf AC_MSG macros rather than just echo/exit. 2001-11-24 05:38:35 +00:00
Martin Pool
56901bc7c3 Call this pre3. 2001-11-24 05:33:35 +00:00
Martin Pool
5c7f570b16 IPv6 is off by default. 2001-11-24 05:31:40 +00:00
Martin Pool
4f6e5fe323 IPv6 is off by default -- it seems to break header files on too many systems. 2001-11-24 05:30:27 +00:00
Martin Pool
7d682ffea7 Note IPv6 and nohang patches. 2001-11-24 05:13:12 +00:00
Martin Pool
cef40af209 Get rid of rule disliked by Sun Make. 2001-11-24 05:06:07 +00:00
Martin Pool
a358449ab1 Set rsync version in configure.in
Show IPv6 availability in --version.
2001-11-24 04:57:41 +00:00
Martin Pool
8ef6b72514 Fix Makefile syntax problem when LIBOBJS is defined. 2001-11-24 04:33:07 +00:00
Martin Pool
620bbabc61 Try to get IPv6 support, unless --disable-ipv6 is explicitly specified. 2001-11-24 04:29:37 +00:00
Martin Pool
7ef6aa6405 Improved error messages. 2001-11-24 04:22:20 +00:00
Martin Pool
7ad1d4fd66 Rebuild if headers changed. 2001-11-24 04:16:18 +00:00
Martin Pool
bf5c2bf604 More autoconf fixes. 2001-11-24 04:12:54 +00:00
Martin Pool
b8fe70a516 Ignore trash 2001-11-23 07:37:26 +00:00
Martin Pool
06963d0fca Merge KAME.net IPv6 patch: you can now (in theory) pass IPv6 hostnames
or literal IP addresses to rsync, and if your platform supports them
they will be used.  Also there are -4 and -6 command-line options to
choose the default address type.  Thankyou!
2001-11-23 07:35:49 +00:00
David Dykstra
b964901f7d Fix to make_file() to exit earlier if a file is excluded, because doing
readlink_stat() on an excluded file can be a problem when using the
--copy-links option (also known as -L) and the excluded file is a symlink
that points nowhere.
2001-11-16 19:19:44 +00:00
Martin Pool
b52c1d9d3a Document chroot confusion. 2001-11-09 06:58:39 +00:00
Martin Pool
a24e12e6dd More notes. 2001-09-12 14:35:39 +00:00
Martin Pool
3c6cd53b23 Think think. 2001-09-12 14:20:44 +00:00
Martin Pool
4f69fe59c7 Start to wrap up all thoughts on what should happen for rsync 3. 2001-09-12 08:51:24 +00:00
Martin Pool
d2e02b7d96 Fix from Marc Espie to make included-popt work with VPATH builds. 2001-09-12 08:46:29 +00:00
Andrew Tridgell
a57873b710 fixed check for timeout in generator
the generator can easily make no progress for a long time, so don't do
timeout processing checks
2001-09-09 04:42:09 +00:00
Andrew Tridgell
30ce7e8a64 64-bit files depends on the size of OFF_T, not off64_t 2001-09-09 04:41:14 +00:00
Andrew Tridgell
f0af1e5ec6 debian stable screws up largefile support for fcntl locking. This adds
a test for the screwup and disables largefile support
2001-09-08 12:48:50 +00:00
Martin Pool
f7ca98bdc4 Doc. 2001-09-07 07:57:10 +00:00
Martin Pool
7df0935a51 Add a little implementation of ls(1) so that we can look at all and
only the attributes of files that rsync is meant to synchronize.

Test cases should depend on testing tools.
2001-09-07 07:52:34 +00:00
Martin Pool
f22ee86517 Add a little implementation of ls(1) so that we can look at all and
only the attributes of files that rsync is meant to synchronize.
2001-09-07 07:52:09 +00:00
Martin Pool
8f98c608b9 Remove test trace stuff. 2001-09-07 07:50:31 +00:00
Martin Pool
32c58f06e0 Try to exit 0 if nothing fails. 2001-09-07 07:49:34 +00:00
Martin Pool
040f7b6595 Update copyright notice. 2001-09-07 07:35:08 +00:00
Martin Pool
d2476f0db3 Debug exit status -- on Sun1/cc all the tests pass, but make sees an
exit status of 1. ???
2001-09-06 13:12:28 +00:00
Martin Pool
952cf8f4f3 Oops, some machines don't have which. 2001-09-06 13:07:52 +00:00
Martin Pool
a138e47560 Oops, some machines don't have which. 2001-09-06 13:04:48 +00:00
Martin Pool
7d6916547f See if head(1) works -- broken on some systems? 2001-09-06 06:34:24 +00:00
Martin Pool
6cd7888e46 You cannot do "export VAR=VALUE" all on one line; the export must be
separate from the assignment.  (SCO SysV)
2001-09-06 06:30:09 +00:00
Martin Pool
1d54358e52 Fix selective definition of *snprintf. (Welcome to mbp's breakage world.) 2001-09-06 06:27:02 +00:00
Martin Pool
4c80c473ed More testsuite cleanups. Now I hope we cope without 'cp -a', though
we still need 'cp -p'.
2001-09-06 06:21:15 +00:00
Martin Pool
571a4b2654 BSD machines don't seem to have head(1). 2001-09-06 06:06:13 +00:00
Martin Pool
501972bf72 Split the 'longdir' test into its own script, and make it work without
'mkdir -p'.
2001-09-06 05:57:27 +00:00
Martin Pool
99cdaff70d Add a makepath() function to cope with machines that do not have
'mkdir -p'.  (Stone knives and bearskins...)
2001-09-06 05:52:40 +00:00
Martin Pool
c36b5017b8 Doc.
Look at $whichtests to run just a subset -- good for calling from Make.
2001-09-06 05:50:48 +00:00
Martin Pool
a4cf6bec19 Fix comment. 2001-09-06 04:56:55 +00:00
Martin Pool
0154b302ce Fiddle umask again. 2001-09-06 04:56:02 +00:00
Martin Pool
ec99e9da81 Clean up output a little. 2001-09-06 02:30:06 +00:00
Martin Pool
e052b21f32 Set umask so that symlinks will have the right permissions on BSD. 2001-09-06 02:26:21 +00:00
Martin Pool
b2f0246498 For log messages containing ridiculously long strings that might
overflow a buffer rsync no longer aborts, but rather prints an
ellipsis at the end of the string.  (Patch from Ed Santiago.)
2001-09-04 03:12:55 +00:00
Martin Pool
c1659c79ef Clean up from rsync+ patch; fix compiler warning. 2001-08-31 09:27:35 +00:00
Martin Pool
4a7cb3e8a8 Fix sh syntax for FreeBSD. 2001-08-31 09:26:34 +00:00
Martin Pool
0de40240bb If we're using built-in *printf functions, then provide prototypes. 2001-08-31 09:23:06 +00:00
Martin Pool
d79c77caca Cope on machines without INADDR_LOOPBACK. 2001-08-31 08:22:00 +00:00
Martin Pool
2b106d0b3a Ignore test tmp dir. 2001-08-31 08:16:23 +00:00
Martin Pool
8fef024528 Run the daemon test using faked tcp connections. 2001-08-31 08:13:57 +00:00
Martin Pool
6963e540db Grammar fix. 2001-08-31 08:12:35 +00:00
Martin Pool
3ef526f5fa Add comment about handling of 'use chroot' 2001-08-31 08:08:42 +00:00
Martin Pool
eecd22ff7b Merge in the LIBSMB_PROG idea from samba, so that you can do
RSYNC_CONNECT_PROG='./rsync --daemon' ./rsync -vvvvvv  localhost::

to test as a daemon without actually having to listen on a port.
2001-08-31 07:06:13 +00:00
Martin Pool
add7e8fb6b Doc.
Try to give a better error message when there is a remote option error.
2001-08-31 06:48:35 +00:00
Martin Pool
f6e09367a7 Option should be --recursive, not --recurse. (This is what it was in
--help and 2.4.6.)
2001-08-31 06:29:45 +00:00
Martin Pool
3aae15ecfb Fix rsyncd.conf generation. 2001-08-31 05:49:16 +00:00
Martin Pool
f5ad6eb18d Fix message. 2001-08-31 05:48:19 +00:00
Martin Pool
7f1b717ac7 Show rsync version before doing anything else. 2001-08-31 05:45:49 +00:00
Martin Pool
55bdb41632 Skip SSH tests if $rsync_enable_ssh_tests is not set 2001-08-31 05:41:45 +00:00
David Dykstra
7c06e407ec The --compare-dest option was not listed as accepting a string parameter
like it was supposed to.  There should probably be a testsuite test for
--compare-dest.
2001-08-30 16:24:03 +00:00
Martin Pool
c13ad7ec47 fix bashism 2001-08-30 08:28:53 +00:00
Martin Pool
d2094cc33d Split out generic functions for starting rsyncd. 2001-08-30 07:14:57 +00:00
Martin Pool
c3469aed19 Notes on an interactive shell for rsync. 2001-08-30 07:11:46 +00:00
Martin Pool
232ce2b2c8 Start testing daemon functionality 2001-08-30 07:10:45 +00:00
Martin Pool
882582b307 Run all scripts in the testsuite/ directory, not just named ones. I'd
like to make this script not rsync-specific if possible.
2001-08-30 07:10:20 +00:00
Martin Pool
ebaa0489b4 Abandoned 2001-08-30 06:56:57 +00:00
Martin Pool
1a1c244dc3 Obsolete 2001-08-30 06:54:59 +00:00
Martin Pool
320989b05d On BSD, this seemed to always exit after test failure. Try different
shell syntax.
2001-08-30 06:54:15 +00:00
Martin Pool
9d682a8dc1 More debug output for testing SSH. 2001-08-30 06:51:58 +00:00
Martin Pool
37c3cf430d Try using diff -c' not diff -u' because the latter seems to be
broken on SCO2.
2001-08-30 06:35:48 +00:00
Martin Pool
751411c40d Use rsync source rather than /etc for files because things in /etc
might be protected or missing on some systems.
2001-08-29 09:38:28 +00:00
Martin Pool
6a46226b3a BSD doesn't have /etc/resolv.conf or /etc/inittab, and hands.test was
trying to use them as a source of noise.
2001-08-29 09:27:43 +00:00
Martin Pool
42e66aa24c Apparently `set -x' in the shell works on some Bourne shells, but not SCO. 2001-08-29 09:24:35 +00:00
Martin Pool
5cb1f5c795 Apparently '!' to invert a pipeline result doesn't work on UnixWare. 2001-08-29 09:23:19 +00:00
Martin Pool
12b9c8409e Return the *number of tests that failed*, so that it will show up
nicely in the overall summary.
2001-08-29 09:20:35 +00:00
Martin Pool
e8ca590142 Cleanup check_logs feature.
`ps ax' is not portable -- don't use it to generate random text.  Use
`ls -lR' instead.
2001-08-29 09:18:45 +00:00
Martin Pool
863dff5179 Cleanup check_logs feature. 2001-08-29 09:15:17 +00:00
Martin Pool
3fedd74ba2 Clean up Phil's test more.
Make the checkit() routine more generic.

Split out ssh tests.
2001-08-29 09:13:01 +00:00
Martin Pool
78ffe4787f $RSYNC and similar variables must be set to absolute path so that it
can be passed to --rsync-path.

Add a nopersist=yes option that makes runtests bomb out as soon as one
test fails -- this is good if you're watching the trace output.
2001-08-29 09:12:05 +00:00
Martin Pool
a4b4af889b $RSYNC must be set to absolute path so that it can be passed to --rsync-path 2001-08-29 09:11:14 +00:00
Martin Pool
d286ee98b9 Count overall failure if some expected scripts were missing. 2001-08-29 08:48:00 +00:00
Martin Pool
42be591878 Remove testtmp directory on 'clean'.
Run test scripts in POSIX mode to try to catch portability problems.
2001-08-29 08:46:18 +00:00
Martin Pool
3a4c683f04 More test case work:
* make sure to build rsync before running 'make check'

 * Put back in the loglevel concept from the samba scripts.  If >8,
   then turn on shell tracing.

 * Allow tests to return 77 if they want to count as 'skipped'.

 * Add more docs.

 * Mangle Phil's script to get ready to run on non-Linux systems: we
   need to not use shell functions, cp -a, etc.  Not there yet.
2001-08-29 08:13:19 +00:00
Martin Pool
e7d29902a6 Redraft testsuite driver script to unify 'make check', 'make
installcheck' and buildfarm tests.

Add note from discussion with Tim about finding files/directories
under different circumstances.  Now works (?) with VPATH build.
2001-08-29 07:33:27 +00:00
Martin Pool
64bd756832 Add comment: cyeoh says that getpass is deprecated, because it may
return a truncated password on some systems, and it is not in the LSB.
2001-08-29 07:23:30 +00:00
David Dykstra
8642efd0d6 The --with-rsync-path configure option was using the wrong configure
variable "$with_rsync_name" instead of "$with_rsync_path".
2001-08-27 16:23:41 +00:00
Martin Pool
063393d62d Only use the "@RSYNC EXIT" tag if we're talking to a client about
version 25.  This prevents it appearing and messing up the module list
when an old client connects to a 2.4.7 server.
2001-08-23 06:14:54 +00:00
Martin Pool
7a55d06e0d Allow the server to terminate the module list by just closing the
socket, rather than sending a proper EXIT command.  Keep the
global-variable hack to do this, but try to make it only apply in the
specific case where that occurs, not on all lines we read.
2001-08-22 04:15:50 +00:00
Martin Pool
6f82f7a6f6 Add a little more protocol documentation. 2001-08-22 04:14:05 +00:00
Martin Pool
33d213bb37 Note about cross-testing different versions. 2001-08-22 04:09:07 +00:00
Martin Pool
a426e396c4 Return 1 if any tests failed so that the build farm can pick it up. 2001-08-21 14:06:52 +00:00
Martin Pool
fafeb69cb6 Change test directory again. 2001-08-21 13:44:08 +00:00
Martin Pool
b9277bdb6a Don't look at $srcdir if it's not set. (Why isn't it set??) 2001-08-21 13:26:30 +00:00
Martin Pool
b53713d322 Show trace while testing. 2001-08-21 13:20:53 +00:00
Martin Pool
2f22174f21 Try again to find the right directory on both local and farm builds. 2001-08-21 13:10:18 +00:00
Martin Pool
d820215b35 More test suite stuff 2001-08-21 13:00:55 +00:00
Martin Pool
ea4a03762a Print source directory. 2001-08-21 12:49:23 +00:00
Martin Pool
46ef7d1dc8 Update notes; add idea about rsyncsh 2001-08-18 23:50:27 +00:00
Martin Pool
e340a8203e Export autoconf settings to test scripts. Use this to cope with
systems that don't use "echo -n".
2001-08-17 01:57:42 +00:00
Martin Pool
3459d319d1 Set up scratch directory for tests. 2001-08-17 01:44:13 +00:00
Martin Pool
09ec75a629 Don't pause at end of tests. 2001-08-17 01:43:13 +00:00
Martin Pool
4df7868d39 Try to fix "make check" directory path.
Don't wait for input at end of tests.
2001-08-17 01:34:31 +00:00
Martin Pool
bc888e05da Find the right directory to run the test components. 2001-08-17 00:58:21 +00:00
Martin Pool
26c7f120e6 Try to get test scripts to run properly. 2001-08-17 00:51:20 +00:00
Martin Pool
5b7be6ee4a Show number of passed/failed/skipped tests. 2001-08-16 09:37:54 +00:00
Martin Pool
951351a537 Don't print test headers unless the test is about to run. 2001-08-16 09:35:21 +00:00
Martin Pool
0b21c485ec Note test suite.
Note autoconf2.52 is required.
2001-08-16 09:16:08 +00:00
Martin Pool
068a7221ce Move Phil Hand's test under the control of the master test suite. 2001-08-16 09:13:37 +00:00
Martin Pool
a4772a4dbc Start to unify the "make check" and build farm test suites 2001-08-16 09:08:29 +00:00
Martin Pool
2ee91aedb1 Use set -x until this script works properly. 2001-08-16 08:13:13 +00:00
Martin Pool
d95447229b Fix typo. 2001-08-16 08:12:55 +00:00
Martin Pool
40ec33b604 Gave directory its proper name 2001-08-16 07:08:26 +00:00
Martin Pool
35e3b2d555 fix filename 2001-08-16 06:27:51 +00:00
Martin Pool
aa9c2df9d9 Updated directory name for rsync tests 2001-08-16 06:24:56 +00:00
Martin Pool
f472cdf017 Try to execute rsync --version as part of the test suite -- see if
this works on the farm.
2001-08-16 05:44:17 +00:00
Martin Pool
1dc587af1b Fix cast warning. 2001-08-15 08:52:10 +00:00
Martin Pool
aeb6292d0d Try to get tests to run with old buildfarm clients 2001-08-15 08:06:26 +00:00
Martin Pool
7d91d5a619 Check that gethostbyname does actually return AF_INET addresses, since
that's all we can handle.

Also, try a new method of handling in_addr and hostent that will
hopefully work on Cray machines without 32-bit types.
2001-08-15 07:52:28 +00:00
Martin Pool
7169bb4aa9 Fix a bug introduced in 1.119, whereby strings like
"mirror.aarnet.edu.au::" were not properly digested.

It wasn't even my bug! :-)
2001-08-15 07:50:07 +00:00
Martin Pool
2db52650fc Fix another format cast. 2001-08-15 06:50:46 +00:00
Martin Pool
c1f62a573a Use socklen_t for getpeername, since we hopefully now have it defined
on all platforms.
2001-08-15 06:47:40 +00:00
Martin Pool
08a740ff43 Fix casts when some variables are printed out. 2001-08-15 06:41:24 +00:00
Martin Pool
b67381d0dc Drop dead variables introduced in rsync+ patch. 2001-08-15 06:38:23 +00:00
Martin Pool
07e9500818 Fix trace message which was missing a parameter.
Drop dead variable introduced in rsync+ patch.
2001-08-15 06:34:28 +00:00
Martin Pool
c77cf82206 Add the start of a buildfarm test suite for rsync. It doesn't do much
yet -- I just want to see if it runs.
2001-08-15 05:47:57 +00:00
Martin Pool
f8014b864e Typo. Shouldn't depend on assert(). 2001-08-15 05:47:29 +00:00
Martin Pool
d58911fb37 Better error messages for DNS. 2001-08-15 05:08:07 +00:00
Martin Pool
b335d74565 Fix bug in --address handling. 2001-08-15 05:07:29 +00:00
Martin Pool
3405fe45f4 Note UNICOS works again 2001-08-14 02:28:12 +00:00
Martin Pool
095efec1d6 Spec file from Jason Haar that works on RedHat 7.1. Not tested by me yet. 2001-08-14 02:24:09 +00:00
Martin Pool
7ca6e85649 Commit getconf/socklen_t/largefile patch suggested by Albert Chin.
This is tested on
  Solaris 2.5.2, 2.6, 7, 8/SPARC, HP-UX 10.20, 11.00,
  Tru64 UNIX 4.0D, 5.0A, IRIX 6.2, 6.5, AIX 4.3.2
and it works ok.

This patch *requires* autoconf 2.52.
2001-08-14 02:18:04 +00:00
Martin Pool
74be4fc399 Remove incorrect news message 2001-08-14 02:14:09 +00:00
Martin Pool
3b4b1984ef Update version message to mention batch files. 2001-08-14 02:08:17 +00:00
Martin Pool
6902ed178b Merge across rsync+ patch; add a little documentation to the manpage. More documentation would be better. 2001-08-14 02:04:47 +00:00
Martin Pool
fab9a9c547 Another try at socklen_t: just check for it, and otherwise use int.
The HP manual says this will work on old HP/UX versions; I'm not sure
about other systems.  Possibly it will break on old BSD-derived
systems with 32-bit int, 64-bit size_t and no socklen_t, if there are
any such.
2001-08-08 10:04:40 +00:00
Andrew Tridgell
376acbfad5 don't need to lookup our own name in open_socket_in() 2001-08-08 08:55:24 +00:00
Martin Pool
12458878c2 Try various different types as replacements for socklen_t until we
find one that works.  This helps on platforms like HP/UX and UNICOS
where the argument to getsockopt is neither socklen_t nor int.
2001-08-08 08:11:50 +00:00
Martin Pool
546434f867 Two more instances of socklen_t. 2001-08-06 12:31:23 +00:00
Martin Pool
ac2a1a449d Use socklen_t if defined, or otherwise int. This tries to fix
warnings on platforms (e.g. AIX) where this type is defined and not
int.
2001-08-06 12:27:04 +00:00
Martin Pool
e1bd49d6f3 Try to fix "infinite loop" warning on AIX and other compilers. (We
exit on a signal.)
2001-08-06 12:25:45 +00:00
Martin Pool
ab94af5c6f Correct over-zealous edit for UNICOS. 2001-08-06 12:23:50 +00:00
Martin Pool
c88ca682ef Fix for UNICOS CC: first argument to readlink must not be const, or we
get an error.
2001-08-06 12:16:20 +00:00
Martin Pool
fc990e81cb Document autoconf updates. 2001-08-06 08:51:48 +00:00
Martin Pool
e2ba16ccea Fix check for ino_t to work with both autoconf2.50 and autoconf2.13. 2001-08-06 08:49:19 +00:00
Martin Pool
76d4988d06 Fix m4 quoting to make autoconf2.50 happy. I checked it still works
on 2.13.  See "info:(autoconf)New Macros".
2001-08-06 08:41:13 +00:00
Martin Pool
25ea348bd1 Summarize all the changes since 2.4.6 so we have them in one place. 2001-08-06 04:31:05 +00:00
Andrew Tridgell
8ca5756339 updated config scripts from subversion 2001-07-22 02:39:06 +00:00
Andrew Tridgell
029c171330 reap children in sigchld handler 2001-07-17 10:48:31 +00:00
Andrew Tridgell
8f04bb36e7 prevent nasty error msgs when listing shares 2001-07-17 10:45:54 +00:00
Andrew Tridgell
b7334b4c31 removed remnant test code for cray 2001-06-28 05:07:15 +00:00
Andrew Tridgell
a7f8404ecd fixed md4 on 64 bit boxes 2001-06-26 03:09:14 +00:00
Andrew Tridgell
6c65e14634 applied simple nohang patch from Wayne Davison 2001-06-26 01:20:42 +00:00
David Dykstra
ddd491d45e Improve the description of --with-default-rsync. 2001-06-22 20:36:43 +00:00
Andrew Tridgell
5d78a10232 allow shell wildcards in auth users lines 2001-06-22 10:16:04 +00:00
Martin Pool
4d66e00afa If binding to a low-numbered port fails with EACCES, then the error
message should explain that you probably need to be root.

(Why leave off the final S?  Kernighan must have been a *really* slow
typist.)
2001-06-21 06:19:00 +00:00
Martin Pool
531d06b824 Fix from Wayne Davison:
The --cvs-exclude option is broken in the CVS version of rsync
  because of a cut-and-paste-induced bug in exclude.c:

  This bug could cause the sending rsync to crash when it dereferenced
  a NULL pointer.
2001-06-21 06:15:34 +00:00
David Dykstra
c6a7f2f48a Simplify the --with-rsync-path option implementation. Can directly pass
the double-quotes to AC_DEFINE_UNQUOTED instead of having a separate step.
2001-06-13 16:47:22 +00:00
David Dykstra
d4e4cbe105 Use 3rd parameter in AC_DEFINE and AC_DEFINE_UNQUOTED to avoid having to
manually put the defines into acconfig.h.
2001-06-12 21:35:26 +00:00
David Dykstra
41bd28fee3 Add --with-rsync-path option. 2001-06-12 19:33:41 +00:00
David Dykstra
a1a440c23e Make --whole-file the default when source and target are on the local machine. 2001-05-29 14:37:54 +00:00
David Dykstra
089e73f8d6 Ran rsync.yo through yodl2man to produce rsync.1. I found that the string
"file(s)" in rsync.yo was being improperly translated by yodl2man so I
changed it to just "files".
2001-05-24 18:01:56 +00:00
David Dykstra
2c5548d25e Add --ignore-errors documentation. 2001-05-22 14:33:38 +00:00
Andrew Tridgell
65c2a918d4 forgot 1 place that used slprintf 2001-05-07 08:59:48 +00:00
Andrew Tridgell
8950ac03f8 imported new snprintf.c from samba, got rid of slprintf 2001-05-07 06:59:37 +00:00
Andrew Tridgell
26ef00bd3c no space after -I or Tru64 barfs 2001-05-06 13:25:11 +00:00
Andrew Tridgell
efe3037cf5 use _S_IFLNK not S_IFLNK 2001-05-02 11:13:21 +00:00
Andrew Tridgell
f62c17e378 use mkstemp on systems where it is secure 2001-05-02 08:33:18 +00:00
Andrew Tridgell
0f62178580 better pid file location 2001-05-02 05:05:12 +00:00
Andrew Tridgell
81c99202d3 use %.0f instead of %ld 2001-04-13 12:25:19 +00:00
David Dykstra
3473b5b4d8 Add the words "on destination machine" to the --compare-dist description
in rsync.yo.  Re-ran yodl2man which I see pulled in a few other changes
from rsync.yo that hadn't yet made it into rsync.1.
2001-03-23 15:12:52 +00:00
Andrew Tridgell
ba35824322 "rsync error" is better than "transfer error", especially for -h 2001-03-23 03:46:56 +00:00
Andrew Tridgell
6afe7f23b0 got rid of dependency on alloca in popt 2001-03-23 03:44:50 +00:00
Andrew Tridgell
19b27a485e improved error handling again. Now we report messages for the remote
shell failing and propogate errors in a better fashion
2001-03-23 01:26:04 +00:00
Andrew Tridgell
ff81e809f4 new error handling system
we now give a non-0 exit code if *any* of the files we have been asked
to transfer fail to transfer
2001-03-22 07:36:51 +00:00
Andrew Tridgell
fd2dd2aa23 better error msg for "invalid uid" and "invalid gid" 2001-03-21 23:44:48 +00:00
Andrew Tridgell
82ed910630 i hate makefiles that automatically run configure
:)
2001-03-21 23:36:23 +00:00
Andrew Tridgell
90ba34e27c I came up with a new way of avoiding the error handling lockup bug in
rsync. It isn't pretty, but it does work and should completely avoid
that class of lockup.
2001-03-21 13:12:44 +00:00
Martin Pool
8ee3d639b2 Check for alloca.h and mcheck.h, as included popt needs to know about
them.
2001-03-20 05:26:27 +00:00
Martin Pool
0c5a792ac7 Oops, fix edit mistake. 2001-03-19 08:19:11 +00:00
Martin Pool
2af27ad9aa More accurately, the uid/gid is set to -2, not "nobody". 2001-03-17 01:35:59 +00:00
Martin Pool
3b2b534567 Add some todo comments. 2001-03-17 01:34:22 +00:00
Martin Pool
3fa64fd008 Don't unconditionally define _LARGEFILE_SOURCE, but instead include
some autoconf-2.13 macros that make the appropriate settings.  Thanks
to Albert Chin <china@thewrittenword.com> and Paul Eggert
<eggert@twinsun.com>.
2001-03-17 01:06:34 +00:00
Martin Pool
b557c4c7eb Define _LARGE_FILES to turn on LFS support on AIX (and some others?).
See http://www.rs6000.ibm.com/doc_link/en_US/a_doc_lib/aixprggd/genprogc/prg_lrg_files.htm

Thanks to Todd Willeat <TWilleat@MHP.SMHS.com>
2001-03-16 05:23:33 +00:00
Martin Pool
0882faa2b2 Doc. 2001-03-16 02:11:53 +00:00
Martin Pool
3cd5eb3b3b Add my name and a suggestion to read the FAQ for unanswered questions. 2001-02-27 01:49:19 +00:00
Martin Pool
4ff3d9d6b4 Explain that the mktemp warning is harmless.
If the autoconf inputs are changed, then try to reconfigure.  Don't
worry if we can't do it, though.
2001-02-27 01:46:34 +00:00
Martin Pool
26c08b6c21 Add some brief notes on how to install. 2001-02-24 01:45:21 +00:00
Martin Pool
4db4149283 popt-1.5 is const-correct. 2001-02-24 01:39:19 +00:00
Martin Pool
1ac15cd8ad Upgrade from including popt1.2 to a version of popt1.5 trimmed down to
include only source and build from our Makefile.
Don't scan for libpopt if we're using our own; this makes
autoconf confused.
2001-02-24 01:37:48 +00:00
Martin Pool
b348deae3d Upgrade from popt 1.2 to a cut-down 1.5 2001-02-24 01:32:22 +00:00
Martin Pool
18c71e96f8 Doc. 2001-02-23 01:45:46 +00:00
Martin Pool
f0f5767f15 Change from getopt to popt -- requires const-correctness on arguments. 2001-02-23 01:44:56 +00:00
Martin Pool
15b7b73d7d Change from getopt to popt.
Add comments.
Show listening port number in startup log message.
2001-02-23 01:44:04 +00:00
Martin Pool
e420b9d854 Change from getopt to popt.
Add comment.
2001-02-23 01:02:55 +00:00
Martin Pool
2855f61f4a Change from getopt to popt.
Include more details in --version output: say whether symlinks and
hardlinks are supported.
When hardlink support is missing, explain whether the problem is on
the client or server.
When a bad option is encountered, don't just print it to stderr but
send it to the rsync log mechanism.  (However, server errors currently
seem to get lost in transit because of bugs in logging.)
2001-02-23 01:02:31 +00:00
Martin Pool
2d1ebe9c72 Change from getopt to popt.
Automatically build included libpopt if there is none on the system,
or if --with-included-popt is specified.
Add --enable-debug.
2001-02-23 00:48:11 +00:00
Martin Pool
c485a357cc Change from getopt to popt.
Automatically build included libpopt if there is none on the system.
2001-02-23 00:47:09 +00:00
Martin Pool
5013576705 Change from getopt to popt. 2001-02-23 00:45:07 +00:00
Martin Pool
8886f8d0e6 Add comments.
Better error message in the case of eof on read_timeout.
2001-02-22 13:02:39 +00:00
Martin Pool
fcb6d28d0b Note about multiplexing. 2001-02-22 13:01:27 +00:00
Martin Pool
62402cb14b Check in built-in copy of libpopt in preparation for switching
from getopt
2001-02-22 13:01:09 +00:00
Martin Pool
305ab1331b Doc. 2001-02-21 08:25:07 +00:00
Martin Pool
8212336aaa More explanation of return values. 2001-02-21 08:16:45 +00:00
Martin Pool
3e3dcd624f Better message grammar. 2001-02-21 07:18:50 +00:00
Martin Pool
b30b3bb899 Call this 2.4.6dev so that we don't get bug reports claiming to be
about 2.4.6.
2001-02-14 22:59:03 +00:00
Martin Pool
55b64e4b5e Add table of exit values, from errcode.h. 2001-02-14 22:47:28 +00:00
Martin Pool
e411463442 Document shortcoming of "unrecognised option" message. 2001-02-08 03:28:19 +00:00
Martin Pool
660c6fbdaa Include strerror message when there's a socket error. 2001-01-08 10:25:00 +00:00
Martin Pool
ce6c7c6318 Improved error message. 2001-01-08 03:39:53 +00:00
Martin Pool
fa994de488 Ignore generated files that are not stored in CVS. 2001-01-08 03:39:32 +00:00
Martin Pool
2348926995 Typo fix from Jim Meyering 2001-01-08 01:10:58 +00:00
David Dykstra
735a816e54 Better explain how the --blocking-io option works. 2001-01-05 17:57:11 +00:00
Martin Pool
a1b1b1da46 Add comments. 2000-11-15 05:53:45 +00:00
Martin Pool
c3563c46ed Doc. 2000-11-15 03:16:06 +00:00
Martin Pool
0c80cd8ee9 In --version, say whether we have socketpair() or not 2000-11-10 03:41:47 +00:00
Martin Pool
b79f79e3aa Ignore dummy output file 2000-11-10 03:41:17 +00:00
Martin Pool
af642a61b3 If an error occurs, print an explanatory string rather
than just an RERR code.
2000-11-10 03:28:15 +00:00
Martin Pool
ef1aa91039 Doc. 2000-11-10 03:17:08 +00:00
Martin Pool
1960e2280c Drop dead variable. 2000-11-09 09:45:19 +00:00
Martin Pool
7c1b4daa6f Document getsockopt POSIX confusion. 2000-11-09 09:27:34 +00:00
Martin Pool
7a24c346b0 Print a warning message in the version if the platform cannot support 32-bit ints 2000-11-09 09:05:14 +00:00
Martin Pool
64c2cf8fea Better error messages 2000-11-09 09:02:16 +00:00
Martin Pool
81d538ce23 Better error messages when unlink fails 2000-11-08 09:45:16 +00:00
Martin Pool
e327acece4 Better error messages when unlink fails 2000-11-08 09:32:11 +00:00
Martin Pool
4e40377ac2 Better error messages when unlink fails 2000-11-08 09:32:10 +00:00
Martin Pool
eeb1568fd5 Correct license name. Note new address of pserver. Correct documentation. 2000-11-02 11:38:13 +00:00
Martin Pool
0ba481368c Add some comments. 2000-11-02 11:37:34 +00:00
Andrew Tridgell
38bf526fc5 fix bug in handling of : 2000-10-31 10:59:50 +00:00
Martin Pool
bc363ea983 Display a warning about pointlessly using --rsh with clientserver mode. 2000-10-31 01:05:42 +00:00
Martin Pool
84f69dad19 Draft documentation of the client-server protocol. 2000-10-26 08:05:36 +00:00
Martin Pool
4a13b9d57a Print strerror when a system error occurs; add a new function rsyserr
to do this.  This is not used in every case yet -- I've just changed a
few cases that were causing trouble.  Please convert others as you see them.
2000-10-26 07:31:29 +00:00
Martin Pool
a039749b4c Print strerror when a system error occurs; add a new function rsyserr
to do this.  This is not used in every case yet -- I've just changed a
few cases that were causing trouble.  Please convert others as you see them.
2000-10-26 07:24:18 +00:00
David Dykstra
15b84e142a Make sure the log file is always opened before root privileges (if any)
are given up.
2000-10-25 19:57:42 +00:00
David Dykstra
45a8354004 When running as --daemon in the background and using a "log file" rsyncd.conf
directive, close the log file every time it is open when going to sleep on
the socket.  This allows the log file to get cleaned out by another process.
2000-10-24 18:50:08 +00:00
Andrew Tridgell
c32d024071 don't clobber argv[0], so ps shows the right thing 2000-10-19 00:47:48 +00:00
David Dykstra
205c27ac67 Add note in "secrets file" section to see "strict modes". 2000-10-13 13:49:31 +00:00
Martin Pool
f5c2081302 Clear up conditions for running as root. 2000-10-13 03:28:12 +00:00
Martin Pool
e6c64e7933 Oops: manpage updates should go into the yodl source. 2000-10-13 03:25:07 +00:00
Martin Pool
a036580649 Quick list of things to do. 2000-10-11 00:57:27 +00:00
Martin Pool
796d484b44 Clearer "nothing to do" message. 2000-10-10 01:26:55 +00:00
Martin Pool
1f52f4c407 Get rid of const modifiers; they're problematic with old compilers. 2000-10-09 03:48:47 +00:00
Martin Pool
d567322fbc include/exclude cluestick: with -vv, print out whether files are
included or excluded and why.
2000-10-09 03:46:38 +00:00
John H Terpstra
3ff1e677a1 Added provision for packaging for Linux Standards Base compliant Linux systems. 2000-09-11 18:04:35 +00:00
Andrew Tridgell
ef325f0cf4 neater getconf test 2000-09-06 07:15:37 +00:00
rsync-bugs
3d8810c928 preparing for release of 2.4.6 2000-09-06 02:47:00 +00:00
Andrew Tridgell
d153974ee2 README update 2000-09-06 02:39:45 +00:00
Andrew Tridgell
5b56cc19fb added --modify-window option from David Bolen <db3l@fitlinxx.com> 2000-09-06 02:12:13 +00:00
Andrew Tridgell
c48b22c858 minor man page update 2000-09-06 01:27:46 +00:00
Andrew Tridgell
65d0a49f5c removed spurious error message 2000-09-06 00:48:52 +00:00
Andrew Tridgell
6a48ca56eb added LFS support for Solaris 8 2000-09-05 23:21:27 +00:00
Andrew Tridgell
a20aa42ac4 a simple fix to the memory problems with the string pool patch. The
string pools conflict with the lastdir memory saving tricks.
2000-08-31 23:01:28 +00:00
Andrew Tridgell
e92ee12893 make sure we don't chew too much CPU when the outgoing fd is full 2000-08-29 05:07:08 +00:00
Andrew Tridgell
5c66303ad6 some string_area cleanups 2000-08-29 04:47:39 +00:00
Andrew Tridgell
27e3e9c906 detect list_only a bit earlier 2000-08-29 04:46:50 +00:00
Andrew Tridgell
f0b36a48c8 the 2nd half of the hack 2000-08-29 04:46:27 +00:00
Andrew Tridgell
25cf88936f a hack to make listing remote sites (by leaving off a target) more
useful
2000-08-29 04:45:49 +00:00
Andrew Tridgell
ae682c3e11 got rid of some unused variables 2000-08-19 15:25:05 +00:00
rsync-bugs
99994aef3e preparing for release of 2.4.5 2000-08-19 13:10:57 +00:00
Andrew Tridgell
78043d1969 man page updates 2000-08-19 13:04:48 +00:00
Andrew Tridgell
43e46b4cf6 allow 0.0.0.0/0 syntax in hosts allow/deny
patch from Charles Levert <charles@comm.polymtl.ca>
2000-08-19 13:04:29 +00:00
Andrew Tridgell
9ec16c83be added msleep() function 2000-08-19 12:53:51 +00:00
Andrew Tridgell
a24c687094 sleep for a smaller time while waiting for a process to exit 2000-08-19 12:53:24 +00:00
Andrew Tridgell
60cb2f9016 added "ignore nonreadable" option (useful for hiding files in public archives) 2000-08-19 12:53:00 +00:00
Andrew Tridgell
ac1a0994b6 added an explicit noexcludes flag to make_file()
this fixes a bug with --backup-dir and -x

added "ignore nonreadable" option (useful for hiding files in public archives)
2000-08-19 12:52:39 +00:00
Andrew Tridgell
f2cbf44ba5 added an explicit noexcludes flag to make_file() 2000-08-19 12:51:26 +00:00
Andrew Tridgell
dab552237e I don't like automatic header dependencies 2000-08-19 12:51:00 +00:00
Andrew Tridgell
2201ba580e added MacOS support to config.guess (from wsanchez@apple.com) 2000-08-19 12:09:52 +00:00
Andrew Tridgell
b7c33e3bde fixed backup_dir bug introduced with recent memory handling patches 2000-08-19 11:06:04 +00:00
Andrew Tridgell
82980a2384 fixed timing problem with cleanup and io_flush() by using non-blocking
waitpid()
2000-08-16 08:34:18 +00:00
David Dykstra
b6a30afc98 Undo last setting of blocking_io. I hadn't reviewed the code well enough;
turns out that when client is talking to a server daemon it never executes
this leg of code.  Oops.  The people who said it made a difference when
they changed the code must have been wrong.
2000-08-04 21:26:17 +00:00
David Dykstra
ed91f3e418 Turn on blocking_io when starting client of rsync server daemon. 2000-08-04 21:18:23 +00:00
David Dykstra
60c8d7bc7f Enable --compare-dest to work in combination with --always-checksum.
Problem and suggested patch from Dean Scothern dino@cricinfo.com (although
I re-wrote the patch).
2000-08-04 21:11:46 +00:00
rsync-bugs
5783c065ba preparing for release of 2.4.4 2000-07-29 05:05:38 +00:00
Andrew Tridgell
adc19c987b fix from T.J.Adye@rl.ac.uk for final goodbye message with new protocol 2000-07-29 04:58:24 +00:00
Andrew Tridgell
3d38277706 optimisations from Rich Salz <rsalz@caveosystems.com> 2000-07-29 04:52:05 +00:00
Andrew Tridgell
64c704f0b9 added blocking-io docs 2000-07-29 04:41:19 +00:00
Andrew Tridgell
69c6522734 added *.bz2 and *.tbz to default dont compress list 2000-06-24 13:20:21 +00:00
Andrew Tridgell
0f8f98c8ff added insure debug support 2000-06-24 13:19:53 +00:00
Andrew Tridgell
e384bfbdcb if the remote shell is rsh then use blocking IO 2000-06-24 13:19:25 +00:00
Andrew Tridgell
08e5094d7f added some comments on blocking-io 2000-06-23 13:54:29 +00:00
Andrew Tridgell
4b3977bf00 get rid of annoying symlink error messages 2000-06-23 13:54:08 +00:00
Andrew Tridgell
c80ccabb0c added --blocking-io option 2000-06-23 13:50:18 +00:00
David Dykstra
ef5d23ebcd Add --bwlimit option contributed by Matthew Demicco and Jamie Gritton. 2000-06-06 21:13:05 +00:00
David Dykstra
27b9a19be0 Do better job at describing exclude/include in man page. Based on suggestions
from Harry Putnam <reader@newsguy.com>.
2000-05-19 14:58:28 +00:00
Andrew Tridgell
14175f1e77 fixed bug in replacement inet_aton() 2000-04-19 05:49:15 +00:00
Andrew Tridgell
269833af78 test was the wrong way around 2000-04-19 05:44:43 +00:00
Andrew Tridgell
fca3ef06cd autoconf test for broken solaris inet_aton() 2000-04-19 05:33:39 +00:00
Andrew Tridgell
07a14ef8b2 by default don't gzip .iso images 2000-04-19 05:33:06 +00:00
rsync-bugs
21cde2888c preparing for release of 2.4.3 2000-04-09 02:53:57 +00:00
Andrew Tridgell
4a7481889c use 1 second sleeps in the sleep loop as some OSes (NT for example)
don't get interrupted during a sleep.
2000-04-09 02:32:57 +00:00
Andrew Tridgell
0adb99b9dc don't pprint the IO timeout message if we are a server or daemon (can
cause recursive error messages)
2000-04-09 02:32:18 +00:00
Andrew Tridgell
36349ea0be a very simple fix - if I'd only thought if it last week :)
rsh relies on stdin being blocking
ssh relies on stdout being non-blocking

what we've done before is to set both stdin and stdout to either
blocking or non-blocking. Now I set stdin to blocking and stdout to
non-blocking. This seems to fix all cases I've tested.
2000-04-09 02:16:42 +00:00
rsync-bugs
ec3f7d1b61 preparing for release of 2.4.2 2000-03-30 14:24:37 +00:00
Andrew Tridgell
f0359dd00d went back to non-blokcing IO
it looks like ssh is willing to accept a non-blocking fd when used as
a transport, this seems to avoid the Solaris socketpair bug
2000-03-30 14:15:00 +00:00
Andrew Tridgell
ef55c686bc add a --ignore-errors option 2000-03-21 04:06:04 +00:00
David Dykstra
5f7ce2041c Describe symbolic link handling when writing to a "use chroot = no" module. 2000-02-25 17:02:45 +00:00
David Dykstra
328fcf113a Somebody was confused into thinking that "Here are some examples" in the
section on exclude/include was supposed to be about "+/-" so I changed
the statement to "Here are some exclude/include examples".
2000-02-22 19:47:44 +00:00
David Dykstra
24c857f1de Change socketpair test to verify that it works rather than just exists,
because I have an obscure system (Amdahl's UTS 2.1.2) in which socketpair()
exists but is broken.
2000-02-22 15:55:40 +00:00
David Dykstra
a784e10d00 Move the checking for -lsocket -lnsl ahead of the checking for most of
the functions, especially "socketpair" so that socket-related functions will
be properly discovered on SVR4-based systems such as Solaris.  Problem
discovered by Kenji Miyake <kenji@miyake.org>
2000-02-15 22:44:18 +00:00
rsync-bugs
7eb6bf0397 preparing for release of 2.4.1 2000-01-30 01:02:59 +00:00
Andrew Tridgell
49d6fdc036 patch from Jim Delahanty <mail_us@swbell.net> to ensure files are
deleted after being backed up in a rename operation
2000-01-30 00:56:43 +00:00
Andrew Tridgell
8b35435f7c another hang-at-end fix. It looks like we are more sensiitive to
these with socketpairs. The receiver now sleeps until it gets a signal
to tell it to exit

also fixed test.sh to use the current version remotely
2000-01-30 00:50:19 +00:00
Andrew Tridgell
8ada751890 damn.
with the new error handling code it is possible for rsync to get stuck
on the final transaction, leaving it hung.

looks like 2.4.1 will be pretty soon
2000-01-29 23:49:36 +00:00
rsync-bugs
1a52e84874 preparing for release of 2.4.0 2000-01-29 11:35:39 +00:00
Andrew Tridgell
53c5cbed23 change version to 2.4.0pre2 2000-01-29 05:25:53 +00:00
Andrew Tridgell
4a81463880 use full buffer length, not strlen 2000-01-29 05:16:13 +00:00
Andrew Tridgell
09b7f5dbb1 move the read only daemon test to after the protocol setup 2000-01-29 05:02:23 +00:00
Andrew Tridgell
6d7b6081ac damn!
the last pre-release had a bug that didn't setup the multiplexing
correctly. This means that pre-release will get "unexpected tag -7"
whenm talking to the fixed code.
2000-01-29 04:50:01 +00:00
Andrew Tridgell
31b7d79afe I've decided that this release will be 2.4.0, updated version to 2.4.0pre1 2000-01-29 03:11:07 +00:00
Andrew Tridgell
b2999e457f don't need PIPE_BUF any more 2000-01-29 02:56:36 +00:00
Andrew Tridgell
0f3203c312 fixed some logcode warnings 2000-01-29 02:49:03 +00:00
Andrew Tridgell
a2edb26cd6 fixed a bug in test suite that I introduced yesterday 2000-01-29 02:39:52 +00:00
Andrew Tridgell
9bec528606 runtime detect fnmatch() bug if ** is used.
its all too common to compile with a working libc and run on a broken
one.
2000-01-29 02:35:01 +00:00
Andrew Tridgell
2f0e3b30a9 changed version to 2.3.3pre2 2000-01-28 15:35:08 +00:00
Andrew Tridgell
ff41a59f58 - switched on multiplexing for all connections, not just daemon
connections (this fixes the stderr/stdout problem). Upped
  protocol version for backward compat
- use multiplexing on error fd
- upped minimal protocol version
- got rid of some ugly code in the write buffering
2000-01-28 15:29:59 +00:00
Andrew Tridgell
08f15335b5 switch to using socketpair instead of pipe if possible. This fixes the
ssh clag problems as long as you also fix the same problem in sshd

removed all the old read buffering code from io.c as this was only
there to try to reduce the chance of clagging up sshd.
2000-01-28 12:37:58 +00:00
Andrew Tridgell
bd36966bed report exit code when failing a test 2000-01-27 04:54:02 +00:00
Andrew Tridgell
f76933b149 fixed the error code problem with test.sh
(was a minor bug in send_file_list)
2000-01-27 04:53:39 +00:00
Andrew Tridgell
378a074c82 patch from James Delahanty <jimd@gie.com> to make --backup-dir work
cross-filesystem
2000-01-27 02:45:56 +00:00
Andrew Tridgell
c36cd31713 the convoluted nest of #ifdefs that is fnmatch.c caught us again. On
my system the LIBC tests meant it never compiled and we used the
broken system one.

hacked it so it does compile
2000-01-25 14:17:21 +00:00
Andrew Tridgell
5e12ce1186 fix segv bug in --progress handling 2000-01-25 13:16:42 +00:00
Andrew Tridgell
166aa72332 patch from David Murn to make sure the final 100% is always printed
when using --progress
2000-01-25 06:39:33 +00:00
Andrew Tridgell
f9f6184f38 updated version.h 2000-01-25 01:33:05 +00:00
Andrew Tridgell
f625af9400 updated config.guess from latest autoconf CVS tree 2000-01-24 13:12:20 +00:00
Andrew Tridgell
fc7952e7f3 updated --password-file docs 2000-01-24 12:28:45 +00:00
Andrew Tridgell
cbce490e13 reinstated the MAX_READ_BUFFER code. Its a nasty tradeoff - using lots
of memory vs. ssh bugs. uggh.
2000-01-24 12:23:39 +00:00
Andrew Tridgell
74a7f81d57 updated a debug message 2000-01-24 12:22:58 +00:00
Andrew Tridgell
5b5591d8a8 make the replacement inet_aton() function independent of
inet_addr(). Some systems were detecting a missing inet_aton(), but
actually had it and inet_addr() called it, causing infinite recursion
2000-01-24 12:02:44 +00:00
Andrew Tridgell
c55f70218c fixed a rare SEGV that can happen when a file disappears (due to
another program) during an update
2000-01-24 11:41:08 +00:00
Andrew Tridgell
6957ae33a9 moved file deletion to before the fork() to prevent a race condition
pointed out by byrnes@curl.com
2000-01-24 11:20:25 +00:00
Andrew Tridgell
8a5d6bba09 don't use stderr after we become a daemon 2000-01-24 09:19:44 +00:00
Andrew Tridgell
1d2c275fff I can't believe it - solaris allows unlink of a non-empty directory as
root, leaving a corrupt filesystem. Are those guys on drugs?

try to avoid the problem as best we can.
2000-01-24 09:13:39 +00:00
Andrew Tridgell
d0fd26aa16 added some more debug info to the "buffer overflow in
receive_file_entry" message
2000-01-24 08:16:57 +00:00
Andrew Tridgell
e20c5e9521 -a now implies -o and -D whether you are root or not 2000-01-24 05:52:44 +00:00
Andrew Tridgell
66203a982b added --backup-dir option from Bob Edwards
this is very useful for incremental backups
2000-01-24 04:58:53 +00:00
Andrew Tridgell
b315601ce0 removed Daves include-only optimisation. One of the bug reports turned
out to be caused by it and it seems rather a lot of extra effort for
what must really be a minor optimisation in most cases
2000-01-23 13:16:30 +00:00
Andrew Tridgell
5f808dfbd7 fix a problem with files > 2GB
(thanks to T.J.Adye@rl.ac.uk)
2000-01-23 12:30:34 +00:00
Andrew Tridgell
0b73ca12fa added --max-delete option 2000-01-23 11:43:04 +00:00
Andrew Tridgell
03e2d0e329 fixed mdfour code on Cray (64 bit problems)
Thanks to roebel@kgw.tu-berlin.de
2000-01-23 11:26:10 +00:00
Andrew Tridgell
182517e692 removed u_sleep() as it is no longer used anywhere 2000-01-23 07:38:20 +00:00
Andrew Tridgell
554e0a8dd0 added some really ugly code to allow errors to propogate to
clients when writing to a rsync server

it works like this:

- we have an extra pipe from the receiver to the generator
- the server always runs with multiplexing on
- errors from the generator go down the multiplexed connection
- errors from the receiver go over the pipe, and from there to
  the multiplexed conn

it required some incredibly ugly code. damn.
2000-01-23 07:36:56 +00:00
Andrew Tridgell
b0f3f5784c open on paths starting with // fails on win32 2000-01-23 03:00:27 +00:00
Andrew Tridgell
3060d4aa1d handle systems that don't take a 2nd argument to gettimeofday() 2000-01-23 02:16:51 +00:00
Andrew Tridgell
1347d5126a added --existing option, similar to one suggested by Gildas Quiniou <gildas@stip.fr> 2000-01-23 01:53:18 +00:00
Andrew Tridgell
5d1e1dcf4b don't try to write errors to a dead socket 2000-01-23 01:11:43 +00:00
David Dykstra
74f5442401 Make all the rsync objects dependent on all the header files except the
zlib header fiels in Makefile.in.  I've been burned several times because
objects did not get rebuilt when header files changed.
2000-01-10 22:39:45 +00:00
David Dykstra
c08bb0fb73 Needed to comment out the inclusion of headers in fnmatch.c because it
couldn't find some of them (especially <fnmatch.h>, because it wasn't
looking in the current directory).  The header files are included better
from ../rsync.h.
2000-01-10 20:36:20 +00:00
Andrew Tridgell
e30f065766 make --address work for a client connecting to a server 2000-01-10 04:49:51 +00:00
David Dykstra
9dce9b45b3 Upgrade lib/fnmatch.[ch] to the latest from glibc-2.1.2 because the
FNM_PATHNAME flag (to stop at slashes in path names) was not working.

Ironically, the bug in glibc's fnmatch was reported on the rsync mailing
list in late October, and rsync's configure.in was changed to detect the
bad glibc and use the internal fnmatch, but the internal fnmatch was based
on the same buggy glibc!
2000-01-07 17:58:44 +00:00
David Dykstra
60be6acf46 If a destination file cannot be opened, pretend it doesn't exist rather
than skipping it and thus not updating it.  For example, the ownership or
mode on a file may prevent opening it, but the directory may still be
writable so the file could be completely replaced.
2000-01-06 16:15:36 +00:00
Andrew Tridgell
a5827a28d2 when we do a lchown() on a file we have to flush the cached perms on
the file if the file has the setuid or setgid bits set as the chown
has a side effect of removing the setuid and setgid bits.
we re-do the stat in this case
2000-01-06 00:26:00 +00:00
David Dykstra
dcc875e41e Define the WEXITSTATUS macro for systems that don't have it. 1999-12-29 21:11:57 +00:00
David Dykstra
128cf58433 When writing to a daemon with read only = false and uid = root and -g,
was not preserving group permisions.  Bug was introduced March 1 in
version 1.100 of rsync.c with an error in re-ordering of the boolean
expressions.  In order to completely preserve the earlier semantics,
change_gid should depend on "(am_root || !am_daemon)", but I don't see why
group ownership should behave differently in a non-root daemon.
1999-12-29 20:50:48 +00:00
David Dykstra
7e0ca8e2f0 When not using -p and file being copied to already existed, was mistakenly
using all the mode bits of the existing file rather than just the permissions,
including the file type.
1999-12-29 20:45:23 +00:00
Andrew Tridgell
d79d1c69f7 fixed a bug with waitpid() - I'd forgotten about WEXITSTATUS ! 1999-12-09 06:46:11 +00:00
Andrew Tridgell
a7d068abff fixed man page typo 1999-12-03 04:24:25 +00:00
Andrew Tridgell
7f931a0002 fixed a segv bug when handling symlinks.
thanks to taver@otenet.gr
1999-12-02 05:50:09 +00:00
Andrew Tridgell
07b7c86c06 don't write more than PIPE_BUF bytes in any one write() in io.c
this makes sure that the write never blocks.
1999-11-23 08:43:16 +00:00
Andrew Tridgell
1f5c6343e6 removed old non-blocking fd code (a hangover from a earlier version of
io.c). Thanks to Theo for pointing out this brokenness.
1999-11-15 01:32:20 +00:00
rsync-bugs
290b615a16 preparing for release of 2.3.2 1999-11-08 13:15:48 +00:00
Andrew Tridgell
57df171bc0 added --delete-after option (suggested by Jason) 1999-11-08 13:03:05 +00:00
Andrew Tridgell
f08baea3dd removed ACCESSPERMS mask when transferring a file without perms
copy. This makes us match GNU cp more closely.
1999-11-08 10:47:14 +00:00
Andrew Tridgell
2fb139c11b fixed passing of directory exclude options to remote side (thanks to
andrewdagger@xerox.gbr.com)

added note about multiple excludes per exclude option
1999-11-08 09:12:42 +00:00
David Dykstra
3420c8e6e0 Fixed bug introduced by calling do_open() for O_RDONLY files. Changed it
so the check for dry_run and CHECK_RO are not done when flags is O_RDONLY.
Only do the adding of O_BINARY, which was the intention.
1999-11-04 15:43:38 +00:00
Andrew Tridgell
b17bc22bb3 added a replacement inet_aton() for systems that don't have it.
thanks to Dave for pointing this out.
1999-11-01 21:35:15 +00:00
Andrew Tridgell
3adffb52e6 forgot to commit the fnmatch.h changes 1999-11-01 21:25:39 +00:00
Andrew Tridgell
4df9f36841 solved the problem of not using the right permissions when
preserve_perms is off.
1999-10-31 04:28:03 +00:00
Andrew Tridgell
5c9730a46c added --address option for virtual hosting 1999-10-31 03:21:02 +00:00
Andrew Tridgell
d9fcc198cf added -P option
it is equivalent to --partial --progress
1999-10-31 02:47:30 +00:00
Andrew Tridgell
c831379436 updated test suite from Phil. 1999-10-31 02:39:34 +00:00
Andrew Tridgell
d73ee7b70e updated rsync-path man page entry 1999-10-31 02:37:21 +00:00
Andrew Tridgell
cda2ae84b3 added "ignore errors" option in rsyncd.conf 1999-10-31 02:19:24 +00:00
Andrew Tridgell
e7d6e0aa0c updated the configure test for fnmatch() to see if FNM_PATHNAME is
working correctly.
1999-10-27 13:17:16 +00:00
Andrew Tridgell
8c9fd200f9 use do_open() instead of open() in several places to help the WinXX port
and O_BINARY
1999-10-25 22:04:09 +00:00
David Dykstra
79f118d859 Minor change suggesting people put in the right path in inetd.conf.
Suggested by Roger Price <rprice@cs.uml.edu>
1999-10-19 17:50:39 +00:00
Andrew Tridgell
7b10f91d8f added a note about using -v with --progress 1999-09-06 02:04:20 +00:00
Andrew Tridgell
3d19b4c83e separated out the make_backup code in preparation for some patches
from Bob Edwards
1999-08-30 08:19:47 +00:00
David Dykstra
79452d4693 Add a couple clarifying points to the sanitize_path() comments.
One is a note that a leading "/" in a symlink target will not behave
exactly as if a chroot had occurred, but I decided it wasn't worth the
making it the same.

The other is note about an extra harmless trailing "." that is added under
some rare circumstances.
1999-07-09 17:07:59 +00:00
David Dykstra
cb13abfed0 Fix significant security holes with "use chroot = no" in an rsync daemon:
1. The file paths being sent and received were not "sanitized" to
	ensure that there weren't any ".." components that would escape the
	top level directory.  This can't happen with the standard rsync
	client, but it could be exploited on both read and write if someone
	modified an rsync client.  This fix sanitizes all incoming and
	outgoing paths when "use chroot = no".

    2. If a module is also "read only = no", clients could have created
	symbolic links with ".." components that would allow writing
	outside of the module.  This could happen with the standard rsync
	client.  This fix sanitizes all incoming symbolic link targets
	when "use chroot = no".

Previously, only top-level paths (anything passed in command line arguments)
were sanitized.  Sorry, I didn't think about the individual file paths
before now.
1999-07-09 15:49:46 +00:00
Andrew Tridgell
0503f06089 continue calling waitpid() while still reapingchildren (patch from
Matti Aarnio)
1999-06-27 04:12:12 +00:00
Andrew Tridgell
f855a7d01a fixed a bug that made us use only 16 bits of the file checksum when
comparing checksums for the --checksum (-c) option.
1999-06-26 01:06:38 +00:00
Andrew Tridgell
4c3b4b2557 added RSYNC_PROXY support from Stephen Rothwell. This allows access to
rsync servers via a web proxy (useful for getting through firewalls)
1999-04-13 03:53:30 +00:00
rsync-bugs
79b5aa09a0 preparing for release of 2.3.1 1999-04-06 15:09:28 +00:00
Andrew Tridgell
9bd6597666 set the exit code to RERR_FILEIO is io_error is set when we exit. This
catches most sorts of io errors and ensures we report a error in our
exit status.
1999-04-06 14:52:32 +00:00
Andrew Tridgell
6fe076b3d7 these aren't used any more 1999-04-06 14:17:44 +00:00
Andrew Tridgell
cec8aa7724 handle the case of an empty file list in get_local_name 1999-04-06 12:30:36 +00:00
Andrew Tridgell
4c36a13ef2 don't abort the server side if the file list is empty (perhaps because
all files have been excluded).
1999-04-06 12:28:54 +00:00
Andrew Tridgell
24986abd07 note in the man page that:
1) rsync won't copy directories at all if recursion isn't selected
2) --delete won't do anything if recursion isn't selected
1999-04-06 11:52:45 +00:00
Andrew Tridgell
8dfac376b5 fix the man page to reflect the fact that exclude options in
rsyncd.conf are not passed to the client and thus only affect the file
lists on the server.
1999-04-06 11:34:06 +00:00
Andrew Tridgell
e78733d975 fixed a nasty bug in the handling of "local_name" when setting the
permissions on directories after a transfer.
1999-04-06 10:56:18 +00:00
Andrew Tridgell
dffba35e01 quote RPM_OPT_FLAGS
patch from racke@linuxia.de
1999-04-06 10:27:34 +00:00
David Dykstra
bd4ed7f719 Small bug fix for the --compare-dest option: when a file's contents
hadn't changed but its permissions had, the file wasn't copied but
its permissions were attempted to be set anyway.  Made a change to
skip setting the permissions in that case.
1999-04-02 18:24:27 +00:00
David Dykstra
752eaba41f Backed out the change to create missing parent directories when using
--compare-dest.  It was due to an incomplete analysis of the problem,
sorry.  I left a comment in its place indicating that normally the
parent directories should already have been created.

It turned out to actually be a bug in nsbd in which it was not always
including all the parent directories in the include list like it was
supposed to.  The files themselves were still being sent but that was only
because my exclude_the_rest optimization was kicking in; if it weren't,
excluding the parent directories would have had the side effect of
excluding the files too.  So it really had nothing to do with the
--compare-dest option after all, just with the requirement that if you use
--exclude '*' you need to explicitly include all parent directories of
files you include.
1999-03-24 19:28:03 +00:00
David Dykstra
ad517ce5b3 The "pid file" was getting created mode 666, not applying the umask
because at that point in the program the umask is set to 0.  Now creating
the file with mode (666 & ~orig_umask).
1999-03-24 16:39:07 +00:00
David Dykstra
1f8413449d Fix bug with --compare-dest option where missing parent directories in the
target destination were not getting created.  There was a case in
receiver.c to do that but it was only getting invoked when the -R option is
specified, although I don't know why it was limited to that.

It's too bad I didn't get a chance to more fully test the use of
--compare-dest by my nsbd program before releasing rsync 2.3.0.  I'll
probably need to put a workaround in nsbd too until the next release
of rsync.
1999-03-23 22:20:10 +00:00
rsync-bugs
d0a7c8a487 preparing for release of 2.3.0 1999-03-15 21:23:26 +00:00
David Dykstra
ebb00c8e29 Changed the protocol version to 20 so that --stats will work without -v in
both directions.
1999-03-15 21:17:58 +00:00
David Dykstra
6543dc0c4c Fix typo in comment in rsync.h, suggested by bje@cygnus.com 1999-03-15 17:04:22 +00:00
David Dykstra
e459239d27 Make a special version number 2.3.0-beta for a short period because
I'll be encouraging extra testing before the release.
1999-03-12 21:45:37 +00:00
David Dykstra
651443a7ff Allow + and - in the "include" and "exclude" directives in rsyncd.conf.
Patch submitted by Damian A Ivereigh <damian@cisco.com>
1999-03-12 21:42:51 +00:00
David Dykstra
79fc6bdb45 Include a test for a working getopt_long because the one on some versions
of cygwin doesn't work.  Thanks to Martin Krumpolec <krumpo@pobox.sk> for
the patch.  At the same time, include cache checks in configure.in for a few
items that were missing the checks.
1999-03-12 18:21:53 +00:00
David Dykstra
245fbb5129 When -R is used, send the permissions of the original top directories to
the receiver even when not combined with -r.  Without this, the directories
were getting created mode 777 because the default umask on receivers is
often 00.
1999-03-12 17:36:52 +00:00
David Dykstra
c7c11a0d4c When a file cannot be deleted because of ETXTBSY (in particular, when an
executable is busy on HPUX), rename it instead to .rsyncNNN.  Most of
the code was submitted by Ketil Kristiansen <ketil-k@osc.no>
1999-03-11 22:17:42 +00:00
David Dykstra
c27f25922e Check for EINVAL from a rename error call in addition to ENOENT because
David Campbell <david@pastornet.net.au> reported that that helps data
be received onto a windows box running cygwin b19.
1999-03-09 21:55:16 +00:00
David Dykstra
af21c12fbc Add distclean target to Makefile.in. 1999-03-09 21:47:18 +00:00
David Dykstra
32b1f1de0e Update config.sub to the latest from automake in addition to config.guess. 1999-03-09 21:46:15 +00:00
David Dykstra
529e60864f Update config.guess from a new official GNU version.
I believe this is the latest, which comes with automake 1.4 (somebody
else is in charge of installing the GNU stuff on my system so I'm not
100% sure it's the absolute latest, but it was updated just a couple
weeks ago).
1999-03-05 16:37:44 +00:00
David Dykstra
972a3619c4 The change a couple days ago to create files initially without group and
other access resulted in group and other access being left off when the
'-p' option was not used.  This fixes it by reintroducing the ACCESSPERMS
mask and setting permissions to (file->mode & ACCESSPERMS) if preserve_perms
is off.  I decided to change the mask INITPERMMASK to INITACCESSPERMS at
the same time.  When preserve_perms is off, rsync is restored to the
previous behavior of having the permissions of the original file with the
umask and setuid/setgid bits shut off.

Also, I decided that a check for "(updated && (file->mode & ~ACCESSPERMS))"
is no longer needed since as far as I can tell that would have only affected
permissions when not running as root and when a chgrp was done to a group
the user was not a member of, using system V chgrp semantics.  This is no
longer allowed.
1999-03-04 21:48:52 +00:00
David Dykstra
8458724d25 Disable the optimization that treats include-only files as a special case
whenever delete_mode is on.  People reported problems when it kicked in
while using --delete and while using --delete-excluded.
1999-03-02 20:56:17 +00:00
David Dykstra
9422bb3fdf Change getgroups to use GETGROUPS_T as the type of the group array returned,
as calculated by the configure macro AC_TYPE_GETGROUPS.  Without that, it
doesn't work properly on systems like sunos 4 where gid_t is defined to
be an unsigned short but getgroups is defined to return an array of integers.
1999-03-02 16:42:46 +00:00
David Dykstra
5afd8aedce Change the mask used when creating temporary files from 777 to 700, to prevent
an obscure race-condition security hole where a file may for a short time
have the wrong group.  Could have used 707 instead but that's just too weird
of a permission.  The define name used to be ACCESSPERMS but that is defined
as 777 on Linux, so changed the name to INITPERMMASK.
1999-03-01 21:22:54 +00:00
David Dykstra
86692050b5 When comparing -1 to a group id, cast -1 with gid_t because on some systems
such as sunos4 gid_t is an unsigned short.  This prevented the just-added
non-mapped group test from working on sunos4.
1999-03-01 21:16:49 +00:00
David Dykstra
460f6b990a Prevent the -g option from preserving groups that a non-root receiver
does not belong to, in these two ways:
    1. If a group mapping doesn't exist for a group name, do not preserve
	it for a non-root receiver.  This is especially evident with the
	sender is a daemon using chroot because then no mappings are
	available.
    2. Before setting the group on a file make sure that it is in the list
	of groups returned by getgroups().  The same thing is done by chgrp
	on systems that support bsd-style chown/chgrp, and this enforces
	that it happens the same way on all systems.  Overhead is very
	little, especially since most systems don't allow more then 16
	groups per user.
1999-03-01 19:24:39 +00:00
David Dykstra
896bd482c0 Removed am_client variable. It was being set in one place, when a client
of a socket (that is, a --daemon) server, but never looked at.  The way to
test whether or not on a client is (!am_server).
1999-02-25 17:58:31 +00:00
David Dykstra
53f821f1e6 Fix a bug with rsync -R --delete from ./ as reported in PR#1532 1999-02-24 22:38:36 +00:00
David Dykstra
b33b791e6b Add --delete-excluded option to delete files on the receiving side that
are excluded.  Implies --delete.
1999-02-22 19:55:57 +00:00
David Dykstra
17d31b380b Changed --stats implementation to work without -v in only these two
situations:
    1. the client is the receiver of files.  Can't do it otherwise yet
	because without -v the bytes written from the sender's generator
	process will not be counted.
    2. both the remote and local protocol versions are >=20.  I did not
	change the protocol version yet because it is such a minor change
	that it isn't worth it, although I did test it with the protocol
	version set to 20.
If neither of the situations hold, it prints a message saying to use -v.
1999-02-18 17:23:44 +00:00
David Dykstra
a8b9d4edec Changed exclude/include matching so that normally wildcards will stop at
slashes.  The old behavior of crossing slashes can be achieved by using a
double-asterisk ('**') anywhere in a pattern.  Note that this can change
some existing exclude patterns in a subtle way.  Also note that if the
remote side is an older release the processing on the two sides might not
be exactly the same when there's no double-asterisk, which can affect which
files are excluded from deletion, but they're close enough that people will
probably not notice.  I considered changing the protocol version and
checking the remote_version number to ensure the same processing on both
sides, but the exclude patterns are pre-processed before the remote version
number is known and it's just not worth going through extraordinary efforts.
Suggested by Cameron Simpson <cs@zip.com.au>
1999-02-18 16:27:36 +00:00
Andrew Tridgell
f83f054875 added --size-only option. Useful when starting to use rsync after a
ftp based mirror system so that timestamps may not be right.
1999-02-18 03:48:24 +00:00
David Dykstra
15800c7e89 Changed man page documentation of --force to say it is hardly ever needed
any more except in very obscure cases.
1999-02-17 21:39:45 +00:00
David Dykstra
b531360763 Added --copy-unsafe-links option which is like --copy-links except it is
only for symlinks that point outside the source tree.  Suggested by Charles
Hines <chuck_hines@VNET.IBM.COM> in PR#1376.  Also apply the option to any
symbolic links in the source portion of a path when --relative is used,
as suggested by Francis Montagnac <Francis.Montagnac@sophia.inria.fr> on
the rsync mailing list in a message titled "New option: --copy-parent-links".
1999-02-17 19:34:40 +00:00
David Dykstra
b567933566 Be consistent on use of '=' on options that take a parameter. 1999-02-15 17:48:06 +00:00
David Dykstra
52d7d78865 Change the implementation of memmove in lib/compat.c to call bcopy instead
of memcpy because bcopy is guaranteed to work with overlapping memory and
memcpy is not.  Bug fix for PR#1584 in which log entries in the rsync
daemon log on Sunos 4.1.4 were garbled.
1999-02-12 17:27:22 +00:00
David Dykstra
23c5aef18e A slight compensation I had just added for total bytes read when using -v
was incorrect.  It's hard to tell how many bytes are actually read because
transferring the value changes it and depending on its value it may
transfer 4 or 12 bytes so instead change the sender side to not include the
length of the counters it sends at all (it had been including one but three
are sent).
1999-02-10 22:16:32 +00:00
David Dykstra
e19452a96c Allow --stats to work without -v. 1999-02-10 21:54:12 +00:00
David Dykstra
9ef5390714 Changed Usage in the rsync --help message to indicate how there can be
multiple SRCs.  Also moved the --suffix option to show up right after
--backup and included the default backup suffix and block size along with
their corresponding options rather than at the end.  Copied the new help
message to rsync.yo and README and used the Usage also in the SYNOPSIS
section at the top of rsync.yo rather than the different one that used
"path" instead of SRC and DEST.  That last change was inspired by a
suggestion from Michael Bleyer in PR #1523.
1999-02-10 19:33:05 +00:00
David Dykstra
fd0abefa43 Changed error message that just said "open %s: %s" to "cannot create %s: %s"
in receiver.c because it confuses people when they do something like
    rsync /etc/passwd /tmp/nonexistentdir/passwd
and it printed out something like
    open /tmp/noniexistentdir/.passwd.a004d5 : No such file or directory
Reported by kurt_granroth@pobox.com in PR #1253.
1999-02-10 18:44:25 +00:00
David Dykstra
19c14f987e Changed the optimized include mode (which kicks in when there are a series
of non-wildcard includes followed by an exclude of *) so that it will silently
ignore included files that don't exist rather than saying "No such file or
directory".  This is more like the behavior of the non-optimized include mode.
1999-02-10 18:03:59 +00:00
David Dykstra
122f19a615 Support '#' and ';' comments in exclude files. It would actually not
probably cause any harm if they were treated as normal exclude or include
patterns because they just wouldn't match anything, but it's better to
explicitly ignore them.  Suggested by David Holland <uholld1@lexis-nexis.com>
1999-02-09 22:31:52 +00:00
David Dykstra
3ca8e68f58 Added "strict modes" option. When set false (default is true), it allows
the secrets file to be readable by other users.  Added to support the Windows
port under cygwin.  Problem reported by Martin Krumpolec krumpo@pobox.sk
1999-02-09 19:27:15 +00:00
David Dykstra
d41c7d025c Use MAXHOSTNAMELEN (256) for the array holding the host_name in socket.c
instead of 200.  Move the defines of True and False to rsync.h.  Eliminate
the defines of BOOL in loadparm.c and params.c because it is already
defined in rsync.h.  Changes suggested by Roman Gollent roman.gollent@wdr.com
1999-02-09 18:35:29 +00:00
David Dykstra
b86f0cefa2 Add --quiet/-q option. Contributed by Rich Salz salzr@certco.com. 1999-02-09 17:25:35 +00:00
David Dykstra
c226b7c2fd Move the initialization of push_dir, which calls getcwd, to early in main.
The reason for that is that on SVR2-based UTS 2.1.2 (which along with many
other old systems implements getcwd by forking "pwd") getcwd hangs when
called when other child processes are running.

I also added a quick return from push_dir if name == NULL so it doesn't
actually have to chdir anywhere when just initializing.

An initializing call to push_dir("/",0) had previously been put in at the
beginning of daemon_main() to avoid calling getcwd after a chroot, but
since that is no longer I needed I removed it and changed the call to
chdir("/") after chroot into a push_dir("/",0) so it will remember the
correct current directory.
1999-02-03 15:38:06 +00:00
David Dykstra
5865fcdd63 When calling lchown, pass the current known uid and gid rather than -1
to not change it, since the old SVR2-based UTS 2.1.2 does not support
leaving uid and gid alone when the value is -1.
1999-02-03 15:15:56 +00:00
David Dykstra
e68f34816f Add alternate implementation of waitpid() for systems that have wait4 but
not wait3, in particular Amdahl's SVR2-based UTS 2.1.2.  The code comes
from apache, but I contributed it to apache in the first place.
1999-02-03 15:11:40 +00:00
David Dykstra
716baed7ff Fix serious bug with "use chroot = no" option which caused "uid =" and "gid ="
to be ignored.  At the same time, change the "uid =" and "gid =" options to
be ignored when not running the daemon as super-user, to make it more
convenient for those people and to make it portable to systems such as
cygwin which don't support the uid/gid notions.
1999-01-21 17:10:32 +00:00
David Dykstra
b882b49747 Document the fact that the %t log format option includes the date, and
that the "log file" option always prepends "%t [%p] ".
1999-01-20 21:32:46 +00:00
David Dykstra
1f0610ef82 Fix segmentation fault when using -vvv. Suggested by assar@sics.se. 1999-01-11 17:07:27 +00:00
Andrew Tridgell
379e689dac fixed bug where strtok() could return NULL in getpassf(). 1999-01-08 10:42:29 +00:00
Andrew Tridgell
65575e9670 added --password-file patch from Alex Schlessinger <alex@inconnect.com>
(yes, I know I'm not supposed to be doing rsync work at the moment!
only four weeks to go ...)
1999-01-08 10:32:56 +00:00
Andrew Tridgell
5e71c4446e made the "max connections" and "lock file" local rather than global
options so you can set them on a per-module basis (requested by
kernel.org mirror maintiner)
1999-01-08 07:51:25 +00:00
David Dykstra
94a7fce217 Ran yodl2man on rsync.yo, and updated modification date. 1999-01-07 16:27:38 +00:00
Andrew Tridgell
3bc67f0c4f add warning about using RSYNC_PASSWORD on systems where env varibables
are visible to all users.
1999-01-07 07:19:03 +00:00
David Dykstra
117af10225 Change the receive log message from "send" to "recv". Fix from
Rick Smith <rick@rbsmith.com>.
1999-01-05 20:08:45 +00:00
Andrew Tridgell
536541d52b moved the block length mismatch code to another part of the loop. 1999-01-05 06:43:59 +00:00
Andrew Tridgell
496d9272c1 don't try to match checksums of two blocks which are of unequal
size. This explains the high false_alarms rate that I saw for one of
the sample data files used in my thesis.

The bug was harmless as the strong checksum easily caught all the
false matches but it's been bugging me as I couldn't explain it :)
1999-01-05 06:31:58 +00:00
Andrew Tridgell
34d3eed462 fixed a bug in the adjacent target optimisation 1999-01-05 01:57:13 +00:00
Andrew Tridgell
923fa97808 an optimization that tries to make rsync choose adjacent matches if
multiple matching blocks are available. This make the run-length
coding of the output more efficient.
1999-01-05 01:15:32 +00:00
Andrew Tridgell
4440b8aa3f no longer use mmap() in rsync because of the risk of a SIGBUS when
another program (such as a mailer) truncates a file.

To offset the speed loss I have rewritten the map_ptr() code to make
much better use of read().
1998-12-30 14:48:45 +00:00
David Dykstra
5a554d5b14 steve.ingram@icl-gis.com noticed several mistakes in rsync.1. Some of
them had already been fixed but yodl2man hadn't been run, and a couple
others were new.
1998-12-07 18:48:46 +00:00
David Dykstra
2cfeab21ce Fix minor man page typo, suggested by jbm@jbm.org. 1998-12-07 14:51:32 +00:00
Andrew Tridgell
2b086e033c paranoia change - treat list_only like read_only and refuse all
syscalls that might change the filesystem. This shouldn't be needed,
but I like paranoid coding :)
1998-12-05 01:56:45 +00:00
Andrew Tridgell
241fc706a9 - slprintf() takes sizeof(buf) not sizeof(buf)-1
- fixed incorrect format string in rename error
1998-12-05 01:55:37 +00:00
David Dykstra
7fadb4bc58 Support newer rpm's which define $RPM_OPT_FLAGS as a set of options
separated by spaces.  Suggested by pavel_roskin@geocities.com.
1998-12-01 16:13:25 +00:00
David Dykstra
6c7c2ef372 Minor documentation change suggested by pavel_roskin@geocities.com. 1998-12-01 16:11:40 +00:00
rsync-bugs
86a2dd0a0a preparing for release of 2.2.1 1998-11-25 16:24:56 +00:00
David Dykstra
63f0774f75 Back out change that treated "refuse options = compress" the same as
"dont compress = *", by request of Tridge.  Instead, mention the difference
in the man page.  Also, put in a shortcut in set_compression() to recognize
"*" earlier instead of going through malloc/strtok/fnmatch/free cycle.
1998-11-25 15:37:50 +00:00
David Dykstra
d47741cac6 When "refuse options = compress" is set in rsyncd.conf, silently send files
at compression level 0 instead of printing an error and exitting.  This is
the same effect as "dont compress = *".
1998-11-24 22:03:16 +00:00
David Dykstra
5d5811f7d9 Always include "." when processing exclude lists. This avoids confusion
when people do --exclude "*".  Also, add an example to the man page that
shows explicitly including parent directories when itemizing specific
paths to include followed by --exclude "*".
1998-11-24 21:26:38 +00:00
David Dykstra
dcc3a131d1 Update the README file to reflect current usage options. 1998-11-24 20:54:56 +00:00
David Dykstra
7212be9237 Don't list cleaned-out duplicate file names as "<NULL>" when doing
list_only mode; skip them instead.
1998-11-24 20:51:45 +00:00
David Dykstra
44e2e57837 Change sanitize_path() function to not malloc a copy since it only shrinks
paths and it is only used in places that have already just done a copy.
1998-11-24 20:18:11 +00:00
David Dykstra
d1be231290 Make sure secrets file is not other-accessible, and owned by root if the
daemon is running as root.  Suggested by
    Mike Richardson <mike@quaking.demon.co.uk>
1998-11-24 19:52:35 +00:00
David Dykstra
a926daecbf Always add the O_BINARY flag in do_open if it is defined, for Windows.
Suggestion from Mart.Laak@hansa.ee
1998-11-24 19:10:21 +00:00
David Dykstra
53dd3135f1 Backup deleted files when using --delete and --backup. Based on a
suggested patch from Kanai Makoto (kanai@hallab.co.jp).
1998-11-24 19:01:24 +00:00
David Dykstra
cd64343a7a Add "include" and "include from" rsyncd.conf options. Contributed
by Dennis Gilbert <dennis@oit.pdx.edu>.
1998-11-23 21:54:01 +00:00
Andrew Tridgell
9e3c856a39 updates to reflect new samba.org domain
the main web site is now http://rsync.samba.org/
1998-11-23 00:30:27 +00:00
Andrew Tridgell
1e8ae5ede6 changed an example slightly 1998-11-20 22:46:42 +00:00
Andrew Tridgell
83fff1aa60 added "dont compress" option with the default setting of
*.gz *.tgz *.zip *.z *.rpm *.deb
1998-11-20 22:26:29 +00:00
Andrew Tridgell
055af77666 improved the "refuse options" code a bit 1998-11-19 06:45:21 +00:00
Andrew Tridgell
cd8185f2bd added "refuse options" option 1998-11-19 06:35:49 +00:00
David Dykstra
6bd98f0617 Look for strcasecmp in -lresolv for Unixware. 1998-11-18 17:53:22 +00:00
David Dykstra
14d43f1fcf Minor documentation patches, due mostly to
Jason Henry Parker <henry@freezer.humbug.org.au>
1998-11-18 17:36:36 +00:00
David Dykstra
3a64ad1fd0 Change --log-format documentation to make it clear that it is for the client
logging to stdout.
1998-11-18 16:20:22 +00:00
David Dykstra
5557c8e3e0 Remove a debugging statement I accidentally included in the last commit. 1998-11-18 16:02:23 +00:00
David Dykstra
baf3e5049e Change documentation to explain that a lack of -t in effect causes -I to be
assumed on the next transfer.
1998-11-18 15:54:50 +00:00
David Dykstra
b389939f87 Apply sanitize_paths() to glob expansions when use chroot = no. 1998-11-17 21:56:18 +00:00
Andrew Tridgell
af77cc6b57 don't interpret %h and %a when using --log-format locally 1998-11-16 23:50:28 +00:00
Andrew Tridgell
1309d90dde fixed a bug handling files larger than 2GB 1998-11-16 03:53:43 +00:00
Andrew Tridgell
a9766ef147 log filename(line) in exit_cleanup() to make tracking down problems
easier in rsync daemons.
1998-11-15 01:21:42 +00:00
Andrew Tridgell
5a788adec1 use native strlcat() and strlcpy() if available 1998-11-15 01:04:16 +00:00
Andrew Tridgell
50abd20bb3 compile with optimisation by default on all compilers
(the mdfour code really needs it)
1998-11-14 23:49:08 +00:00
Andrew Tridgell
37f9805dab changed strlcat() and strlcpy() to have the same semantics as the
OpenBSD functions of the same name.

changed slprintf() to take buffer length rather than buffer length -1
1998-11-14 23:31:58 +00:00
David Dykstra
b5f9e67d57 Change sanitize_path() to not use clean_fname() because it removes the
trailing slash.  This caused a problem when using "use chroot" and sources
that contained a trailing slash (which prevents the last filename component
of the source from being included in the destination).  Instead, have
sanitize_path() remove "." components and duplicated slashes ("//") itself.
1998-11-06 17:07:07 +00:00
Andrew Tridgell
ed06894a01 fixed typo 1998-11-06 10:37:10 +00:00
David Dykstra
d532c0f569 Add comment before call to mktemp saying it is deliberately chosen over
mkstemp.
1998-11-05 14:33:38 +00:00
David Dykstra
ec9df38086 Fix confusion between RERR_NOSUPPORT and RERR_UNSUPPORTED for exit codes
that indicate a feature is not supported.  Two places that are normally
ifdefed out used RERR_UNSUPPORTED whereas one other place and errcode.h
used RERR_NOSUPPORT.  Changed them all to consistently use RERR_UNSUPPORTED.
The two things that had the bad values were #ifndef SUPPORT_LINKS and
#ifdef NO_INT64.  The former is probably for non-Unix operating systems
and the latter was at least on the default Unixware compiler.
1998-11-04 16:47:33 +00:00
Andrew Tridgell
81791cfccb added timeout option in rsyncd.conf 1998-11-04 03:14:22 +00:00
Andrew Tridgell
2fb27e9146 use macros to make mdfour faster on systems that don't do inlining
well. Also helps when optimisation level is low.
1998-11-04 02:35:18 +00:00
David Dykstra
946347b8ff Remove statement in rsync.1 that a rsync:// URL can only be used if
a username is not needed.
1998-11-03 22:30:52 +00:00
rsync-bugs
c239825783 preparing for release of 2.2.0 1998-11-03 22:00:59 +00:00
David Dykstra
33e817e37e Document the fact that you can use [USER@] in an rsync URL.
Note: the same thing works for ftp and http URLs in netscape.
1998-11-03 21:58:08 +00:00
David Dykstra
1b8e662a24 Call clean_fname() in sanitize_path() to catch some more strange but
legal file name syntaxes.
1998-11-03 21:49:38 +00:00
David Dykstra
2acf81eb00 Add support for optional ":PORT" in rsync URL. 1998-11-03 21:17:40 +00:00
Andrew Tridgell
654175798b patch from Alberto Accomazzi <aaccomazzi@cfa.harvard.edu> to add
different exit codes for different conditions.
1998-11-03 07:08:27 +00:00
Andrew Tridgell
3e578a1909 documented --delete disabling on IO errors 1998-11-03 05:14:41 +00:00
Andrew Tridgell
b606265491 added the --log-format option to allow users to request arbitrary
per-file logging of interactive rsync sessions.
1998-11-03 03:48:47 +00:00
Andrew Tridgell
263cf2ed55 remove double / from filenames in display 1998-11-02 07:26:36 +00:00
Andrew Tridgell
ab7104da8f the logging wasn't showing the full prefix for filenames 1998-11-02 06:40:11 +00:00
Andrew Tridgell
1b7c47cb55 Jason told me that's its very important for his site to log exactly
how many bytes were needed to be transferred for each file. I added %b
and %c log format options to cover this. See the man page for details.
1998-11-02 04:17:56 +00:00
Andrew Tridgell
039faa8660 - document the rsync:// URL format 1998-11-02 00:55:21 +00:00
Andrew Tridgell
f7632fc60d if no local destination is provided for the transfer then provide
a "ls -l" style listing of the files that would be transferred
1998-11-02 00:52:01 +00:00
Andrew Tridgell
2f098547ea added copyright notice from Patrick Powell 1998-10-31 04:35:44 +00:00
Andrew Tridgell
c7c056410c get the date comparison the right way around 1998-10-31 00:12:59 +00:00
Andrew Tridgell
e803090538 use the orig_umask when choosing perms for the log file. 1998-10-30 23:50:12 +00:00
Andrew Tridgell
6265551a5a fixed perms on rsyncd log file 1998-10-30 23:03:08 +00:00
Andrew Tridgell
958f373550 move the time init before the logfile opening. 1998-10-30 11:18:38 +00:00
Andrew Tridgell
2c51d5deec added a perl script to summarise the rsyncd log format 1998-10-30 06:12:14 +00:00
Andrew Tridgell
97cb8dc29b added %m, %P and %u options to logging 1998-10-30 05:53:05 +00:00
Andrew Tridgell
cd957c70c4 need BIG_ENDIAN test for inet_ntoa replacement 1998-10-30 02:52:42 +00:00
Andrew Tridgell
7b3d425783 check for a broken inet_ntoa() on IRIX 1998-10-30 02:50:02 +00:00
Andrew Tridgell
b24203b323 get null termination right in logging 1998-10-30 02:43:10 +00:00
Andrew Tridgell
3472009789 get null termination right in logging 1998-10-30 02:36:05 +00:00
Andrew Tridgell
f27b53f5b5 hopefuly fix logging of "transfer interrupted" messages 1998-10-30 02:32:29 +00:00
Andrew Tridgell
e08bfe1248 added "log format" option to allow admins to choose the format for
rsyncd log file entries
1998-10-30 02:24:47 +00:00
Andrew Tridgell
74e708d85a hanle null strings in -vvv output 1998-10-30 02:23:01 +00:00
Andrew Tridgell
7597e1a96a fixed cacheing of some values (using code from Samba) 1998-10-29 23:44:30 +00:00
David Dykstra
692da0b555 Fix for systems such as Unixware that have a cc that does not support -o
with -c.
1998-10-29 22:28:56 +00:00
Andrew Tridgell
67ea0d4844 put the pid on each line of the log file to facilitate
auto-parsing. Requested by Jarkko Hietaniemi (jhi@iki.fi)
1998-10-29 11:16:51 +00:00
Andrew Tridgell
9b73d1c0e9 put the pid on each line of the log file to facilitate
auto-parsing. Requested by Jarkko Hietaniemi (jhi@iki.fi)
1998-10-29 11:11:38 +00:00
Andrew Tridgell
f3737e0648 some minor optimisations 1998-10-29 06:39:43 +00:00
Andrew Tridgell
19a013837e a change I made yesterday corrupted the displayed filename in some
cases. cosmetic fix.
1998-10-29 06:10:31 +00:00
Andrew Tridgell
d730b113f4 final change needed to get rsync working on a CRAY J90 1998-10-29 05:48:11 +00:00
Andrew Tridgell
7ae359c331 kfixed char* casts 1998-10-29 05:06:51 +00:00
Andrew Tridgell
8de330a387 changes to get rsync working on a CRAY J90. This machine doesn't have
a 4 byte integer type (short is 8 bytes). I needed to use a new md4
implementation (I used the portable one I wrote for Samba).
1998-10-29 05:01:47 +00:00
Andrew Tridgell
27d3cdbc94 syslog support in rsync daemon has been broken since I added the "log
file" option. I wonder why noone reported it? Or did everyone just use
"log file" ?
1998-10-28 10:43:31 +00:00
Andrew Tridgell
106005004e fixed handling of %.0f in replacement snprintf.c 1998-10-28 04:06:43 +00:00
Andrew Tridgell
92ad2c90c4 fixed a typo 1998-10-28 03:37:53 +00:00
Andrew Tridgell
11a5a3c704 and I thought I wasn't going to do any rsync coding for a while ...
Jason Andrade convinced me to add ftpd style logging of transfers,
enabled with a "transfer logging" option in rsyncd.conf

you can customise the format in log.c
1998-10-28 03:28:30 +00:00
David Dykstra
8bb5aa8fe8 Document the fact that --numeric-ids is implied if the source system is
a daemon using chroot.
1998-10-27 17:30:28 +00:00
David Dykstra
4040be4d60 - Define bindir and mandir as per gnu makefile standards
- Add install-strip target as per gnu makefile standards
Contributed by Fred Sanchez <wsanchez@apple.com>
1998-10-27 16:07:51 +00:00
Andrew Tridgell
a9685611e2 fixed a typecast 1998-10-27 14:19:35 +00:00
Andrew Tridgell
b280a1f47e handle OSes (such as Unicos) which use a different value for S_IFLNK 1998-10-27 14:09:28 +00:00
Andrew Tridgell
f8be5ef4cb added a vsnprintf() implementation from cvslock. See the notes on the
license at the top of lib/snprintf.c
1998-10-26 23:23:45 +00:00
David Dykstra
587cb08dc4 Fix bug in --include and --include-from which didn't work as advertised;
could only include files before if "+ " was explicitly prefixed on files
from any exclude or include option.  Also simplified the code by removing
the "orig" exclude_struct element, and reduced the number of bytes
transferred from client to server by never including "- " prefixes in the
transmitted exclude list because exclusion is the default.
1998-10-26 22:03:18 +00:00
David Dykstra
8638dd48f7 Add "use chroot" and "pid file" rsyncd.conf options. The former allows one
to disable the use of chroot so rsync --daemon can be run as a non-root
user (if a non-privileged --port is used).  The latter allows one to
specify a file in which to write the process id of the daemon, which is
useful when rsync --daemon is not run from inetd.
1998-10-26 21:51:47 +00:00
David Dykstra
2bca43f627 Optimize server for special case of a long list of includes ("+") followed
by a match-all exclude "- *".
1998-10-26 21:45:23 +00:00
David Dykstra
375a4556c7 Add --compare-dest option which enables specifying an additional destination
for comparisons when syncing.  Useful for syncing into a scratch area and
doing a flash-cutover when it is completed.
1998-10-26 21:42:38 +00:00
rsync-bugs
b41c3f9273 preparing for release of 2.1.1 1998-09-09 07:07:11 +00:00
Andrew Tridgell
35bdd146e4 fixed timestring() bug 1998-09-09 07:06:44 +00:00
Andrew Tridgell
8d249b635c don't complain about not setting times on directories
because some filesystems can't do it
1998-09-09 06:37:13 +00:00
Andrew Tridgell
932be9aa52 handle sstem (sco 3) with glob but not glob.h 1998-09-09 06:31:13 +00:00
Andrew Tridgell
c6b81a9865 handle OSes where you can't rename a open file in the cleanup code. 1998-09-09 06:23:27 +00:00
Andrew Tridgell
e0414f4202 put the time in when using log file. 1998-09-09 06:06:08 +00:00
Andrew Tridgell
6e4fb64e61 added finddead target, removed dead code and made some functions
static
1998-09-09 05:57:34 +00:00
Andrew Tridgell
37863201ad doc updates 1998-09-09 05:52:25 +00:00
Andrew Tridgell
4f6325c362 added "log file" option for those systems with broken syslog (like
AIX)
1998-09-09 05:51:42 +00:00
Andrew Tridgell
f98df1d9b7 wanr people who use path names to rsync :: 1998-09-09 05:51:08 +00:00
Andrew Tridgell
3d913675a1 fixed a small memory leak when using -C
thanks to kalt@research.bell-labs.com for this fix.
1998-08-27 05:17:21 +00:00
Andrew Tridgell
2f9af90118 removed the limit on the read buffer size until I fully understand the
interactions with ssh. The old ssh freezes have shown up again and
some debugging (with help from James Welborn) showed that the cause
was the read buffer hitting maximum size. I think this means that ssh
must be misbehaving about blocking IO.

This change gets rid of the freezes at the expense of memory
usage. Where it would have frozen it uses more memory instead.
1998-08-27 05:07:52 +00:00
Andrew Tridgell
3eb388185b a couple of changes to where the nonblocking settings are called. 1998-08-27 05:05:14 +00:00
Andrew Tridgell
858fb9ebad fix PATTERN/FILE in --help output 1998-07-25 09:20:33 +00:00
Andrew Tridgell
2f03f956f4 rsync.c was getting a bit unwieldy so I split the code into 3 modules,
for the 3 logical stages of rsync; generator, sender and receiver.
1998-07-25 02:25:22 +00:00
Andrew Tridgell
0199b05f25 fixed the relative paths bug pointed out by Alberto Accomazzi 1998-07-23 03:09:14 +00:00
rsync-bugs
e2d1033d5d preparing for release of 2.1.0 1998-07-20 05:43:51 +00:00
Andrew Tridgell
c46ded4621 I think I might havefinally fixed the rsync hanging bug. It was caused
by a read during an io_flush() triggered during a readfd(). A simple
logic bug in the io code :(
1998-07-20 05:36:25 +00:00
Andrew Tridgell
8cd9fd4e8c always use a timeout to select, even if --timeout is not
specified. This makes things easier to debug.
1998-07-19 10:51:26 +00:00
Andrew Tridgell
41979ff87c - defer the error message from the options parsing until after the
socket is multiplexed. This allows clients sending new options which
the remote server doesn't understand to get a sensible error message.
1998-07-19 05:22:05 +00:00
Andrew Tridgell
b11ed3b150 - close stdout and stderr and reopen then as /dev/null when running as
a daemon. This prevents library functions (such as getopt) stuffing up
our protocol stream when errors are detected.

- defer the error message from the options parsing until after the
socket is multiplexed. This allows clients sending new options which
the remote server doesn't understand to get a sensible error message.
1998-07-19 04:50:48 +00:00
rsync-bugs
42245f1b56 preparing for release of 2.0.19 1998-07-17 14:53:00 +00:00
Andrew Tridgell
c29ee43dbd handle hard links on systems with 16 bit ino_t 1998-07-17 14:42:59 +00:00
Andrew Tridgell
d310a212f7 added a bit in the man page about the clean shell error 1998-07-17 14:25:14 +00:00
Andrew Tridgell
ca6c93f817 check whether there is a / before a : in the rsync command line. If
there is then assume that the : is from a filename, not a host:dir
separator. This allows you to copy files with a : in them. (suggestion
from pfeifer@wait.de)
1998-07-17 14:05:57 +00:00
Andrew Tridgell
72914a606e make rsync behave more like GNU cp with regard to file permissions
when -p (preserve permissions) isn't set.

It works by taking the sending file permissions and masking them with
the umask to create the destination file permissions. (There is really
no "correct" way of doing this but at least we now behave like GNU cp
which fits the principle of least surprise.)

also fixed a race condition in copy_file()
1998-07-17 13:18:32 +00:00
Andrew Tridgell
4b957c2238 added the --safe-links option to disallow symlinks outside the
destination tree
1998-07-17 10:00:48 +00:00
Andrew Tridgell
d853783f21 added the --safe-links option to disallow symlinks outside the
destination tree
1998-07-17 10:00:43 +00:00
Andrew Tridgell
298c10d5bb some code reformatting 1998-07-17 07:42:04 +00:00
Andrew Tridgell
6608462cac removed old "make dist" target 1998-07-17 07:26:08 +00:00
Andrew Tridgell
ca8e96946e changed wording of an error message 1998-07-17 07:25:42 +00:00
Andrew Tridgell
6ed67e6dd5 moved getopt.h above unistd.h to prevent problems with uwin on NT 1998-07-17 07:17:11 +00:00
Andrew Tridgell
1f658d4207 fixed a problem with rsync buffering the debug output when redirected
to a file.
1998-07-17 07:07:23 +00:00
Andrew Tridgell
d3bc0b68ab make a function static 1998-07-17 05:38:51 +00:00
Andrew Tridgell
1a0de6c68b remove a useless debug message 1998-07-17 05:38:21 +00:00
Andrew Tridgell
eb601ffeb8 code style change 1998-07-17 05:37:56 +00:00
Andrew Tridgell
8d72ef6e52 use error to detect lockfile open failures vs. max connections reached
and report an appropriate error message
1998-07-17 05:37:18 +00:00
Andrew Tridgell
bcf5b1335d - use explicit flushes instead of setlinebuf. I've had reports of
verbose info not being line buffered to files.

- add a call to localtime() in open_log() in order to prime the C
  libraries timezone cache before the chroot(). This should fix the
  problem of rsyncd log entries being in GMT time.
1998-07-02 10:57:20 +00:00
Andrew Tridgell
bd7e05d799 remove a redundent continue statement 1998-07-02 03:02:14 +00:00
Andrew Tridgell
c95f1aa9d3 prioritise reading over writing in the select loop. (this is another
ssh-friendly attempt)
1998-07-02 02:59:04 +00:00
Andrew Tridgell
86ffe37f11 fix the problem of --timeout waiting for twice the specified time. 1998-07-02 02:48:09 +00:00
Andrew Tridgell
b536f47e3c - don't show "created directory" message unless verbose is selected
- check for null buf in show_progress
1998-07-02 02:08:55 +00:00
Andrew Tridgell
43b06eeae9 output progress % every 1k instead of every 1%, this is better for
large files.
1998-07-02 01:28:39 +00:00
Andrew Tridgell
067857e0ac the recv_generator can be static 1998-07-02 01:27:51 +00:00
Andrew Tridgell
b3e10ed75b enable output buffering in the recv generator. This makes a
significant difference when the transport is ssh as ssh will otherwise
output a complete frame for each checksum record, which increases the
checksum data in size by a factor of around 4.
1998-07-02 01:27:14 +00:00
Andrew Tridgell
a353d56337 don't need to send --progress option to server as the server never
prints progress info.
1998-07-02 00:48:20 +00:00
Andrew Tridgell
eb86d661d7 added --progress option which shows the progress of transfers. This
gives bored users something to watch.
1998-07-02 00:47:13 +00:00
Andrew Tridgell
fe055c718a - only keep a partial file if some literal data has been transferred,
this prevents a second interrupted transfer from reducing the size of
the transferred file.

- set SIGUSR1 to SIG_IGN early to prevent a race condition that
prevents the --partial code from working properly
1998-07-01 11:03:50 +00:00
Andrew Tridgell
31f440e68b I've had reports of rsyncd leaving zombies under digital unix. This
patch tries to address the problem in two ways:

1) reinstall the SIGCHLD handler before each fork
2) reap any children not caught by the handler using waitpid with
WNOHANG.

I expect this will fix the problem.
1998-07-01 05:10:42 +00:00
Andrew Tridgell
c95da96a0c added a --partial option which tells rsync to keep partially
transferred files if the transfer is interrupted.

added a "options summary" section to the man page
1998-07-01 03:36:03 +00:00
Andrew Tridgell
bf9f01689f if we get EWOULDBLOCK on a write then reduce the amount of data we are
trying to write. This guarantees that the maximum amount of data that
can be written at any one time is written.
1998-06-19 00:55:19 +00:00
Andrew Tridgell
da81e21536 use LDFLAGS in Makefile.in (fix from arndt@schoenewald.de) 1998-06-18 14:15:16 +00:00
Andrew Tridgell
46831d6fcf fixed chmod bug pointed out by Han Holl <jeholl@euronet.nl> 1998-06-18 13:26:10 +00:00
rsync-bugs
b58ad6c569 preparing for release of 2.0.18 1998-06-18 13:06:00 +00:00
Andrew Tridgell
22b1933287 fixed a race condition in rsync that opened a security hole. The
temporary files were being created with the same permissions as the
original file. So if the file was setuid but not owned by the user
doing the transfer then there was a window of opportunity for a
malicious user to execute it with the wrong permissions while it was
being transferred.

Thanks to snabb@epipe.fi for pointing this out.
1998-06-18 12:17:23 +00:00
rsync-bugs
5a03f68a5a preparing for release of 2.0.17 1998-06-18 10:30:48 +00:00
Andrew Tridgell
e81da93e86 if as non-root we failed to update the group of a file then don't
print the file name.
1998-06-18 10:03:44 +00:00
Andrew Tridgell
f578043391 for consistency use memcpy/memset everywhere instead of bcopy/bzero 1998-06-18 09:51:44 +00:00
Andrew Tridgell
e8f5b936ad move include of compat.h after other includes. 1998-06-18 09:37:21 +00:00
Andrew Tridgell
667e72a195 change the order of chmod and chown calls so that setuid bits don't
get removed by chown calls.
1998-06-18 09:36:24 +00:00
Andrew Tridgell
e1b3d5c4be set network file descriptors non-blocking before starting main rsync
algorithm.
1998-06-18 09:34:56 +00:00
Andrew Tridgell
f7b9377863 handle non-blocking file descriptors for both read and write. Add a
workaround for buggy systems that say there is space to write when
there isn't.
1998-06-18 09:33:46 +00:00
Andrew Tridgell
a5343e765b put set_nonblocking() code back in. 1998-06-18 09:32:45 +00:00
Andrew Tridgell
704f908eae --help changes suggested by Francois 1998-06-18 09:31:42 +00:00
Andrew Tridgell
de2fd20eb7 manpage updates, mostly suggested by Francois 1998-06-18 09:30:51 +00:00
Andrew Tridgell
100e5241b0 the tag table should be of type int* not tag*.
This bug resulted in rsync being much less efficient that it could be
for files with more than 64k blocks. With the adaptive block size code
giving a maximum block size of 16k this means that files larger than
1GB were handled very inefficiently. The transfer was still accurate,
just slow.
1998-06-03 02:47:52 +00:00
Andrew Tridgell
ddecf7060b if the user passes a block size on the command line then don't adapt
the block size.
1998-06-03 02:35:51 +00:00
Andrew Tridgell
56cdbccb92 added note to docs saying that --stats doesn't work unless -v is used 1998-06-02 12:50:23 +00:00
Andrew Tridgell
fc8a6b9705 added some fflush() calls to make sure the statistics lines are
printed when redirecting output to a file.
1998-06-02 12:46:46 +00:00
rsync-bugs
143384f367 preparing for release of 2.0.16 1998-06-01 13:49:12 +00:00
Andrew Tridgell
8c3b04730b added some notes to test.sh 1998-06-01 13:44:06 +00:00
Andrew Tridgell
aa9b77a56c replace calls to strcmp() with a u_strcmp() function that uses only
unsigned comparisons. Transferring files between two machines that
treated strcmp() differently led to the files being given the wrong
name at the destination if the filenames had characters > 128 (such as
Kanji characters) and the source and destination machines treated
strcmp() differently (ie. one treated strings as signed and the other
as unsigned).

We now treat all string comparisons for file list sorting as unsigned.
1998-06-01 13:39:54 +00:00
Andrew Tridgell
b72f24c719 updated the usage info 1998-06-01 10:38:24 +00:00
Andrew Tridgell
a800434a82 added --stats option for verbose stats on the file transfer 1998-06-01 03:42:14 +00:00
rsync-bugs
3b3c3d4390 preparing for release of 2.0.15 1998-05-30 02:10:18 +00:00
Andrew Tridgell
d846b09874 replace BAD with zBAD so it compiles on AIX 1998-05-30 02:07:36 +00:00
Andrew Tridgell
1d3754aede cosmetic fix.
reset offset to 0 at the start of each loop so the filenames get
printed correctly when sending directories followed by local names.
1998-05-30 02:03:29 +00:00
Andrew Tridgell
e44f9a12c4 make sure that io_flush() doesn't call writefd_unbuffered from within
a writefd_unbuffered call!

this should fix the "decompressor lost sync" bug
1998-05-30 02:02:23 +00:00
Andrew Tridgell
5243c216d6 replaced chdir and getcwd calls with push_dir/pop_dir functions. These
are faster and don't cause problems in a chrooted environment on any
systems.
1998-05-29 14:36:39 +00:00
rsync-bugs
79a51e7ee6 preparing for release of 2.0.14 1998-05-29 02:29:33 +00:00
Andrew Tridgell
cad2bba7d8 fixed a bug in the flist sending code that caused the flist sending to
get out of sync.
1998-05-29 02:28:33 +00:00
Andrew Tridgell
fe8c0a9824 use Realloc instead of realloc 1998-05-28 06:40:25 +00:00
Andrew Tridgell
6cdc6b1344 fix realloc call for systems that don't handle realloc(NULL, ...) 1998-05-28 06:29:57 +00:00
Andrew Tridgell
05848a2cc7 don't do recursive deletion if the recurse option is not selected. 1998-05-28 05:05:26 +00:00
Andrew Tridgell
528bfcd79a cosmetic fix. don't display a EOF error when displaying just the motd
from a rsync server
1998-05-28 01:58:33 +00:00
rsync-bugs
a1e13a937c preparing for release of 2.0.13 1998-05-27 13:54:41 +00:00
Andrew Tridgell
e3fe383aaa reduce IO_BUFFER_SIZE by 4 bytes so when then length word gets added
it is a power of 2.
1998-05-27 13:47:34 +00:00
Andrew Tridgell
43bd68e5dd added new include/exclude options to man page 1998-05-27 13:39:40 +00:00
Andrew Tridgell
ea2111d10a - always flush the IO write buffer when reading
- handle start of line in exclude properly
1998-05-27 13:05:05 +00:00
Andrew Tridgell
4c36ddbeec heaps of cleanup in the io code.
we no longer use non-blocking IO, instead it uses select a lot more,
being careful to always allow for reading whenever a valid read fd is
available and chcking timeouts.

also split the file io calls into fileio.c
1998-05-27 12:37:22 +00:00
Andrew Tridgell
2b6b4d539b added support for --include, --include-from and the +/- syntax 1998-05-27 11:02:33 +00:00
Andrew Tridgell
35f69d8ad9 new test code from Phil 1998-05-27 06:31:37 +00:00
Andrew Tridgell
7b1ce0d746 fixed a race condition in the --delete handling code. The bug led to
spurious error messages about not be able to delete some files.

this fix also makes --delete processing more efficient
1998-05-27 06:30:50 +00:00
rsync-bugs
54816348d1 preparing for release of 2.0.12 1998-05-26 14:45:05 +00:00
Andrew Tridgell
49d11b78c1 fixed a bug in the handling of very long filenames (longer than 255
chars) where two neighboring filenames share more than 255 characters
at the start of their names.
1998-05-26 14:39:18 +00:00
Andrew Tridgell
bb0f7089fe check for munmap as well as mmap. NextStep only has mmap in standard
libs
1998-05-26 14:18:59 +00:00
Andrew Tridgell
1ff5450d31 formatting changes 1998-05-26 14:17:27 +00:00
Andrew Tridgell
2f7512b006 error formatting changes 1998-05-26 14:16:20 +00:00
Andrew Tridgell
943882a289 - don't allow chown for the group of a file if running as a daemon and
uid!=0

- reset am_root after startup as a daemon
1998-05-23 05:57:08 +00:00
Andrew Tridgell
6c82f74b6f don't treat intermediate link directories as links in the relative
path code
1998-05-23 03:13:46 +00:00
Andrew Tridgell
8a5b8b263b need strchr check in configure.in 1998-05-22 14:22:41 +00:00
Andrew Tridgell
d47a7fcf0f use a simpler mmap() test in autoconf as we don't need all the
features of mmap that the standard test uses, and it reports Ultrix as
having no working mmap() when in fact any mmap will do what we want
for rsync.
1998-05-22 14:03:30 +00:00
Andrew Tridgell
e24c850818 need a ifdef around some mmap code 1998-05-22 13:51:26 +00:00
rsync-bugs
6c612747e3 preparing for release of 2.0.11 1998-05-22 13:46:30 +00:00
Andrew Tridgell
505c7ea2bc add a cast to initialisation of mask 1998-05-22 13:27:55 +00:00
Andrew Tridgell
9add51f18e change WRAP to ZWRAP so it doesn't conflict with IRIX includes 1998-05-22 13:02:22 +00:00
Andrew Tridgell
f7bd44eb32 added a README.rsync to explain what we have changed in zlib and to
tell people that any bugs are our responsibility.
1998-05-22 12:20:07 +00:00
Andrew Tridgell
e3ac52f2e1 no longer needed 1998-05-22 12:13:07 +00:00
Andrew Tridgell
06e27ef78e - fix redefinition of MAX
- fix shadow of variable "overflow"
1998-05-22 12:08:49 +00:00
Andrew Tridgell
23e43fceeb fix shadowed variable 1998-05-22 12:07:23 +00:00
Andrew Tridgell
f900f5fe71 removing an unused variable 1998-05-22 12:06:25 +00:00
Andrew Tridgell
db199cfae0 don't need two AC_OUTPUT lines in configure.in 1998-05-22 12:05:53 +00:00
Paul Mackerras
5914bf15d2 Update to use the new zlib-1.1.2 code.
The compressed token code now handles the null (-2)
token from the match logic.
1998-05-22 06:58:52 +00:00
Andrew Tridgell
45f133b976 this fixes two problems:
1) handle 64 bit file offsets in the token code. I wonder how large
bit files worked up till now?

2) send a null token when we have passed over a large lump of data
without finding a token match. This reduces the number of IOs
considerably as it removes the need for seeks/reads on the checksum
calculation and literal send code. This is not enabled yet for the
compressed case as the deflate token code can't handle it yet.
1998-05-22 01:53:02 +00:00
Andrew Tridgell
c5eb365011 formatting changes. committed separately so they don't mask the coming
token changes.
1998-05-21 05:57:15 +00:00
Andrew Tridgell
2f326946a1 now that we slide the mmap window we can use a smaller MAX_MAP_SIZE
and thus consume less virtual memory on the sending side.
1998-05-21 05:55:33 +00:00
Andrew Tridgell
754d120c98 use mmap() for files of any size. This should be much more buffer
cache friendly.
1998-05-21 05:52:37 +00:00
Andrew Tridgell
8e9871303b someone didn't realise that you need rsync at both ends! 1998-05-21 05:32:36 +00:00
Andrew Tridgell
de5fb3744d added DNS spoofing test to host access control 1998-05-20 00:20:12 +00:00
rsync-bugs
6e47bda08e preparing for release of 2.0.10 1998-05-18 14:30:22 +00:00
Andrew Tridgell
130b4ae447 strip any leading / off absolute paths when using relative path names 1998-05-18 14:11:43 +00:00
Andrew Tridgell
ba5e128d23 fixed a bug in the glob expansion code (pointed out by
hazard.bsn@blkseanet.net.eu.org)
1998-05-18 14:00:24 +00:00
rsync-bugs
79b34efe92 preparing for release of 2.0.9 1998-05-18 10:30:53 +00:00
Andrew Tridgell
679e765768 fixed a multiplexing bug 1998-05-18 10:23:47 +00:00
Andrew Tridgell
e08c961083 handle rsh clients that don't like half-open connections 1998-05-18 09:34:33 +00:00
Andrew Tridgell
8d9dc9f99d this is a large commit which adds io multiplexing, thus giving error
messages from the server when using the socket code.

I've doen a fair bit of testing and I don't seem to have broken
anything, but it is a very complex change. More testing needed!
1998-05-18 08:20:26 +00:00
Andrew Tridgell
593fde2d3b if f_in == f_out then don't close one of them 1998-05-17 15:18:25 +00:00
rsync-bugs
7544c45b1d preparing for release of 2.0.8 1998-05-17 15:10:34 +00:00
Andrew Tridgell
fdee2ba3df rpm is fussy about changelog formats 1998-05-17 15:10:13 +00:00
rsync-bugs
c120bb2235 preparing for release of 2.0.8 1998-05-17 14:58:20 +00:00
Andrew Tridgell
5d58c8d664 updated so I can auto-build rsync packages 1998-05-17 14:32:57 +00:00
Andrew Tridgell
22d6234e04 close some unnecessary file descriptors in do_recv() 1998-05-17 07:22:53 +00:00
Andrew Tridgell
5dd7e03167 put a limit (default 1MB) on the read buffer size. This stops it
growing too much if the sender is much faster than the receiver
1998-05-17 05:56:32 +00:00
Andrew Tridgell
08ac228fbd moved usage mesage after am_daemon test (I'd broken daemon mode) 1998-05-17 03:51:41 +00:00
Andrew Tridgell
6c29af2251 close the other half of the pipe in do_recv(). This fixes the problem
where a rsync receive process could hang around after the connection
has gone away if a fatal error occurs (such as someone killing the
other end)
1998-05-17 01:24:16 +00:00
Andrew Tridgell
6c00346849 check for right number of arguments _after_ the option parsing.
this stops "rsync -v" causing a segv.
1998-05-16 15:18:07 +00:00
Andrew Tridgell
d0d56395c8 for authenticated access record the authenticated username in the logs 1998-05-16 07:45:26 +00:00
rsync-bugs
e9d736a7e8 preparing for release of 2.0.7 1998-05-16 05:38:33 +00:00
rsync-bugs
e9ace0c77a put only the ftp directory in the template file 1998-05-16 05:35:56 +00:00
rsync-bugs
1c31ffa9af added a template file for the rsync spec file to enable automatic spec
generation
1998-05-16 05:30:33 +00:00
Andrew Tridgell
d186eb1a56 - print the stats at the right place when uploading in the rsync
daemon
- update spec file
1998-05-16 05:24:40 +00:00
John H Terpstra
18baf523dc Spec file for building Red Hat RPM packages. 1998-05-16 04:23:41 +00:00
Andrew Tridgell
7b372642ec - distinguish downloads and uploads in the syslog messages
- add stats on uploads in syslog
1998-05-16 03:03:57 +00:00
rsync-bugs
4f189177dc preparing for release of 2.0.6 1998-05-16 00:57:37 +00:00
Andrew Tridgell
f72399f867 fixed handling of vsprintf on SunOS 1998-05-16 00:46:16 +00:00
rsync-bugs
d64488e169 preparing for release of 2.0.5 1998-05-15 14:12:06 +00:00
Andrew Tridgell
29110570f8 removed some debug code 1998-05-15 14:01:04 +00:00
Andrew Tridgell
3e607d2354 got rid of "EOF in map_ptr" problem. If a file shrinks mid transfer
then we supply a zero filled buffer at the end and rely on the
checksum to cause a retry. This is really the best we can do as there
is no correct semantics for copying a changing file!
1998-05-15 14:00:12 +00:00
Andrew Tridgell
a6801c3977 added a "socket options" option to rsyncd.conf. This option will
provide hours of fun for those people who like to tune their systems
to the utmost degree.
1998-05-15 13:25:19 +00:00
rsync-bugs
3ef56fee8f preparing for release of 2.0.4 1998-05-15 10:58:03 +00:00
Andrew Tridgell
f9e940efc7 load just the globals section of the config file when the daemon
starts so we know the syslog facility for the "starting" message
1998-05-15 10:52:54 +00:00
Andrew Tridgell
1a016bfdec - changed the log messages to show the requested path
- some more paranoid buffer size checks
- separate open syslog call
- handle systems without LOG_NDELAY
1998-05-15 10:34:07 +00:00
Andrew Tridgell
e42c9458c2 use strlcat() strlcpy() and slprintf() whenever possible to avoid any
chance of a buffer overflow
1998-05-15 09:26:01 +00:00
Andrew Tridgell
087bf010d2 allow the specification of multiple filenames (with or without
wildcards) to a rsync server. For example you can do:

rsync -avz samba::'ftp/pub/samba/README ftp/pub/samba/*.gz' .
1998-05-15 08:43:11 +00:00
rsync-bugs
f240c06902 preparing for release of 2.0.3 1998-05-15 07:55:05 +00:00
Andrew Tridgell
a87b3b2ac2 use a separate "make man" target so people don't need yodl 1998-05-15 07:53:41 +00:00
rsync-bugs
ed0992b888 preparing for release of 2.0.2 1998-05-15 07:37:00 +00:00
Andrew Tridgell
d6dead6bb1 added write buffering during the file list sending. This makes things
a bit more efficient (less system calls)
1998-05-15 07:34:19 +00:00
Andrew Tridgell
344fb1276b fixed a select bug which caused rsync to use far more cpu time than
necessary on the server
1998-05-15 07:11:29 +00:00
Andrew Tridgell
e095b568d0 updated the README a bit 1998-05-15 05:42:56 +00:00
Andrew Tridgell
4c3d16be50 - added some notes about encryption and authentication to the man
pages

- documented the RSYNC_PASSWORD environment variable
1998-05-15 05:37:34 +00:00
rsync-bugs
715e727784 preparing for release of 2.0.1 1998-05-15 01:19:42 +00:00
Andrew Tridgell
5805327b28 fixed typo in rsyncd exclude handling 1998-05-15 01:14:48 +00:00
Andrew Tridgell
8f3a2d54a6 added "exclude" and "exclude from" options to rsyncd.conf.
This is useful for mirroring a web site when you don't want users to
mirror everything.
1998-05-15 01:02:49 +00:00
Andrew Tridgell
e22de16264 fixed SIGCLD -> SIGCHLD
fixed formatting of man page (thanks to Karsten)
1998-05-15 00:29:45 +00:00
rsync-bugs
c725d76c5a preparing for release of 2.0.0 1998-05-14 07:22:45 +00:00
Andrew Tridgell
5315b793d2 fixed spelling mistakes 1998-05-14 06:57:50 +00:00
Andrew Tridgell
41059f75b5 documentation!
I've written a rsyncd.conf man page (in yodl) and updated the rsync
man page.
1998-05-14 06:51:28 +00:00
Andrew Tridgell
248fbb8c23 syslog some stats 1998-05-14 04:49:30 +00:00
Andrew Tridgell
fabf5ea72d now support integers or strings for syslog facility 1998-05-14 04:40:23 +00:00
Andrew Tridgell
09e13ae2dc changed "syslog facility" to an enumerated type so the string name is
used in rsyncd.conf
1998-05-14 04:38:17 +00:00
Andrew Tridgell
5a96ee0599 make host access controls case insensitive 1998-05-14 04:31:03 +00:00
Andrew Tridgell
0cea42440f removed a debug line 1998-05-13 15:56:03 +00:00
Andrew Tridgell
874895d51a added globbing support in the rsync daemon. This will allow you to
specify wildcards when grabbing files from a anon rsync daemon.
1998-05-13 15:44:04 +00:00
Andrew Tridgell
f855d1a309 vsprintf returns char* on sunos4 1998-05-13 13:48:25 +00:00
Andrew Tridgell
9fc310dafe added replacement memmove 1998-05-13 13:27:36 +00:00
Andrew Tridgell
0473e2a14a define INADDR_NONE if necessary 1998-05-13 13:22:26 +00:00
Andrew Tridgell
c8e78d87ad improved the authentication and in particular the error reporting 1998-05-13 12:21:10 +00:00
Andrew Tridgell
bcb7e50250 first working version of challenge response authentication. needs
testing.
1998-05-13 11:49:05 +00:00
Andrew Tridgell
31593dd610 improved max connections code. Now use fcntl instead of flock.
also started on authentication code (I'm doing a challenge response
system initially)
1998-05-13 09:38:54 +00:00
Andrew Tridgell
91eee5946a save another couple of round trip latencies. This set of changes is
backwards compatible.
1998-05-13 09:08:05 +00:00
Andrew Tridgell
6c8f537302 need sys/file.h for flock() 1998-05-13 09:01:11 +00:00
Andrew Tridgell
13c5fc0e14 save one round trip (version swapping) for daemon.
This is an imcompatible change in the socket protocol. You get "is
your shell clean" if using an older rsync client
1998-05-13 08:58:07 +00:00
Andrew Tridgell
0c515f17c4 added two new options "max connections" and "lock file" 1998-05-13 08:52:12 +00:00
Andrew Tridgell
851dbdb775 added "syslog facility" option. It is an integer and defaults to the
value of LOG_DAEMON.
1998-05-13 08:12:51 +00:00
Andrew Tridgell
56c473b795 added hosts allow and hosts deny support. I ended up writing my own as
the tcpd code is not quite what I wanted.
1998-05-13 08:03:47 +00:00
Andrew Tridgell
df5e03da7b check argc and show usage if no args 1998-05-13 07:04:40 +00:00
Andrew Tridgell
4cdf25e42e load the config file on each connect rather than at startup 1998-05-13 00:08:03 +00:00
Andrew Tridgell
eb697c999b fixed a bug in the new . filename code 1998-05-11 12:29:19 +00:00
Andrew Tridgell
d4ebe7a7b1 changed the name of the temporary filename to include a leading . so
that it appears hidden while being transferred. This should be useful
when using rsync for mirroring so users accessing via ftp don't get
confused by the temporary files.
1998-05-10 13:45:03 +00:00
Andrew Tridgell
d7ff63cf1a the statistics reporting was the wrong way around for client receipt
mode! It reported the read/written backwards.
1998-05-10 13:01:59 +00:00
Andrew Tridgell
e45e009309 changed a couple of places to use strlcpy() 1998-05-10 12:37:26 +00:00
Andrew Tridgell
45ccc5c08c only call openlog once
fix a segv in loadparm.c
1998-05-10 08:31:50 +00:00
Andrew Tridgell
ff8b29b8c6 use syslog instead of /var/adm/rsyncd.log 1998-05-10 08:24:38 +00:00
Andrew Tridgell
8ef4ffd698 change to allow names or numbers to be used for uid and gid. 1998-05-10 08:05:56 +00:00
Andrew Tridgell
c596dad1d1 fixed typo in socket test 1998-05-10 07:45:14 +00:00
Andrew Tridgell
7d29d4ba13 look for -lsocket by checking for connect() 1998-05-10 07:40:20 +00:00
Andrew Tridgell
7a6421fa76 split the options parsing code into options.c
added the --port and --config options

use strlcpy() instead of strncpy()

some cleanups and formatting changes
1998-05-10 07:25:40 +00:00
Andrew Tridgell
2c91d3d311 better negotiation of protocol versions 1998-05-10 03:08:22 +00:00
Andrew Tridgell
3591c0660c cleanup code a bit 1998-05-10 01:46:06 +00:00
Andrew Tridgell
0b76cd63ee configuration parsing and loading code for rsyncd. This is based
on the Samba config code, so you'll find that the config files will
be eerily familiar if you have ever worked with Samba.
1998-05-09 14:00:55 +00:00
Andrew Tridgell
f0fca04e4e first vesrion of working socket based rsync. It still needs a lot of
work, but at least it works :-)
1998-05-09 13:58:54 +00:00
Andrew Tridgell
bc2e93eb8e just a stub for now 1998-05-07 14:53:02 +00:00
Andrew Tridgell
d3394de178 removed some quoted printable stuff from this so it works again 1998-05-07 14:52:38 +00:00
Andrew Tridgell
9486289ce4 some large systematic changes to make socket conversion easier. The
biggest one is the use of rprintf() instead of fprintf()
1998-05-07 14:50:22 +00:00
Andrew Tridgell
5d6bcd4472 some code cleanup in preparation for a cleaner client/server split 1998-05-07 12:30:47 +00:00
Andrew Tridgell
94f3c3b047 improve the autoconf warning for broken readdir 1998-05-07 12:29:56 +00:00
Paul Mackerras
d4286ec49d Add pristine zlib-1.1.2 code, ready for hacking. 1998-05-07 06:19:41 +00:00
Andrew Tridgell
dad5e9d0b5 now using autoheader as well as autoconf 1998-05-07 03:57:26 +00:00
Andrew Tridgell
b79223389b hopefully better support for systems where sizeof(int)==8 1998-05-06 14:13:03 +00:00
Andrew Tridgell
fa37d4bbaf don't need off64_t code on systems where off_t is already 64 bits 1998-05-06 08:01:00 +00:00
Andrew Tridgell
f28ee65baa damn solaris doesn't prototype it's functions correctly. grrr. 1998-05-06 07:35:37 +00:00
Andrew Tridgell
94c9ef1fc3 handle mmap() failures 1998-05-06 07:28:14 +00:00
Andrew Tridgell
59503278bf better test for solaris broken readdir 1998-05-06 07:18:06 +00:00
Andrew Tridgell
d6e6ecbdbf handle broken readdir() on Solaris 2.6 (it returns the name offset by
2 characters!)
1998-05-06 07:00:38 +00:00
Andrew Tridgell
73233f0f12 add support for lseek64() under solaris 2.6 1998-05-06 06:34:18 +00:00
Andrew Tridgell
debb45054a Solaris 2.6 doesn't support "signed char". What a broken system! 1998-05-06 06:21:35 +00:00
Andrew Tridgell
efb2f6bf62 use floating point for printout of stats - this wrks on machines
without long long but with a 64 bit off_t
1998-05-06 06:07:06 +00:00
Andrew Tridgell
bcacc18bdf added support for 64 bit file offsets under Solaris 2.6. Not tested
yet.
1998-05-06 05:43:36 +00:00
Andrew Tridgell
3bee67337d fix up the int64 handling a little. It should work on a few more
systems now (tested on OSF1)
1998-05-06 05:05:00 +00:00
Andrew Tridgell
0944563eb9 a leading / in a pattern now means "use a absolute path match". This
allows you to exclude root directories without excluding
subdirectories of the same name.
1998-05-05 11:23:51 +00:00
Andrew Tridgell
a0b65b1805 added support for sockets and fifos 1998-04-28 05:53:18 +00:00
Andrew Tridgell
ddddf27b28 a much improved test script from Phil. 1998-04-17 15:48:10 +00:00
rsync-bugs
1f1b3b8ee7 preparing for release of 1.7.4 1998-04-17 06:49:05 +00:00
Andrew Tridgell
5806b30f0f this is a little test script to test some of rsyncs features
(contributed by Phil Hands)
1998-04-17 06:08:59 +00:00
Andrew Tridgell
3333ffbd43 revamped the -delete code. The last few bugs with it revealed that it
had a fundamental flaw in the way it detected duplicate deletion
scanning (which is very important when -R is used). I now store
inode/device numbers and use those to do the detection. This should be
a much less fragile method.
1998-04-17 06:07:23 +00:00
Andrew Tridgell
a16bbc3990 a few code cleanups 1998-04-13 07:26:37 +00:00
rsync-bugs
cf0d1d819a preparing for release of 1.7.3 1998-04-13 07:00:55 +00:00
Andrew Tridgell
0a25de67e9 fixed a bug in the handling of -R with --delete
I introduced this bug in the last version as a side effect of fixing
the permissions on intermediate directories with -R. drat.
1998-04-13 06:39:33 +00:00
Andrew Tridgell
317302412e not quite so many decimal places in "speedup" :-) 1998-04-13 04:44:49 +00:00
Andrew Tridgell
1250f24ed2 fixed a bug in handling the -c option and non-regular files. It hadn't
turned up before because Linux had a bug in the handling of NULL
pointers to read()/write() on pipes, so I never noticed the bug in my
testing.

I've also sent a patch to Linus.
1998-04-09 00:38:40 +00:00
131 changed files with 30626 additions and 9975 deletions

View File

@@ -1,21 +1,15 @@
.ignore
.cvsignore
ID
Makefile
a
b
config.cache
config.h
config.log
config.status
dist.tar.gz
gmon.out
rsync
rsync-*
rsync.aux
rsync.dvi
rsync.log
tech_report.aux
tech_report.dvi
tech_report.log
tech_report.ps
test
shconfig
testdir
tests-dont-exist
testtmp
testtmp.*
tls
zlib/dummy

42
INSTALL Normal file
View File

@@ -0,0 +1,42 @@
To build and install rsync
$ ./configure
$ make
# make install
You may set the installation directory and other parameters by options
to ./configure. To see them, use:
$ ./configure --help
As of 2.4.7, rsync uses Eric Troan's popt option-parsing library. A
cut-down copy of release 1.5 is included in the rsync distribution,
and will be used it there is no popt library on your build host, or if
the --with-included-popt option is passed to ./configure.
HP-UX NOTES
-----------
The HP-UX 10.10 "bundled" C compiler seems not to be able to cope with
ANSI C. You may see this error message in config.log if ./configure
fails:
(Bundled) cc: "configure", line 2162: error 1705: Function prototypes are an ANSI feature.
Install gcc or HP's "ANSI/C Compiler".
MAC OSX NOTES
-------------
Mac OS X (Darwin) seems to have an IPv6 stack, but it does not
completely implement the "New Sockets" API.
<http://www.ipv6.org/impl/mac.html> says that Apple do not support
IPv6 yet. If your build fails, try again with --disable-ipv6.

View File

@@ -3,52 +3,132 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
INSTALL_BIN=$(exec_prefix)/bin
INSTALL_MAN=$(prefix)/man
bindir=@bindir@
mandir=@mandir@
LIBS=@LIBS@
CC=@CC@
CFLAGS=@CFLAGS@
LDFLAGS=@LDFLAGS@
INSTALLCMD=@INSTALL@
VPATH=@srcdir@
srcdir=@srcdir@
VPATH=$(srcdir)
SHELL=/bin/sh
VERSION=@VERSION@
.SUFFIXES:
.SUFFIXES: .c .o
LIBOBJ=lib/getopt.o lib/fnmatch.o lib/zlib.o lib/compat.o
OBJS1=rsync.o exclude.o util.o md4.o main.o checksum.o match.o syscall.o
OBJS=$(OBJS1) flist.o io.o compat.o hlink.o token.o uidlist.o $(LIBOBJ)
LIBOBJ=lib/fnmatch.o lib/compat.o lib/snprintf.o lib/mdfour.o \
lib/permstring.o \
@LIBOBJS@
ZLIBOBJ=zlib/deflate.o zlib/infblock.o zlib/infcodes.o zlib/inffast.o \
zlib/inflate.o zlib/inftrees.o zlib/infutil.o zlib/trees.o \
zlib/zutil.o zlib/adler32.o
OBJS1=rsync.o generator.o receiver.o cleanup.o sender.o exclude.o util.o main.o checksum.o match.o syscall.o log.o backup.o
OBJS2=options.o flist.o io.o compat.o hlink.o token.o uidlist.o socket.o fileio.o batch.o
DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o
popt_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \
popt/popthelp.o popt/poptparse.o
OBJS=$(OBJS1) $(OBJS2) $(DAEMON_OBJ) $(LIBOBJ) $(ZLIBOBJ) @BUILD_POPT@
tls_OBJ = tls.o syscall.o lib/permstring.o
# Programs we must have to run the test cases
CHECK_PROGS = rsync tls
# note that the -I. is needed to handle config.h when using VPATH
.c.o:
$(CC) -I. -I$(srcdir) $(CFLAGS) -c $< -o $@
@OBJ_SAVE@
$(CC) -I. -I$(srcdir) $(CFLAGS) -c $< @CC_SHOBJ_FLAG@
@OBJ_RESTORE@
all: rsync
man: rsync.1 rsyncd.conf.5
install: all
-mkdir -p ${INSTALL_BIN}
${INSTALLCMD} -m 755 rsync ${INSTALL_BIN}
-mkdir -p ${INSTALL_MAN}/man1
${INSTALLCMD} -m 644 $(srcdir)/rsync.1 ${INSTALL_MAN}/man1
-mkdir -p ${bindir}
${INSTALLCMD} -m 755 rsync ${bindir}
-mkdir -p ${mandir}/man1
-mkdir -p ${mandir}/man5
${INSTALLCMD} -m 644 $(srcdir)/rsync.1 ${mandir}/man1
${INSTALLCMD} -m 644 $(srcdir)/rsyncd.conf.5 ${mandir}/man5
install-strip:
$(MAKE) INSTALLCMD='$(INSTALLCMD) -s' install
rsync: $(OBJS)
$(CC) $(CFLAGS) -o rsync $(OBJS) $(LIBS)
@echo "Please ignore warnings below about mktemp -- it is used in a safe way"
$(CC) $(CFLAGS) $(LDFLAGS) -o rsync $(OBJS) $(LIBS)
$(OBJS): config.h
tls: $(tls_OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(tls_OBJ) $(LIBS)
Makefile: Makefile.in configure config.status
echo "WARNING: You need to run ./config.status --recheck"
# don't actually run autoconf, just issue a warning
configure: configure.in
echo "WARNING: you need to rerun autoconf"
rsync.1: rsync.yo
yodl2man -o rsync.1 rsync.yo
rsyncd.conf.5: rsyncd.conf.yo
yodl2man -o rsyncd.conf.5 rsyncd.conf.yo
proto:
cat *.c | awk -f mkproto.awk > proto.h
cat *.c lib/compat.c | awk -f mkproto.awk > proto.h
clean:
rm -f *~ $(OBJS) rsync config.cache config.log config.status
rm -f *~ $(OBJS) rsync $(TLS_OBJ) tls
rm -rf ./testtmp
rm -f config.cache
dist:
tar --exclude-from .ignore -czf dist.tar.gz .
-mkdir rsync-$(VERSION)
(cd rsync-$(VERSION) ; tar xzf ../dist.tar.gz)
tar -czf rsync-$(VERSION).tar.gz rsync-$(VERSION)
rm -f dist.tar.gz
echo rsync-$(VERSION) >> .cvsignore
distclean: clean
rm -f Makefile config.h config.status
# this target is really just for my use. It only works on a limited
# range of machines and is used to produce a list of potentially
# dead (ie. unused) functions in the code. (tridge)
finddead:
nm *.o */*.o |grep 'U ' | awk '{print $$2}' | sort -u > nmused.txt
nm *.o */*.o |grep 'T ' | awk '{print $$3}' | sort -u > nmfns.txt
comm -13 nmused.txt nmfns.txt
# 'check' is the GNU name, 'test' is the name for everybody else :-)
.PHONY: check test
test: check
# There seems to be no standard way to specify some variables as
# exported from a Makefile apart from listing them like this.
# TODO: Tests that depend on built test aide programs like tls need to
# know where the build directory is.
# This depends on building rsync; if we need any helper programs it
# should depend on them too.
# We try to run the scripts with POSIX mode on, in the hope that will
# catch Bash-isms earlier even if we're running on GNU. Of course, we
# might lose in the future where POSIX diverges from old sh.
check: all $(CHECK_PROGS)
POSIXLY_CORRECT=1 TLS=`pwd`/tls rsync_bin=`pwd`/rsync srcdir="$(srcdir)" $(srcdir)/runtests.sh
# This does *not* depend on building or installing: you can use it to
# check a version installed from a binary or some other source tree,
# if you want.
installcheck: $(CHECK_PROGS)
POSIXLY_CORRECT=1 TLS=`pwd`/tls rsync_bin="$(bindir)/rsync" srcdir="$(srcdir)" $(srcdir)/runtests.sh
# TODO: Add 'dist' target; need to know which files will be included

7
NEWS Normal file
View File

@@ -0,0 +1,7 @@
rsync 2.4.7 (???)
SECURITY FIXES:
* Signedness security patch from Sebastian Krahmer
<krahmer@suse.de> -- in some cases we were not sufficiently
careful about reading integers from the network.

148
OLDNEWS Normal file
View File

@@ -0,0 +1,148 @@
rsync 2.5.1 (2002-01-03)
BUG FIXES:
* Fix for segfault in --daemon mode configuration parser. (Paul
Mackerras)
* Correct string<->address parsing for both IPv4 and 6.
(YOSHIFUJI Hideaki, SUMIKAWA Munechika and Jun-ichiro "itojun"
Hagino)
* Various fixes for IPv6 support. (Dave Dykstra)
* rsync.1 typo fix. (Matt Kraai)
* Test suite typo fixes. (Tom Schmidt)
* rsync.1 grammar and clarity improvements. (Edward
Welbourne)
* Correction to ./configure tests for inet_ntop. (Jeff Garzik)
ENHANCEMENTS:
* --progress and -P now show estimated data transfer rate (in a
multiple of bytes/s) and estimated time to completion. (Rik
Faith)
* --no-detach option, required to run as a W32 service and also
useful when running on Unix under daemontools, AIX's SRC, or a
debugger. (Max Bowsher, Jos Backus)
* Clearer error messages for some conditions.
rsync 2.5.0 (2001-11-30)
ANNOUNCEMENTS
* Martin Pool <mbp@samba.org> is now a co-maintainer.
NEW FEATURES
* Support for LSB-compliant packaging <http://www.linuxbase.org/>
* Shell wildcards are allowed in "auth users" lines.
* Merged UNC rsync+ patch to support creation of standalone patch
sets. By Bert J. Dempsey and Debra Weiss, updated by Jos
Backus. <http://www.ils.unc.edu/i2dsi/unc_rsync+.html>
* IPv6 support based on a patch from KAME.net, on systems
including modern versions of Linux, Solaris, and HP-UX. Also
includes IPv6 compatibility functions for old OSs by the
Internet Software Consortium, Paul Vixie, the OpenSSH
portability project, and OpenBSD.
ENHANCEMENTS
* Include/exclude cluestick: with -vv, print out whether files are
included or excluded and why.
* Many error messages have more friendly explanations and more
details.
* Manual page improvements plus scanty protocol documentation.
* When running as --daemon in the background and using a "log
file" rsyncd.conf directive, close the log file every time it is
open when going to sleep on the socket. This allows the log
file to get cleaned out by another process.
* Change to using libpopt rather than getopt for processing
options. This makes the code cleaner and the behaviour more
consistent across platforms. popt is included and built if not
installed on the platform.
* More details in --version, including note about whether 64-bit
files, symlinks and hardlinks are supported.
* MD4 code may use less CPU cycles.
* Use mkstemp on systems where it is secure. If we use mktemp,
explain that we do it in a secure way.
* --whole-file is the default when source and target are on the
local machine.
BUG FIXES:
* Fix for various bugs causing rsync to hang.
* Attempt to fix Large File Summit support on AIX.
* Attempt to fix error handling lockup bug.
* Give a non-0 exit code if *any* of the files we have been asked
to transfer fail to transfer
* For log messages containing ridiculously long strings that might
overflow a buffer rsync no longer aborts, but rather prints an
ellipsis at the end of the string. (Patch from Ed Santiago.)
PLATFORMS:
* Improved support for UNICOS (tested on Cray T3E and Cray SV1)
* autoconf2.52 (or later) is now required to rebuild the autoconf
scripts. It is not required to simply build rsync.
* Platforms thought to work in this release:
Cray SV1 UNICOS 10.0.0.8 cc
Debian Linux 2.2 UltraSparc gcc
Debian Linux testing/unstable ARM gcc
FreeBSD 3.3-RELEASE i386 cc
FreeBSD 4.1.1-RELEASE i386 cc
FreeBSD 4.3-STABLE i386 cc
HP PA-RISC HP-UX 10.20 gcc
HP PA-RISC HP-UX 11.11 cc
IRIX 6.5 MIPS cc
IRIX 6.5 MIPS gcc
Mac OS X PPC (--disable-ipv6) cc
NetBSD 1.5 i386 gcc
NetBSD Current i386 cc
OpenBSD 2.5 Sparc gcc
OpenBSD 2.9 i386 cc
OpenBSD Current i386 cc
RedHat 6.2 i386 gcc
RedHat 6.2 i386 insure++
RedHat 7.0 i386 gcc
RedHat 7.1 i386 (Kernel 2.4.10) gcc
Slackware 8.0 i686 (Kernel 2.4.10)
Solaris 8 UltraSparc cc
Solaris 8 UltraSparc gcc
Solaris 8 i386 gcc
SuSE 7.1 i386 gcc2.95.2
SuSE 7.1 ppc gcc2.95.2
i386-pc-sco3.2v5.0.5 cc
i386-pc-sco3.2v5.0.5 gcc
powerpc-ibm-aix4.3.3.0 cc
i686-unknown-sysv5UnixWare7.1.0 gcc
i686-unknown-sysv5UnixWare7.1.0 cc
TESTING:
* The existing test.sh script by Phil Hands has been merged into a
test framework that works from both "make check" and the Samba
build farm.

164
README
View File

@@ -20,61 +20,106 @@ USAGE
Basically you use rsync just like rcp, but rsync has many additional options.
Here is a brief description of available options:
Here is a brief description of rsync usage:
Usage: rsync [OPTION]... SRC [SRC]... [USER@]HOST:DEST
or rsync [OPTION]... [USER@]HOST:SRC DEST
or rsync [OPTION]... SRC [SRC]... DEST
or rsync [OPTION]... [USER@]HOST::SRC [DEST]
or rsync [OPTION]... SRC [SRC]... [USER@]HOST::DEST
or rsync [OPTION]... rsync://[USER@]HOST[:PORT]/SRC [DEST]
SRC on single-colon remote HOST will be expanded by remote shell
SRC on server remote HOST may contain shell wildcards or multiple
sources separated by space as long as they have same top-level
Options
-v, --verbose increase verbosity
-q, --quiet decrease verbosity
-c, --checksum always checksum
-a, --archive archive mode
-r, --recursive recurse into directories
-R, --relative use relative path names
-b, --backup make backups (default ~ suffix)
--suffix=SUFFIX override backup suffix
-u, --update update only (don't overwrite newer files)
-l, --links preserve soft links
-L, --copy-links treat soft links like regular files
--copy-unsafe-links copy links outside the source tree
--safe-links ignore links outside the destination tree
-H, --hard-links preserve hard links
-p, --perms preserve permissions
-o, --owner preserve owner (root only)
-g, --group preserve group
-D, --devices preserve devices (root only)
-t, --times preserve times
-S, --sparse handle sparse files efficiently
-n, --dry-run show what would have been transferred
-W, --whole-file copy whole files, no incremental checks
-x, --one-file-system don't cross filesystem boundaries
-B, --block-size=SIZE checksum blocking size (default 700)
-e, --rsh=COMMAND specify rsh replacement
--rsync-path=PATH specify path to rsync on the remote machine
-C, --cvs-exclude auto ignore files in the same way CVS does
--delete delete files that don't exist on the sending side
--delete-excluded also delete excluded files on the receiving side
--partial keep partially transferred files
--force force deletion of directories even if not empty
--numeric-ids don't map uid/gid values by user/group name
--timeout=TIME set IO timeout in seconds
-I, --ignore-times don't exclude files that match length and time
--size-only only use file size when determining if a file should be transferred
-T --temp-dir=DIR create temporary files in directory DIR
--compare-dest=DIR also compare destination files relative to DIR
-z, --compress compress file data
--exclude=PATTERN exclude files matching PATTERN
--exclude-from=FILE exclude patterns listed in FILE
--include=PATTERN don't exclude files matching PATTERN
--include-from=FILE don't exclude patterns listed in FILE
--version print version number
--daemon run as a rsync daemon
--config=FILE specify alternate rsyncd.conf file
--port=PORT specify alternate rsyncd port number
--stats give some file transfer stats
--progress show progress during transfer
--log-format=FORMAT log file transfers using specified format
--password-file=FILE get password from FILE
-h, --help show this help screen
Options:
-v, --verbose increase verbosity
-c, --checksum always checksum
-a, --archive archive mode (same as -rlptDog)
-r, --recursive recurse into directories
-R, --relative use relative path names
-b, --backup make backups (default ~ extension)
-u, --update update only (don't overwrite newer files)
-l, --links preserve soft links
-L, --copy-links treat soft links like regular files
-H, --hard-links preserve hard links
-p, --perms preserve permissions
-o, --owner preserve owner (root only)
-g, --group preserve group
-D, --devices preserve devices (root only)
-t, --times preserve times
-S, --sparse handle sparse files efficiently
-n, --dry-run show what would have been transferred
-W, --whole-file copy whole files, no incremental checks
-x, --one-file-system don't cross filesystem boundaries
-B, --block-size SIZE checksum blocking size
-e, --rsh COMMAND specify rsh replacement
--rsync-path PATH specify path to rsync on the remote machine
-C, --cvs-exclude auto ignore files in the same way CVS does
--delete delete files that don't exist on the sending side
--force force deletion of directories even if not empty
--numeric-ids don't map uid/gid values by user/group name
--timeout TIME set IO timeout in seconds
-I, --ignore-times don't exclude files that match length and time
-T --temp-dir DIR create temporary files in directory DIR
-z, --compress compress file data
--exclude FILE exclude file FILE
--exclude-from FILE exclude files listed in FILE
--suffix SUFFIX override backup suffix
--version print version number
SETUP
-----
Rsync uses rsh or ssh for communication. It does not need to be setuid
and requires no special privilages for installation. It does not
require a inetd entry or a daemon. You must, however, have a working
rsh or ssh system. Using ssh is recommended for its security
features.
Rsync normally uses rsh or ssh for communication. It does not need to
be setuid and requires no special privileges for installation. You
must, however, have a working rsh or ssh system. Using ssh is
recommended for its security features.
Alternatively, rsync can run in `daemon' mode, listening on a socket.
This is generally used for public file distribution, although
authentication and access control are available.
To install rsync, first run the "configure" script. This will create a
Makefile and config.h appropriate for your system. Then type
"make".
Note that on some systems you will have to force configure not to use
gcc because gcc may not support some features (such as 64 bit file
offsets) that your system may support. Set the environment variable CC
to the name of your native compiler before running configure in this
case.
Once built put a copy of rsync in your search path on the local and
remote systems (or use "make install"). That's it!
RSYNC SERVERS
-------------
rsync can also talk to "rsync servers" which can provide anonymous or
authenticated rsync. See the rsyncd.conf(5) man page for details on how
to setup a rsync server. See the rsync(1) man page for info on how to
connect to a rsync server.
MAILING LIST
------------
@@ -83,25 +128,22 @@ There is a mailing list for the discussion of rsync and its
applications. It is open to anyone to join. I will announce new
versions on this list.
To join the mailing list send mail to listproc@samba.anu.edu.au with
no subject and a body of "subscribe rsync Your Name".
To join the mailing list see the web page at http://lists.samba.org/
To send mail to everyone on the list send it to rsync@samba.anu.edu.au
To send mail to everyone on the list send it to rsync@samba.org
BUG REPORTS
-----------
If you have web access then please look at
http://samba.anu.edu.au/rsync/
http://rsync.samba.org/rsync/
This will give you access to the bug tracking system used by the
developers of rsync and will allow you to look at other bug reports or
submit a new bug report.
If you don't have web access then mail bug reports to
rsync-bugs@samba.anu.edu.au or (if you think it will be of interest to
lots of people) send it to rsync@samba.anu.edu.au
If you don't have web access then mail bug reports to rsync@samba.org.
CVS TREE
@@ -111,31 +153,29 @@ If you want to get the very latest version of rsync direct from the
source code repository then you can use anonymous cvs. You will need a
recent version of cvs then use the following commands:
cvs -d :pserver:cvs@samba.anu.edu.au:/cvsroot login
cvs -d :pserver:cvs@pserver.samba.org:/cvsroot login
Password: cvs
cvs -d :pserver:cvs@samba.anu.edu.au:/cvsroot co rsync
cvs -d :pserver:cvs@pserver.samba.org:/cvsroot co rsync
Look at the cvs documentation for more details.
Look at the cvs documentation, or http://samba.org/cvs.html, for more
details.
COPYRIGHT
---------
Rsync was written by Andrew Tridgell and Paul Mackerras, and is
available under the Gnu Public License.
rsync was originally written by Andrew Tridgell and has been improved
by many developers around the world. rsync may be used, modified and
redistributed only under the terms of the GNU General Public License,
found in the file COPYING in this distribution, or at
tridge@samba.anu.edu.au
paulus@cs.anu.edu.au
http://www.fsf.org/licenses/gpl.html
AVAILABILITY
------------
The main ftp site for rsync is ftp://samba.anu.edu.au/pub/rsync
Mirrors are available at:
ftp://sunsite.auc.dk/pub/unix/rsync
ftp://ftp.sunet.se/pub/unix/admin/rsync
ftp://ftp.fu-berlin.de/pub/unix/network/rsync/
The main web site for rsync is http://rsync.samba.org/
The main ftp site is ftp://rsync.samba.org/pub/rsync/
This is also available as rsync://rsync.samba.org/rsyncftp/

309
TODO Normal file
View File

@@ -0,0 +1,309 @@
-*- indented-text -*-
URGENT ---------------------------------------------------------------
IMPORTANT ------------------------------------------------------------
Cross-test versions
Part of the regression suite should be making sure that we don't
break backwards compatibility: old clients vs new servers and so
on. Ideally we would test the cross product of versions.
It might be sufficient to test downloads from well-known public
rsync servers running different versions of rsync. This will give
some testing and also be the most common case for having different
versions and not being able to upgrade.
use chroot
If the platform doesn't support it, then don't even try.
If running as non-root, then don't fail, just give a warning.
(There was a thread about this a while ago?)
http://lists.samba.org/pipermail/rsync/2001-August/thread.html
http://lists.samba.org/pipermail/rsync/2001-September/thread.html
--files-from
Avoids traversal. Better option than a pile of --include statements
for people who want to generate the file list using a find(1)
command or a script.
Performance
Traverse just one directory at a time. Tridge says it's possible.
At the moment rsync reads the whole file list into memory at the
start, which makes us use a lot of memory and also not pipeline
network access as much as we could.
Handling duplicate names
We need to be careful of duplicate names getting into the file list.
See clean_flist(). This could happen if multiple arguments include
the same file. Bad.
I think duplicates are only a problem if they're both flowing
through the pipeline at the same time. For example we might have
updated the first occurrence after reading the checksums for the
second. So possibly we just need to make sure that we don't have
both in the pipeline at the same time.
Possibly if we did one directory at a time that would be sufficient.
Alternatively we could pre-process the arguments to make sure no
duplicates will ever be inserted. There could be some bad cases
when we're collapsing symlinks.
We could have a hash table.
The root of the problem is that we do not want more than one file
list entry referring to the same file. At first glance there are
several ways this could happen: symlinks, hardlinks, and repeated
names on the command line.
If names are repeated on the command line, they may be present in
different forms, perhaps by traversing directory paths in different
ways, traversing paths including symlinks. Also we need to allow
for expansion of globs by rsync.
At the moment, clean_flist() requires having the entire file list in
memory. Duplicate names are detected just by a string comparison.
We don't need to worry about hard links causing duplicates because
files are never updated in place. Similarly for symlinks.
I think even if we're using a different symlink mode we don't need
to worry.
Unless we're really clever this will introduce a protocol
incompatibility, so we need to be able to accept the old format as
well.
Memory accounting
At exit, show how much memory was used for the file list, etc.
Also we do a wierd exponential-growth allocation in flist.c. I'm
not sure this makes sense with modern mallocs. At any rate it will
make us allocate a huge amount of memory for large file lists.
We can try using the GNU/SVID/XPG mallinfo() function to get some
heap statistics.
Hard-link handling
At the moment hardlink handling is very expensive, so it's off by
default. It does not need to be so.
Since most of the solutions are rather intertwined with the file
list it is probably better to fix that first, although fixing
hardlinks is possibly simpler.
We can rule out hardlinked directories since they will probably
screw us up in all kinds of ways. They simply should not be used.
At the moment rsync only cares about hardlinks to regular files. I
guess you could also use them for sockets, devices and other beasts,
but I have not seen them.
When trying to reproduce hard links, we only need to worry about
files that have more than one name (nlinks>1 && !S_ISDIR).
The basic point of this is to discover alternate names that refer to
the same file. All operations, including creating the file and
writing modifications to it need only to be done for the first name.
For all later names, we just create the link and then leave it
alone.
If hard links are to be preserved:
Before the generator/receiver fork, the list of files is received
from the sender (recv_file_list), and a table for detecting hard
links is built.
The generator looks for hard links within the file list and does
not send checksums for them, though it does send other metadata.
The sender sends the device number and inode with file entries, so
that files are uniquely identified.
The receiver goes through and creates hard links (do_hard_links)
after all data has been written, but before directory permissions
are set.
At the moment device and inum are sent as 4-byte integers, which
will probably cause problems on large filesystems. On Linux the
kernel uses 64-bit ino_t's internally, and people will soon have
filesystems big enough to use them. We ought to follow NFS4 in
using 64-bit device and inode identification, perhaps with a
protocol version bump.
Once we've seen all the names for a particular file, we no longer
need to think about it and we can deallocate the memory.
We can also have the case where there are links to a file that are
not in the tree being transferred. There's nothing we can do about
that. Because we rename the destination into place after writing,
any hardlinks to the old file are always going to be orphaned. In
fact that is almost necessary because otherwise we'd get really
confused if we were generating checksums for one name of a file and
modifying another.
At the moment the code seems to make a whole second copy of the file
list, which seems unnecessary.
We should have a test case that exercises hard links. Since it
might be hard to compare ./tls output where the inodes change we
might need a little program to check whether several names refer to
the same file.
IPv6
Implement suggestions from http://www.kame.net/newsletter/19980604/
and ftp://ftp.iij.ad.jp/pub/RFC/rfc2553.txt
If a host has multiple addresses, then listen try to connect to all
in order until we get through. (getaddrinfo may return multiple
addresses.) This is kind of implemented already.
Possibly also when starting as a server we may need to listen on
multiple passive addresses. This might be a bit harder, because we
may need to select on all of them. Hm.
Define a syntax for IPv6 literal addresses. Since they include
colons, they tend to break most naming systems, including ours.
Based on the HTTP IPv6 syntax, I think we should use
rsync://[::1]/foo/bar
[::1]::bar
which should just take a small change to the parser code.
Errors
If we hang or get SIGINT, then explain where we were up to. Perhaps
have a static buffer that contains the current function name, or
some kind of description of what we were trying to do. This is a
little easier on people than needing to run strace/truss.
"The dungeon collapses! You are killed." Rather than "unexpected
eof" give a message that is more detailed if possible and also more
helpful.
File attributes
Device major/minor numbers should be at least 32 bits each. See
http://lists.samba.org/pipermail/rsync/2001-November/005357.html
Transfer ACLs. Need to think of a standard representation.
Probably better not to even try to convert between NT and POSIX.
Possibly can share some code with Samba.
Empty directories
With the current common --include '*/' --exclude '*' pattern, people
can end up with many empty directories. We might avoid this by
lazily creating such directories.
zlib
Perhaps don't use our own zlib. Will we actually be incompatible,
or just be slightly less efficient?
logging
Perhaps flush stdout after each filename, so that people trying to
monitor progress in a log file can do so more easily. See
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=48108
At the connections that just get a list of modules are not logged,
but they should be.
rsyncd over ssh
There are already some patches to do this.
proxy authentication
Allow RSYNC_PROXY to be http://user:pass@proxy.foo:3128/, and do
HTTP Basic Proxy-Authentication.
Multiple schemes are possible, up to and including the insanity that
is NTLM, but Basic probably covers most cases.
SOCKS
Add --with-socks, and then perhaps a command-line option to put them
on or off. This might be more reliable than LD_PRELOAD hacks.
PLATFORMS ------------------------------------------------------------
Win32
Don't detach, because this messes up --srvany.
http://sources.redhat.com/ml/cygwin/2001-08/msg00234.html
According to "Effective TCP/IP Programming" (??) close() on a socket
has incorrect behaviour on Windows -- it sends a RST packet to the
other side, which gives a "connection reset by peer" error. On that
platform we should probably do shutdown() instead. However, on Unix
we are correct to call close(), because shutdown() discards
untransmitted data.
DOCUMENTATION --------------------------------------------------------
Update README
BUILD FARM -----------------------------------------------------------
Add machines
AMDAHL UTS (Dave Dykstra)
Cygwin (on different versions of Win32?)
HP-UX variants (via HP?)
SCO
NICE -----------------------------------------------------------------
--no-detach and --no-fork options
Very useful for debugging. Also good when running under a
daemon-monitoring process that tries to restart the service when the
parent exits.
hang/timeout friendliness
verbose output
Indicate whether files are new, updated, or deleted
internationalization
Change to using gettext(). Probably need to ship this for platforms
that don't have it.
Solicit translations.
Does anyone care?
rsyncsh
Write a small emulation of interactive ftp as a Pythonn program
that calls rsync. Commands such as "cd", "ls", "ls *.c" etc map
fairly directly into rsync commands: it just needs to remember the
current host, directory and so on. We can probably even do
completion of remote filenames.
%K%

131
access.c Normal file
View File

@@ -0,0 +1,131 @@
/*
Copyright (C) Andrew Tridgell 1998
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
hosts allow/deny code for rsync
*/
#include "rsync.h"
static int match_hostname(char *host, char *tok)
{
if (!host || !*host) return 0;
return (fnmatch(tok, host, 0) == 0);
}
static int match_address(char *addr, char *tok)
{
char *p;
unsigned long a, t, mask = (unsigned long)~0;
if (!addr || !*addr) return 0;
if (!isdigit(tok[0])) return 0;
p = strchr(tok,'/');
if (p) *p = 0;
a = inet_addr(addr);
t = inet_addr(tok);
if (p) {
*p = '/';
}
if (t == INADDR_NONE) {
rprintf(FERROR,"malformed address %s\n", tok);
return 0;
}
a = ntohl(a);
t = ntohl(t);
if (p) {
if (strchr(p+1,'.')) {
mask = inet_addr(p+1);
if (mask == INADDR_NONE) {
rprintf(FERROR,"malformed mask in %s\n", tok);
return 0;
}
mask = ntohl(mask);
} else {
int bits = atoi(p+1);
if (bits == 0) return 1;
if (bits <= 0 || bits > 32) {
rprintf(FERROR,"malformed mask in %s\n", tok);
return 0;
}
mask &= (mask << (32-bits));
}
}
return ((a&mask) == (t&mask));
}
static int access_match(char *list, char *addr, char *host)
{
char *tok;
char *list2 = strdup(list);
if (!list2) out_of_memory("access_match");
strlower(list2);
if (host) strlower(host);
for (tok=strtok(list2," ,\t"); tok; tok=strtok(NULL," ,\t")) {
if (match_hostname(host, tok) || match_address(addr, tok)) {
free(list2);
return 1;
}
}
free(list2);
return 0;
}
int allow_access(char *addr, char *host, char *allow_list, char *deny_list)
{
/* if theres no deny list and no allow list then allow access */
if ((!deny_list || !*deny_list) && (!allow_list || !*allow_list))
return 1;
/* if there is an allow list but no deny list then allow only hosts
on the allow list */
if (!deny_list || !*deny_list)
return(access_match(allow_list, addr, host));
/* if theres a deny list but no allow list then allow
all hosts not on the deny list */
if (!allow_list || !*allow_list)
return(!access_match(deny_list,addr,host));
/* if there are both type of list then allow all hosts on the
allow list */
if (access_match(allow_list,addr,host))
return 1;
/* if there are both type of list and it's not on the allow then
allow it if its not on the deny */
if (access_match(deny_list,addr,host))
return 0;
return 1;
}

10
acconfig.h Normal file
View File

@@ -0,0 +1,10 @@
#undef ino_t
#undef HAVE_CONNECT
#undef HAVE_SHORT_INO_T
#undef HAVE_GETOPT_LONG
#undef REPLACE_INET_NTOA
#undef REPLACE_INET_ATON
#undef HAVE_GETTIMEOFDAY_TZ
#undef ENABLE_IPV6
#undef HAVE_SOCKADDR_LEN
#undef HAVE_SOCKETPAIR

71
aclocal.m4 vendored Normal file
View File

@@ -0,0 +1,71 @@
dnl AC_VALIDATE_CACHE_SYSTEM_TYPE[(cmd)]
dnl if the cache file is inconsistent with the current host,
dnl target and build system types, execute CMD or print a default
dnl error message.
AC_DEFUN(AC_VALIDATE_CACHE_SYSTEM_TYPE, [
AC_REQUIRE([AC_CANONICAL_SYSTEM])
AC_MSG_CHECKING([config.cache system type])
if { test x"${ac_cv_host_system_type+set}" = x"set" &&
test x"$ac_cv_host_system_type" != x"$host"; } ||
{ test x"${ac_cv_build_system_type+set}" = x"set" &&
test x"$ac_cv_build_system_type" != x"$build"; } ||
{ test x"${ac_cv_target_system_type+set}" = x"set" &&
test x"$ac_cv_target_system_type" != x"$target"; }; then
AC_MSG_RESULT([different])
ifelse($#, 1, [$1],
[AC_MSG_ERROR(["you must remove config.cache and restart configure"])])
else
AC_MSG_RESULT([same])
fi
ac_cv_host_system_type="$host"
ac_cv_build_system_type="$build"
ac_cv_target_system_type="$target"
])
dnl Check for socklen_t: historically on BSD it is an int, and in
dnl POSIX 1g it is a type of its own, but some platforms use different
dnl types for the argument to getsockopt, getpeername, etc. So we
dnl have to test to find something that will work.
dnl This is no good, because passing the wrong pointer on C compilers is
dnl likely to only generate a warning, not an error. We don't call this at
dnl the moment.
AC_DEFUN([TYPE_SOCKLEN_T],
[
AC_CHECK_TYPE([socklen_t], ,[
AC_MSG_CHECKING([for socklen_t equivalent])
AC_CACHE_VAL([rsync_cv_socklen_t_equiv],
[
# Systems have either "struct sockaddr *" or
# "void *" as the second argument to getpeername
rsync_cv_socklen_t_equiv=
for arg2 in "struct sockaddr" void; do
for t in int size_t unsigned long "unsigned long"; do
AC_TRY_COMPILE([
#include <sys/types.h>
#include <sys/socket.h>
int getpeername (int, $arg2 *, $t *);
],[
$t len;
getpeername(0,0,&len);
],[
rsync_cv_socklen_t_equiv="$t"
break
])
done
done
if test "x$rsync_cv_socklen_t_equiv" = x; then
AC_MSG_ERROR([Cannot find a type to use in place of socklen_t])
fi
])
AC_MSG_RESULT($rsync_cv_socklen_t_equiv)
AC_DEFINE_UNQUOTED(socklen_t, $rsync_cv_socklen_t_equiv,
[type to use in place of socklen_t if not defined])],
[#include <sys/types.h>
#include <sys/socket.h>])
])

289
authenticate.c Normal file
View File

@@ -0,0 +1,289 @@
/* -*- c-file-style: "linux"; -*-
Copyright (C) 1998-2000 by Andrew Tridgell
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* support rsync authentication */
#include "rsync.h"
/***************************************************************************
encode a buffer using base64 - simple and slow algorithm. null terminates
the result.
***************************************************************************/
static void base64_encode(char *buf, int len, char *out)
{
char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int bit_offset, byte_offset, idx, i;
unsigned char *d = (unsigned char *)buf;
int bytes = (len*8 + 5)/6;
memset(out, 0, bytes+1);
for (i=0;i<bytes;i++) {
byte_offset = (i*6)/8;
bit_offset = (i*6)%8;
if (bit_offset < 3) {
idx = (d[byte_offset] >> (2-bit_offset)) & 0x3F;
} else {
idx = (d[byte_offset] << (bit_offset-2)) & 0x3F;
if (byte_offset+1 < len) {
idx |= (d[byte_offset+1] >> (8-(bit_offset-2)));
}
}
out[i] = b64[idx];
}
}
/* create a 16 byte challenge buffer */
static void gen_challenge(char *addr, char *challenge)
{
char input[32];
struct timeval tv;
memset(input, 0, sizeof(input));
strlcpy((char *)input, addr, 17);
sys_gettimeofday(&tv);
SIVAL(input, 16, tv.tv_sec);
SIVAL(input, 20, tv.tv_usec);
SIVAL(input, 24, getpid());
sum_init();
sum_update(input, sizeof(input));
sum_end(challenge);
}
/* return the secret for a user from the sercret file. maximum length
is len. null terminate it */
static int get_secret(int module, char *user, char *secret, int len)
{
char *fname = lp_secrets_file(module);
int fd, found=0;
char line[MAXPATHLEN];
char *p, *pass=NULL;
STRUCT_STAT st;
int ok = 1;
extern int am_root;
if (!fname || !*fname) return 0;
fd = open(fname,O_RDONLY);
if (fd == -1) return 0;
if (do_stat(fname, &st) == -1) {
rsyserr(FERROR, errno, "stat(%s)", fname);
ok = 0;
} else if (lp_strict_modes(module)) {
if ((st.st_mode & 06) != 0) {
rprintf(FERROR,"secrets file must not be other-accessible (see strict modes option)\n");
ok = 0;
} else if (am_root && (st.st_uid != 0)) {
rprintf(FERROR,"secrets file must be owned by root when running as root (see strict modes)\n");
ok = 0;
}
}
if (!ok) {
rprintf(FERROR,"continuing without secrets file\n");
close(fd);
return 0;
}
while (!found) {
int i = 0;
memset(line, 0, sizeof line);
while ((size_t) i < (sizeof(line)-1)) {
if (read(fd, &line[i], 1) != 1) {
memset(line, 0, sizeof(line));
close(fd);
return 0;
}
if (line[i] == '\r') continue;
if (line[i] == '\n') break;
i++;
}
line[i] = 0;
if (line[0] == '#') continue;
p = strchr(line,':');
if (!p) continue;
*p = 0;
if (strcmp(user, line)) continue;
pass = p+1;
found = 1;
}
close(fd);
if (!found) return 0;
strlcpy(secret, pass, len);
return 1;
}
static char *getpassf(char *filename)
{
char buffer[100];
int fd=0;
STRUCT_STAT st;
int ok = 1;
extern int am_root;
char *envpw=getenv("RSYNC_PASSWORD");
if (!filename) return NULL;
if ( (fd=open(filename,O_RDONLY)) == -1) {
rsyserr(FERROR, errno, "could not open password file \"%s\"",filename);
if (envpw) rprintf(FERROR,"falling back to RSYNC_PASSWORD environment variable.\n");
return NULL;
}
if (do_stat(filename, &st) == -1) {
rsyserr(FERROR, errno, "stat(%s)", filename);
ok = 0;
} else if ((st.st_mode & 06) != 0) {
rprintf(FERROR,"password file must not be other-accessible\n");
ok = 0;
} else if (am_root && (st.st_uid != 0)) {
rprintf(FERROR,"password file must be owned by root when running as root\n");
ok = 0;
}
if (!ok) {
rprintf(FERROR,"continuing without password file\n");
if (envpw) rprintf(FERROR,"using RSYNC_PASSWORD environment variable.\n");
close(fd);
return NULL;
}
if (envpw) rprintf(FERROR,"RSYNC_PASSWORD environment variable ignored\n");
buffer[sizeof(buffer)-1]='\0';
if (read(fd,buffer,sizeof(buffer)-1) > 0)
{
char *p = strtok(buffer,"\n\r");
close(fd);
if (p) p = strdup(p);
return p;
}
return NULL;
}
/* generate a 16 byte hash from a password and challenge */
static void generate_hash(char *in, char *challenge, char *out)
{
char buf[16];
sum_init();
sum_update(in, strlen(in));
sum_update(challenge, strlen(challenge));
sum_end(buf);
base64_encode(buf, 16, out);
}
/* possible negotiate authentication with the client. Use "leader" to
start off the auth if necessary
return NULL if authentication failed
return "" if anonymous access
otherwise return username
*/
char *auth_server(int fd, int module, char *addr, char *leader)
{
char *users = lp_auth_users(module);
char challenge[16];
char b64_challenge[30];
char line[MAXPATHLEN];
static char user[100];
char secret[100];
char pass[30];
char pass2[30];
char *tok;
/* if no auth list then allow anyone in! */
if (!users || !*users) return "";
gen_challenge(addr, challenge);
base64_encode(challenge, 16, b64_challenge);
io_printf(fd,"%s%s\n", leader, b64_challenge);
if (!read_line(fd, line, sizeof(line)-1)) {
return NULL;
}
memset(user, 0, sizeof(user));
memset(pass, 0, sizeof(pass));
if (sscanf(line,"%99s %29s", user, pass) != 2) {
return NULL;
}
users = strdup(users);
if (!users) return NULL;
for (tok=strtok(users," ,\t"); tok; tok = strtok(NULL," ,\t")) {
if (fnmatch(tok, user, 0) == 0) break;
}
free(users);
if (!tok) {
return NULL;
}
memset(secret, 0, sizeof(secret));
if (!get_secret(module, user, secret, sizeof(secret)-1)) {
memset(secret, 0, sizeof(secret));
return NULL;
}
generate_hash(secret, b64_challenge, pass2);
memset(secret, 0, sizeof(secret));
if (strcmp(pass, pass2) == 0)
return user;
return NULL;
}
void auth_client(int fd, char *user, char *challenge)
{
char *pass;
char pass2[30];
extern char *password_file;
if (!user || !*user) return;
if (!(pass=getpassf(password_file)) && !(pass=getenv("RSYNC_PASSWORD"))) {
/* XXX: cyeoh says that getpass is deprecated, because
it may return a truncated password on some systems,
and it is not in the LSB. */
pass = getpass("Password: ");
}
if (!pass || !*pass) {
pass = "";
}
generate_hash(pass, challenge, pass2);
io_printf(fd, "%s %s\n", user, pass2);
}

291
backup.c Normal file
View File

@@ -0,0 +1,291 @@
/*
Copyright (C) Andrew Tridgell 1999
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* backup handling code */
#include "rsync.h"
extern int verbose;
extern char *backup_suffix;
extern char *backup_dir;
extern int am_root;
extern int preserve_devices;
extern int preserve_links;
extern int preserve_hard_links;
/* simple backup creates a backup with a suffix in the same directory */
static int make_simple_backup(char *fname)
{
char fnamebak[MAXPATHLEN];
if (strlen(fname) + strlen(backup_suffix) > (MAXPATHLEN-1)) {
rprintf(FERROR,"backup filename too long\n");
return 0;
}
snprintf(fnamebak,sizeof(fnamebak),"%s%s",fname,backup_suffix);
if (do_rename(fname,fnamebak) != 0) {
/* cygwin (at least version b19) reports EINVAL */
if (errno != ENOENT && errno != EINVAL) {
rsyserr(FERROR, errno, "rename %s to backup %s", fname, fnamebak);
return 0;
}
} else if (verbose > 1) {
rprintf(FINFO,"backed up %s to %s\n",fname,fnamebak);
}
return 1;
}
/* recursively make a directory path */
static int make_dir(char *name, int mask)
{
char newdir [MAXPATHLEN];
char *p, *d;
/* copy pathname over, look for last '/' */
for (p = d = newdir; *name; *d++ = *name++)
if (*name == '/')
p = d;
if (p == newdir)
return 0;
*p = 0;
/* make the new directory, if that fails then make its parent */
while (do_mkdir (newdir, mask) != 0)
if ((errno != ENOENT) || !make_dir (newdir, mask))
return 0;
return 1;
} /* make_dir */
/****************************************************************************
Create a directory given an absolute path, perms based upon another directory
path
****************************************************************************/
static int make_bak_dir(char *fname,char *bak_path)
{
STRUCT_STAT st;
STRUCT_STAT *st2;
char fullpath[MAXPATHLEN];
extern int orig_umask;
char *p;
char *q;
while(strncmp(bak_path,"./",2)==0) bak_path += 2;
if(bak_path[strlen(bak_path)-1]!='/') {
snprintf(fullpath,sizeof(fullpath),"%s/",bak_path);
} else {
snprintf(fullpath,sizeof(fullpath),"%s",bak_path);
}
p=fullpath;
q=&fullpath[strlen(fullpath)]; /* End of bak_path string */
strcat(fullpath,fname);
/* Make the directories */
while ((p=strchr(p,'/'))) {
*p = 0;
if(do_lstat(fullpath,&st)!=0) {
do_mkdir(fullpath,0777 & ~orig_umask);
if(p>q) {
if(do_lstat(q,&st)!=0) {
rprintf(FERROR,"make_bak_dir stat %s : %s\n",fullpath,strerror(errno));
} else {
st2=&st;
set_modtime(fullpath,st2->st_mtime);
if(do_lchown(fullpath,st2->st_uid,st2->st_gid)!=0) {
rprintf(FERROR,"make_bak_dir chown %s : %s\n",fullpath,strerror(errno));
};
if(do_chmod(fullpath,st2->st_mode)!=0) {
rprintf(FERROR,"make_bak_dir failed to set permissions on %s : %s\n",fullpath,strerror(errno));
};
};
}
};
*p = '/';
p++;
}
return 0;
}
/* robustly move a file, creating new directory structures if necessary */
static int robust_move(char *src, char *dst)
{
int keep_trying = 4;
int keep_path_extfs = 0;
int failed;
while (keep_trying) {
if (keep_path_extfs) {
failed = copy_file(src, dst, 0755);
if (!failed) {
do_unlink(src);
}
} else {
failed = robust_rename (src, dst);
}
if (failed) {
if (verbose > 2)
rprintf (FERROR, "robust_move failed: %s(%d)\n",
strerror (errno), errno);
switch (errno) {
/* external filesystem */
case EXDEV:
keep_path_extfs = 1;
keep_trying--;
break;
/* no directory to write to */
case ENOENT:
make_dir (dst, 0755);
keep_trying--;
break;
default:
keep_trying = 0;
} /* switch */
} else
keep_trying = 0;
} /* while */
return (!failed);
} /* robust_move */
/* if we have a backup_dir, then we get here from make_backup().
We will move the file to be deleted into a parallel directory tree */
static int keep_backup(char *fname)
{
static int initialised;
char keep_name [MAXPATHLEN];
STRUCT_STAT st;
struct file_struct *file;
int kept=0;
int ret_code;
if (!initialised) {
if (backup_dir[strlen(backup_dir) - 1] == '/')
backup_dir[strlen(backup_dir) - 1] = 0;
if (verbose > 0)
rprintf (FINFO, "backup_dir is %s\n", backup_dir);
initialised = 1;
}
/* return if no file to keep */
#if SUPPORT_LINKS
if (do_lstat (fname, &st)) return 1;
#else
if (do_stat (fname, &st)) return 1;
#endif
file = make_file(-1, fname, NULL, 1);
/* the file could have disappeared */
if (!file) return 1;
/* make a complete pathname for backup file */
if (strlen(backup_dir) + strlen(fname) > (MAXPATHLEN - 1)) {
rprintf (FERROR, "keep_backup filename too long\n");
return 0;
}
snprintf(keep_name, sizeof (keep_name), "%s/%s", backup_dir, fname);
#ifdef HAVE_MKNOD
/* Check to see if this is a device file, or link */
if(IS_DEVICE(file->mode)) {
if(am_root && preserve_devices) {
make_bak_dir(fname,backup_dir);
if(do_mknod(keep_name,file->mode,file->rdev)!=0) {
rprintf(FERROR,"mknod %s : %s\n",keep_name,strerror(errno));
} else {
if(verbose>2)
rprintf(FINFO,"make_backup : DEVICE %s successful.\n",fname);
};
};
kept=1;
do_unlink(fname);
};
#endif
if(!kept && S_ISDIR(file->mode)) {
/* make an empty directory */
make_bak_dir(fname,backup_dir);
do_mkdir(keep_name,file->mode);
ret_code=do_rmdir(fname);
if(verbose>2)
rprintf(FINFO,"make_backup : RMDIR %s returns %i\n",fname,ret_code);
kept=1;
};
#if SUPPORT_LINKS
if(!kept && preserve_links && S_ISLNK(file->mode)) {
extern int safe_symlinks;
if (safe_symlinks && unsafe_symlink(file->link, keep_name)) {
if (verbose) {
rprintf(FINFO,"ignoring unsafe symlink %s -> %s\n",
keep_name,file->link);
}
kept=1;
}
make_bak_dir(fname,backup_dir);
if(do_symlink(file->link,keep_name) != 0) {
rprintf(FERROR,"link %s -> %s : %s\n",keep_name,file->link,strerror(errno));
};
do_unlink(fname);
kept=1;
};
#endif
if(!kept && preserve_hard_links && check_hard_link(file)) {
if(verbose > 1) rprintf(FINFO,"%s is a hard link\n",f_name(file));
};
if(!kept && !S_ISREG(file->mode)) {
rprintf(FINFO,"make_bak: skipping non-regular file %s\n",fname);
}
/* move to keep tree if a file */
if(!kept) {
if (!robust_move (fname, keep_name))
rprintf(FERROR, "keep_backup failed %s -> %s : %s\n",
fname, keep_name, strerror(errno));
};
set_perms (keep_name, file, NULL, 0);
free_file (file);
free (file);
if (verbose > 1)
rprintf (FINFO, "keep_backup %s -> %s\n", fname, keep_name);
return 1;
} /* keep_backup */
/* main backup switch routine */
int make_backup(char *fname)
{
if (backup_dir)
return (keep_backup(fname));
else
return (make_simple_backup(fname));
}

605
batch.c Normal file
View File

@@ -0,0 +1,605 @@
/* -*- c-file-style: "linux" -*-
Weiss 1/1999
Batch utilities for rsync.
*/
#include "rsync.h"
#include <time.h>
char rsync_flist_file[27] = "rsync_flist.";
char rsync_csums_file[27] = "rsync_csums.";
char rsync_delta_file[27] = "rsync_delta.";
char rsync_argvs_file[27] = "rsync_argvs.";
char batch_file_ext[15];
int fdb;
int fdb_delta;
int fdb_open;
int fdb_close;
struct file_list *batch_flist;
void create_batch_file_ext()
{
struct tm *timeptr;
time_t elapsed_seconds;
/* Save run date and time to use for batch file extensions */
time(&elapsed_seconds);
timeptr = localtime(&elapsed_seconds);
sprintf(batch_file_ext, "%4d%02d%02d%02d%02d%02d",
timeptr->tm_year + 1900, timeptr->tm_mon + 1,
timeptr->tm_mday, timeptr->tm_hour, timeptr->tm_min,
timeptr->tm_sec);
rprintf(FINFO,"batch file extension: %s\n", batch_file_ext);
}
void set_batch_file_ext(char *ext)
{
strcpy(batch_file_ext, ext);
}
void write_batch_flist_file(char *buff, int bytes_to_write)
{
if (fdb_open) {
/* Set up file extension */
strcat(rsync_flist_file, batch_file_ext);
/* Open batch flist file for writing; create it if it doesn't exist */
fdb =
do_open(rsync_flist_file, O_WRONLY | O_CREAT | O_TRUNC,
S_IREAD | S_IWRITE);
if (fdb == -1) {
rprintf(FERROR, "Batch file %s open error: %s\n",
rsync_flist_file, strerror(errno));
close(fdb);
exit_cleanup(1);
}
fdb_open = 0;
}
/* Write buffer to batch flist file */
if (write(fdb, buff, bytes_to_write) == -1) {
rprintf(FERROR, "Batch file %s write error: %s\n",
rsync_flist_file, strerror(errno));
close(fdb);
exit_cleanup(1);
}
if (fdb_close) {
close(fdb);
}
}
void write_batch_flist_info(int flist_count, struct file_struct **fptr)
{
int i;
int bytes_to_write;
/* Write flist info to batch file */
bytes_to_write =
sizeof(unsigned) +
sizeof(time_t) +
sizeof(OFF_T) +
sizeof(mode_t) +
sizeof(INO64_T) +
sizeof(DEV64_T) +
sizeof(DEV64_T) +
sizeof(uid_t) +
sizeof(gid_t);
fdb_open = 1;
fdb_close = 0;
for (i = 0; i < flist_count; i++) {
write_batch_flist_file((char *) fptr[i], bytes_to_write);
write_char_bufs(fptr[i]->basename);
write_char_bufs(fptr[i]->dirname);
write_char_bufs(fptr[i]->basedir);
write_char_bufs(fptr[i]->link);
if (i == flist_count - 1) {
fdb_close = 1;
}
write_char_bufs(fptr[i]->sum);
}
}
void write_char_bufs(char *buf)
{
/* Write the size of the string which will follow */
char b[4];
if (buf != NULL)
SIVAL(b, 0, strlen(buf));
else {
SIVAL(b, 0, 0);
}
write_batch_flist_file(b, sizeof(int));
/* Write the string if there is one */
if (buf != NULL) {
write_batch_flist_file(buf, strlen(buf));
}
}
void write_batch_argvs_file(int argc, char *argv[])
{
int fdb;
int i;
char buff[256];
strcat(rsync_argvs_file, batch_file_ext);
/* Open batch argvs file for writing; create it if it doesn't exist */
fdb = do_open(rsync_argvs_file, O_WRONLY | O_CREAT | O_TRUNC,
S_IREAD | S_IWRITE | S_IEXEC);
if (fdb == -1) {
rprintf(FERROR, "Batch file %s open error: %s\n",
rsync_argvs_file, strerror(errno));
close(fdb);
exit_cleanup(1);
}
buff[0] = '\0';
/* Write argvs info to batch file */
for (i = 0; i < argc; ++i) {
if (i == argc - 2)
continue;
/*
* FIXME:
* I think directly manipulating argv[] is probably bogus
*/
if (!strcmp(argv[i], "--write-batch")) {
/* Safer to change it here than script */
/* Change to --read-batch + ext * to get ready for remote */
strlcat(buff, "--read-batch ", sizeof(buff));
strlcat(buff, batch_file_ext, sizeof(buff));
} else {
strlcat(buff, argv[i], sizeof(buff));
}
if (i < (argc - 1)) {
strlcat(buff, " ", sizeof(buff));
}
}
strlcat(buff, "\n", sizeof(buff));
if (!write(fdb, buff, strlen(buff))) {
rprintf(FERROR, "Batch file %s write error: %s\n",
rsync_argvs_file, strerror(errno));
close(fdb);
exit_cleanup(1);
}
close(fdb);
}
struct file_list *create_flist_from_batch()
{
unsigned char flags;
fdb_open = 1;
fdb_close = 0;
batch_flist = (struct file_list *) malloc(sizeof(batch_flist[0]));
if (!batch_flist) {
out_of_memory("create_flist_from_batch");
}
batch_flist->count = 0;
batch_flist->malloced = 1000;
batch_flist->files =
(struct file_struct **) malloc(sizeof(batch_flist->files[0]) *
batch_flist->malloced);
if (!batch_flist->files) {
out_of_memory("create_flist_from_batch"); /* dw -- will exit */
}
for (flags = read_batch_flags(); flags; flags = read_batch_flags()) {
int i = batch_flist->count;
if (i >= batch_flist->malloced) {
if (batch_flist->malloced < 1000)
batch_flist->malloced += 1000;
else
batch_flist->malloced *= 2;
batch_flist->files =
(struct file_struct **) realloc(batch_flist->
files,
sizeof
(batch_flist->
files[0]) *
batch_flist->
malloced);
if (!batch_flist->files)
out_of_memory("create_flist_from_batch");
}
read_batch_flist_info(&batch_flist->files[i]);
batch_flist->files[i]->flags = flags;
batch_flist->count++;
}
return batch_flist;
}
int read_batch_flist_file(char *buff, int len)
{
int bytes_read;
if (fdb_open) {
/* Set up file extension */
strcat(rsync_flist_file, batch_file_ext);
/* Open batch flist file for reading */
fdb = do_open(rsync_flist_file, O_RDONLY, 0);
if (fdb == -1) {
rprintf(FERROR, "Batch file %s open error: %s\n",
rsync_flist_file, strerror(errno));
close(fdb);
exit_cleanup(1);
}
fdb_open = 0;
}
/* Read flist batch file */
bytes_read = read(fdb, buff, len);
if (bytes_read == -1) {
rprintf(FERROR, "Batch file %s read error: %s\n",
rsync_flist_file, strerror(errno));
close(fdb);
exit_cleanup(1);
}
if (bytes_read == 0) { /* EOF */
close(fdb);
}
return bytes_read;
}
unsigned char read_batch_flags()
{
int flags;
if (read_batch_flist_file((char *) &flags, 4)) {
return 1;
} else {
return 0;
}
}
void read_batch_flist_info(struct file_struct **fptr)
{
int int_str_len;
char char_str_len[4];
char buff[256];
struct file_struct *file;
file = (struct file_struct *) malloc(sizeof(*file));
if (!file)
out_of_memory("read_batch_flist_info");
memset((char *) file, 0, sizeof(*file));
(*fptr) = file;
read_batch_flist_file((char *) &file->modtime, sizeof(time_t));
read_batch_flist_file((char *) &file->length, sizeof(OFF_T));
read_batch_flist_file((char *) &file->mode, sizeof(mode_t));
read_batch_flist_file((char *) &file->inode, sizeof(INO64_T));
read_batch_flist_file((char *) &file->dev, sizeof(DEV64_T));
read_batch_flist_file((char *) &file->rdev, sizeof(DEV64_T));
read_batch_flist_file((char *) &file->uid, sizeof(uid_t));
read_batch_flist_file((char *) &file->gid, sizeof(gid_t));
read_batch_flist_file(char_str_len, sizeof(char_str_len));
int_str_len = IVAL(char_str_len, 0);
if (int_str_len > 0) {
read_batch_flist_file(buff, int_str_len);
buff[int_str_len] = '\0';
file->basename = strdup(buff);
} else {
file->basename = NULL;
}
read_batch_flist_file(char_str_len, sizeof(char_str_len));
int_str_len = IVAL(char_str_len, 0);
if (int_str_len > 0) {
read_batch_flist_file(buff, int_str_len);
buff[int_str_len] = '\0';
file[0].dirname = strdup(buff);
} else {
file[0].dirname = NULL;
}
read_batch_flist_file(char_str_len, sizeof(char_str_len));
int_str_len = IVAL(char_str_len, 0);
if (int_str_len > 0) {
read_batch_flist_file(buff, int_str_len);
buff[int_str_len] = '\0';
file[0].basedir = strdup(buff);
} else {
file[0].basedir = NULL;
}
read_batch_flist_file(char_str_len, sizeof(char_str_len));
int_str_len = IVAL(char_str_len, 0);
if (int_str_len > 0) {
read_batch_flist_file(buff, int_str_len);
buff[int_str_len] = '\0';
file[0].link = strdup(buff);
} else {
file[0].link = NULL;
}
read_batch_flist_file(char_str_len, sizeof(char_str_len));
int_str_len = IVAL(char_str_len, 0);
if (int_str_len > 0) {
read_batch_flist_file(buff, int_str_len);
buff[int_str_len] = '\0';
file[0].sum = strdup(buff);
} else {
file[0].sum = NULL;
}
}
void write_batch_csums_file(void *buff, int bytes_to_write)
{
static int fdb_open = 1;
if (fdb_open) {
/* Set up file extension */
strcat(rsync_csums_file, batch_file_ext);
/* Open batch csums file for writing; create it if it doesn't exist */
fdb =
do_open(rsync_csums_file, O_WRONLY | O_CREAT | O_TRUNC,
S_IREAD | S_IWRITE);
if (fdb == -1) {
rprintf(FERROR, "Batch file %s open error: %s\n",
rsync_csums_file, strerror(errno));
close(fdb);
exit_cleanup(1);
}
fdb_open = 0;
}
/* Write buffer to batch csums file */
if (write(fdb, buff, bytes_to_write) == -1) {
rprintf(FERROR, "Batch file %s write error: %s\n",
rsync_csums_file, strerror(errno));
close(fdb);
exit_cleanup(1);
}
}
void close_batch_csums_file()
{
close(fdb);
}
void write_batch_csum_info(int *flist_entry, int flist_count,
struct sum_struct *s)
{
size_t i;
unsigned int int_zero = 0;
extern int csum_length;
fdb_open = 1;
/* Write csum info to batch file */
/* FIXME: This will break if s->count is ever not exactly an int. */
write_batch_csums_file(flist_entry, sizeof(int));
if (s)
write_batch_csums_file(&s->count, sizeof(int));
else
write_batch_csums_file(&int_zero, sizeof (int));
if (s) {
for (i = 0; i < s->count; i++) {
write_batch_csums_file(&s->sums[i].sum1, sizeof(uint32));
if ((*flist_entry == flist_count - 1)
&& (i == s->count - 1)) {
fdb_close = 1;
}
write_batch_csums_file(s->sums[i].sum2,
csum_length);
}
}
}
int read_batch_csums_file(char *buff, int len)
{
static int fdb_open = 1;
int bytes_read;
if (fdb_open) {
/* Set up file extension */
strcat(rsync_csums_file, batch_file_ext);
/* Open batch flist file for reading */
fdb = do_open(rsync_csums_file, O_RDONLY, 0);
if (fdb == -1) {
rprintf(FERROR, "Batch file %s open error: %s\n",
rsync_csums_file, strerror(errno));
close(fdb);
exit_cleanup(1);
}
fdb_open = 0;
}
/* Read csums batch file */
bytes_read = read(fdb, buff, len);
if (bytes_read == -1) {
rprintf(FERROR, "Batch file %s read error: %s\n",
rsync_csums_file, strerror(errno));
close(fdb);
exit_cleanup(1);
}
return bytes_read;
}
void read_batch_csum_info(int flist_entry, struct sum_struct *s,
int *checksums_match)
{
int i;
int file_flist_entry;
int file_chunk_ct;
uint32 file_sum1;
char file_sum2[SUM_LENGTH];
extern int csum_length;
read_batch_csums_file((char *) &file_flist_entry, sizeof(int));
if (file_flist_entry != flist_entry) {
rprintf(FINFO, "file_list_entry NE flist_entry\n");
rprintf(FINFO, "file_flist_entry = %d flist_entry = %d\n",
file_flist_entry, flist_entry);
close(fdb);
exit_cleanup(1);
} else {
read_batch_csums_file((char *) &file_chunk_ct,
sizeof(int));
*checksums_match = 1;
for (i = 0; i < file_chunk_ct; i++) {
read_batch_csums_file((char *) &file_sum1,
sizeof(uint32));
read_batch_csums_file(file_sum2, csum_length);
if ((s->sums[i].sum1 != file_sum1) ||
(memcmp
(s->sums[i].sum2, file_sum2,
csum_length) != 0)) {
*checksums_match = 0;
}
} /* end for */
}
}
void write_batch_delta_file(char *buff, int bytes_to_write)
{
static int fdb_delta_open = 1;
if (fdb_delta_open) {
/* Set up file extension */
strcat(rsync_delta_file, batch_file_ext);
/* Open batch delta file for writing; create it if it doesn't exist */
fdb_delta =
do_open(rsync_delta_file, O_WRONLY | O_CREAT | O_TRUNC,
S_IREAD | S_IWRITE);
if (fdb_delta == -1) {
rprintf(FERROR, "Batch file %s open error: %s\n",
rsync_delta_file, strerror(errno));
close(fdb_delta);
exit_cleanup(1);
}
fdb_delta_open = 0;
}
/* Write buffer to batch delta file */
if (write(fdb_delta, buff, bytes_to_write) == -1) {
rprintf(FERROR, "Batch file %s write error: %s\n",
rsync_delta_file, strerror(errno));
close(fdb_delta);
exit_cleanup(1);
}
}
void close_batch_delta_file()
{
close(fdb_delta);
}
int read_batch_delta_file(char *buff, int len)
{
static int fdb_delta_open = 1;
int bytes_read;
if (fdb_delta_open) {
/* Set up file extension */
strcat(rsync_delta_file, batch_file_ext);
/* Open batch flist file for reading */
fdb_delta = do_open(rsync_delta_file, O_RDONLY, 0);
if (fdb_delta == -1) {
rprintf(FERROR, "Batch file %s open error: %s\n",
rsync_delta_file, strerror(errno));
close(fdb_delta);
exit_cleanup(1);
}
fdb_delta_open = 0;
}
/* Read delta batch file */
bytes_read = read(fdb_delta, buff, len);
if (bytes_read == -1) {
rprintf(FERROR, "Batch file %s read error: %s\n",
rsync_delta_file, strerror(errno));
close(fdb_delta);
exit_cleanup(1);
}
return bytes_read;
}
void show_flist(int index, struct file_struct **fptr)
{
/* for debugging show_flist(flist->count, flist->files * */
int i;
for (i = 0; i < index; i++) {
rprintf(FINFO, "flist->flags=%#x\n", fptr[i]->flags);
rprintf(FINFO, "flist->modtime=%#lx\n",
(long unsigned) fptr[i]->modtime);
rprintf(FINFO, "flist->length=%.0f\n",
(double) fptr[i]->length);
rprintf(FINFO, "flist->mode=%#o\n", (int) fptr[i]->mode);
rprintf(FINFO, "flist->basename=%s\n", fptr[i]->basename);
if (fptr[i]->dirname)
rprintf(FINFO, "flist->dirname=%s\n",
fptr[i]->dirname);
if (fptr[i]->basedir)
rprintf(FINFO, "flist->basedir=%s\n",
fptr[i]->basedir);
}
}
void show_argvs(int argc, char *argv[])
{
/* for debugging * */
int i;
rprintf(FINFO, "BATCH.C:show_argvs,argc=%d\n", argc);
for (i = 0; i < argc; i++) {
/* if (argv[i]) */
rprintf(FINFO, "i=%d,argv[i]=%s\n", i, argv[i]);
}
}

View File

@@ -34,7 +34,7 @@ uint32 get_checksum1(char *buf1,int len)
{
int i;
uint32 s1, s2;
signed char *buf = (signed char *)buf1;
schar *buf = (schar *)buf1;
s1 = s2 = 0;
for (i = 0; i < (len-4); i+=4) {
@@ -49,82 +49,71 @@ uint32 get_checksum1(char *buf1,int len)
}
static void sum_put(MDstruct *md,char *sum)
{
SIVAL(sum,0,md->buffer[0]);
if (csum_length <= 4) return;
SIVAL(sum,4,md->buffer[1]);
if (csum_length <= 8) return;
SIVAL(sum,8,md->buffer[2]);
if (csum_length <= 12) return;
SIVAL(sum,12,md->buffer[3]);
}
void get_checksum2(char *buf,int len,char *sum)
{
int i;
MDstruct MD;
static char *buf1;
static int len1;
int i;
static char *buf1;
static int len1;
struct mdfour m;
if (len > len1) {
if (buf1) free(buf1);
buf1 = (char *)malloc(len+4);
len1 = len;
if (!buf1) out_of_memory("get_checksum2");
}
MDbegin(&MD);
bcopy(buf,buf1,len);
if (checksum_seed) {
SIVAL(buf1,len,checksum_seed);
len += 4;
}
for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
MDupdate(&MD, buf1+i, CSUM_CHUNK*8);
}
if (len - i > 0)
MDupdate(&MD, buf1+i, (len-i)*8);
sum_put(&MD,sum);
if (len > len1) {
if (buf1) free(buf1);
buf1 = (char *)malloc(len+4);
len1 = len;
if (!buf1) out_of_memory("get_checksum2");
}
mdfour_begin(&m);
memcpy(buf1,buf,len);
if (checksum_seed) {
SIVAL(buf1,len,checksum_seed);
len += 4;
}
for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
mdfour_update(&m, (uchar *)(buf1+i), CSUM_CHUNK);
}
if (len - i > 0) {
mdfour_update(&m, (uchar *)(buf1+i), (len-i));
}
mdfour_result(&m, (uchar *)sum);
}
void file_checksum(char *fname,char *sum,off_t size)
void file_checksum(char *fname,char *sum,OFF_T size)
{
off_t i;
MDstruct MD;
struct map_struct *buf;
int fd;
off_t len = size;
char tmpchunk[CSUM_CHUNK];
OFF_T i;
struct map_struct *buf;
int fd;
OFF_T len = size;
char tmpchunk[CSUM_CHUNK];
struct mdfour m;
memset(sum,0,MD4_SUM_LENGTH);
fd = do_open(fname, O_RDONLY, 0);
if (fd == -1) return;
buf = map_file(fd,size);
mdfour_begin(&m);
bzero(sum,csum_length);
for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
memcpy(tmpchunk, map_ptr(buf,i,CSUM_CHUNK), CSUM_CHUNK);
mdfour_update(&m, (uchar *)tmpchunk, CSUM_CHUNK);
}
fd = open(fname,O_RDONLY);
if (fd == -1) return;
if (len - i > 0) {
memcpy(tmpchunk, map_ptr(buf,i,len-i), len-i);
mdfour_update(&m, (uchar *)tmpchunk, (len-i));
}
buf = map_file(fd,size);
mdfour_result(&m, (uchar *)sum);
MDbegin(&MD);
for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
bcopy(map_ptr(buf,i,CSUM_CHUNK),tmpchunk,CSUM_CHUNK);
MDupdate(&MD, tmpchunk, CSUM_CHUNK*8);
}
if (len - i > 0) {
bcopy(map_ptr(buf,i,len-i),tmpchunk,len-i);
MDupdate(&MD, tmpchunk, (len-i)*8);
}
sum_put(&MD,sum);
close(fd);
unmap_file(buf);
close(fd);
unmap_file(buf);
}
@@ -138,58 +127,54 @@ void checksum_init(void)
static MDstruct sumMD;
static int sumresidue;
static char sumrbuf[CSUM_CHUNK];
static struct mdfour md;
void sum_init(void)
{
char s[4];
MDbegin(&sumMD);
sumresidue=0;
SIVAL(s,0,checksum_seed);
sum_update(s,4);
char s[4];
mdfour_begin(&md);
sumresidue=0;
SIVAL(s,0,checksum_seed);
sum_update(s,4);
}
void sum_update(char *p,int len)
{
int i;
if (len + sumresidue < CSUM_CHUNK) {
bcopy(p,sumrbuf+sumresidue,len);
sumresidue += len;
return;
}
int i;
if (len + sumresidue < CSUM_CHUNK) {
memcpy(sumrbuf+sumresidue, p, len);
sumresidue += len;
return;
}
if (sumresidue) {
i = MIN(CSUM_CHUNK-sumresidue,len);
bcopy(p,sumrbuf+sumresidue,i);
MDupdate(&sumMD, sumrbuf, (i+sumresidue)*8);
len -= i;
p += i;
}
if (sumresidue) {
i = MIN(CSUM_CHUNK-sumresidue,len);
memcpy(sumrbuf+sumresidue,p,i);
mdfour_update(&md, (uchar *)sumrbuf, (i+sumresidue));
len -= i;
p += i;
}
for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
bcopy(p+i,sumrbuf,CSUM_CHUNK);
MDupdate(&sumMD, sumrbuf, CSUM_CHUNK*8);
}
for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
memcpy(sumrbuf,p+i,CSUM_CHUNK);
mdfour_update(&md, (uchar *)sumrbuf, CSUM_CHUNK);
}
if (len - i > 0) {
sumresidue = len-i;
bcopy(p+i,sumrbuf,sumresidue);
} else {
sumresidue = 0;
}
if (len - i > 0) {
sumresidue = len-i;
memcpy(sumrbuf,p+i,sumresidue);
} else {
sumresidue = 0;
}
}
void sum_end(char *sum)
{
if (sumresidue)
MDupdate(&sumMD, sumrbuf, sumresidue*8);
if (sumresidue) {
mdfour_update(&md, (uchar *)sumrbuf, sumresidue);
}
SIVAL(sum,0,sumMD.buffer[0]);
SIVAL(sum,4,sumMD.buffer[1]);
SIVAL(sum,8,sumMD.buffer[2]);
SIVAL(sum,12,sumMD.buffer[3]);
mdfour_result(&md, (uchar *)sum);
}

108
cleanup.c Normal file
View File

@@ -0,0 +1,108 @@
/* -*- c-file-style: "linux" -*-
Copyright (C) 1996-2000 by Andrew Tridgell
Copyright (C) Paul Mackerras 1996
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "rsync.h"
/* handling the cleanup when a transfer is interrupted is tricky when
--partial is selected. We need to ensure that the partial file is
kept if any real data has been transferred */
int cleanup_got_literal=0;
static char *cleanup_fname;
static char *cleanup_new_fname;
static struct file_struct *cleanup_file;
static int cleanup_fd1, cleanup_fd2;
static struct map_struct *cleanup_buf;
static int cleanup_pid = 0;
extern int io_error;
pid_t cleanup_child_pid = -1;
/*
* Code is one of the RERR_* codes from errcode.h.
*/
void _exit_cleanup(int code, const char *file, int line)
{
extern int keep_partial;
extern int log_got_error;
signal(SIGUSR1, SIG_IGN);
signal(SIGUSR2, SIG_IGN);
if (cleanup_child_pid != -1) {
int status;
if (waitpid(cleanup_child_pid, &status, WNOHANG) == cleanup_child_pid) {
status = WEXITSTATUS(status);
if (status > code) code = status;
}
}
if (cleanup_got_literal && cleanup_fname && keep_partial) {
char *fname = cleanup_fname;
cleanup_fname = NULL;
if (cleanup_buf) unmap_file(cleanup_buf);
if (cleanup_fd1 != -1) close(cleanup_fd1);
if (cleanup_fd2 != -1) close(cleanup_fd2);
finish_transfer(cleanup_new_fname, fname, cleanup_file);
}
io_flush();
if (cleanup_fname)
do_unlink(cleanup_fname);
if (code) {
kill_all(SIGUSR1);
}
if ((cleanup_pid != 0) && (cleanup_pid == (int) getpid())) {
char *pidf = lp_pid_file();
if (pidf && *pidf) {
unlink(lp_pid_file());
}
}
if (code == 0 && (io_error || log_got_error)) {
code = RERR_PARTIAL;
}
if (code) log_exit(code, file, line);
exit(code);
}
void cleanup_disable(void)
{
cleanup_fname = NULL;
cleanup_got_literal = 0;
}
void cleanup_set(char *fnametmp, char *fname, struct file_struct *file,
struct map_struct *buf, int fd1, int fd2)
{
cleanup_fname = fnametmp;
cleanup_new_fname = fname;
cleanup_file = file;
cleanup_buf = buf;
cleanup_fd1 = fd1;
cleanup_fd2 = fd2;
}
void cleanup_set_pid(int pid)
{
cleanup_pid = pid;
}

541
clientserver.c Normal file
View File

@@ -0,0 +1,541 @@
/* -*- c-file-style: "linux"; -*-
Copyright (C) 1998-2001 by Andrew Tridgell <tridge@samba.org>
Copyright (C) 2001 by Martin Pool <mbp@samba.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* the socket based protocol for setting up a connection with rsyncd */
#include "rsync.h"
extern int module_id;
extern int read_only;
extern int verbose;
extern int rsync_port;
char *auth_user;
int sanitize_paths = 0;
/*
* Run a client connected to an rsyncd. The alternative to this
* function for remote-shell connections is do_cmd.
*/
int start_socket_client(char *host, char *path, int argc, char *argv[])
{
int fd, i;
char *sargs[MAX_ARGS];
int sargc=0;
char line[MAXPATHLEN];
char *p, *user=NULL;
extern int remote_version;
extern int am_sender;
extern char *shell_cmd;
extern int kludge_around_eof;
extern char *bind_address;
extern int default_af_hint;
if (argc == 0 && !am_sender) {
extern int list_only;
list_only = 1;
}
/* This is just a friendliness enhancement: if the connection
* is to an rsyncd then there is no point specifying the -e option.
* Note that this is only set if the -e was explicitly specified,
* not if the environment variable just happens to be set.
* See http://lists.samba.org/pipermail/rsync/2000-September/002744.html
*/
if (shell_cmd) {
rprintf(FERROR, "WARNING: --rsh or -e option ignored when "
"connecting to rsync daemon\n");
/* continue */
}
if (*path == '/') {
rprintf(FERROR,"ERROR: The remote path must start with a module name not a /\n");
return -1;
}
p = strchr(host, '@');
if (p) {
user = host;
host = p+1;
*p = 0;
}
if (!user) user = getenv("USER");
if (!user) user = getenv("LOGNAME");
fd = open_socket_out_wrapped (host, rsync_port, bind_address,
default_af_hint);
if (fd == -1) {
exit_cleanup(RERR_SOCKETIO);
}
server_options(sargs,&sargc);
sargs[sargc++] = ".";
if (path && *path)
sargs[sargc++] = path;
sargs[sargc] = NULL;
io_printf(fd,"@RSYNCD: %d\n", PROTOCOL_VERSION);
if (!read_line(fd, line, sizeof(line)-1)) {
return -1;
}
if (sscanf(line,"@RSYNCD: %d", &remote_version) != 1) {
return -1;
}
p = strchr(path,'/');
if (p) *p = 0;
io_printf(fd,"%s\n",path);
if (p) *p = '/';
/* Old servers may just drop the connection here,
rather than sending a proper EXIT command. Yuck. */
kludge_around_eof = remote_version < 25;
while (1) {
if (!read_line(fd, line, sizeof(line)-1)) {
return -1;
}
if (strncmp(line,"@RSYNCD: AUTHREQD ",18) == 0) {
auth_client(fd, user, line+18);
continue;
}
if (strcmp(line,"@RSYNCD: OK") == 0) break;
if (strcmp(line,"@RSYNCD: EXIT") == 0) exit(0);
rprintf(FINFO,"%s\n", line);
}
kludge_around_eof = False;
for (i=0;i<sargc;i++) {
io_printf(fd,"%s\n", sargs[i]);
}
io_printf(fd,"\n");
if (remote_version < 23) {
if (remote_version == 22 || (remote_version > 17 && !am_sender))
io_start_multiplex_in(fd);
}
return client_run(fd, fd, -1, argc, argv);
}
static int rsync_module(int fd, int i)
{
int argc=0;
char *argv[MAX_ARGS];
char **argp;
char line[MAXPATHLEN];
uid_t uid = (uid_t)-2; /* canonically "nobody" */
gid_t gid = (gid_t)-2;
char *p;
char *addr = client_addr(fd);
char *host = client_name(fd);
char *name = lp_name(i);
int use_chroot = lp_use_chroot(i);
int start_glob=0;
int ret;
char *request=NULL;
extern int am_sender;
extern int remote_version;
extern int am_root;
if (!allow_access(addr, host, lp_hosts_allow(i), lp_hosts_deny(i))) {
rprintf(FERROR,"rsync denied on module %s from %s (%s)\n",
name, host, addr);
io_printf(fd,"@ERROR: access denied to %s from %s (%s)\n",
name, host, addr);
return -1;
}
if (!claim_connection(lp_lock_file(i), lp_max_connections(i))) {
if (errno) {
rprintf(FERROR,"failed to open lock file %s : %s\n",
lp_lock_file(i), strerror(errno));
io_printf(fd,"@ERROR: failed to open lock file %s : %s\n",
lp_lock_file(i), strerror(errno));
} else {
rprintf(FERROR,"max connections (%d) reached\n",
lp_max_connections(i));
io_printf(fd,"@ERROR: max connections (%d) reached - try again later\n", lp_max_connections(i));
}
return -1;
}
auth_user = auth_server(fd, i, addr, "@RSYNCD: AUTHREQD ");
if (!auth_user) {
rprintf(FERROR,"auth failed on module %s from %s (%s)\n",
name, client_name(fd), client_addr(fd));
io_printf(fd,"@ERROR: auth failed on module %s\n",name);
return -1;
}
module_id = i;
am_root = (getuid() == 0);
if (am_root) {
p = lp_uid(i);
if (!name_to_uid(p, &uid)) {
if (!isdigit(*p)) {
rprintf(FERROR,"Invalid uid %s\n", p);
io_printf(fd,"@ERROR: invalid uid %s\n", p);
return -1;
}
uid = atoi(p);
}
p = lp_gid(i);
if (!name_to_gid(p, &gid)) {
if (!isdigit(*p)) {
rprintf(FERROR,"Invalid gid %s\n", p);
io_printf(fd,"@ERROR: invalid gid %s\n", p);
return -1;
}
gid = atoi(p);
}
}
/* TODO: If we're not root, but the configuration requests
* that we change to some uid other than the current one, then
* log a warning. */
/* TODO: Perhaps take a list of gids, and make them into the
* supplementary groups. */
p = lp_include_from(i);
add_exclude_file(p, 1, 1);
p = lp_include(i);
add_include_line(p);
p = lp_exclude_from(i);
add_exclude_file(p, 1, 0);
p = lp_exclude(i);
add_exclude_line(p);
log_init();
if (use_chroot) {
/*
* XXX: The 'use chroot' flag is a fairly reliable
* source of confusion, because it fails under two
* important circumstances: running as non-root,
* running on Win32 (or possibly others). On the
* other hand, if you are running as root, then it
* might be better to always use chroot.
*
* So, perhaps if we can't chroot we should just issue
* a warning, unless a "require chroot" flag is set,
* in which case we fail.
*/
if (chroot(lp_path(i))) {
rsyserr(FERROR, errno, "chroot %s failed", lp_path(i));
io_printf(fd,"@ERROR: chroot failed\n");
return -1;
}
if (!push_dir("/", 0)) {
rsyserr(FERROR, errno, "chdir %s failed\n", lp_path(i));
io_printf(fd,"@ERROR: chdir failed\n");
return -1;
}
} else {
if (!push_dir(lp_path(i), 0)) {
rsyserr(FERROR, errno, "chdir %s failed\n", lp_path(i));
io_printf(fd,"@ERROR: chdir failed\n");
return -1;
}
sanitize_paths = 1;
}
if (am_root) {
if (setgid(gid)) {
rsyserr(FERROR, errno, "setgid %d failed", (int) gid);
io_printf(fd,"@ERROR: setgid failed\n");
return -1;
}
if (setuid(uid)) {
rsyserr(FERROR, errno, "setuid %d failed", (int) uid);
io_printf(fd,"@ERROR: setuid failed\n");
return -1;
}
am_root = (getuid() == 0);
}
io_printf(fd,"@RSYNCD: OK\n");
argv[argc++] = "rsyncd";
while (1) {
if (!read_line(fd, line, sizeof(line)-1)) {
return -1;
}
if (!*line) break;
p = line;
argv[argc] = strdup(p);
if (!argv[argc]) {
return -1;
}
if (start_glob) {
if (start_glob == 1) {
request = strdup(p);
start_glob++;
}
glob_expand(name, argv, &argc, MAX_ARGS);
} else {
argc++;
}
if (strcmp(line,".") == 0) {
start_glob = 1;
}
if (argc == MAX_ARGS) {
return -1;
}
}
if (sanitize_paths) {
/*
* Note that this is applied to all parameters, whether or not
* they are filenames, but no other legal parameters contain
* the forms that need to be sanitized so it doesn't hurt;
* it is not known at this point which parameters are files
* and which aren't.
*/
for (i = 1; i < argc; i++) {
sanitize_path(argv[i], NULL);
}
}
argp = argv;
ret = parse_arguments(&argc, (const char ***) &argp, 0);
if (request) {
if (*auth_user) {
rprintf(FINFO,"rsync %s %s from %s@%s (%s)\n",
am_sender?"on":"to",
request, auth_user, host, addr);
} else {
rprintf(FINFO,"rsync %s %s from %s (%s)\n",
am_sender?"on":"to",
request, host, addr);
}
free(request);
}
#ifndef DEBUG
/* don't allow the logs to be flooded too fast */
if (verbose > 1) verbose = 1;
#endif
if (remote_version < 23) {
if (remote_version == 22 || (remote_version > 17 && am_sender))
io_start_multiplex_out(fd);
}
/* For later protocol versions, we don't start multiplexing
* until we've configured nonblocking in start_server. That
* means we're in a sticky situation now: there's no way to
* convey errors to the client. */
/* FIXME: Hold off on reporting option processing errors until
* we've set up nonblocking and multiplexed IO and can get the
* message back to them. */
if (!ret) {
option_error();
exit_cleanup(RERR_UNSUPPORTED);
}
if (lp_timeout(i)) {
extern int io_timeout;
io_timeout = lp_timeout(i);
}
start_server(fd, fd, argc, argp);
return 0;
}
/* send a list of available modules to the client. Don't list those
with "list = False". */
static void send_listing(int fd)
{
int n = lp_numservices();
int i;
extern int remote_version;
for (i=0;i<n;i++)
if (lp_list(i))
io_printf(fd, "%-15s\t%s\n", lp_name(i), lp_comment(i));
if (remote_version >= 25)
io_printf(fd,"@RSYNCD: EXIT\n");
}
/* this is called when a socket connection is established to a client
and we want to start talking. The setup of the system is done from
here */
static int start_daemon(int fd)
{
char line[200];
char *motd;
int i = -1;
extern char *config_file;
extern int remote_version;
if (!lp_load(config_file, 0)) {
exit_cleanup(RERR_SYNTAX);
}
set_socket_options(fd,"SO_KEEPALIVE");
set_socket_options(fd,lp_socket_options());
set_nonblocking(fd);
io_printf(fd,"@RSYNCD: %d\n", PROTOCOL_VERSION);
motd = lp_motd_file();
if (motd && *motd) {
FILE *f = fopen(motd,"r");
while (f && !feof(f)) {
int len = fread(line, 1, sizeof(line)-1, f);
if (len > 0) {
line[len] = 0;
io_printf(fd,"%s", line);
}
}
if (f) fclose(f);
io_printf(fd,"\n");
}
if (!read_line(fd, line, sizeof(line)-1)) {
return -1;
}
if (sscanf(line,"@RSYNCD: %d", &remote_version) != 1) {
io_printf(fd,"@ERROR: protocol startup error\n");
return -1;
}
while (i == -1) {
line[0] = 0;
if (!read_line(fd, line, sizeof(line)-1)) {
return -1;
}
if (!*line || strcmp(line,"#list")==0) {
send_listing(fd);
return -1;
}
if (*line == '#') {
/* it's some sort of command that I don't understand */
io_printf(fd,"@ERROR: Unknown command '%s'\n", line);
return -1;
}
i = lp_number(line);
if (i == -1) {
io_printf(fd,"@ERROR: Unknown module '%s'\n", line);
return -1;
}
}
return rsync_module(fd, i);
}
int daemon_main(void)
{
extern char *config_file;
extern int orig_umask;
char *pid_file;
extern int no_detach;
if (is_a_socket(STDIN_FILENO)) {
int i;
/* we are running via inetd - close off stdout and
stderr so that library functions (and getopt) don't
try to use them. Redirect them to /dev/null */
for (i=1;i<3;i++) {
close(i);
open("/dev/null", O_RDWR);
}
return start_daemon(STDIN_FILENO);
}
if (!no_detach)
become_daemon();
if (!lp_load(config_file, 1)) {
exit_cleanup(RERR_SYNTAX);
}
log_init();
rprintf(FINFO, "rsyncd version %s starting, listening on port %d\n",
RSYNC_VERSION,
rsync_port);
/* TODO: If listening on a particular address, then show that
* address too. In fact, why not just do inet_ntop on the
* local address??? */
if (((pid_file = lp_pid_file()) != NULL) && (*pid_file != '\0')) {
char pidbuf[16];
int fd;
int pid = (int) getpid();
cleanup_set_pid(pid);
if ((fd = do_open(lp_pid_file(), O_WRONLY|O_CREAT|O_TRUNC,
0666 & ~orig_umask)) == -1) {
cleanup_set_pid(0);
rsyserr(FLOG, errno, "failed to create pid file %s", pid_file);
exit_cleanup(RERR_FILEIO);
}
snprintf(pidbuf, sizeof(pidbuf), "%d\n", pid);
write(fd, pidbuf, strlen(pidbuf));
close(fd);
}
start_accept_loop(rsync_port, start_daemon);
return -1;
}

View File

@@ -23,8 +23,6 @@
extern int am_server;
extern int csum_length;
extern int preserve_links;
extern int preserve_perms;
extern int preserve_devices;
@@ -38,37 +36,40 @@ extern int checksum_seed;
extern int remote_version;
extern int verbose;
extern int read_batch; /* dw */
extern int write_batch; /* dw */
void setup_protocol(int f_out,int f_in)
{
if (am_server) {
remote_version = read_int(f_in);
write_int(f_out,PROTOCOL_VERSION);
write_flush(f_out);
} else {
write_int(f_out,PROTOCOL_VERSION);
write_flush(f_out);
remote_version = read_int(f_in);
}
if (remote_version == 0) {
if (am_server) {
remote_version = read_int(f_in);
write_int(f_out,PROTOCOL_VERSION);
} else {
write_int(f_out,PROTOCOL_VERSION);
remote_version = read_int(f_in);
}
}
if (remote_version < MIN_PROTOCOL_VERSION ||
remote_version > MAX_PROTOCOL_VERSION) {
fprintf(FERROR,"protocol version mismatch - is your shell clean?\n");
exit_cleanup(1);
}
if (verbose > 2)
fprintf(FINFO, "local_version=%d remote_version=%d\n",
PROTOCOL_VERSION, remote_version);
if (remote_version >= 12) {
if (am_server) {
checksum_seed = time(NULL);
write_int(f_out,checksum_seed);
} else {
checksum_seed = read_int(f_in);
}
}
checksum_init();
if (remote_version < MIN_PROTOCOL_VERSION ||
remote_version > MAX_PROTOCOL_VERSION) {
rprintf(FERROR,"protocol version mismatch - is your shell clean?\n");
rprintf(FERROR,"(see the rsync man page for an explanation)\n");
exit_cleanup(RERR_PROTOCOL);
}
if (remote_version >= 12) {
if (am_server) {
if (read_batch || write_batch) /* dw */
checksum_seed = 32761;
else
checksum_seed = time(NULL);
write_int(f_out,checksum_seed);
} else {
checksum_seed = read_int(f_in);
}
}
checksum_init();
}

1301
config.guess vendored Executable file
View File

File diff suppressed because it is too large Load Diff

1375
config.sub vendored Executable file
View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,21 +1,236 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT(byteorder.h)
AC_INIT()
AC_CONFIG_SRCDIR([byteorder.h])
AC_CONFIG_HEADER(config.h)
AC_PREREQ(2.52)
RSYNC_VERSION=2.5.2pre3
AC_SUBST(RSYNC_VERSION)
AC_MSG_NOTICE([Configuring rsync $RSYNC_VERSION])
AC_DEFINE_UNQUOTED(RSYNC_VERSION, ["$RSYNC_VERSION"], [rsync release version])
LDFLAGS=${LDFLAGS-""}
AC_CANONICAL_TARGET([])
dnl Checks for programs.
AC_PROG_CC
AC_PROG_CPP
AC_PROG_INSTALL
AC_PROG_CC_STDC
AC_SUBST(SHELL)
AC_CHECK_PROG(HAVE_REMSH, remsh, 1, 0)
AC_DEFINE_UNQUOTED(HAVE_REMSH, $HAVE_REMSH)
AC_DEFINE([_GNU_SOURCE], 1,
[Define _GNU_SOURCE so that we get all necessary prototypes])
if test "$xac_cv_prog_cc_stdc" = xno
then
AC_MSG_WARN([rsync requires an ANSI C compiler and you don't seem to have one])
fi
# We must decide this before testing the compiler.
# Please allow this to default to yes, so that your users have more
# chance of getting a useful stack trace if problems occur.
AC_MSG_CHECKING([whether to include debugging symbols])
AC_ARG_ENABLE(debug,
AC_HELP_STRING([--enable-debug],
[including debugging symbols and features (default yes)]),
[], [])
if test x"$enable_debug" = x"no"
then
AC_MSG_RESULT(no)
CFLAGS=${CFLAGS-"-O"}
else
AC_MSG_RESULT([yes])
# leave CFLAGS alone; AC_PROG_CC will try to include -g if it can
dnl AC_DEFINE(DEBUG, 1, [Define to turn on debugging code that may slow normal operation])
dnl CFLAGS=${CFLAGS-"-g"}
fi
AC_ARG_ENABLE(profile,
AC_HELP_STRING([--enable-profile],
[turn on CPU profiling (default no)],
[], []))
if test x"$enable_profile" = xyes
then
CFLAGS="$CFLAGS -pg"
fi
# This is needed for our included version of popt. Kind of silly, but
# I don't want our version too far out of sync.
CFLAGS="$CFLAGS -DHAVE_CONFIG_H"
# If GCC, turn on warnings.
if test "x$GCC" = "xyes"
then
CFLAGS="$CFLAGS -Wall -W"
fi
AC_ARG_WITH(included-popt,
[ --with-included-popt use bundled popt library, not from system])
AC_ARG_WITH(rsync-path,
[ --with-rsync-path=PATH set default --rsync-path to PATH (default: \"rsync\")],
[ RSYNC_PATH="$with_rsync_path" ],
[ RSYNC_PATH="rsync" ])
AC_DEFINE_UNQUOTED(RSYNC_PATH, "$RSYNC_PATH", [ ])
AC_CHECK_PROG(HAVE_REMSH, remsh, 1, 0)
AC_DEFINE_UNQUOTED(HAVE_REMSH, $HAVE_REMSH, [ ])
# arrgh. libc in the current debian stable screws up the largefile
# stuff, getting byte range locking wrong
AC_CACHE_CHECK([for broken largefile support],rsync_cv_HAVE_BROKEN_LARGEFILE,[
AC_TRY_RUN([
#define _FILE_OFFSET_BITS 64
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void)
{
struct flock lock;
int status;
int fd = open("conftest.dat", O_CREAT|O_RDWR, 0600);
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 1;
lock.l_pid = 0;
fcntl(fd,F_SETLK,&lock);
if (fork() == 0) {
lock.l_start = 1;
exit(fcntl(fd,F_SETLK,&lock) == 0);
}
wait(&status);
unlink("conftest.dat");
exit(WEXITSTATUS(status));
}
],
rsync_cv_HAVE_BROKEN_LARGEFILE=yes,rsync_cv_HAVE_BROKEN_LARGEFILE=no,rsync_cv_HAVE_BROKEN_LARGEFILE=cross)])
if test x"$rsync_cv_HAVE_BROKEN_LARGEFILE" != x"yes"; then
AC_SYS_LARGEFILE
fi
ipv6type=unknown
ipv6lib=none
ipv6trylibc=yes
AC_ARG_ENABLE(ipv6,
AC_HELP_STRING([--disable-ipv6], [don't even try to use IPv6]))
if test "x$enable_ipv6" != xno
then
AC_MSG_CHECKING([ipv6 stack type])
for i in inria kame linux-glibc linux-inet6 toshiba v6d zeta; do
case $i in
inria)
# http://www.kame.net/
AC_EGREP_CPP(yes, [
#include <netinet/in.h>
#ifdef IPV6_INRIA_VERSION
yes
#endif],
[ipv6type=$i;
AC_DEFINE(INET6, 1, [true if you have IPv6])
])
;;
kame)
# http://www.kame.net/
AC_EGREP_CPP(yes, [
#include <netinet/in.h>
#ifdef __KAME__
yes
#endif],
[ipv6type=$i;
AC_DEFINE(INET6, 1, [true if you have IPv6])])
;;
linux-glibc)
# http://www.v6.linux.or.jp/
AC_EGREP_CPP(yes, [
#include <features.h>
#if defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
yes
#endif],
[ipv6type=$i;
AC_DEFINE(INET6, 1, [true if you have IPv6])])
;;
linux-inet6)
# http://www.v6.linux.or.jp/
if test -d /usr/inet6 -o -f /usr/inet6/lib/libinet6.a; then
ipv6type=$i
ipv6lib=inet6
ipv6libdir=/usr/inet6/lib
ipv6trylibc=yes;
AC_DEFINE(INET6, 1, [true if you have IPv6])
CFLAGS="-I/usr/inet6/include $CFLAGS"
fi
;;
toshiba)
AC_EGREP_CPP(yes, [
#include <sys/param.h>
#ifdef _TOSHIBA_INET6
yes
#endif],
[ipv6type=$i;
ipv6lib=inet6;
ipv6libdir=/usr/local/v6/lib;
AC_DEFINE(INET6, 1, [true if you have IPv6])])
;;
v6d)
AC_EGREP_CPP(yes, [
#include </usr/local/v6/include/sys/v6config.h>
#ifdef __V6D__
yes
#endif],
[ipv6type=$i;
ipv6lib=v6;
ipv6libdir=/usr/local/v6/lib;
AC_DEFINE(INET6, 1, [true if you have IPv6])])
;;
zeta)
AC_EGREP_CPP(yes, [
#include <sys/param.h>
#ifdef _ZETA_MINAMI_INET6
yes
#endif],
[ipv6type=$i;
ipv6lib=inet6;
ipv6libdir=/usr/local/v6/lib;
AC_DEFINE(INET6, 1, [true if you have IPv6])])
;;
esac
if test "$ipv6type" != "unknown"; then
break
fi
done
AC_MSG_RESULT($ipv6type)
AC_SEARCH_LIBS(getaddrinfo, inet6)
fi
AC_C_BIGENDIAN
AC_HEADER_DIRENT
AC_HEADER_TIME
AC_HEADER_SYS_WAIT
AC_CHECK_HEADERS(sys/fcntl.h sys/select.h fcntl.h sys/time.h sys/unistd.h unistd.h utime.h grp.h)
AC_CHECK_HEADERS(compat.h sys/param.h ctype.h sys/wait.h sys/ioctl.h)
AC_CHECK_HEADERS(sys/filio.h string.h stdlib.h sys/socket.h sys/mode.h)
AC_CHECK_HEADERS(glob.h alloca.h mcheck.h sys/sysctl.h arpa/inet.h arpa/nameser.h)
AC_CHECK_HEADERS(netdb.h)
AC_CHECK_HEADERS(malloc.h)
AC_CHECK_SIZEOF(int)
AC_CHECK_SIZEOF(long)
@@ -29,38 +244,315 @@ AC_TYPE_MODE_T
AC_TYPE_OFF_T
AC_TYPE_SIZE_T
AC_TYPE_PID_T
AC_STRUCT_ST_RDEV
AC_CHECK_TYPE(ino_t,unsigned)
AC_TYPE_GETGROUPS
AC_CHECK_MEMBERS([struct stat.st_rdev])
echo $ac_n "checking for errno in errno.h... $ac_c"
AC_TRY_COMPILE([#include <errno.h>],[int i = errno],
echo yes; AC_DEFINE(HAVE_ERRNO_DECL),
echo no)
AC_CHECK_TYPE([ino_t], [unsigned])
TYPE_SOCKLEN_T
AC_CACHE_CHECK([for errno in errno.h],rsync_cv_errno, [
AC_TRY_COMPILE([#include <errno.h>],[int i = errno],
rsync_cv_errno=yes,rsync_cv_have_errno_decl=no)])
if test x"$rsync_cv_errno" = x"yes"; then
AC_DEFINE(HAVE_ERRNO_DECL, 1, [ ])
fi
# The following test taken from the cvs sources
# If we can't find connect, try looking in -lsocket, -lnsl, and -linet.
# These need checks to be before checks for any other functions that
# might be in the same libraries.
# The Irix 5 libc.so has connect and gethostbyname, but Irix 5 also has
# libsocket.so which has a bad implementation of gethostbyname (it
# only looks in /etc/hosts), so we only look for -lsocket if we need
# it.
AC_CHECK_FUNCS(connect)
if test x"$ac_cv_func_connect" = x"no"; then
case "$LIBS" in
*-lnsl*) ;;
*) AC_CHECK_LIB(nsl_s, printf) ;;
esac
case "$LIBS" in
*-lnsl*) ;;
*) AC_CHECK_LIB(nsl, printf) ;;
esac
case "$LIBS" in
*-lsocket*) ;;
*) AC_CHECK_LIB(socket, connect) ;;
esac
case "$LIBS" in
*-linet*) ;;
*) AC_CHECK_LIB(inet, connect) ;;
esac
dnl We can't just call AC_CHECK_FUNCS(connect) here, because the value
dnl has been cached.
if test x"$ac_cv_lib_socket_connect" = x"yes" ||
test x"$ac_cv_lib_inet_connect" = x"yes"; then
# ac_cv_func_connect=yes
# don't! it would cause AC_CHECK_FUNC to succeed next time configure is run
AC_DEFINE(HAVE_CONNECT, 1, [ ])
fi
fi
AC_CHECK_LIB(resolv, inet_ntop)
dnl AC_MSG_NOTICE([Looking in libraries: $LIBS])
AC_CHECK_FUNCS(inet_ntop, , AC_LIBOBJ(lib/inet_ntop))
AC_CHECK_FUNCS(inet_pton, , AC_LIBOBJ(lib/inet_pton))
AC_CHECK_FUNCS(getaddrinfo, , AC_LIBOBJ(lib/getaddrinfo))
AC_CHECK_FUNCS(getnameinfo, , AC_LIBOBJ(lib/getnameinfo))
AC_CHECK_MEMBER([struct sockaddr.sa_len],
[ AC_DEFINE(HAVE_SOCKADDR_LEN) ],
[],
[
#include <sys/types.h>
#include <sys/socket.h>
])
AC_MSG_CHECKING(struct sockaddr_storage)
AC_TRY_COMPILE([#include <sys/types.h>
#include <sys/socket.h>],
[struct sockaddr_storage x;],
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_SOCKADDR_STORAGE, 1,
[Define if you have strct sockaddr_storage.] ),
AC_MSG_RESULT(no))
# if we can't find strcasecmp, look in -lresolv (for Unixware at least)
#
AC_CHECK_FUNCS(strcasecmp)
if test x"$ac_cv_func_strcasecmp" = x"no"; then
AC_CHECK_LIB(resolv, strcasecmp)
fi
dnl At the moment we don't test for a broken memcmp(), because all we
dnl need to do is test for equality, not comparison, and it seems that
dnl every platform has a memcmp that can do at least that.
dnl AC_FUNC_MEMCMP
AC_FUNC_MEMCMP
AC_FUNC_MMAP
AC_FUNC_UTIME_NULL
AC_CHECK_FUNCS(waitpid strtok pipe getcwd mkdir strdup strerror chown chmod mknod)
AC_CHECK_FUNCS(fchmod fstat strchr bcopy bzero readlink link utime utimes)
AC_CHECK_FUNCS(memmove getopt_long lchown setlinebuf)
AC_CHECK_FUNCS(waitpid wait4 getcwd strdup strerror chown chmod mknod)
AC_CHECK_FUNCS(fchmod fstat strchr readlink link utime utimes strftime)
AC_CHECK_FUNCS(memmove lchown vsnprintf snprintf asprintf setsid glob strpbrk)
AC_CHECK_FUNCS(strlcat strlcpy mtrace mallinfo)
echo $ac_n "checking for working fnmatch... $ac_c"
AC_CACHE_CHECK([for working socketpair],rsync_cv_HAVE_SOCKETPAIR,[
AC_TRY_RUN([
#include <sys/types.h>
#include <sys/socket.h>
main() {
int fd[2];
exit((socketpair(AF_UNIX, SOCK_STREAM, 0, fd) != -1) ? 0 : 1);
}],
rsync_cv_HAVE_SOCKETPAIR=yes,rsync_cv_HAVE_SOCKETPAIR=no,rsync_cv_HAVE_SOCKETPAIR=cross)])
if test x"$rsync_cv_HAVE_SOCKETPAIR" = x"yes"; then
AC_DEFINE(HAVE_SOCKETPAIR, 1, [ ])
fi
AC_CACHE_CHECK([for working fnmatch],rsync_cv_HAVE_FNMATCH,[
AC_TRY_RUN([#include <fnmatch.h>
main() { exit(fnmatch("*.o", "x.o", 0) == 0? 0: 1); }],
echo yes;AC_DEFINE(HAVE_FNMATCH),
echo no)
main() { exit((fnmatch("*.o", "x.o", FNM_PATHNAME) == 0 &&
fnmatch("a/b/*", "a/b/c/d", FNM_PATHNAME) != 0) ? 0: 1); }],
rsync_cv_HAVE_FNMATCH=yes,rsync_cv_HAVE_FNMATCH=no,rsync_cv_HAVE_FNMATCH=cross)])
if test x"$rsync_cv_HAVE_FNMATCH" = x"yes"; then
AC_DEFINE(HAVE_FNMATCH, 1, [ ])
fi
echo $ac_n "checking for long long... $ac_c"
if test x"$with_included_popt" != x"yes"
then
AC_CHECK_LIB(popt, poptGetContext, , [with_included_popt=yes])
fi
AC_MSG_CHECKING([whether to use included libpopt])
if test x"$with_included_popt" = x"yes"
then
AC_MSG_RESULT($srcdir/popt)
BUILD_POPT='$(popt_OBJS)'
CFLAGS="$CFLAGS -I$srcdir/popt"
else
AC_MSG_RESULT(no)
fi
AC_CACHE_CHECK([for long long],rsync_cv_HAVE_LONGLONG,[
AC_TRY_RUN([#include <stdio.h>
main() { long long x = 1000000000000; char b[20]; sprintf(b,"%lld", x); exit(strcmp("1000000000000", b) == 0? 0: 1); }],
echo yes;AC_DEFINE(HAVE_LONGLONG),
echo no)
main() { long long x = 1000000; x *= x; exit(((x/1000000) == 1000000)? 0: 1); }],
rsync_cv_HAVE_LONGLONG=yes,rsync_cv_HAVE_LONGLONG=no,rsync_cv_HAVE_LONGLONG=cross)])
if test x"$rsync_cv_HAVE_LONGLONG" = x"yes"; then
AC_DEFINE(HAVE_LONGLONG, 1, [ ])
fi
echo $ac_n "checking for utimbuf ... $ac_c"
AC_CACHE_CHECK([for off64_t],rsync_cv_HAVE_OFF64_T,[
AC_TRY_RUN([#include <stdio.h>
#include <sys/stat.h>
main() { struct stat64 st; off64_t s; if (sizeof(off_t) == sizeof(off64_t)) exit(1); exit((lstat64("/dev/null", &st)==0)?0:1); }],
rsync_cv_HAVE_OFF64_T=yes,rsync_cv_HAVE_OFF64_T=no,rsync_cv_HAVE_OFF64_T=cross)])
if test x"$rsync_cv_HAVE_OFF64_T" = x"yes"; then
AC_DEFINE(HAVE_OFF64_T, 1, [ ])
fi
AC_CACHE_CHECK([for short ino_t],rsync_cv_HAVE_SHORT_INO_T,[
AC_TRY_RUN([#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
main() { if (sizeof(ino_t) < sizeof(unsigned int)) return 0; return 1; }],
rsync_cv_HAVE_SHORT_INO_T=yes,rsync_cv_HAVE_SHORT_INO_T=no,rsync_cv_HAVE_SHORT_INO_T=cross)])
if test x"$rsync_cv_HAVE_SHORT_INO_T" = x"yes"; then
AC_DEFINE(HAVE_SHORT_INO_T, 1, [ ])
fi
AC_CACHE_CHECK([for unsigned char],rsync_cv_HAVE_UNSIGNED_CHAR,[
AC_TRY_RUN([#include <stdio.h>
main() { char c; c=250; exit((c > 0)?0:1); }],
rsync_cv_HAVE_UNSIGNED_CHAR=yes,rsync_cv_HAVE_UNSIGNED_CHAR=no,rsync_cv_HAVE_UNSIGNED_CHAR=cross)])
if test x"$rsync_cv_HAVE_UNSIGNED_CHAR" = x"yes"; then
AC_DEFINE(HAVE_UNSIGNED_CHAR, 1, [ ])
fi
AC_CACHE_CHECK([for broken readdir],rsync_cv_HAVE_BROKEN_READDIR,[
AC_TRY_RUN([#include <sys/types.h>
#include <dirent.h>
main() { struct dirent *di; DIR *d = opendir("."); di = readdir(d);
if (di && di->d_name[-2] == '.' && di->d_name[-1] == 0 &&
di->d_name[0] == 0) exit(0); exit(1);} ],
rsync_cv_HAVE_BROKEN_READDIR=yes,rsync_cv_HAVE_BROKEN_READDIR=no,rsync_cv_HAVE_BROKEN_READDIR=cross)])
if test x"$rsync_cv_HAVE_BROKEN_READDIR" = x"yes"; then
AC_DEFINE(HAVE_BROKEN_READDIR, 1, [ ])
fi
AC_CACHE_CHECK([for utimbuf],rsync_cv_HAVE_UTIMBUF,[
AC_TRY_COMPILE([#include <sys/types.h>
#include <utime.h>],
[struct utimbuf tbuf; tbuf.actime = 0; tbuf.modtime = 1; return utime("foo.c",&tbuf);],
echo yes;AC_DEFINE(HAVE_UTIMBUF),
echo no)
[struct utimbuf tbuf; tbuf.actime = 0; tbuf.modtime = 1; exit(utime("foo.c",&tbuf));],
rsync_cv_HAVE_UTIMBUF=yes,rsync_cv_HAVE_UTIMBUF=no,rsync_cv_HAVE_UTIMBUF=cross)])
if test x"$rsync_cv_HAVE_UTIMBUF" = x"yes"; then
AC_DEFINE(HAVE_UTIMBUF, 1, [ ])
fi
AC_OUTPUT(Makefile lib/dummy)
AC_CACHE_CHECK([if gettimeofday takes tz argument],rsync_cv_HAVE_GETTIMEOFDAY_TZ,[
AC_TRY_RUN([
#include <sys/time.h>
#include <unistd.h>
main() { struct timeval tv; exit(gettimeofday(&tv, NULL));}],
rsync_cv_HAVE_GETTIMEOFDAY_TZ=yes,rsync_cv_HAVE_GETTIMEOFDAY_TZ=no,rsync_cv_HAVE_GETTIMEOFDAY_TZ=cross)])
if test x"$rsync_cv_HAVE_GETTIMEOFDAY_TZ" = x"yes"; then
AC_DEFINE(HAVE_GETTIMEOFDAY_TZ, 1, [ ])
fi
AC_CACHE_CHECK([for C99 vsnprintf],rsync_cv_HAVE_C99_VSNPRINTF,[
AC_TRY_RUN([
#include <sys/types.h>
#include <stdarg.h>
void foo(const char *format, ...) {
va_list ap;
int len;
char buf[5];
va_start(ap, format);
len = vsnprintf(0, 0, format, ap);
va_end(ap);
if (len != 5) exit(1);
if (snprintf(buf, 3, "hello") != 5 || strcmp(buf, "he") != 0) exit(1);
exit(0);
}
main() { foo("hello"); }
],
rsync_cv_HAVE_C99_VSNPRINTF=yes,rsync_cv_HAVE_C99_VSNPRINTF=no,rsync_cv_HAVE_C99_VSNPRINTF=cross)])
if test x"$rsync_cv_HAVE_C99_VSNPRINTF" = x"yes"; then
AC_DEFINE(HAVE_C99_VSNPRINTF, 1, [ ])
fi
AC_CACHE_CHECK([for secure mkstemp],rsync_cv_HAVE_SECURE_MKSTEMP,[
AC_TRY_RUN([#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
main() {
struct stat st;
char tpl[20]="/tmp/test.XXXXXX";
int fd = mkstemp(tpl);
if (fd == -1) exit(1);
unlink(tpl);
if (fstat(fd, &st) != 0) exit(1);
if ((st.st_mode & 0777) != 0600) exit(1);
exit(0);
}],
rsync_cv_HAVE_SECURE_MKSTEMP=yes,
rsync_cv_HAVE_SECURE_MKSTEMP=no,
rsync_cv_HAVE_SECURE_MKSTEMP=cross)])
if test x"$rsync_cv_HAVE_SECURE_MKSTEMP" = x"yes"; then
AC_DEFINE(HAVE_SECURE_MKSTEMP, 1, [ ])
fi
AC_CACHE_CHECK([for broken inet_ntoa],rsync_cv_REPLACE_INET_NTOA,[
AC_TRY_RUN([
#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
main() { struct in_addr ip; ip.s_addr = 0x12345678;
if (strcmp(inet_ntoa(ip),"18.52.86.120") &&
strcmp(inet_ntoa(ip),"120.86.52.18")) { exit(1); }
exit(0);}],
rsync_cv_REPLACE_INET_NTOA=no,rsync_cv_REPLACE_INET_NTOA=yes,rsync_cv_REPLACE_INET_NTOA=cross)])
if test x"$rsync_cv_REPLACE_INET_NTOA" = x"yes"; then
AC_DEFINE(REPLACE_INET_NTOA, 1, [ ])
fi
AC_CACHE_CHECK([for broken inet_aton],rsync_cv_REPLACE_INET_ATON,[
AC_TRY_RUN([
#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
main() { struct in_addr ip;
if (inet_aton("example", &ip) == 0) exit(0); exit(1);}],
rsync_cv_REPLACE_INET_ATON=no,rsync_cv_REPLACE_INET_ATON=yes,rsync_cv_REPLACE_INET_ATON=cross)])
if test x"$rsync_cv_REPLACE_INET_ATON" = x"yes"; then
AC_DEFINE(REPLACE_INET_ATON, 1, [ ])
fi
#
# The following test was mostly taken from the tcl/tk plus patches
#
AC_CACHE_CHECK([whether -c -o works],rsync_cv_DASHC_WORKS_WITH_DASHO,[
rm -rf conftest*
cat > conftest.$ac_ext <<EOF
int main() { return 0; }
EOF
${CC-cc} -c -o conftest..o conftest.$ac_ext
if test -f conftest..o; then
rsync_cv_DASHC_WORKS_WITH_DASHO=yes
else
rsync_cv_DASHC_WORKS_WITH_DASHO=no
fi
rm -rf conftest*
])
if test x"$rsync_cv_DASHC_WORKS_WITH_DASHO" = x"yes"; then
OBJ_SAVE="#"
OBJ_RESTORE="#"
CC_SHOBJ_FLAG='-o $@'
else
OBJ_SAVE=' @b=`basename $@ .o`;rm -f $$b.o.sav;if test -f $$b.o; then mv $$b.o $$b.o.sav;fi;'
OBJ_RESTORE=' @b=`basename $@ .o`;if test "$$b.o" != "$@"; then mv $$b.o $@; if test -f $$b.o.sav; then mv $$b.o.sav $$b.o; fi; fi'
CC_SHOBJ_FLAG=""
fi
AC_SUBST(OBJ_SAVE)
AC_SUBST(OBJ_RESTORE)
AC_SUBST(CC_SHOBJ_FLAG)
AC_SUBST(BUILD_POPT)
AC_CONFIG_FILES([Makefile lib/dummy zlib/dummy popt/dummy shconfig])
AC_OUTPUT
AC_MSG_RESULT()
AC_MSG_RESULT([ rsync ${RSYNC_VERSION} configuration successful])
AC_MSG_RESULT()

49
connection.c Normal file
View File

@@ -0,0 +1,49 @@
/*
Copyright (C) Andrew Tridgell 1998
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* support the max connections option */
#include "rsync.h"
/****************************************************************************
simple routine to do connection counting
****************************************************************************/
int claim_connection(char *fname,int max_connections)
{
int fd, i;
if (max_connections <= 0)
return 1;
fd = open(fname,O_RDWR|O_CREAT, 0600);
if (fd == -1) {
return 0;
}
/* find a free spot */
for (i=0;i<max_connections;i++) {
if (lock_range(fd, i*4, 4)) return 1;
}
/* only interested in open failures */
errno = 0;
close(fd);
return 0;
}

82
csprotocol.txt Normal file
View File

@@ -0,0 +1,82 @@
This is kind of informal and may be wrong, but it helped me. It's
basically a summary of clientserver.c and authenticate.c.
-- Martin Pool <mbp@samba.org>
$Id$
This is the protocol used for rsync --daemon; i.e. connections to port
873 rather than invocations over a remote shell.
When the server accepts a connection, it prints a greeting
@RSYNCD: <version>
where <version> is the numeric version; currently 24. It follows this
with a free text message-of-the-day. It expects to see a similar
greeting back from the client.
The server is now in the connected state. The client can either send
the command
#list
to get a listing of modules, or the name of a module. After this, the
connection is now bound to a particular module. Access per host for
this module is now checked, as is per-module connection limits.
If authentication is required to use this module, the server will say
@RSYNCD: AUTHREQD <challenge>
where <challenge> is a random string of base64 characters. The client
must respond with
<user> <response>
where <user> is the username they claim to be, and <response> is the
base64 form of the MD4 hash of challenge+password.
At this point the server applies all remaining constraints before
handing control to the client, including switching uid/gid, setting up
include and exclude lists, moving to the root of the module, and doing
chroot.
If the login is acceptable, then the server will respond with
@RSYNCD: OK
The client now writes some rsync options, as if it were remotely
executing the command. The server parses these arguments as if it had
just been invoked with them, but they're added to the existing state.
So if the client specifies a list of files to be included or excluded,
they'll defer to existing limits specified in the server
configuration.
At this point the client and server both switch to using a
multiplexing layer across the socket. The main point of this is to
allow the server to asynchronously pass errors back, while still
allowing streamed and pipelined data.
Unfortunately, the multiplex protocol is not used at every stage. We
start up in plain socket mode and then change over by calling
io_start_buffering. Of course both the client and the server have to
do this at the same point.
The server then talks to the client as normal across the socket,
passing checksums, file lists and so on. For documentation of that,
stay tuned (or write it yourself!).
------------
Protocol version changes
25 (2001-08-20, 2.4.7pre2)
Send an explicit "@RSYNC EXIT" command at the end of the
module listing. We never intentionally end the transmission
by just closing the socket anymore.

57
errcode.h Normal file
View File

@@ -0,0 +1,57 @@
/* -*- c-file-style: "linux"; -*-
Copyright (C) 1998-2000 by Andrew Tridgell
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* error codes returned by rsync. If you change these, please also update the
* string mappings in log.c
*/
#define RERR_SYNTAX 1 /* syntax or usage error */
#define RERR_PROTOCOL 2 /* protocol incompatibility */
#define RERR_FILESELECT 3 /* errors selecting input/output files, dirs */
#define RERR_UNSUPPORTED 4 /* requested action not supported */
#define RERR_SOCKETIO 10 /* error in socket IO */
#define RERR_FILEIO 11 /* error in file IO */
#define RERR_STREAMIO 12 /* error in rsync protocol data stream */
#define RERR_MESSAGEIO 13 /* errors with program diagnostics */
#define RERR_IPC 14 /* error in IPC code */
#define RERR_SIGNAL 20 /* status returned when sent SIGUSR1, SIGINT */
#define RERR_WAITCHILD 21 /* some error returned by waitpid() */
#define RERR_MALLOC 22 /* error allocating core memory buffers */
#define RERR_PARTIAL 23 /* partial transfer */
#define RERR_TIMEOUT 30 /* timeout in data send/receive */
/* Although it doesn't seem to be specified anywhere,
* ssh and the shell seem to return these values:
*
* 124 if the command exited with status 255
* 125 if the command is killed by a signal
* 126 if the command cannot be run
* 127 if the command is not found
*
* and we could use this to give a better explanation if the remote
* command is not found.
*/
#define RERR_CMD_FAILED 124
#define RERR_CMD_KILLED 125
#define RERR_CMD_RUN 126
#define RERR_CMD_NOTFOUND 127

425
exclude.c
View File

@@ -17,157 +17,330 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
a lot of this stuff was derived from GNU tar
*/
/* a lot of this stuff was originally derived from GNU tar, although
it has now changed so much that it is hard to tell :) */
#include "rsync.h"
extern int verbose;
extern int am_server;
extern int delete_mode;
static char **exclude_list;
static struct exclude_struct **exclude_list;
static int is_regex(char *str)
/* build an exclude structure given a exclude pattern */
static struct exclude_struct *make_exclude(char *pattern, int include)
{
return strchr(str, '*') || strchr(str, '[') || strchr(str, '?');
struct exclude_struct *ret;
ret = (struct exclude_struct *)malloc(sizeof(*ret));
if (!ret) out_of_memory("make_exclude");
memset(ret, 0, sizeof(*ret));
if (strncmp(pattern,"- ",2) == 0) {
pattern += 2;
} else if (strncmp(pattern,"+ ",2) == 0) {
ret->include = 1;
pattern += 2;
} else {
ret->include = include;
}
ret->pattern = strdup(pattern);
if (!ret->pattern) out_of_memory("make_exclude");
if (strpbrk(pattern, "*[?")) {
ret->regular_exp = 1;
ret->fnmatch_flags = FNM_PATHNAME;
if (strstr(pattern, "**")) {
static int tested;
if (!tested) {
tested = 1;
if (fnmatch("a/b/*", "a/b/c/d", FNM_PATHNAME)==0) {
rprintf(FERROR,"WARNING: fnmatch FNM_PATHNAME is broken on your system\n");
}
}
ret->fnmatch_flags = 0;
}
}
if (strlen(pattern) > 1 && pattern[strlen(pattern)-1] == '/') {
ret->pattern[strlen(pattern)-1] = 0;
ret->directory = 1;
}
if (!strchr(ret->pattern,'/')) {
ret->local = 1;
}
return ret;
}
static void free_exclude(struct exclude_struct *ex)
{
free(ex->pattern);
memset(ex,0,sizeof(*ex));
free(ex);
}
static int check_one_exclude(char *name,struct exclude_struct *ex,
STRUCT_STAT *st)
{
char *p;
int match_start=0;
char *pattern = ex->pattern;
if (ex->local && (p=strrchr(name,'/')))
name = p+1;
if (!name[0]) return 0;
if (ex->directory && !S_ISDIR(st->st_mode)) return 0;
if (*pattern == '/' && *name != '/') {
match_start = 1;
pattern++;
}
if (ex->regular_exp) {
if (fnmatch(pattern, name, ex->fnmatch_flags) == 0) {
return 1;
}
} else {
int l1 = strlen(name);
int l2 = strlen(pattern);
if (l2 <= l1 &&
strcmp(name+(l1-l2),pattern) == 0 &&
(l1==l2 || (!match_start && name[l1-(l2+1)] == '/'))) {
return 1;
}
}
return 0;
}
static int check_one_exclude(char *name,char *pattern)
int check_exclude(char *name,struct exclude_struct **local_exclude_list,
STRUCT_STAT *st)
{
char *p;
int n;
if (!strchr(pattern,'/') && (p=strrchr(name,'/')))
name = p+1;
if (name && (name[0] == '.') && !name[1])
/* never exclude '.', even if somebody does --exclude '*' */
return 0;
if (!name[0]) return 0;
if (exclude_list) {
for (n=0; exclude_list[n]; n++)
if (check_one_exclude(name,exclude_list[n],st))
return !exclude_list[n]->include;
}
if (is_regex(pattern)) {
if (fnmatch(pattern, name, 0) == 0)
return 1;
} else {
int l1 = strlen(name);
int l2 = strlen(pattern);
if (l2 <= l1 &&
strcmp(name+(l1-l2),pattern) == 0 &&
(l1==l2 || name[l1-(l2+1)] == '/'))
return 1;
}
if (local_exclude_list) {
for (n=0; local_exclude_list[n]; n++)
if (check_one_exclude(name,local_exclude_list[n],st))
return !local_exclude_list[n]->include;
}
return 0;
return 0;
}
int check_exclude(char *name,char **local_exclude_list)
void add_exclude_list(char *pattern,struct exclude_struct ***list, int include)
{
int n;
int len=0;
if (list && *list)
for (; (*list)[len]; len++) ;
if (exclude_list) {
for (n=0; exclude_list[n]; n++)
if (check_one_exclude(name,exclude_list[n]))
return 1;
}
if (strcmp(pattern,"!") == 0) {
if (verbose > 2)
rprintf(FINFO,"clearing exclude list\n");
while ((len)--) {
free_exclude((*list)[len]);
}
free((*list));
*list = NULL;
return;
}
if (local_exclude_list) {
for (n=0; local_exclude_list[n]; n++)
if (check_one_exclude(name,local_exclude_list[n]))
return 1;
}
*list = (struct exclude_struct **)Realloc(*list,sizeof(struct exclude_struct *)*(len+2));
if (!*list || !((*list)[len] = make_exclude(pattern, include)))
out_of_memory("add_exclude");
if (verbose > 2)
rprintf(FINFO,"add_exclude(%s)\n",pattern);
(*list)[len+1] = NULL;
}
return 0;
void add_exclude(char *pattern, int include)
{
add_exclude_list(pattern,&exclude_list, include);
}
struct exclude_struct **make_exclude_list(char *fname,
struct exclude_struct **list1,
int fatal, int include)
{
struct exclude_struct **list=list1;
FILE *f = fopen(fname,"r");
char line[MAXPATHLEN];
if (!f) {
if (fatal) {
rprintf(FERROR,"%s : %s\n",fname,strerror(errno));
exit_cleanup(RERR_FILEIO);
}
return list;
}
while (fgets(line,MAXPATHLEN,f)) {
int l = strlen(line);
if (l && line[l-1] == '\n') l--;
line[l] = 0;
if (line[0] && (line[0] != ';') && (line[0] != '#')) {
/* Skip lines starting with semicolon or pound.
It probably wouldn't cause any harm to not skip
them but there's no need to save them. */
add_exclude_list(line,&list,include);
}
}
fclose(f);
return list;
}
void add_exclude_list(char *pattern,char ***list)
void add_exclude_file(char *fname,int fatal,int include)
{
int len=0;
if (list && *list)
for (; (*list)[len]; len++) ;
if (!fname || !*fname) return;
if (strcmp(pattern,"!") == 0) {
if (verbose > 2)
fprintf(FINFO,"clearing exclude list\n");
while ((len)--)
free((*list)[len]);
free((*list));
*list = NULL;
return;
}
if (!*list) {
*list = (char **)malloc(sizeof(char *)*2);
} else {
*list = (char **)realloc(*list,sizeof(char *)*(len+2));
}
if (!*list || !((*list)[len] = strdup(pattern)))
out_of_memory("add_exclude");
if (verbose > 2)
fprintf(FINFO,"add_exclude(%s)\n",pattern);
(*list)[len+1] = NULL;
}
void add_exclude(char *pattern)
{
add_exclude_list(pattern,&exclude_list);
}
char **make_exclude_list(char *fname,char **list1,int fatal)
{
char **list=list1;
FILE *f = fopen(fname,"r");
char line[MAXPATHLEN];
if (!f) {
if (fatal) {
fprintf(FERROR,"%s : %s\n",fname,strerror(errno));
exit_cleanup(1);
}
return list;
}
while (fgets(line,MAXPATHLEN,f)) {
int l = strlen(line);
if (l && line[l-1] == '\n') l--;
line[l] = 0;
if (line[0]) add_exclude_list(line,&list);
}
fclose(f);
return list;
}
void add_exclude_file(char *fname,int fatal)
{
exclude_list = make_exclude_list(fname,exclude_list,fatal);
exclude_list = make_exclude_list(fname,exclude_list,fatal,include);
}
void send_exclude_list(int f)
{
int i;
if (exclude_list)
for (i=0;exclude_list[i];i++) {
int l = strlen(exclude_list[i]);
if (l == 0) continue;
write_int(f,l);
write_buf(f,exclude_list[i],l);
}
write_int(f,0);
int i;
extern int remote_version;
extern int list_only, recurse;
/* this is a complete hack - blame Rusty */
if (list_only && !recurse) {
add_exclude("/*/*", 0);
}
if (!exclude_list) {
write_int(f,0);
return;
}
for (i=0;exclude_list[i];i++) {
int l;
char pattern[MAXPATHLEN];
strlcpy(pattern,exclude_list[i]->pattern,sizeof(pattern));
if (exclude_list[i]->directory) strlcat(pattern,"/", sizeof(pattern));
l = strlen(pattern);
if (l == 0) continue;
if (exclude_list[i]->include) {
if (remote_version < 19) {
rprintf(FERROR,"remote rsync does not support include syntax - aborting\n");
exit_cleanup(RERR_UNSUPPORTED);
}
write_int(f,l+2);
write_buf(f,"+ ",2);
} else {
write_int(f,l);
}
write_buf(f,pattern,l);
}
write_int(f,0);
}
void recv_exclude_list(int f)
{
char line[MAXPATHLEN];
int l;
while ((l=read_int(f))) {
if (l >= MAXPATHLEN) overflow("recv_exclude_list");
read_sbuf(f,line,l);
add_exclude(line);
}
char line[MAXPATHLEN];
unsigned int l;
while ((l=read_int(f))) {
if (l >= MAXPATHLEN) overflow("recv_exclude_list");
read_sbuf(f,line,l);
add_exclude(line,0);
}
}
/* Get the next include/exclude arg from the string. It works in a similar way
** to strtok - initially an arg is sent over, from then on NULL. This
** routine takes into account any +/- in the strings and does not
** consider the space following it as a delimeter.
*/
char *get_exclude_tok(char *p)
{
static char *s;
static int more;
char *t;
if (p) {
s=p;
if (*p)
more=1;
}
if (!more)
return(NULL);
/* Skip over any initial spaces */
while(isspace(*s))
s++;
/* Are we at the end of the string? */
if (*s) {
/* remember the beginning of the token */
t=s;
/* Is this a '+' or '-' followed by a space (not whitespace)? */
if ((*s=='+' || *s=='-') && *(s+1)==' ')
s+=2;
/* Skip to the next space or the end of the string */
while(!isspace(*s) && *s!='\0')
s++;
} else {
t=NULL;
}
/* Have we reached the end of the string? */
if (*s)
*s++='\0';
else
more=0;
return(t);
}
void add_exclude_line(char *p)
{
char *tok;
if (!p || !*p) return;
p = strdup(p);
if (!p) out_of_memory("add_exclude_line");
for (tok=get_exclude_tok(p); tok; tok=get_exclude_tok(NULL))
add_exclude(tok, 0);
free(p);
}
void add_include_line(char *p)
{
char *tok;
if (!p || !*p) return;
p = strdup(p);
if (!p) out_of_memory("add_include_line");
for (tok=get_exclude_tok(p); tok; tok=get_exclude_tok(NULL))
add_exclude(tok, 1);
free(p);
}
@@ -182,21 +355,17 @@ static char *cvs_ignore_list[] = {
void add_cvs_excludes(void)
{
char fname[MAXPATHLEN];
char *p;
int i;
char fname[MAXPATHLEN];
char *p;
int i;
for (i=0; cvs_ignore_list[i]; i++)
add_exclude(cvs_ignore_list[i]);
for (i=0; cvs_ignore_list[i]; i++)
add_exclude(cvs_ignore_list[i], 0);
if ((p=getenv("HOME")) && strlen(p) < (MAXPATHLEN-12)) {
sprintf(fname,"%s/.cvsignore",p);
add_exclude_file(fname,0);
}
if ((p=getenv("HOME")) && strlen(p) < (MAXPATHLEN-12)) {
slprintf(fname,sizeof(fname), "%s/.cvsignore",p);
add_exclude_file(fname,0,0);
}
if ((p=getenv("CVSIGNORE"))) {
char *tok;
for (tok=strtok(p," "); tok; tok=strtok(NULL," "))
add_exclude(tok);
}
add_exclude_line(getenv("CVSIGNORE"));
}

213
fileio.c Normal file
View File

@@ -0,0 +1,213 @@
/*
Copyright (C) Andrew Tridgell 1998
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
File IO utilities used in rsync
*/
#include "rsync.h"
static char last_byte;
static int last_sparse;
extern int sparse_files;
int sparse_end(int f)
{
if (last_sparse) {
do_lseek(f,-1,SEEK_CUR);
return (write(f,&last_byte,1) == 1 ? 0 : -1);
}
last_sparse = 0;
return 0;
}
static int write_sparse(int f,char *buf,size_t len)
{
int l1=0,l2=0;
int ret;
for (l1=0;l1<len && buf[l1]==0;l1++) ;
for (l2=0;l2<(len-l1) && buf[len-(l2+1)]==0;l2++) ;
last_byte = buf[len-1];
if (l1 == len || l2 > 0)
last_sparse=1;
if (l1 > 0) {
do_lseek(f,l1,SEEK_CUR);
}
if (l1 == len)
return len;
if ((ret=write(f,buf+l1,len-(l1+l2))) != len-(l1+l2)) {
if (ret == -1 || ret == 0) return ret;
return (l1+ret);
}
if (l2 > 0)
do_lseek(f,l2,SEEK_CUR);
return len;
}
int write_file(int f,char *buf,size_t len)
{
int ret = 0;
if (!sparse_files) {
return write(f,buf,len);
}
while (len>0) {
int len1 = MIN(len, SPARSE_WRITE_SIZE);
int r1 = write_sparse(f, buf, len1);
if (r1 <= 0) {
if (ret > 0) return ret;
return r1;
}
len -= r1;
buf += r1;
ret += r1;
}
return ret;
}
/* this provides functionality somewhat similar to mmap() but using
read(). It gives sliding window access to a file. mmap() is not
used because of the possibility of another program (such as a
mailer) truncating the file thus giving us a SIGBUS */
struct map_struct *map_file(int fd,OFF_T len)
{
struct map_struct *map;
map = (struct map_struct *)malloc(sizeof(*map));
if (!map) out_of_memory("map_file");
map->fd = fd;
map->file_size = len;
map->p = NULL;
map->p_size = 0;
map->p_offset = 0;
map->p_fd_offset = 0;
map->p_len = 0;
return map;
}
/* slide the read window in the file */
char *map_ptr(struct map_struct *map,OFF_T offset,int len)
{
int nread;
OFF_T window_start, read_start;
int window_size, read_size, read_offset;
if (len == 0) {
return NULL;
}
/* can't go beyond the end of file */
if (len > (map->file_size - offset)) {
len = map->file_size - offset;
}
/* in most cases the region will already be available */
if (offset >= map->p_offset &&
offset+len <= map->p_offset+map->p_len) {
return (map->p + (offset - map->p_offset));
}
/* nope, we are going to have to do a read. Work out our desired window */
if (offset > 2*CHUNK_SIZE) {
window_start = offset - 2*CHUNK_SIZE;
window_start &= ~((OFF_T)(CHUNK_SIZE-1)); /* assumes power of 2 */
} else {
window_start = 0;
}
window_size = MAX_MAP_SIZE;
if (window_start + window_size > map->file_size) {
window_size = map->file_size - window_start;
}
if (offset + len > window_start + window_size) {
window_size = (offset+len) - window_start;
}
/* make sure we have allocated enough memory for the window */
if (window_size > map->p_size) {
map->p = (char *)Realloc(map->p, window_size);
if (!map->p) out_of_memory("map_ptr");
map->p_size = window_size;
}
/* now try to avoid re-reading any bytes by reusing any bytes from the previous
buffer. */
if (window_start >= map->p_offset &&
window_start < map->p_offset + map->p_len &&
window_start + window_size >= map->p_offset + map->p_len) {
read_start = map->p_offset + map->p_len;
read_offset = read_start - window_start;
read_size = window_size - read_offset;
memmove(map->p, map->p + (map->p_len - read_offset), read_offset);
} else {
read_start = window_start;
read_size = window_size;
read_offset = 0;
}
if (read_size <= 0) {
rprintf(FINFO,"Warning: unexpected read size of %d in map_ptr\n", read_size);
} else {
if (map->p_fd_offset != read_start) {
if (do_lseek(map->fd,read_start,SEEK_SET) != read_start) {
rprintf(FERROR,"lseek failed in map_ptr\n");
exit_cleanup(RERR_FILEIO);
}
map->p_fd_offset = read_start;
}
if ((nread=read(map->fd,map->p + read_offset,read_size)) != read_size) {
if (nread < 0) nread = 0;
/* the best we can do is zero the buffer - the file
has changed mid transfer! */
memset(map->p+read_offset+nread, 0, read_size - nread);
}
map->p_fd_offset += nread;
}
map->p_offset = window_start;
map->p_len = window_size;
return map->p + (offset - map->p_offset);
}
void unmap_file(struct map_struct *map)
{
if (map->p) {
free(map->p);
map->p = NULL;
}
memset(map, 0, sizeof(*map));
free(map);
}

880
flist.c
View File

File diff suppressed because it is too large Load Diff

503
generator.c Normal file
View File

@@ -0,0 +1,503 @@
/* -*- c-file-style: "linux" -*-
rsync -- fast file replication program
Copyright (C) 1996-2000 by Andrew Tridgell
Copyright (C) Paul Mackerras 1996
Copyright (C) 2002 by Martin Pool <mbp@samba.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "rsync.h"
extern int verbose;
extern int dry_run;
extern int relative_paths;
extern int preserve_links;
extern int am_root;
extern int preserve_devices;
extern int preserve_hard_links;
extern int update_only;
extern int whole_file;
extern int block_size;
extern int csum_length;
extern int ignore_times;
extern int size_only;
extern int io_timeout;
extern int remote_version;
extern int always_checksum;
extern int modify_window;
extern char *compare_dest;
/* choose whether to skip a particular file */
static int skip_file(char *fname,
struct file_struct *file, STRUCT_STAT *st)
{
if (st->st_size != file->length) {
return 0;
}
/* if always checksum is set then we use the checksum instead
of the file time to determine whether to sync */
if (always_checksum && S_ISREG(st->st_mode)) {
char sum[MD4_SUM_LENGTH];
char fnamecmpdest[MAXPATHLEN];
if (compare_dest != NULL) {
if (access(fname, 0) != 0) {
snprintf(fnamecmpdest,MAXPATHLEN,"%s/%s",
compare_dest,fname);
fname = fnamecmpdest;
}
}
file_checksum(fname,sum,st->st_size);
if (remote_version < 21) {
return (memcmp(sum,file->sum,2) == 0);
} else {
return (memcmp(sum,file->sum,MD4_SUM_LENGTH) == 0);
}
}
if (size_only) {
return 1;
}
if (ignore_times) {
return 0;
}
return (cmp_modtime(st->st_mtime,file->modtime) == 0);
}
/* use a larger block size for really big files */
static int adapt_block_size(struct file_struct *file, int bsize)
{
int ret;
if (bsize != BLOCK_SIZE) return bsize;
ret = file->length / (10000); /* rough heuristic */
ret = ret & ~15; /* multiple of 16 */
if (ret < bsize) ret = bsize;
if (ret > CHUNK_SIZE/2) ret = CHUNK_SIZE/2;
return ret;
}
/*
send a sums struct down a fd
*/
static void send_sums(struct sum_struct *s, int f_out)
{
if (s) {
size_t i;
/* tell the other guy how many we are going to be
doing and how many bytes there are in the last
chunk */
write_int(f_out, s->count);
write_int(f_out, s->n);
write_int(f_out, s->remainder);
for (i = 0; i < s->count; i++) {
write_int(f_out, s->sums[i].sum1);
write_buf(f_out, s->sums[i].sum2, csum_length);
}
} else {
/* we don't have checksums */
write_int(f_out, 0);
write_int(f_out, block_size);
write_int(f_out, 0);
}
}
/*
generate a stream of signatures/checksums that describe a buffer
generate approximately one checksum every n bytes
*/
static struct sum_struct *generate_sums(struct map_struct *buf,OFF_T len,int n)
{
int i;
struct sum_struct *s;
int count;
int block_len = n;
int remainder = (len%block_len);
OFF_T offset = 0;
count = (len+(block_len-1))/block_len;
s = (struct sum_struct *)malloc(sizeof(*s));
if (!s) out_of_memory("generate_sums");
s->count = count;
s->remainder = remainder;
s->n = n;
s->flength = len;
if (count==0) {
s->sums = NULL;
return s;
}
if (verbose > 3)
rprintf(FINFO,"count=%d rem=%d n=%d flength=%.0f\n",
s->count,s->remainder,s->n,(double)s->flength);
s->sums = (struct sum_buf *)malloc(sizeof(s->sums[0])*s->count);
if (!s->sums) out_of_memory("generate_sums");
for (i=0;i<count;i++) {
int n1 = MIN(len,n);
char *map = map_ptr(buf,offset,n1);
s->sums[i].sum1 = get_checksum1(map,n1);
get_checksum2(map,n1,s->sums[i].sum2);
s->sums[i].offset = offset;
s->sums[i].len = n1;
s->sums[i].i = i;
if (verbose > 3)
rprintf(FINFO,"chunk[%d] offset=%.0f len=%d sum1=%08x\n",
i,(double)s->sums[i].offset,s->sums[i].len,s->sums[i].sum1);
len -= n1;
offset += n1;
}
return s;
}
/*
* Acts on file number I from FLIST, whose name is fname.
*
* First fixes up permissions, then generates checksums for the file.
*
* (This comment was added later by mbp who was trying to work it out;
* it might be wrong.)
*/
void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
{
int fd;
STRUCT_STAT st;
struct map_struct *buf;
struct sum_struct *s;
int statret;
struct file_struct *file = flist->files[i];
char *fnamecmp;
char fnamecmpbuf[MAXPATHLEN];
extern char *compare_dest;
extern int list_only;
extern int preserve_perms;
extern int only_existing;
if (list_only) return;
if (verbose > 2)
rprintf(FINFO,"recv_generator(%s,%d)\n",fname,i);
statret = link_stat(fname,&st);
if (only_existing && statret == -1 && errno == ENOENT) {
/* we only want to update existing files */
if (verbose > 1) rprintf(FINFO, RSYNC_NAME
": not creating new file \"%s\"\n",fname);
return;
}
if (statret == 0 &&
!preserve_perms &&
(S_ISDIR(st.st_mode) == S_ISDIR(file->mode))) {
/* if the file exists already and we aren't perserving
presmissions then act as though the remote end sent
us the file permissions we already have */
file->mode = (file->mode & _S_IFMT) | (st.st_mode & ~_S_IFMT);
}
if (S_ISDIR(file->mode)) {
/* The file to be received is a directory, so we need
* to prepare appropriately. If there is already a
* file of that name and it is *not* a directory, then
* we need to delete it. If it doesn't exist, then
* recursively create it. */
if (dry_run) return; /* XXXX -- might cause inaccuracies?? -- mbp */
if (statret == 0 && !S_ISDIR(st.st_mode)) {
if (robust_unlink(fname) != 0) {
rprintf(FERROR, RSYNC_NAME
": recv_generator: unlink \"%s\" to make room for directory: %s\n",
fname,strerror(errno));
return;
}
statret = -1;
}
if (statret != 0 && do_mkdir(fname,file->mode) != 0 && errno != EEXIST) {
if (!(relative_paths && errno==ENOENT &&
create_directory_path(fname)==0 &&
do_mkdir(fname,file->mode)==0)) {
rprintf(FERROR, RSYNC_NAME ": recv_generator: mkdir \"%s\": %s (2)\n",
fname,strerror(errno));
}
}
/* f_out is set to -1 when doing final directory
permission and modification time repair */
if (set_perms(fname,file,NULL,0) && verbose && (f_out != -1))
rprintf(FINFO,"%s/\n",fname);
return;
}
if (preserve_links && S_ISLNK(file->mode)) {
#if SUPPORT_LINKS
char lnk[MAXPATHLEN];
int l;
extern int safe_symlinks;
if (safe_symlinks && unsafe_symlink(file->link, fname)) {
if (verbose) {
rprintf(FINFO,RSYNC_NAME ": ignoring unsafe symlink \"%s\" -> \"%s\"\n",
fname,file->link);
}
return;
}
if (statret == 0) {
l = readlink(fname,lnk,MAXPATHLEN-1);
if (l > 0) {
lnk[l] = 0;
/* A link already pointing to the
* right place -- no further action
* required. */
if (strcmp(lnk,file->link) == 0) {
set_perms(fname,file,&st,1);
return;
}
}
/* Not a symlink, so delete whatever's
* already there and put a new symlink
* in place. */
delete_file(fname);
}
if (do_symlink(file->link,fname) != 0) {
rprintf(FERROR,RSYNC_NAME": symlink \"%s\" -> \"%s\": %s\n",
fname,file->link,strerror(errno));
} else {
set_perms(fname,file,NULL,0);
if (verbose) {
rprintf(FINFO,RSYNC_NAME": %s -> %s\n",
fname,file->link);
}
}
#endif
return;
}
#ifdef HAVE_MKNOD
if (am_root && preserve_devices && IS_DEVICE(file->mode)) {
if (statret != 0 ||
st.st_mode != file->mode ||
st.st_rdev != file->rdev) {
delete_file(fname);
if (verbose > 2)
rprintf(FINFO,"mknod(%s,0%o,0x%x)\n",
fname,(int)file->mode,(int)file->rdev);
if (do_mknod(fname,file->mode,file->rdev) != 0) {
rprintf(FERROR,"mknod %s : %s\n",fname,strerror(errno));
} else {
set_perms(fname,file,NULL,0);
if (verbose)
rprintf(FINFO,"%s\n",fname);
}
} else {
set_perms(fname,file,&st,1);
}
return;
}
#endif
if (preserve_hard_links && check_hard_link(file)) {
if (verbose > 1)
rprintf(FINFO, RSYNC_NAME
": \"%s\" is a hard link\n",f_name(file));
return;
}
if (!S_ISREG(file->mode)) {
rprintf(FINFO, RSYNC_NAME
": skipping non-regular file \"%s\"\n",fname);
return;
}
fnamecmp = fname;
if ((statret == -1) && (compare_dest != NULL)) {
/* try the file at compare_dest instead */
int saveerrno = errno;
snprintf(fnamecmpbuf,MAXPATHLEN,"%s/%s",compare_dest,fname);
statret = link_stat(fnamecmpbuf,&st);
if (!S_ISREG(st.st_mode))
statret = -1;
if (statret == -1)
errno = saveerrno;
else
fnamecmp = fnamecmpbuf;
}
if (statret == -1) {
if (errno == ENOENT) {
write_int(f_out,i);
if (!dry_run) send_sums(NULL,f_out);
} else {
if (verbose > 1)
rprintf(FERROR, RSYNC_NAME
": recv_generator failed to open \"%s\": %s\n",
fname, strerror(errno));
}
return;
}
if (!S_ISREG(st.st_mode)) {
if (delete_file(fname) != 0) {
return;
}
/* now pretend the file didn't exist */
write_int(f_out,i);
if (!dry_run) send_sums(NULL,f_out);
return;
}
if (update_only && cmp_modtime(st.st_mtime,file->modtime)>0 && fnamecmp == fname) {
if (verbose > 1)
rprintf(FINFO,"%s is newer\n",fname);
return;
}
if (skip_file(fname, file, &st)) {
if (fnamecmp == fname)
set_perms(fname,file,&st,1);
return;
}
if (dry_run) {
write_int(f_out,i);
return;
}
if (whole_file) {
write_int(f_out,i);
send_sums(NULL,f_out);
return;
}
/* open the file */
fd = do_open(fnamecmp, O_RDONLY, 0);
if (fd == -1) {
rprintf(FERROR,RSYNC_NAME": failed to open \"%s\", continuing : %s\n",fnamecmp,strerror(errno));
/* pretend the file didn't exist */
write_int(f_out,i);
send_sums(NULL,f_out);
return;
}
if (st.st_size > 0) {
buf = map_file(fd,st.st_size);
} else {
buf = NULL;
}
if (verbose > 3)
rprintf(FINFO,"gen mapped %s of size %.0f\n",fnamecmp,(double)st.st_size);
s = generate_sums(buf,st.st_size,adapt_block_size(file, block_size));
if (verbose > 2)
rprintf(FINFO,"sending sums for %d\n",i);
write_int(f_out,i);
send_sums(s,f_out);
close(fd);
if (buf) unmap_file(buf);
free_sums(s);
}
void generate_files(int f,struct file_list *flist,char *local_name,int f_recv)
{
int i;
int phase=0;
if (verbose > 2)
rprintf(FINFO,"generator starting pid=%d count=%d\n",
(int)getpid(),flist->count);
/* we expect to just sit around now, so don't exit on a
timeout. If we really get a timeout then the other process should
exit */
io_timeout = 0;
for (i = 0; i < flist->count; i++) {
struct file_struct *file = flist->files[i];
mode_t saved_mode = file->mode;
if (!file->basename) continue;
/* we need to ensure that any directories we create have writeable
permissions initially so that we can create the files within
them. This is then fixed after the files are transferred */
if (!am_root && S_ISDIR(file->mode)) {
file->mode |= S_IWUSR; /* user write */
/* XXX: Could this be causing a problem on SCO? Perhaps their
* handling of permissions is strange? */
}
recv_generator(local_name?local_name:f_name(file),
flist,i,f);
file->mode = saved_mode;
}
phase++;
csum_length = SUM_LENGTH;
ignore_times=1;
if (verbose > 2)
rprintf(FINFO,"generate_files phase=%d\n",phase);
write_int(f,-1);
if (remote_version >= 13) {
/* in newer versions of the protocol the files can cycle through
the system more than once to catch initial checksum errors */
for (i=read_int(f_recv); i != -1; i=read_int(f_recv)) {
struct file_struct *file = flist->files[i];
recv_generator(local_name?local_name:f_name(file),
flist,i,f);
}
phase++;
if (verbose > 2)
rprintf(FINFO,"generate_files phase=%d\n",phase);
write_int(f,-1);
}
}

188
hlink.c
View File

@@ -1,6 +1,7 @@
/*
Copyright (C) Andrew Tridgell 1996
Copyright (C) Paul Mackerras 1996
Copyright (C) 2002 by Martin Pool <mbp@samba.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,24 +20,26 @@
#include "rsync.h"
extern int am_server;
extern int dry_run;
extern int verbose;
#if SUPPORT_HARD_LINKS
static int hlink_compare(struct file_struct *f1,struct file_struct *f2)
static int hlink_compare(struct file_struct *f1, struct file_struct *f2)
{
if (!S_ISREG(f1->mode) && !S_ISREG(f2->mode)) return 0;
if (!S_ISREG(f1->mode)) return -1;
if (!S_ISREG(f2->mode)) return 1;
if (!S_ISREG(f1->mode) && !S_ISREG(f2->mode))
return 0;
if (!S_ISREG(f1->mode))
return -1;
if (!S_ISREG(f2->mode))
return 1;
if (f1->dev != f2->dev)
return (int)(f1->dev - f2->dev);
if (f1->dev != f2->dev)
return (int) (f1->dev > f2->dev ? 1 : -1);
if (f1->inode != f2->inode)
return (f1->inode - f2->inode);
if (f1->inode != f2->inode)
return (int) (f1->inode > f2->inode ? 1 : -1);
return file_compare(&f1,&f2);
return file_compare(&f1, &f2);
}
@@ -48,22 +51,25 @@ void init_hard_links(struct file_list *flist)
{
#if SUPPORT_HARD_LINKS
int i;
if (flist->count < 2) return;
if (flist->count < 2)
return;
if (hlink_list) free(hlink_list);
if (!(hlink_list =
(struct file_struct *)malloc(sizeof(hlink_list[0])*flist->count)))
if (hlink_list)
free(hlink_list);
if (!(hlink_list =
(struct file_struct *) malloc(sizeof(hlink_list[0]) *
flist->count)))
out_of_memory("init_hard_links");
for (i = 0; i < flist->count; i++)
bcopy(flist->files[i], &hlink_list[i], sizeof(hlink_list[0]));
memcpy(&hlink_list[i], flist->files[i],
sizeof(hlink_list[0]));
qsort(hlink_list,flist->count,
sizeof(hlink_list[0]),
(int (*)())hlink_compare);
qsort(hlink_list, flist->count,
sizeof(hlink_list[0]), (int (*)()) hlink_compare);
hlink_count=flist->count;
hlink_count = flist->count;
#endif
}
@@ -72,78 +78,102 @@ void init_hard_links(struct file_list *flist)
int check_hard_link(struct file_struct *file)
{
#if SUPPORT_HARD_LINKS
int low=0,high=hlink_count-1;
int ret=0;
int low = 0, high = hlink_count - 1;
int ret = 0;
if (!hlink_list || !S_ISREG(file->mode)) return 0;
if (!hlink_list || !S_ISREG(file->mode))
return 0;
while (low != high) {
int mid = (low+high)/2;
ret = hlink_compare(&hlink_list[mid],file);
if (ret == 0) {
low = mid;
break;
}
if (ret > 0)
high=mid;
else
low=mid+1;
}
while (low != high) {
int mid = (low + high) / 2;
ret = hlink_compare(&hlink_list[mid], file);
if (ret == 0) {
low = mid;
break;
}
if (ret > 0)
high = mid;
else
low = mid + 1;
}
if (hlink_compare(&hlink_list[low],file) != 0) return 0;
if (hlink_compare(&hlink_list[low], file) != 0)
return 0;
if (low > 0 &&
S_ISREG(hlink_list[low-1].mode) &&
file->dev == hlink_list[low-1].dev &&
file->inode == hlink_list[low-1].inode)
return 1;
if (low > 0 &&
S_ISREG(hlink_list[low - 1].mode) &&
file->dev == hlink_list[low - 1].dev &&
file->inode == hlink_list[low - 1].inode)
return 1;
#endif
return 0;
return 0;
}
/* create any hard links in the flist */
void do_hard_links(struct file_list *flist)
#if SUPPORT_HARD_LINKS
static void hard_link_one(int i)
{
STRUCT_STAT st1, st2;
if (link_stat(f_name(&hlink_list[i - 1]), &st1) != 0)
return;
if (link_stat(f_name(&hlink_list[i]), &st2) != 0) {
if (do_link
(f_name(&hlink_list[i - 1]),
f_name(&hlink_list[i])) != 0) {
if (verbose > 0)
rprintf(FINFO, "link %s => %s : %s\n",
f_name(&hlink_list[i]),
f_name(&hlink_list[i - 1]),
strerror(errno));
return;
}
} else {
if (st2.st_dev == st1.st_dev && st2.st_ino == st1.st_ino)
return;
if (robust_unlink(f_name(&hlink_list[i])) != 0 ||
do_link(f_name(&hlink_list[i - 1]),
f_name(&hlink_list[i])) != 0) {
if (verbose > 0)
rprintf(FINFO, "link %s => %s : %s\n",
f_name(&hlink_list[i]),
f_name(&hlink_list[i - 1]),
strerror(errno));
return;
}
}
if (verbose > 0)
rprintf(FINFO, "%s => %s\n",
f_name(&hlink_list[i]),
f_name(&hlink_list[i - 1]));
}
#endif
/**
* Create any hard links in the global hlink_list. They were put
* there by running init_hard_links on the filelist.
**/
void do_hard_links(void)
{
#if SUPPORT_HARD_LINKS
int i;
if (!hlink_list) return;
int i;
for (i=1;i<hlink_count;i++) {
if (S_ISREG(hlink_list[i].mode) &&
S_ISREG(hlink_list[i-1].mode) &&
hlink_list[i].basename && hlink_list[i-1].basename &&
hlink_list[i].dev == hlink_list[i-1].dev &&
hlink_list[i].inode == hlink_list[i-1].inode) {
struct stat st1,st2;
if (!hlink_list)
return;
if (link_stat(f_name(&hlink_list[i-1]),&st1) != 0) continue;
if (link_stat(f_name(&hlink_list[i]),&st2) != 0) {
if (do_link(f_name(&hlink_list[i-1]),f_name(&hlink_list[i])) != 0) {
if (verbose > 0)
fprintf(FINFO,"link %s => %s : %s\n",
f_name(&hlink_list[i]),
f_name(&hlink_list[i-1]),strerror(errno));
continue;
for (i = 1; i < hlink_count; i++) {
if (S_ISREG(hlink_list[i].mode) &&
S_ISREG(hlink_list[i - 1].mode) &&
hlink_list[i].basename && hlink_list[i - 1].basename &&
hlink_list[i].dev == hlink_list[i - 1].dev &&
hlink_list[i].inode == hlink_list[i - 1].inode) {
hard_link_one(i);
}
}
} else {
if (st2.st_dev == st1.st_dev && st2.st_ino == st1.st_ino) continue;
if (do_unlink(f_name(&hlink_list[i])) != 0 ||
do_link(f_name(&hlink_list[i-1]),f_name(&hlink_list[i])) != 0) {
if (verbose > 0)
fprintf(FINFO,"link %s => %s : %s\n",
f_name(&hlink_list[i]),
f_name(&hlink_list[i-1]),strerror(errno));
continue;
}
}
if (verbose > 0)
fprintf(FINFO,"%s => %s\n",
f_name(&hlink_list[i]),f_name(&hlink_list[i-1]));
}
}
#endif
}

785
io.c
View File

@@ -18,89 +18,34 @@
*/
/*
Utilities used in rsync
socket and pipe IO utilities used in rsync
tridge, June 1996
*/
#include "rsync.h"
static int64 total_written;
static int64 total_read;
/* if no timeout is specified then use a 60 second select timeout */
#define SELECT_TIMEOUT 60
extern int verbose;
extern int sparse_files;
extern int io_timeout;
int64 write_total(void)
{
return total_written;
}
int64 read_total(void)
{
return total_read;
}
static int buffer_f_in = -1;
void setup_nonblocking(int f_in,int f_out)
{
set_blocking(f_out,0);
buffer_f_in = f_in;
}
static char *read_buffer;
static char *read_buffer_p;
static int read_buffer_len;
static int read_buffer_size;
/* This function was added to overcome a deadlock problem when using
* ssh. It looks like we can't allow our receive queue to get full or
* ssh will clag up. Uggh. */
static void read_check(int f)
{
int n;
if (f == -1) return;
if (read_buffer_len == 0) {
read_buffer_p = read_buffer;
}
if ((n=num_waiting(f)) <= 0)
return;
/* things could deteriorate if we read in really small chunks */
if (n < 10) n = 1024;
if (read_buffer_p != read_buffer) {
memmove(read_buffer,read_buffer_p,read_buffer_len);
read_buffer_p = read_buffer;
}
if (n > (read_buffer_size - read_buffer_len)) {
read_buffer_size += n;
if (!read_buffer)
read_buffer = (char *)malloc(read_buffer_size);
else
read_buffer = (char *)realloc(read_buffer,read_buffer_size);
if (!read_buffer) out_of_memory("read check");
read_buffer_p = read_buffer;
}
n = read(f,read_buffer+read_buffer_len,n);
if (n > 0) {
read_buffer_len += n;
}
}
extern int bwlimit;
static int io_multiplexing_out;
static int io_multiplexing_in;
static int multiplex_in_fd;
static int multiplex_out_fd;
static time_t last_io;
static int eof_error=1;
extern int verbose;
extern int io_timeout;
extern struct stats stats;
static int io_error_fd = -1;
static void read_loop(int fd, char *buf, size_t len);
static void check_timeout(void)
{
extern int am_server, am_daemon;
time_t t;
if (!io_timeout) return;
@@ -112,70 +57,222 @@ static void check_timeout(void)
t = time(NULL);
if (last_io && io_timeout && (t-last_io)>io_timeout) {
fprintf(FERROR,"read timeout after %d second - exiting\n",
(int)(t-last_io));
exit_cleanup(1);
if (last_io && io_timeout && (t-last_io) >= io_timeout) {
if (!am_server && !am_daemon) {
rprintf(FERROR,"io timeout after %d second - exiting\n",
(int)(t-last_io));
}
exit_cleanup(RERR_TIMEOUT);
}
}
static int readfd(int fd,char *buffer,int N)
/* setup the fd used to propogate errors */
void io_set_error_fd(int fd)
{
io_error_fd = fd;
}
/* read some data from the error fd and write it to the write log code */
static void read_error_fd(void)
{
char buf[200];
int n;
int fd = io_error_fd;
int tag, len;
io_error_fd = -1;
read_loop(fd, buf, 4);
tag = IVAL(buf, 0);
len = tag & 0xFFFFFF;
tag = tag >> 24;
tag -= MPLEX_BASE;
while (len) {
n = len;
if (n > (sizeof(buf)-1)) n = sizeof(buf)-1;
read_loop(fd, buf, n);
rwrite((enum logcode)tag, buf, n);
len -= n;
}
io_error_fd = fd;
}
static int no_flush;
/* read from a socket with IO timeout. return the number of
bytes read. If no bytes can be read then exit, never return
a number <= 0 */
static int read_timeout(int fd, char *buf, size_t len)
{
int n, ret=0;
io_flush();
while (ret == 0) {
fd_set fds;
struct timeval tv;
int fd_count = fd+1;
FD_ZERO(&fds);
FD_SET(fd, &fds);
if (io_error_fd != -1) {
FD_SET(io_error_fd, &fds);
if (io_error_fd > fd) fd_count = io_error_fd+1;
}
tv.tv_sec = io_timeout?io_timeout:SELECT_TIMEOUT;
tv.tv_usec = 0;
errno = 0;
if (select(fd_count, &fds, NULL, NULL, &tv) < 1) {
if (errno == EBADF) {
exit_cleanup(RERR_SOCKETIO);
}
check_timeout();
continue;
}
if (io_error_fd != -1 && FD_ISSET(io_error_fd, &fds)) {
read_error_fd();
}
if (!FD_ISSET(fd, &fds)) continue;
n = read(fd, buf, len);
if (n > 0) {
buf += n;
len -= n;
ret += n;
if (io_timeout)
last_io = time(NULL);
continue;
}
if (n == -1 && errno == EINTR) {
continue;
}
if (n == -1 &&
(errno == EWOULDBLOCK || errno == EAGAIN)) {
continue;
}
if (n == 0) {
if (eof_error) {
rprintf(FERROR,"unexpected EOF in read_timeout\n");
}
exit_cleanup(RERR_STREAMIO);
}
/* this prevents us trying to write errors on a dead socket */
io_multiplexing_close();
rprintf(FERROR,"read error: %s\n", strerror(errno));
exit_cleanup(RERR_STREAMIO);
}
return ret;
}
/* continue trying to read len bytes - don't return until len
has been read */
static void read_loop(int fd, char *buf, size_t len)
{
while (len) {
int n = read_timeout(fd, buf, len);
buf += n;
len -= n;
}
}
/* read from the file descriptor handling multiplexing -
return number of bytes read
never return <= 0 */
static int read_unbuffered(int fd, char *buf, size_t len)
{
static int remaining;
int tag, ret=0;
char line[1024];
if (!io_multiplexing_in || fd != multiplex_in_fd)
return read_timeout(fd, buf, len);
while (ret == 0) {
if (remaining) {
len = MIN(len, remaining);
read_loop(fd, buf, len);
remaining -= len;
ret = len;
continue;
}
read_loop(fd, line, 4);
tag = IVAL(line, 0);
remaining = tag & 0xFFFFFF;
tag = tag >> 24;
if (tag == MPLEX_BASE) continue;
tag -= MPLEX_BASE;
if (tag != FERROR && tag != FINFO) {
rprintf(FERROR,"unexpected tag %d\n", tag);
exit_cleanup(RERR_STREAMIO);
}
if (remaining > sizeof(line)-1) {
rprintf(FERROR,"multiplexing overflow %d\n\n",
remaining);
exit_cleanup(RERR_STREAMIO);
}
read_loop(fd, line, remaining);
line[remaining] = 0;
rprintf((enum logcode)tag,"%s", line);
remaining = 0;
}
return ret;
}
/* do a buffered read from fd. don't return until all N bytes
have been read. If all N can't be read then exit with an error */
static void readfd(int fd,char *buffer,size_t N)
{
int ret;
int total=0;
struct timeval tv;
if (read_buffer_len < N)
read_check(buffer_f_in);
while (total < N) {
if (read_buffer_len > 0 && buffer_f_in == fd) {
ret = MIN(read_buffer_len,N-total);
memcpy(buffer+total,read_buffer_p,ret);
read_buffer_p += ret;
read_buffer_len -= ret;
total += ret;
continue;
}
io_flush();
while ((ret = read(fd,buffer + total,N-total)) == -1) {
fd_set fds;
if (errno != EAGAIN && errno != EWOULDBLOCK)
return -1;
FD_ZERO(&fds);
FD_SET(fd, &fds);
tv.tv_sec = io_timeout;
tv.tv_usec = 0;
if (select(fd+1, &fds, NULL, NULL, &tv) != 1) {
check_timeout();
}
}
if (ret <= 0)
return total;
ret = read_unbuffered(fd,buffer + total,N-total);
total += ret;
}
if (io_timeout)
last_io = time(NULL);
return total;
stats.total_read += total;
}
int read_int(int f)
int32 read_int(int f)
{
int ret;
char b[4];
if ((ret=readfd(f,b,4)) != 4) {
if (verbose > 1)
fprintf(FERROR,"(%d) Error reading %d bytes : %s\n",
getpid(),4,ret==-1?strerror(errno):"EOF");
exit_cleanup(1);
}
total_read += 4;
return IVAL(b,0);
char b[4];
int32 ret;
readfd(f,b,4);
ret = IVAL(b,0);
if (ret == (int32)0xffffffff) return -1;
return ret;
}
int64 read_longint(int f)
@@ -185,20 +282,16 @@ int64 read_longint(int f)
char b[8];
ret = read_int(f);
if (ret != -1) return ret;
if ((int32)ret != (int32)0xffffffff) {
return ret;
}
#ifndef HAVE_LONGLONG
fprintf(FERROR,"Integer overflow - attempted 64 bit offset\n");
exit_cleanup(1);
#ifdef NO_INT64
rprintf(FERROR,"Integer overflow - attempted 64 bit offset\n");
exit_cleanup(RERR_UNSUPPORTED);
#else
if (remote_version >= 16) {
if ((ret=readfd(f,b,8)) != 8) {
if (verbose > 1)
fprintf(FERROR,"(%d) Error reading %d bytes : %s\n",
getpid(),8,ret==-1?strerror(errno):"EOF");
exit_cleanup(1);
}
total_read += 8;
readfd(f,b,8);
ret = IVAL(b,0) | (((int64)IVAL(b,4))<<32);
}
#endif
@@ -206,19 +299,12 @@ int64 read_longint(int f)
return ret;
}
void read_buf(int f,char *buf,int len)
void read_buf(int f,char *buf,size_t len)
{
int ret;
if ((ret=readfd(f,buf,len)) != len) {
if (verbose > 1)
fprintf(FERROR,"(%d) Error reading %d bytes : %s\n",
getpid(),len,ret==-1?strerror(errno):"EOF");
exit_cleanup(1);
}
total_read += len;
readfd(f,buf,len);
}
void read_sbuf(int f,char *buf,int len)
void read_sbuf(int f,char *buf,size_t len)
{
read_buf(f,buf,len);
buf[len] = 0;
@@ -226,211 +312,316 @@ void read_sbuf(int f,char *buf,int len)
unsigned char read_byte(int f)
{
unsigned char c;
read_buf(f,(char *)&c,1);
return c;
unsigned char c;
read_buf(f,(char *)&c,1);
return c;
}
static char last_byte;
static int last_sparse;
int sparse_end(int f)
/* write len bytes to fd */
static void writefd_unbuffered(int fd,char *buf,size_t len)
{
if (last_sparse) {
lseek(f,-1,SEEK_CUR);
return (write(f,&last_byte,1) == 1 ? 0 : -1);
}
last_sparse = 0;
return 0;
}
int total = 0;
fd_set w_fds, r_fds;
int fd_count, count;
struct timeval tv;
no_flush++;
static int write_sparse(int f,char *buf,int len)
{
int l1=0,l2=0;
int ret;
while (total < len) {
FD_ZERO(&w_fds);
FD_ZERO(&r_fds);
FD_SET(fd,&w_fds);
fd_count = fd;
for (l1=0;l1<len && buf[l1]==0;l1++) ;
for (l2=0;l2<(len-l1) && buf[len-(l2+1)]==0;l2++) ;
last_byte = buf[len-1];
if (l1 == len || l2 > 0)
last_sparse=1;
if (l1 > 0)
lseek(f,l1,SEEK_CUR);
if (l1 == len)
return len;
if ((ret=write(f,buf+l1,len-(l1+l2))) != len-(l1+l2)) {
if (ret == -1 || ret == 0) return ret;
return (l1+ret);
}
if (l2 > 0)
lseek(f,l2,SEEK_CUR);
return len;
}
int write_file(int f,char *buf,int len)
{
int ret = 0;
if (!sparse_files)
return write(f,buf,len);
while (len>0) {
int len1 = MIN(len, SPARSE_WRITE_SIZE);
int r1 = write_sparse(f, buf, len1);
if (r1 <= 0) {
if (ret > 0) return ret;
return r1;
if (io_error_fd != -1) {
FD_SET(io_error_fd,&r_fds);
if (io_error_fd > fd_count)
fd_count = io_error_fd;
}
tv.tv_sec = io_timeout?io_timeout:SELECT_TIMEOUT;
tv.tv_usec = 0;
errno = 0;
count = select(fd_count+1,
io_error_fd != -1?&r_fds:NULL,
&w_fds,NULL,
&tv);
if (count <= 0) {
if (errno == EBADF) {
exit_cleanup(RERR_SOCKETIO);
}
check_timeout();
continue;
}
if (io_error_fd != -1 && FD_ISSET(io_error_fd, &r_fds)) {
read_error_fd();
}
if (FD_ISSET(fd, &w_fds)) {
int ret, n = len-total;
ret = write(fd,buf+total,n);
if (ret == -1 && errno == EINTR) {
continue;
}
if (ret == -1 &&
(errno == EWOULDBLOCK || errno == EAGAIN)) {
msleep(1);
continue;
}
if (ret <= 0) {
rprintf(FERROR,"erroring writing %d bytes - exiting\n", len);
exit_cleanup(RERR_STREAMIO);
}
/* Sleep after writing to limit I/O bandwidth */
if (bwlimit)
{
tv.tv_sec = 0;
tv.tv_usec = ret * 1000 / bwlimit;
while (tv.tv_usec > 1000000)
{
tv.tv_sec++;
tv.tv_usec -= 1000000;
}
select(0, NULL, NULL, NULL, &tv);
}
total += ret;
if (io_timeout)
last_io = time(NULL);
}
len -= r1;
buf += r1;
ret += r1;
}
return ret;
no_flush--;
}
static int writefd(int fd,char *buf,int len)
static char *io_buffer;
static int io_buffer_count;
void io_start_buffering(int fd)
{
int total = 0;
fd_set w_fds, r_fds;
int fd_count, count, got_select=0;
struct timeval tv;
if (io_buffer) return;
multiplex_out_fd = fd;
io_buffer = (char *)malloc(IO_BUFFER_SIZE);
if (!io_buffer) out_of_memory("writefd");
io_buffer_count = 0;
}
if (buffer_f_in == -1)
return write(fd,buf,len);
/* write an message to a multiplexed stream. If this fails then rsync
exits */
static void mplex_write(int fd, enum logcode code, char *buf, size_t len)
{
char buffer[4096];
int n = len;
while (total < len) {
int ret = write(fd,buf+total,len-total);
SIVAL(buffer, 0, ((MPLEX_BASE + (int)code)<<24) + len);
if (ret == 0) return total;
if (n > (sizeof(buffer)-4)) {
n = sizeof(buffer)-4;
}
if (ret == -1 && !(errno == EWOULDBLOCK || errno == EAGAIN))
return -1;
memcpy(&buffer[4], buf, n);
writefd_unbuffered(fd, buffer, n+4);
if (ret == -1 && got_select) {
/* hmmm, we got a write select on the fd and then failed to write.
Why doesn't that mean that the fd is dead? It doesn't on some
systems it seems (eg. IRIX) */
u_sleep(1000);
#if 0
fprintf(FERROR,"write exception\n");
exit_cleanup(1);
#endif
}
len -= n;
buf += n;
got_select = 0;
if (ret == -1) {
read_check(buffer_f_in);
fd_count = fd+1;
FD_ZERO(&w_fds);
FD_ZERO(&r_fds);
FD_SET(fd,&w_fds);
if (buffer_f_in != -1) {
FD_SET(buffer_f_in,&r_fds);
if (buffer_f_in > fd)
fd_count = buffer_f_in+1;
}
tv.tv_sec = BLOCKING_TIMEOUT;
tv.tv_usec = 0;
count = select(fd_count,buffer_f_in == -1? NULL: &r_fds,
&w_fds,NULL,&tv);
if (count == -1 && errno != EINTR) {
if (verbose > 1)
fprintf(FERROR,"select error: %s\n", strerror(errno));
exit_cleanup(1);
}
if (count == 0) {
check_timeout();
continue;
}
if (FD_ISSET(fd, &w_fds)) {
got_select = 1;
}
} else {
total += ret;
}
}
if (io_timeout)
last_io = time(NULL);
return total;
if (len) {
writefd_unbuffered(fd, buf, len);
}
}
void write_int(int f,int x)
void io_flush(void)
{
int ret;
char b[4];
SIVAL(b,0,x);
if ((ret=writefd(f,b,4)) != 4) {
fprintf(FERROR,"write_int failed : %s\n",
ret==-1?strerror(errno):"EOF");
exit_cleanup(1);
}
total_written += 4;
int fd = multiplex_out_fd;
if (!io_buffer_count || no_flush) return;
if (io_multiplexing_out) {
mplex_write(fd, FNONE, io_buffer, io_buffer_count);
} else {
writefd_unbuffered(fd, io_buffer, io_buffer_count);
}
io_buffer_count = 0;
}
void io_end_buffering(int fd)
{
io_flush();
if (!io_multiplexing_out) {
free(io_buffer);
io_buffer = NULL;
}
}
/* some OSes have a bug where an exit causes the pending writes on
a socket to be flushed. Do an explicit shutdown to try to prevent this */
void io_shutdown(void)
{
if (multiplex_out_fd != -1) close(multiplex_out_fd);
if (io_error_fd != -1) close(io_error_fd);
multiplex_out_fd = -1;
io_error_fd = -1;
}
static void writefd(int fd,char *buf,size_t len)
{
stats.total_written += len;
if (!io_buffer || fd != multiplex_out_fd) {
writefd_unbuffered(fd, buf, len);
return;
}
while (len) {
int n = MIN(len, IO_BUFFER_SIZE-io_buffer_count);
if (n > 0) {
memcpy(io_buffer+io_buffer_count, buf, n);
buf += n;
len -= n;
io_buffer_count += n;
}
if (io_buffer_count == IO_BUFFER_SIZE) io_flush();
}
}
void write_int(int f,int32 x)
{
char b[4];
SIVAL(b,0,x);
writefd(f,b,4);
}
void write_longint(int f, int64 x)
{
extern int remote_version;
char b[8];
int ret;
if (remote_version < 16 || x <= 0x7FFFFFFF) {
write_int(f, (int)x);
return;
}
write_int(f, -1);
write_int(f, (int32)0xFFFFFFFF);
SIVAL(b,0,(x&0xFFFFFFFF));
SIVAL(b,4,((x>>32)&0xFFFFFFFF));
if ((ret=writefd(f,b,8)) != 8) {
fprintf(FERROR,"write_longint failed : %s\n",
ret==-1?strerror(errno):"EOF");
exit_cleanup(1);
}
total_written += 8;
writefd(f,b,8);
}
void write_buf(int f,char *buf,int len)
void write_buf(int f,char *buf,size_t len)
{
int ret;
if ((ret=writefd(f,buf,len)) != len) {
fprintf(FERROR,"write_buf failed : %s\n",
ret==-1?strerror(errno):"EOF");
exit_cleanup(1);
}
total_written += len;
writefd(f,buf,len);
}
/* write a string to the connection */
static void write_sbuf(int f,char *buf)
{
write_buf(f, buf, strlen(buf));
}
void write_byte(int f,unsigned char c)
{
write_buf(f,(char *)&c,1);
write_buf(f,(char *)&c,1);
}
void write_flush(int f)
int read_line(int f, char *buf, size_t maxlen)
{
eof_error = 0;
while (maxlen) {
buf[0] = 0;
read_buf(f, buf, 1);
if (buf[0] == 0) return 0;
if (buf[0] == '\n') {
buf[0] = 0;
break;
}
if (buf[0] != '\r') {
buf++;
maxlen--;
}
}
if (maxlen == 0) {
*buf = 0;
return 0;
}
eof_error = 1;
return 1;
}
void io_printf(int fd, const char *format, ...)
{
va_list ap;
char buf[1024];
int len;
va_start(ap, format);
len = vslprintf(buf, sizeof(buf), format, ap);
va_end(ap);
if (len < 0) exit_cleanup(RERR_STREAMIO);
write_sbuf(fd, buf);
}
/* setup for multiplexing an error stream with the data stream */
void io_start_multiplex_out(int fd)
{
multiplex_out_fd = fd;
io_flush();
io_start_buffering(fd);
io_multiplexing_out = 1;
}
/* setup for multiplexing an error stream with the data stream */
void io_start_multiplex_in(int fd)
{
multiplex_in_fd = fd;
io_flush();
io_multiplexing_in = 1;
}
/* write an message to the multiplexed error stream */
int io_multiplex_write(enum logcode code, char *buf, size_t len)
{
if (!io_multiplexing_out) return 0;
io_flush();
stats.total_written += (len+4);
mplex_write(multiplex_out_fd, code, buf, len);
return 1;
}
/* write a message to the special error fd */
int io_error_write(int f, enum logcode code, char *buf, size_t len)
{
if (f == -1) return 0;
mplex_write(f, code, buf, len);
return 1;
}
/* stop output multiplexing */
void io_multiplexing_close(void)
{
io_multiplexing_out = 0;
}

View File

@@ -36,7 +36,7 @@
#endif
#ifndef HAVE_GETCWD
char *getcwd(char *buf, int size)
char *getcwd(char *buf, int size)
{
return getwd(buf);
}
@@ -44,9 +44,145 @@ char *getcwd(char *buf, int size)
#ifndef HAVE_WAITPID
pid_t waitpid(pid_t pid, int *statptr, int options)
pid_t waitpid(pid_t pid, int *statptr, int options)
{
#ifdef HAVE_WAIT4
return wait4(pid, statptr, options, NULL);
#else
/* If wait4 is also not available, try wait3 for SVR3 variants */
/* Less ideal because can't actually request a specific pid */
/* At least the WNOHANG option is supported */
/* Code borrowed from apache fragment written by dwd@bell-labs.com */
int tmp_pid, dummystat;;
if (kill(pid, 0) == -1) {
errno = ECHILD;
return -1;
}
if (statptr == NULL)
statptr = &dummystat;
while (((tmp_pid = wait3(statptr, options, 0)) != pid) &&
(tmp_pid != -1) && (tmp_pid != 0) && (pid != -1))
;
return tmp_pid;
#endif
}
#endif
#ifndef HAVE_MEMMOVE
void *memmove(void *dest, const void *src, size_t n)
{
bcopy((char *) src, (char *) dest, n);
return dest;
}
#endif
#ifndef HAVE_STRPBRK
/* Find the first ocurrence in S of any character in ACCEPT.
derived from glibc
*/
char *strpbrk(const char *s, const char *accept)
{
while (*s != '\0') {
const char *a = accept;
while (*a != '\0') {
if (*a++ == *s) return (char *)s;
}
++s;
}
return NULL;
}
#endif
#ifndef HAVE_STRLCPY
/* Like strncpy but does not 0 fill the buffer and always null
* terminates. bufsize is the size of the destination buffer.
*
* Returns the index of the terminating byte. */
size_t strlcpy(char *d, const char *s, size_t bufsize)
{
size_t len = strlen(s);
size_t ret = len;
if (bufsize <= 0) return 0;
if (len >= bufsize) len = bufsize-1;
memcpy(d, s, len);
d[len] = 0;
return ret;
}
#endif
#ifndef HAVE_STRLCAT
/* like strncat but does not 0 fill the buffer and always null
terminates. bufsize is the length of the buffer, which should
be one more than the maximum resulting string length */
size_t strlcat(char *d, const char *s, size_t bufsize)
{
size_t len1 = strlen(d);
size_t len2 = strlen(s);
size_t ret = len1 + len2;
if (len1+len2 >= bufsize) {
len2 = bufsize - (len1+1);
}
if (len2 > 0) {
memcpy(d+len1, s, len2);
d[len1+len2] = 0;
}
return ret;
}
#endif
#ifdef REPLACE_INET_NTOA
char *rep_inet_ntoa(struct in_addr ip)
{
unsigned char *p = (unsigned char *)&ip.s_addr;
static char buf[18];
#if WORDS_BIGENDIAN
snprintf(buf, 18, "%d.%d.%d.%d",
(int)p[0], (int)p[1], (int)p[2], (int)p[3]);
#else
snprintf(buf, 18, "%d.%d.%d.%d",
(int)p[3], (int)p[2], (int)p[1], (int)p[0]);
#endif
return buf;
}
#endif
#ifdef REPLACE_INET_ATON
int inet_aton(const char *cp, struct in_addr *inp)
{
unsigned int a1, a2, a3, a4;
unsigned long ret;
if (strcmp(cp, "255.255.255.255") == 0) {
inp->s_addr = (unsigned) -1;
return 0;
}
if (sscanf(cp, "%u.%u.%u.%u", &a1, &a2, &a3, &a4) != 4 ||
a1 > 255 || a2 > 255 || a3 > 255 || a4 > 255) {
return 0;
}
ret = (a1 << 24) | (a2 << 16) | (a3 << 8) | a4;
inp->s_addr = htonl(ret);
if (inp->s_addr == (unsigned) -1) {
return 0;
}
return 1;
}
#endif
/* some systems don't take the 2nd argument */
int sys_gettimeofday(struct timeval *tv)
{
#if HAVE_GETTIMEOFDAY_TZ
return gettimeofday(tv, NULL);
#else
return gettimeofday(tv);
#endif
}

View File

@@ -1,33 +1,60 @@
#include "../rsync.h"
#ifndef HAVE_FNMATCH
/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
/* ----- THE FOLLOWING UP TO 'END' is glibc-2.1.2 posix/fnmatch.c
except for the parts with '#if 0' */
NOTE: The canonical source of this file is maintained with the GNU C Library.
Bugs can be reported to bug-glibc@prep.ai.mit.edu.
/* Copyright (C) 1991, 92, 93, 96, 97, 98, 99 Free Software Foundation, Inc.
This file is part of the GNU C Library.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
You should have received a copy of the GNU Library General Public
License along with this library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#if defined (STDC_HEADERS) || !defined (isascii)
#define ISASCII(c) 1
#else
#define ISASCII(c) isascii(c)
#if 0 /* header files included better by ../rsync.h */
#if HAVE_CONFIG_H
# include <config.h>
#endif
#define ISUPPER(c) (ISASCII (c) && isupper (c))
/* Enable GNU extensions in fnmatch.h. */
#ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
#endif
#include <errno.h>
#include <fnmatch.h>
#include <ctype.h>
#if HAVE_STRING_H || defined _LIBC
# include <string.h>
#else
# include <strings.h>
#endif
#if defined STDC_HEADERS || defined _LIBC
# include <stdlib.h>
#endif
#endif /* 0 */
/* For platform which support the ISO C amendement 1 functionality we
support user defined character classes. */
#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */
# include <wchar.h>
# include <wctype.h>
#endif
/* Comment out all this code if we are using the GNU C Library, and are not
actually compiling the library itself. This code is part of the GNU C
@@ -37,23 +64,95 @@ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
program understand `configure --with-gnu-libc' and omit the object files,
it is simpler to just do this in the source for each such file. */
#if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS)
extern int errno;
#if 1
# if defined STDC_HEADERS || !defined isascii
# define ISASCII(c) 1
# else
# define ISASCII(c) isascii(c)
# endif
#ifdef isblank
# define ISBLANK(c) (ISASCII (c) && isblank (c))
#else
# define ISBLANK(c) ((c) == ' ' || (c) == '\t')
#endif
#ifdef isgraph
# define ISGRAPH(c) (ISASCII (c) && isgraph (c))
#else
# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
#endif
#define ISPRINT(c) (ISASCII (c) && isprint (c))
#define ISDIGIT(c) (ISASCII (c) && isdigit (c))
#define ISALNUM(c) (ISASCII (c) && isalnum (c))
#define ISALPHA(c) (ISASCII (c) && isalpha (c))
#define ISCNTRL(c) (ISASCII (c) && iscntrl (c))
#define ISLOWER(c) (ISASCII (c) && islower (c))
#define ISPUNCT(c) (ISASCII (c) && ispunct (c))
#define ISSPACE(c) (ISASCII (c) && isspace (c))
#define ISUPPER(c) (ISASCII (c) && isupper (c))
#define ISXDIGIT(c) (ISASCII (c) && isxdigit (c))
# define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
/* The GNU C library provides support for user-defined character classes
and the functions from ISO C amendement 1. */
# ifdef CHARCLASS_NAME_MAX
# define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX
# else
/* This shouldn't happen but some implementation might still have this
problem. Use a reasonable default value. */
# define CHAR_CLASS_MAX_LENGTH 256
# endif
# ifdef _LIBC
# define IS_CHAR_CLASS(string) __wctype (string)
# else
# define IS_CHAR_CLASS(string) wctype (string)
# endif
# else
# define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */
# define IS_CHAR_CLASS(string) \
(STREQ (string, "alpha") || STREQ (string, "upper") \
|| STREQ (string, "lower") || STREQ (string, "digit") \
|| STREQ (string, "alnum") || STREQ (string, "xdigit") \
|| STREQ (string, "space") || STREQ (string, "print") \
|| STREQ (string, "punct") || STREQ (string, "graph") \
|| STREQ (string, "cntrl") || STREQ (string, "blank"))
# endif
/* Avoid depending on library functions or files
whose names are inconsistent. */
# if !defined _LIBC && !defined getenv
extern char *getenv ();
# endif
# ifndef errno
extern int errno;
# endif
/* Match STRING against the filename pattern PATTERN, returning zero if
it matches, nonzero if not. */
int
fnmatch (pattern, string, flags)
const char *pattern;
const char *string;
int flags;
static int
#ifdef _LIBC
internal_function
#endif
internal_fnmatch (const char *pattern, const char *string,
int no_leading_period, int flags)
{
register const char *p = pattern, *n = string;
register char c;
register unsigned char c;
/* Note that this evalutes C many times. */
#define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
/* Note that this evaluates C many times. */
# ifdef _LIBC
# define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c))
# else
# define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
# endif
while ((c = *p++) != '\0')
{
@@ -64,10 +163,11 @@ fnmatch (pattern, string, flags)
case '?':
if (*n == '\0')
return FNM_NOMATCH;
else if ((flags & FNM_FILE_NAME) && *n == '/')
else if (*n == '/' && (flags & FNM_FILE_NAME))
return FNM_NOMATCH;
else if ((flags & FNM_PERIOD) && *n == '.' &&
(n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
else if (*n == '.' && no_leading_period
&& (n == string
|| (n[-1] == '/' && (flags & FNM_FILE_NAME))))
return FNM_NOMATCH;
break;
@@ -75,95 +175,245 @@ fnmatch (pattern, string, flags)
if (!(flags & FNM_NOESCAPE))
{
c = *p++;
if (c == '\0')
/* Trailing \ loses. */
return FNM_NOMATCH;
c = FOLD (c);
}
if (FOLD (*n) != c)
if (FOLD ((unsigned char) *n) != c)
return FNM_NOMATCH;
break;
case '*':
if ((flags & FNM_PERIOD) && *n == '.' &&
(n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
if (*n == '.' && no_leading_period
&& (n == string
|| (n[-1] == '/' && (flags & FNM_FILE_NAME))))
return FNM_NOMATCH;
for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
if (((flags & FNM_FILE_NAME) && *n == '/') ||
(c == '?' && *n == '\0'))
return FNM_NOMATCH;
for (c = *p++; c == '?' || c == '*'; c = *p++)
{
if (*n == '/' && (flags & FNM_FILE_NAME))
/* A slash does not match a wildcard under FNM_FILE_NAME. */
return FNM_NOMATCH;
else if (c == '?')
{
/* A ? needs to match one character. */
if (*n == '\0')
/* There isn't another character; no match. */
return FNM_NOMATCH;
else
/* One character of the string is consumed in matching
this ? wildcard, so *??? won't match if there are
less than three characters. */
++n;
}
}
if (c == '\0')
return 0;
/* The wildcard(s) is/are the last element of the pattern.
If the name is a file name and contains another slash
this does mean it cannot match. */
return ((flags & FNM_FILE_NAME) && strchr (n, '/') != NULL
? FNM_NOMATCH : 0);
else
{
const char *endp;
{
char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
c1 = FOLD (c1);
for (--p; *n != '\0'; ++n)
if ((c == '[' || FOLD (*n) == c1) &&
fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
return 0;
return FNM_NOMATCH;
}
#if 0
endp = __strchrnul (n, (flags & FNM_FILE_NAME) ? '/' : '\0');
#else
/* replace call to internal glibc function with equivalent */
if (!(flags & FNM_FILE_NAME) || ((endp = strchr(n, '/')) == NULL))
endp = n + strlen(n);
#endif
if (c == '[')
{
int flags2 = ((flags & FNM_FILE_NAME)
? flags : (flags & ~FNM_PERIOD));
for (--p; n < endp; ++n)
if (internal_fnmatch (p, n,
(no_leading_period
&& (n == string
|| (n[-1] == '/'
&& (flags
& FNM_FILE_NAME)))),
flags2)
== 0)
return 0;
}
else if (c == '/' && (flags & FNM_FILE_NAME))
{
while (*n != '\0' && *n != '/')
++n;
if (*n == '/'
&& (internal_fnmatch (p, n + 1, flags & FNM_PERIOD,
flags) == 0))
return 0;
}
else
{
int flags2 = ((flags & FNM_FILE_NAME)
? flags : (flags & ~FNM_PERIOD));
if (c == '\\' && !(flags & FNM_NOESCAPE))
c = *p;
c = FOLD (c);
for (--p; n < endp; ++n)
if (FOLD ((unsigned char) *n) == c
&& (internal_fnmatch (p, n,
(no_leading_period
&& (n == string
|| (n[-1] == '/'
&& (flags
& FNM_FILE_NAME)))),
flags2) == 0))
return 0;
}
}
/* If we come here no match is possible with the wildcard. */
return FNM_NOMATCH;
case '[':
{
/* Nonzero if the sense of the character class is inverted. */
static int posixly_correct;
register int not;
char cold;
if (posixly_correct == 0)
posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
if (*n == '\0')
return FNM_NOMATCH;
if ((flags & FNM_PERIOD) && *n == '.' &&
(n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
if (*n == '.' && no_leading_period && (n == string
|| (n[-1] == '/'
&& (flags
& FNM_FILE_NAME))))
return FNM_NOMATCH;
not = (*p == '!' || *p == '^');
if (*n == '/' && (flags & FNM_FILE_NAME))
/* `/' cannot be matched. */
return FNM_NOMATCH;
not = (*p == '!' || (posixly_correct < 0 && *p == '^'));
if (not)
++p;
c = *p++;
for (;;)
{
register char cstart = c, cend = c;
unsigned char fn = FOLD ((unsigned char) *n);
if (!(flags & FNM_NOESCAPE) && c == '\\')
cstart = cend = *p++;
{
if (*p == '\0')
return FNM_NOMATCH;
c = FOLD ((unsigned char) *p);
++p;
cstart = cend = FOLD (cstart);
if (c == fn)
goto matched;
}
else if (c == '[' && *p == ':')
{
/* Leave room for the null. */
char str[CHAR_CLASS_MAX_LENGTH + 1];
size_t c1 = 0;
# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
wctype_t wt;
# endif
const char *startp = p;
if (c == '\0')
for (;;)
{
if (c1 == CHAR_CLASS_MAX_LENGTH)
/* The name is too long and therefore the pattern
is ill-formed. */
return FNM_NOMATCH;
c = *++p;
if (c == ':' && p[1] == ']')
{
p += 2;
break;
}
if (c < 'a' || c >= 'z')
{
/* This cannot possibly be a character class name.
Match it as a normal range. */
p = startp;
c = '[';
goto normal_bracket;
}
str[c1++] = c;
}
str[c1] = '\0';
# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
wt = IS_CHAR_CLASS (str);
if (wt == 0)
/* Invalid character class name. */
return FNM_NOMATCH;
if (__iswctype (__btowc ((unsigned char) *n), wt))
goto matched;
# else
if ((STREQ (str, "alnum") && ISALNUM ((unsigned char) *n))
|| (STREQ (str, "alpha") && ISALPHA ((unsigned char) *n))
|| (STREQ (str, "blank") && ISBLANK ((unsigned char) *n))
|| (STREQ (str, "cntrl") && ISCNTRL ((unsigned char) *n))
|| (STREQ (str, "digit") && ISDIGIT ((unsigned char) *n))
|| (STREQ (str, "graph") && ISGRAPH ((unsigned char) *n))
|| (STREQ (str, "lower") && ISLOWER ((unsigned char) *n))
|| (STREQ (str, "print") && ISPRINT ((unsigned char) *n))
|| (STREQ (str, "punct") && ISPUNCT ((unsigned char) *n))
|| (STREQ (str, "space") && ISSPACE ((unsigned char) *n))
|| (STREQ (str, "upper") && ISUPPER ((unsigned char) *n))
|| (STREQ (str, "xdigit") && ISXDIGIT ((unsigned char) *n)))
goto matched;
# endif
}
else if (c == '\0')
/* [ (unterminated) loses. */
return FNM_NOMATCH;
c = *p++;
c = FOLD (c);
if ((flags & FNM_FILE_NAME) && c == '/')
/* [/] can never match. */
return FNM_NOMATCH;
if (c == '-' && *p != ']')
else
{
cend = *p++;
if (!(flags & FNM_NOESCAPE) && cend == '\\')
cend = *p++;
if (cend == '\0')
return FNM_NOMATCH;
cend = FOLD (cend);
normal_bracket:
if (FOLD (c) == fn)
goto matched;
cold = c;
c = *p++;
}
if (FOLD (*n) >= cstart && FOLD (*n) <= cend)
goto matched;
if (c == '-' && *p != ']')
{
/* It is a range. */
unsigned char cend = *p++;
if (!(flags & FNM_NOESCAPE) && cend == '\\')
cend = *p++;
if (cend == '\0')
return FNM_NOMATCH;
if (cold <= fn && fn <= FOLD (cend))
goto matched;
c = *p++;
}
}
if (c == ']')
break;
}
if (!not)
return FNM_NOMATCH;
break;
matched:;
matched:
/* Skip the rest of the [...] that already matched. */
while (c != ']')
{
@@ -173,8 +423,21 @@ fnmatch (pattern, string, flags)
c = *p++;
if (!(flags & FNM_NOESCAPE) && c == '\\')
/* XXX 1003.2d11 is unclear if this is right. */
++p;
{
if (*p == '\0')
return FNM_NOMATCH;
/* XXX 1003.2d11 is unclear if this is right. */
++p;
}
else if (c == '[' && *p == ':')
{
do
if (*++p == '\0')
return FNM_NOMATCH;
while (*p != ':' || p[1] == ']');
p += 2;
c = *p;
}
}
if (not)
return FNM_NOMATCH;
@@ -182,7 +445,7 @@ fnmatch (pattern, string, flags)
break;
default:
if (c != FOLD (*n))
if (c != FOLD ((unsigned char) *n))
return FNM_NOMATCH;
}
@@ -197,8 +460,23 @@ fnmatch (pattern, string, flags)
return 0;
return FNM_NOMATCH;
# undef FOLD
}
int
fnmatch (pattern, string, flags)
const char *pattern;
const char *string;
int flags;
{
return internal_fnmatch (pattern, string, flags & FNM_PERIOD, flags);
}
#endif /* _LIBC or not __GNU_LIBRARY__. */
/* ----- END glibc-2.1.2 posix/fnmatch.c */
#else /* HAVE_FNMATCH */
void fnmatch_dummy(void) {}
#endif

View File

@@ -1,41 +1,48 @@
/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
/* Copyright (C) 1991, 92, 93, 96, 97, 98 Free Software Foundation, Inc.
This file is part of the GNU C Library.
NOTE: The canonical source of this file is maintained with the GNU C Library.
Bugs can be reported to bug-glibc@prep.ai.mit.edu.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#ifndef _FNMATCH_H
#define _FNMATCH_H 1
#ifdef __cplusplus
extern "C" {
#endif
#if defined (__cplusplus) || (defined (__STDC__) && __STDC__)
#undef __P
#define __P(protos) protos
#if defined __cplusplus || (defined __STDC__ && __STDC__) || defined WINDOWS32
# if !defined __GLIBC__ || !defined __P
# undef __P
# define __P(protos) protos
# endif
#else /* Not C++ or ANSI C. */
#undef __P
#define __P(protos) ()
# undef __P
# define __P(protos) ()
/* We can get away without defining `const' here only because in this file
it is used only inside the prototype for `fnmatch', which is elided in
non-ANSI C where `const' is problematical. */
#endif /* C++ or ANSI C. */
#ifndef const
# if (defined __STDC__ && __STDC__) || defined __cplusplus
# define __const const
# else
# define __const
# endif
#endif
/* We #undef these before defining them because some losing systems
(HP-UX A.08.07 for example) define these in <unistd.h>. */
@@ -48,18 +55,30 @@ extern "C" {
#define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */
#define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */
#if !defined (_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined (_GNU_SOURCE)
#define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */
#define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */
#define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */
#ifndef FNM_FILE_NAME
# define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */
#endif
#ifndef FNM_LEADING_DIR
# define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */
#endif
#ifndef FNM_CASEFOLD
# define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */
#endif
/* Value returned by `fnmatch' if STRING does not match PATTERN. */
#define FNM_NOMATCH 1
/* This value is returned if the implementation does not support
`fnmatch'. Since this is not the case here it will never be
returned but the conformance test suites still require the symbol
to be defined. */
#ifdef _XOPEN_SOURCE
# define FNM_NOSYS (-1)
#endif
/* Match STRING against the filename pattern PATTERN,
returning zero if it matches, FNM_NOMATCH if not. */
extern int fnmatch __P ((const char *__pattern, const char *__string,
extern int fnmatch __P ((__const char *__pattern, __const char *__string,
int __flags));
#ifdef __cplusplus

View File

@@ -1,751 +0,0 @@
#include "../rsync.h"
#ifndef HAVE_GETOPT_LONG
/* Getopt for GNU.
NOTE: getopt is now part of the C library, so if you don't know what
"Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
before changing it!
Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94
Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
Ditto for AIX 3.2 and <stdlib.h>. */
#ifndef _NO_PROTO
#define _NO_PROTO
#endif
/* Comment out all this code if we are using the GNU C Library, and are not
actually compiling the library itself. This code is part of the GNU C
Library, but also included in many other GNU distributions. Compiling
and linking in this code is a waste when using the GNU C library
(especially if it is a shared library). Rather than having every GNU
program understand `configure --with-gnu-libc' and omit the object files,
it is simpler to just do this in the source for each such file. */
#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
/* This is for other GNU distributions with internationalized messages.
The GNU C Library itself does not yet support such messages. */
#if HAVE_LIBINTL_H
# include <libintl.h>
#else
# define gettext(msgid) (msgid)
#endif
/* This version of `getopt' appears to the caller like standard Unix `getopt'
but it behaves differently for the user, since it allows the user
to intersperse the options with the other arguments.
As `getopt' works, it permutes the elements of ARGV so that,
when it is done, all the options precede everything else. Thus
all application programs are extended to handle flexible argument order.
Setting the environment variable POSIXLY_CORRECT disables permutation.
Then the behavior is completely standard.
GNU application programs can use a third alternative mode in which
they can distinguish the relative order of options and other arguments. */
/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
char *optarg = NULL;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns EOF, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
/* XXX 1003.2 says this must be 1 before any call. */
int optind = 0;
/* The next char to be scanned in the option-element
in which the last option character we returned was found.
This allows us to pick up the scan where we left off.
If this is zero, or a null string, it means resume the scan
by advancing to the next ARGV-element. */
static char *nextchar;
/* Callers store zero here to inhibit the error message
for unrecognized options. */
int opterr = 1;
/* Set to an option character which was unrecognized.
This must be initialized on some systems to avoid linking in the
system's own getopt implementation. */
int optopt = '?';
/* Describe how to deal with options that follow non-option ARGV-elements.
If the caller did not specify anything,
the default is REQUIRE_ORDER if the environment variable
POSIXLY_CORRECT is defined, PERMUTE otherwise.
REQUIRE_ORDER means don't recognize them as options;
stop option processing when the first non-option is seen.
This is what Unix does.
This mode of operation is selected by either setting the environment
variable POSIXLY_CORRECT, or using `+' as the first character
of the list of option characters.
PERMUTE is the default. We permute the contents of ARGV as we scan,
so that eventually all the non-options are at the end. This allows options
to be given in any order, even with programs that were not written to
expect this.
RETURN_IN_ORDER is an option available to programs that were written
to expect options and other ARGV-elements in any order and that care about
the ordering of the two. We describe each non-option ARGV-element
as if it were the argument of an option with character code 1.
Using `-' as the first character of the list of option characters
selects this mode of operation.
The special argument `--' forces an end of option-scanning regardless
of the value of `ordering'. In the case of RETURN_IN_ORDER, only
`--' can cause `getopt' to return EOF with `optind' != ARGC. */
static enum
{
REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
} ordering;
/* Value of POSIXLY_CORRECT environment variable. */
static char *posixly_correct;
#ifdef __GNU_LIBRARY__
/* We want to avoid inclusion of string.h with non-GNU libraries
because there are many ways it can cause trouble.
On some systems, it contains special magic macros that don't work
in GCC. */
#include <string.h>
#define my_index strchr
#else
/* Avoid depending on library functions or files
whose names are inconsistent. */
char *getenv ();
static char *
my_index (str, chr)
const char *str;
int chr;
{
while (*str)
{
if (*str == chr)
return (char *) str;
str++;
}
return 0;
}
/* If using GCC, we can safely declare strlen this way.
If not using GCC, it is ok not to declare it. */
#ifdef __GNUC__
/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
That was relevant to code that was here before. */
#if !defined (__STDC__) || !__STDC__
/* gcc with -traditional declares the built-in strlen to return int,
and has done so at least since version 2.4.5. -- rms. */
extern int strlen (const char *);
#endif /* not __STDC__ */
#endif /* __GNUC__ */
#endif /* not __GNU_LIBRARY__ */
/* Handle permutation of arguments. */
/* Describe the part of ARGV that contains non-options that have
been skipped. `first_nonopt' is the index in ARGV of the first of them;
`last_nonopt' is the index after the last of them. */
static int first_nonopt;
static int last_nonopt;
/* Exchange two adjacent subsequences of ARGV.
One subsequence is elements [first_nonopt,last_nonopt)
which contains all the non-options that have been skipped so far.
The other is elements [last_nonopt,optind), which contains all
the options processed since those non-options were skipped.
`first_nonopt' and `last_nonopt' are relocated so that they describe
the new indices of the non-options in ARGV after they are moved. */
static void
exchange (argv)
char **argv;
{
int bottom = first_nonopt;
int middle = last_nonopt;
int top = optind;
char *tem;
/* Exchange the shorter segment with the far end of the longer segment.
That puts the shorter segment into the right place.
It leaves the longer segment in the right place overall,
but it consists of two parts that need to be swapped next. */
while (top > middle && middle > bottom)
{
if (top - middle > middle - bottom)
{
/* Bottom segment is the short one. */
int len = middle - bottom;
register int i;
/* Swap it with the top part of the top segment. */
for (i = 0; i < len; i++)
{
tem = argv[bottom + i];
argv[bottom + i] = argv[top - (middle - bottom) + i];
argv[top - (middle - bottom) + i] = tem;
}
/* Exclude the moved bottom segment from further swapping. */
top -= len;
}
else
{
/* Top segment is the short one. */
int len = top - middle;
register int i;
/* Swap it with the bottom part of the bottom segment. */
for (i = 0; i < len; i++)
{
tem = argv[bottom + i];
argv[bottom + i] = argv[middle + i];
argv[middle + i] = tem;
}
/* Exclude the moved top segment from further swapping. */
bottom += len;
}
}
/* Update records for the slots the non-options now occupy. */
first_nonopt += (optind - last_nonopt);
last_nonopt = optind;
}
/* Initialize the internal data when the first call is made. */
static const char *
_getopt_initialize (optstring)
const char *optstring;
{
/* Start processing options with ARGV-element 1 (since ARGV-element 0
is the program name); the sequence of previously skipped
non-option ARGV-elements is empty. */
first_nonopt = last_nonopt = optind = 1;
nextchar = NULL;
posixly_correct = getenv ("POSIXLY_CORRECT");
/* Determine how to handle the ordering of options and nonoptions. */
if (optstring[0] == '-')
{
ordering = RETURN_IN_ORDER;
++optstring;
}
else if (optstring[0] == '+')
{
ordering = REQUIRE_ORDER;
++optstring;
}
else if (posixly_correct != NULL)
ordering = REQUIRE_ORDER;
else
ordering = PERMUTE;
return optstring;
}
/* Scan elements of ARGV (whose length is ARGC) for option characters
given in OPTSTRING.
If an element of ARGV starts with '-', and is not exactly "-" or "--",
then it is an option element. The characters of this element
(aside from the initial '-') are option characters. If `getopt'
is called repeatedly, it returns successively each of the option characters
from each of the option elements.
If `getopt' finds another option character, it returns that character,
updating `optind' and `nextchar' so that the next call to `getopt' can
resume the scan with the following option character or ARGV-element.
If there are no more option characters, `getopt' returns `EOF'.
Then `optind' is the index in ARGV of the first ARGV-element
that is not an option. (The ARGV-elements have been permuted
so that those that are not options now come last.)
OPTSTRING is a string containing the legitimate option characters.
If an option character is seen that is not listed in OPTSTRING,
return '?' after printing an error message. If you set `opterr' to
zero, the error message is suppressed but we still return '?'.
If a char in OPTSTRING is followed by a colon, that means it wants an arg,
so the following text in the same ARGV-element, or the text of the following
ARGV-element, is returned in `optarg'. Two colons mean an option that
wants an optional arg; if there is text in the current ARGV-element,
it is returned in `optarg', otherwise `optarg' is set to zero.
If OPTSTRING starts with `-' or `+', it requests different methods of
handling the non-option ARGV-elements.
See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
Long-named options begin with `--' instead of `-'.
Their names may be abbreviated as long as the abbreviation is unique
or is an exact match for some defined option. If they have an
argument, it follows the option name in the same ARGV-element, separated
from the option name by a `=', or else the in next ARGV-element.
When `getopt' finds a long-named option, it returns 0 if that option's
`flag' field is nonzero, the value of the option's `val' field
if the `flag' field is zero.
The elements of ARGV aren't really const, because we permute them.
But we pretend they're const in the prototype to be compatible
with other systems.
LONGOPTS is a vector of `struct option' terminated by an
element containing a name which is zero.
LONGIND returns the index in LONGOPT of the long-named option found.
It is only valid when a long-named option has been found by the most
recent call.
If LONG_ONLY is nonzero, '-' as well as '--' can introduce
long-named options. */
int
_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
int argc;
char *const *argv;
const char *optstring;
const struct option *longopts;
int *longind;
int long_only;
{
optarg = NULL;
if (optind == 0)
optstring = _getopt_initialize (optstring);
if (nextchar == NULL || *nextchar == '\0')
{
/* Advance to the next ARGV-element. */
if (ordering == PERMUTE)
{
/* If we have just processed some options following some non-options,
exchange them so that the options come first. */
if (first_nonopt != last_nonopt && last_nonopt != optind)
exchange ((char **) argv);
else if (last_nonopt != optind)
first_nonopt = optind;
/* Skip any additional non-options
and extend the range of non-options previously skipped. */
while (optind < argc
&& (argv[optind][0] != '-' || argv[optind][1] == '\0'))
optind++;
last_nonopt = optind;
}
/* The special ARGV-element `--' means premature end of options.
Skip it like a null option,
then exchange with previous non-options as if it were an option,
then skip everything else like a non-option. */
if (optind != argc && !strcmp (argv[optind], "--"))
{
optind++;
if (first_nonopt != last_nonopt && last_nonopt != optind)
exchange ((char **) argv);
else if (first_nonopt == last_nonopt)
first_nonopt = optind;
last_nonopt = argc;
optind = argc;
}
/* If we have done all the ARGV-elements, stop the scan
and back over any non-options that we skipped and permuted. */
if (optind == argc)
{
/* Set the next-arg-index to point at the non-options
that we previously skipped, so the caller will digest them. */
if (first_nonopt != last_nonopt)
optind = first_nonopt;
return EOF;
}
/* If we have come to a non-option and did not permute it,
either stop the scan or describe it to the caller and pass it by. */
if ((argv[optind][0] != '-' || argv[optind][1] == '\0'))
{
if (ordering == REQUIRE_ORDER)
return EOF;
optarg = argv[optind++];
return 1;
}
/* We have found another option-ARGV-element.
Skip the initial punctuation. */
nextchar = (argv[optind] + 1
+ (longopts != NULL && argv[optind][1] == '-'));
}
/* Decode the current option-ARGV-element. */
/* Check whether the ARGV-element is a long option.
If long_only and the ARGV-element has the form "-f", where f is
a valid short option, don't consider it an abbreviated form of
a long option that starts with f. Otherwise there would be no
way to give the -f short option.
On the other hand, if there's a long option "fubar" and
the ARGV-element is "-fu", do consider that an abbreviation of
the long option, just like "--fu", and not "-f" with arg "u".
This distinction seems to be the most useful approach. */
if (longopts != NULL
&& (argv[optind][1] == '-'
|| (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
{
char *nameend;
const struct option *p;
const struct option *pfound = NULL;
int exact = 0;
int ambig = 0;
int indfound;
int option_index;
for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
/* Do nothing. */ ;
/* Test all long options for either exact match
or abbreviated matches. */
for (p = longopts, option_index = 0; p->name; p++, option_index++)
if (!strncmp (p->name, nextchar, nameend - nextchar))
{
if (nameend - nextchar == strlen (p->name))
{
/* Exact match found. */
pfound = p;
indfound = option_index;
exact = 1;
break;
}
else if (pfound == NULL)
{
/* First nonexact match found. */
pfound = p;
indfound = option_index;
}
else
/* Second or later nonexact match found. */
ambig = 1;
}
if (ambig && !exact)
{
if (opterr)
fprintf (stderr, gettext ("%s: option `%s' is ambiguous\n"),
argv[0], argv[optind]);
nextchar += strlen (nextchar);
optind++;
return '?';
}
if (pfound != NULL)
{
option_index = indfound;
optind++;
if (*nameend)
{
/* Don't test has_arg with >, because some C compilers don't
allow it to be used on enums. */
if (pfound->has_arg)
optarg = nameend + 1;
else
{
if (opterr)
if (argv[optind - 1][1] == '-')
/* --option */
fprintf (stderr,
gettext ("%s: option `--%s' doesn't allow an argument\n"),
argv[0], pfound->name);
else
/* +option or -option */
fprintf (stderr,
gettext ("%s: option `%c%s' doesn't allow an argument\n"),
argv[0], argv[optind - 1][0], pfound->name);
nextchar += strlen (nextchar);
return '?';
}
}
else if (pfound->has_arg == 1)
{
if (optind < argc)
optarg = argv[optind++];
else
{
if (opterr)
fprintf (stderr,
gettext ("%s: option `%s' requires an argument\n"),
argv[0], argv[optind - 1]);
nextchar += strlen (nextchar);
return optstring[0] == ':' ? ':' : '?';
}
}
nextchar += strlen (nextchar);
if (longind != NULL)
*longind = option_index;
if (pfound->flag)
{
*(pfound->flag) = pfound->val;
return 0;
}
return pfound->val;
}
/* Can't find it as a long option. If this is not getopt_long_only,
or the option starts with '--' or is not a valid short
option, then it's an error.
Otherwise interpret it as a short option. */
if (!long_only || argv[optind][1] == '-'
|| my_index (optstring, *nextchar) == NULL)
{
if (opterr)
{
if (argv[optind][1] == '-')
/* --option */
fprintf (stderr, gettext ("%s: unrecognized option `--%s'\n"),
argv[0], nextchar);
else
/* +option or -option */
fprintf (stderr, gettext ("%s: unrecognized option `%c%s'\n"),
argv[0], argv[optind][0], nextchar);
}
nextchar = (char *) "";
optind++;
return '?';
}
}
/* Look at and handle the next short option-character. */
{
char c = *nextchar++;
char *temp = my_index (optstring, c);
/* Increment `optind' when we start to process its last character. */
if (*nextchar == '\0')
++optind;
if (temp == NULL || c == ':')
{
if (opterr)
{
if (posixly_correct)
/* 1003.2 specifies the format of this message. */
fprintf (stderr, gettext ("%s: illegal option -- %c\n"),
argv[0], c);
else
fprintf (stderr, gettext ("%s: invalid option -- %c\n"),
argv[0], c);
}
optopt = c;
return '?';
}
if (temp[1] == ':')
{
if (temp[2] == ':')
{
/* This is an option that accepts an argument optionally. */
if (*nextchar != '\0')
{
optarg = nextchar;
optind++;
}
else
optarg = NULL;
nextchar = NULL;
}
else
{
/* This is an option that requires an argument. */
if (*nextchar != '\0')
{
optarg = nextchar;
/* If we end this ARGV-element by taking the rest as an arg,
we must advance to the next element now. */
optind++;
}
else if (optind == argc)
{
if (opterr)
{
/* 1003.2 specifies the format of this message. */
fprintf (stderr,
gettext ("%s: option requires an argument -- %c\n"),
argv[0], c);
}
optopt = c;
if (optstring[0] == ':')
c = ':';
else
c = '?';
}
else
/* We already incremented `optind' once;
increment it again when taking next ARGV-elt as argument. */
optarg = argv[optind++];
nextchar = NULL;
}
}
return c;
}
}
int
getopt (argc, argv, optstring)
int argc;
char *const *argv;
const char *optstring;
{
return _getopt_internal (argc, argv, optstring,
(const struct option *) 0,
(int *) 0,
0);
}
int
getopt_long (argc, argv, options, long_options, opt_index)
int argc;
char *const *argv;
const char *options;
const struct option *long_options;
int *opt_index;
{
return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
}
#endif /* _LIBC or not __GNU_LIBRARY__. */
#ifdef TEST
/* Compile with -DTEST to make an executable for use in testing
the above definition of `getopt'. */
int
main (argc, argv)
int argc;
char **argv;
{
int c;
int digit_optind = 0;
while (1)
{
int this_option_optind = optind ? optind : 1;
c = getopt (argc, argv, "abc:d:0123456789");
if (c == EOF)
break;
switch (c)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf ("option %c\n", c);
break;
case 'a':
printf ("option a\n");
break;
case 'b':
printf ("option b\n");
break;
case 'c':
printf ("option c with value `%s'\n", optarg);
break;
case '?':
break;
default:
printf ("?? getopt returned character code 0%o ??\n", c);
}
}
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\n");
}
exit (0);
}
#endif /* TEST */
#else /* HAVE_GETOPT_LONG */
void getopt_dummy(void) {}
#endif

View File

@@ -1,129 +0,0 @@
/* Declarations for getopt.
Copyright (C) 1989, 90, 91, 92, 93, 94 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef _GETOPT_H
#define _GETOPT_H 1
#ifdef __cplusplus
extern "C" {
#endif
/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
extern char *optarg;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns EOF, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
extern int optind;
/* Callers store zero here to inhibit the error message `getopt' prints
for unrecognized options. */
extern int opterr;
/* Set to an option character which was unrecognized. */
extern int optopt;
/* Describe the long-named options requested by the application.
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
of `struct option' terminated by an element containing a name which is
zero.
The field `has_arg' is:
no_argument (or 0) if the option does not take an argument,
required_argument (or 1) if the option requires an argument,
optional_argument (or 2) if the option takes an optional argument.
If the field `flag' is not NULL, it points to a variable that is set
to the value given in the field `val' when the option is found, but
left unchanged if the option is not found.
To have a long-named option do something other than set an `int' to
a compiled-in constant, such as set a value from `optarg', set the
option's `flag' field to zero and its `val' field to a nonzero
value (the equivalent single-letter option character, if there is
one). For long options that have a zero `flag' field, `getopt'
returns the contents of the `val' field. */
struct option
{
#if defined (__STDC__) && __STDC__
const char *name;
#else
char *name;
#endif
/* has_arg can't be an enum because some compilers complain about
type mismatches in all the code that assumes it is an int. */
int has_arg;
int *flag;
int val;
};
/* Names for the values of the `has_arg' field of `struct option'. */
#define no_argument 0
#define required_argument 1
#define optional_argument 2
#if defined (__STDC__) && __STDC__
#ifdef __GNU_LIBRARY__
/* Many other libraries have conflicting prototypes for getopt, with
differences in the consts, in stdlib.h. To avoid compilation
errors, only prototype getopt for the GNU C library. */
extern int getopt (int argc, char *const *argv, const char *shortopts);
#else /* not __GNU_LIBRARY__ */
extern int getopt ();
#endif /* __GNU_LIBRARY__ */
extern int getopt_long (int argc, char *const *argv, const char *shortopts,
const struct option *longopts, int *longind);
extern int getopt_long_only (int argc, char *const *argv,
const char *shortopts,
const struct option *longopts, int *longind);
/* Internal only. Users should not call this directly. */
extern int _getopt_internal (int argc, char *const *argv,
const char *shortopts,
const struct option *longopts, int *longind,
int long_only);
#else /* not __STDC__ */
extern int getopt ();
extern int getopt_long ();
extern int getopt_long_only ();
extern int _getopt_internal ();
#endif /* __STDC__ */
#ifdef __cplusplus
}
#endif
#endif /* _GETOPT_H */

184
lib/inet_ntop.c Normal file
View File

@@ -0,0 +1,184 @@
/*
* Copyright (C) 1996-2001 Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
* INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "rsync.h"
#define NS_INT16SZ 2
#define NS_IN6ADDRSZ 16
/*
* WARNING: Don't even consider trying to compile this on a system where
* sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
*/
static const char *inet_ntop4(const unsigned char *src, char *dst,
size_t size);
#ifdef AF_INET6
static const char *inet_ntop6(const unsigned char *src, char *dst,
size_t size);
#endif
/* char *
* isc_net_ntop(af, src, dst, size)
* convert a network format address to presentation format.
* return:
* pointer to presentation format address (`dst'), or NULL (see errno).
* author:
* Paul Vixie, 1996.
*/
const char *
inet_ntop(int af, const void *src, char *dst, size_t size)
{
switch (af) {
case AF_INET:
return (inet_ntop4(src, dst, size));
#ifdef AF_INET6
case AF_INET6:
return (inet_ntop6(src, dst, size));
#endif
default:
errno = EAFNOSUPPORT;
return (NULL);
}
/* NOTREACHED */
}
/* const char *
* inet_ntop4(src, dst, size)
* format an IPv4 address
* return:
* `dst' (as a const)
* notes:
* (1) uses no statics
* (2) takes a unsigned char* not an in_addr as input
* author:
* Paul Vixie, 1996.
*/
static const char *
inet_ntop4(const unsigned char *src, char *dst, size_t size)
{
static const char *fmt = "%u.%u.%u.%u";
char tmp[sizeof "255.255.255.255"];
if ((size_t)sprintf(tmp, fmt, src[0], src[1], src[2], src[3]) >= size)
{
errno = ENOSPC;
return (NULL);
}
strcpy(dst, tmp);
return (dst);
}
/* const char *
* isc_inet_ntop6(src, dst, size)
* convert IPv6 binary address into presentation (printable) format
* author:
* Paul Vixie, 1996.
*/
#ifdef AF_INET6
static const char *
inet_ntop6(const unsigned char *src, char *dst, size_t size)
{
/*
* Note that int32_t and int16_t need only be "at least" large enough
* to contain a value of the specified size. On some systems, like
* Crays, there is no such thing as an integer variable with 16 bits.
* Keep this in mind if you think this function should have been coded
* to use pointer overlays. All the world's not a VAX.
*/
char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
struct { int base, len; } best, cur;
unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ];
int i;
/*
* Preprocess:
* Copy the input (bytewise) array into a wordwise array.
* Find the longest run of 0x00's in src[] for :: shorthanding.
*/
memset(words, '\0', sizeof words);
for (i = 0; i < NS_IN6ADDRSZ; i++)
words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
best.base = -1;
cur.base = -1;
for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
if (words[i] == 0) {
if (cur.base == -1)
cur.base = i, cur.len = 1;
else
cur.len++;
} else {
if (cur.base != -1) {
if (best.base == -1 || cur.len > best.len)
best = cur;
cur.base = -1;
}
}
}
if (cur.base != -1) {
if (best.base == -1 || cur.len > best.len)
best = cur;
}
if (best.base != -1 && best.len < 2)
best.base = -1;
/*
* Format the result.
*/
tp = tmp;
for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
/* Are we inside the best run of 0x00's? */
if (best.base != -1 && i >= best.base &&
i < (best.base + best.len)) {
if (i == best.base)
*tp++ = ':';
continue;
}
/* Are we following an initial run of 0x00s or any real hex? */
if (i != 0)
*tp++ = ':';
/* Is this address an encapsulated IPv4? */
if (i == 6 && best.base == 0 &&
(best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
if (!inet_ntop4(src+12, tp,
sizeof tmp - (tp - tmp)))
return (NULL);
tp += strlen(tp);
break;
}
tp += sprintf(tp, "%x", words[i]);
}
/* Was it a trailing run of 0x00's? */
if (best.base != -1 && (best.base + best.len) ==
(NS_IN6ADDRSZ / NS_INT16SZ))
*tp++ = ':';
*tp++ = '\0';
/*
* Check for overflow, copy, and we're done.
*/
if ((size_t)(tp - tmp) > size) {
errno = ENOSPC;
return (NULL);
}
strcpy(dst, tmp);
return (dst);
}
#endif /* AF_INET6 */

210
lib/inet_pton.c Normal file
View File

@@ -0,0 +1,210 @@
/*
* Copyright (C) 1996-2001 Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
* INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "rsync.h"
#define NS_INT16SZ 2
#define NS_INADDRSZ 4
#define NS_IN6ADDRSZ 16
/*
* WARNING: Don't even consider trying to compile this on a system where
* sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
*/
static int inet_pton4(const char *src, unsigned char *dst);
static int inet_pton6(const char *src, unsigned char *dst);
/* int
* isc_net_pton(af, src, dst)
* convert from presentation format (which usually means ASCII printable)
* to network format (which is usually some kind of binary format).
* return:
* 1 if the address was valid for the specified address family
* 0 if the address wasn't valid (`dst' is untouched in this case)
* -1 if some other error occurred (`dst' is untouched in this case, too)
* author:
* Paul Vixie, 1996.
*/
int
inet_pton(int af,
const char *src,
void *dst)
{
switch (af) {
case AF_INET:
return (inet_pton4(src, dst));
#ifdef INET6
case AF_INET6:
return (inet_pton6(src, dst));
#endif
default:
errno = EAFNOSUPPORT;
return (-1);
}
/* NOTREACHED */
}
/* int
* inet_pton4(src, dst)
* like inet_aton() but without all the hexadecimal and shorthand.
* return:
* 1 if `src' is a valid dotted quad, else 0.
* notice:
* does not touch `dst' unless it's returning 1.
* author:
* Paul Vixie, 1996.
*/
static int
inet_pton4(src, dst)
const char *src;
unsigned char *dst;
{
static const char digits[] = "0123456789";
int saw_digit, octets, ch;
unsigned char tmp[NS_INADDRSZ], *tp;
saw_digit = 0;
octets = 0;
*(tp = tmp) = 0;
while ((ch = *src++) != '\0') {
const char *pch;
if ((pch = strchr(digits, ch)) != NULL) {
unsigned int new = *tp * 10 + (pch - digits);
if (new > 255)
return (0);
*tp = new;
if (! saw_digit) {
if (++octets > 4)
return (0);
saw_digit = 1;
}
} else if (ch == '.' && saw_digit) {
if (octets == 4)
return (0);
*++tp = 0;
saw_digit = 0;
} else
return (0);
}
if (octets < 4)
return (0);
memcpy(dst, tmp, NS_INADDRSZ);
return (1);
}
/* int
* inet_pton6(src, dst)
* convert presentation level address to network order binary form.
* return:
* 1 if `src' is a valid [RFC1884 2.2] address, else 0.
* notice:
* (1) does not touch `dst' unless it's returning 1.
* (2) :: in a full address is silently ignored.
* credit:
* inspired by Mark Andrews.
* author:
* Paul Vixie, 1996.
*/
#ifdef INET6
static int
inet_pton6(src, dst)
const char *src;
unsigned char *dst;
{
static const char xdigits_l[] = "0123456789abcdef",
xdigits_u[] = "0123456789ABCDEF";
unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
const char *xdigits, *curtok;
int ch, saw_xdigit;
unsigned int val;
memset((tp = tmp), '\0', NS_IN6ADDRSZ);
endp = tp + NS_IN6ADDRSZ;
colonp = NULL;
/* Leading :: requires some special handling. */
if (*src == ':')
if (*++src != ':')
return (0);
curtok = src;
saw_xdigit = 0;
val = 0;
while ((ch = *src++) != '\0') {
const char *pch;
if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
pch = strchr((xdigits = xdigits_u), ch);
if (pch != NULL) {
val <<= 4;
val |= (pch - xdigits);
if (val > 0xffff)
return (0);
saw_xdigit = 1;
continue;
}
if (ch == ':') {
curtok = src;
if (!saw_xdigit) {
if (colonp)
return (0);
colonp = tp;
continue;
}
if (tp + NS_INT16SZ > endp)
return (0);
*tp++ = (unsigned char) (val >> 8) & 0xff;
*tp++ = (unsigned char) val & 0xff;
saw_xdigit = 0;
val = 0;
continue;
}
if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
inet_pton4(curtok, tp) > 0) {
tp += NS_INADDRSZ;
saw_xdigit = 0;
break; /* '\0' was seen by inet_pton4(). */
}
return (0);
}
if (saw_xdigit) {
if (tp + NS_INT16SZ > endp)
return (0);
*tp++ = (unsigned char) (val >> 8) & 0xff;
*tp++ = (unsigned char) val & 0xff;
}
if (colonp != NULL) {
/*
* Since some memmove()'s erroneously fail to handle
* overlapping regions, we'll do the shift by hand.
*/
const int n = tp - colonp;
int i;
for (i = 1; i <= n; i++) {
endp[- i] = colonp[n - i];
colonp[n - i] = 0;
}
tp = endp;
}
if (tp != endp)
return (0);
memcpy(dst, tmp, NS_IN6ADDRSZ);
return (1);
}
#endif

256
lib/mdfour.c Normal file
View File

@@ -0,0 +1,256 @@
/*
Unix SMB/Netbios implementation.
Version 1.9.
a implementation of MD4 designed for use in the SMB authentication protocol
Copyright (C) Andrew Tridgell 1997-1998.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "rsync.h"
/* NOTE: This code makes no attempt to be fast!
It assumes that a int is at least 32 bits long
*/
static struct mdfour *m;
#define MASK32 (0xffffffff)
#define F(X,Y,Z) ((((X)&(Y)) | ((~(X))&(Z))))
#define G(X,Y,Z) ((((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z))))
#define H(X,Y,Z) (((X)^(Y)^(Z)))
#define lshift(x,s) (((((x)<<(s))&MASK32) | (((x)>>(32-(s)))&MASK32)))
#define ROUND1(a,b,c,d,k,s) a = lshift((a + F(b,c,d) + M[k])&MASK32, s)
#define ROUND2(a,b,c,d,k,s) a = lshift((a + G(b,c,d) + M[k] + 0x5A827999)&MASK32,s)
#define ROUND3(a,b,c,d,k,s) a = lshift((a + H(b,c,d) + M[k] + 0x6ED9EBA1)&MASK32,s)
/* this applies md4 to 64 byte chunks */
static void mdfour64(uint32 *M)
{
uint32 AA, BB, CC, DD;
uint32 A,B,C,D;
A = m->A; B = m->B; C = m->C; D = m->D;
AA = A; BB = B; CC = C; DD = D;
ROUND1(A,B,C,D, 0, 3); ROUND1(D,A,B,C, 1, 7);
ROUND1(C,D,A,B, 2, 11); ROUND1(B,C,D,A, 3, 19);
ROUND1(A,B,C,D, 4, 3); ROUND1(D,A,B,C, 5, 7);
ROUND1(C,D,A,B, 6, 11); ROUND1(B,C,D,A, 7, 19);
ROUND1(A,B,C,D, 8, 3); ROUND1(D,A,B,C, 9, 7);
ROUND1(C,D,A,B, 10, 11); ROUND1(B,C,D,A, 11, 19);
ROUND1(A,B,C,D, 12, 3); ROUND1(D,A,B,C, 13, 7);
ROUND1(C,D,A,B, 14, 11); ROUND1(B,C,D,A, 15, 19);
ROUND2(A,B,C,D, 0, 3); ROUND2(D,A,B,C, 4, 5);
ROUND2(C,D,A,B, 8, 9); ROUND2(B,C,D,A, 12, 13);
ROUND2(A,B,C,D, 1, 3); ROUND2(D,A,B,C, 5, 5);
ROUND2(C,D,A,B, 9, 9); ROUND2(B,C,D,A, 13, 13);
ROUND2(A,B,C,D, 2, 3); ROUND2(D,A,B,C, 6, 5);
ROUND2(C,D,A,B, 10, 9); ROUND2(B,C,D,A, 14, 13);
ROUND2(A,B,C,D, 3, 3); ROUND2(D,A,B,C, 7, 5);
ROUND2(C,D,A,B, 11, 9); ROUND2(B,C,D,A, 15, 13);
ROUND3(A,B,C,D, 0, 3); ROUND3(D,A,B,C, 8, 9);
ROUND3(C,D,A,B, 4, 11); ROUND3(B,C,D,A, 12, 15);
ROUND3(A,B,C,D, 2, 3); ROUND3(D,A,B,C, 10, 9);
ROUND3(C,D,A,B, 6, 11); ROUND3(B,C,D,A, 14, 15);
ROUND3(A,B,C,D, 1, 3); ROUND3(D,A,B,C, 9, 9);
ROUND3(C,D,A,B, 5, 11); ROUND3(B,C,D,A, 13, 15);
ROUND3(A,B,C,D, 3, 3); ROUND3(D,A,B,C, 11, 9);
ROUND3(C,D,A,B, 7, 11); ROUND3(B,C,D,A, 15, 15);
A += AA; B += BB;
C += CC; D += DD;
A &= MASK32; B &= MASK32;
C &= MASK32; D &= MASK32;
m->A = A; m->B = B; m->C = C; m->D = D;
}
static void copy64(uint32 *M, unsigned char *in)
{
int i;
for (i=0;i<16;i++)
M[i] = (in[i*4+3]<<24) | (in[i*4+2]<<16) |
(in[i*4+1]<<8) | (in[i*4+0]<<0);
}
static void copy4(unsigned char *out,uint32 x)
{
out[0] = x&0xFF;
out[1] = (x>>8)&0xFF;
out[2] = (x>>16)&0xFF;
out[3] = (x>>24)&0xFF;
}
void mdfour_begin(struct mdfour *md)
{
md->A = 0x67452301;
md->B = 0xefcdab89;
md->C = 0x98badcfe;
md->D = 0x10325476;
md->totalN = 0;
}
static void mdfour_tail(unsigned char *in, int n)
{
unsigned char buf[128];
uint32 M[16];
uint32 b;
m->totalN += n;
b = m->totalN * 8;
memset(buf, 0, 128);
if (n) memcpy(buf, in, n);
buf[n] = 0x80;
if (n <= 55) {
copy4(buf+56, b);
copy64(M, buf);
mdfour64(M);
} else {
copy4(buf+120, b);
copy64(M, buf);
mdfour64(M);
copy64(M, buf+64);
mdfour64(M);
}
}
void mdfour_update(struct mdfour *md, unsigned char *in, int n)
{
uint32 M[16];
if (n == 0) mdfour_tail(in, n);
m = md;
while (n >= 64) {
copy64(M, in);
mdfour64(M);
in += 64;
n -= 64;
m->totalN += 64;
}
if (n) mdfour_tail(in, n);
}
void mdfour_result(struct mdfour *md, unsigned char *out)
{
m = md;
copy4(out, m->A);
copy4(out+4, m->B);
copy4(out+8, m->C);
copy4(out+12, m->D);
}
void mdfour(unsigned char *out, unsigned char *in, int n)
{
struct mdfour md;
mdfour_begin(&md);
mdfour_update(&md, in, n);
mdfour_result(&md, out);
}
#ifdef TEST_MDFOUR
static void file_checksum1(char *fname)
{
int fd, i;
struct mdfour md;
unsigned char buf[64*1024], sum[16];
fd = open(fname,O_RDONLY);
if (fd == -1) {
perror("fname");
exit(1);
}
mdfour_begin(&md);
while (1) {
int n = read(fd, buf, sizeof(buf));
if (n <= 0) break;
mdfour_update(&md, buf, n);
}
close(fd);
mdfour_result(&md, sum);
for (i=0;i<16;i++)
printf("%02X", sum[i]);
printf("\n");
}
#if 0
#include "../md4.h"
static void file_checksum2(char *fname)
{
int fd, i;
MDstruct md;
unsigned char buf[64], sum[16];
fd = open(fname,O_RDONLY);
if (fd == -1) {
perror("fname");
exit(1);
}
MDbegin(&md);
while (1) {
int n = read(fd, buf, sizeof(buf));
if (n <= 0) break;
MDupdate(&md, buf, n*8);
}
if (!md.done) {
MDupdate(&md, buf, 0);
}
close(fd);
memcpy(sum, md.buffer, 16);
for (i=0;i<16;i++)
printf("%02X", sum[i]);
printf("\n");
}
#endif
int main(int argc, char *argv[])
{
file_checksum1(argv[1]);
#if 0
file_checksum2(argv[1]);
#endif
return 0;
}
#endif

34
lib/mdfour.h Normal file
View File

@@ -0,0 +1,34 @@
/*
Unix SMB/Netbios implementation.
Version 1.9.
a implementation of MD4 designed for use in the SMB authentication protocol
Copyright (C) Andrew Tridgell 1997-1998.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
struct mdfour {
uint32 A, B, C, D;
uint32 totalN;
};
void mdfour_begin(struct mdfour *md);
void mdfour_update(struct mdfour *md, unsigned char *in, int n);
void mdfour_result(struct mdfour *md, unsigned char *out);
void mdfour(unsigned char *out, unsigned char *in, int n);

61
lib/permstring.c Normal file
View File

@@ -0,0 +1,61 @@
/*
Copyright (C) Andrew Tridgell 1996
Copyright (C) Paul Mackerras 1996
Copyright (C) 2001 by Martin Pool <mbp@samba.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "rsync.h"
/**
* Produce a string representation of Unix mode bits like that used by
* ls(1).
*
* @param buf buffer of at least 11 characters
**/
void permstring(char *perms,
int mode)
{
static const char *perm_map = "rwxrwxrwx";
int i;
strcpy(perms, "----------");
for (i=0;i<9;i++) {
if (mode & (1<<i)) perms[9-i] = perm_map[8-i];
}
/* Handle setuid/sticky bits. You might think the indices are
* off by one, but remember there's a type char at the
* start. */
if (mode & S_ISUID)
perms[3] = (mode & S_IXUSR) ? 's' : 'S';
if (mode & S_ISGID)
perms[6] = (mode & S_IXGRP) ? 's' : 'S';
if (mode & S_ISVTX)
perms[9] = (mode & S_IXOTH) ? 't' : 'T';
if (S_ISLNK(mode)) perms[0] = 'l';
if (S_ISDIR(mode)) perms[0] = 'd';
if (S_ISBLK(mode)) perms[0] = 'b';
if (S_ISCHR(mode)) perms[0] = 'c';
if (S_ISSOCK(mode)) perms[0] = 's';
if (S_ISFIFO(mode)) perms[0] = 'p';
}

3
lib/permstring.h Normal file
View File

@@ -0,0 +1,3 @@
#define PERMSTRING_SIZE 11
void permstring(char *perms, int mode);

937
lib/snprintf.c Normal file
View File

@@ -0,0 +1,937 @@
/*
* Copyright Patrick Powell 1995
* This code is based on code written by Patrick Powell (papowell@astart.com)
* It may be used for any purpose as long as this notice remains intact
* on all source code distributions
*/
/**************************************************************
* Original:
* Patrick Powell Tue Apr 11 09:48:21 PDT 1995
* A bombproof version of doprnt (dopr) included.
* Sigh. This sort of thing is always nasty do deal with. Note that
* the version here does not include floating point...
*
* snprintf() is used instead of sprintf() as it does limit checks
* for string length. This covers a nasty loophole.
*
* The other functions are there to prevent NULL pointers from
* causing nast effects.
*
* More Recently:
* Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
* This was ugly. It is still ugly. I opted out of floating point
* numbers, but the formatter understands just about everything
* from the normal C string format, at least as far as I can tell from
* the Solaris 2.5 printf(3S) man page.
*
* Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
* Ok, added some minimal floating point support, which means this
* probably requires libm on most operating systems. Don't yet
* support the exponent (e,E) and sigfig (g,G). Also, fmtint()
* was pretty badly broken, it just wasn't being exercised in ways
* which showed it, so that's been fixed. Also, formated the code
* to mutt conventions, and removed dead code left over from the
* original. Also, there is now a builtin-test, just compile with:
* gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
* and run snprintf for results.
*
* Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
* The PGP code was using unsigned hexadecimal formats.
* Unfortunately, unsigned formats simply didn't work.
*
* Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
* The original code assumed that both snprintf() and vsnprintf() were
* missing. Some systems only have snprintf() but not vsnprintf(), so
* the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
*
* Andrew Tridgell (tridge@samba.org) Oct 1998
* fixed handling of %.0f
* added test for HAVE_LONG_DOUBLE
*
* tridge@samba.org, idra@samba.org, April 2001
* got rid of fcvt code (twas buggy and made testing harder)
* added C99 semantics
*
**************************************************************/
#ifndef NO_CONFIG_H /* for some tests */
#include "config.h"
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#ifdef HAVE_CTYPE_H
#include <ctype.h>
#endif
#include <sys/types.h>
#include <stdarg.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF)
/* only include stdio.h if we are not re-defining snprintf or vsnprintf */
#include <stdio.h>
/* make the compiler happy with an empty file */
void dummy_snprintf(void) {}
#else
#ifdef HAVE_LONG_DOUBLE
#define LDOUBLE long double
#else
#define LDOUBLE double
#endif
#ifdef HAVE_LONG_LONG
#define LLONG long long
#else
#define LLONG long
#endif
static size_t dopr(char *buffer, size_t maxlen, const char *format,
va_list args);
static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
char *value, int flags, int min, int max);
static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
long value, int base, int min, int max, int flags);
static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
LDOUBLE fvalue, int min, int max, int flags);
static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
/*
* dopr(): poor man's version of doprintf
*/
/* format read states */
#define DP_S_DEFAULT 0
#define DP_S_FLAGS 1
#define DP_S_MIN 2
#define DP_S_DOT 3
#define DP_S_MAX 4
#define DP_S_MOD 5
#define DP_S_CONV 6
#define DP_S_DONE 7
/* format flags - Bits */
#define DP_F_MINUS (1 << 0)
#define DP_F_PLUS (1 << 1)
#define DP_F_SPACE (1 << 2)
#define DP_F_NUM (1 << 3)
#define DP_F_ZERO (1 << 4)
#define DP_F_UP (1 << 5)
#define DP_F_UNSIGNED (1 << 6)
/* Conversion Flags */
#define DP_C_SHORT 1
#define DP_C_LONG 2
#define DP_C_LDOUBLE 3
#define DP_C_LLONG 4
#define char_to_int(p) ((p)- '0')
#ifndef MAX
#define MAX(p,q) (((p) >= (q)) ? (p) : (q))
#endif
static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args)
{
char ch;
LLONG value;
LDOUBLE fvalue;
char *strvalue;
int min;
int max;
int state;
int flags;
int cflags;
size_t currlen;
state = DP_S_DEFAULT;
currlen = flags = cflags = min = 0;
max = -1;
ch = *format++;
while (state != DP_S_DONE) {
if (ch == '\0')
state = DP_S_DONE;
switch(state) {
case DP_S_DEFAULT:
if (ch == '%')
state = DP_S_FLAGS;
else
dopr_outch (buffer, &currlen, maxlen, ch);
ch = *format++;
break;
case DP_S_FLAGS:
switch (ch) {
case '-':
flags |= DP_F_MINUS;
ch = *format++;
break;
case '+':
flags |= DP_F_PLUS;
ch = *format++;
break;
case ' ':
flags |= DP_F_SPACE;
ch = *format++;
break;
case '#':
flags |= DP_F_NUM;
ch = *format++;
break;
case '0':
flags |= DP_F_ZERO;
ch = *format++;
break;
default:
state = DP_S_MIN;
break;
}
break;
case DP_S_MIN:
if (isdigit((unsigned char)ch)) {
min = 10*min + char_to_int (ch);
ch = *format++;
} else if (ch == '*') {
min = va_arg (args, int);
ch = *format++;
state = DP_S_DOT;
} else {
state = DP_S_DOT;
}
break;
case DP_S_DOT:
if (ch == '.') {
state = DP_S_MAX;
ch = *format++;
} else {
state = DP_S_MOD;
}
break;
case DP_S_MAX:
if (isdigit((unsigned char)ch)) {
if (max < 0)
max = 0;
max = 10*max + char_to_int (ch);
ch = *format++;
} else if (ch == '*') {
max = va_arg (args, int);
ch = *format++;
state = DP_S_MOD;
} else {
state = DP_S_MOD;
}
break;
case DP_S_MOD:
switch (ch) {
case 'h':
cflags = DP_C_SHORT;
ch = *format++;
break;
case 'l':
cflags = DP_C_LONG;
ch = *format++;
if (ch == 'l') { /* It's a long long */
cflags = DP_C_LLONG;
ch = *format++;
}
break;
case 'L':
cflags = DP_C_LDOUBLE;
ch = *format++;
break;
default:
break;
}
state = DP_S_CONV;
break;
case DP_S_CONV:
switch (ch) {
case 'd':
case 'i':
if (cflags == DP_C_SHORT)
value = va_arg (args, int);
else if (cflags == DP_C_LONG)
value = va_arg (args, long int);
else if (cflags == DP_C_LLONG)
value = va_arg (args, LLONG);
else
value = va_arg (args, int);
fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
break;
case 'o':
flags |= DP_F_UNSIGNED;
if (cflags == DP_C_SHORT)
value = va_arg (args, unsigned int);
else if (cflags == DP_C_LONG)
value = (long)va_arg (args, unsigned long int);
else if (cflags == DP_C_LLONG)
value = (long)va_arg (args, unsigned LLONG);
else
value = (long)va_arg (args, unsigned int);
fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
break;
case 'u':
flags |= DP_F_UNSIGNED;
if (cflags == DP_C_SHORT)
value = va_arg (args, unsigned int);
else if (cflags == DP_C_LONG)
value = (long)va_arg (args, unsigned long int);
else if (cflags == DP_C_LLONG)
value = (LLONG)va_arg (args, unsigned LLONG);
else
value = (long)va_arg (args, unsigned int);
fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
break;
case 'X':
flags |= DP_F_UP;
case 'x':
flags |= DP_F_UNSIGNED;
if (cflags == DP_C_SHORT)
value = va_arg (args, unsigned int);
else if (cflags == DP_C_LONG)
value = (long)va_arg (args, unsigned long int);
else if (cflags == DP_C_LLONG)
value = (LLONG)va_arg (args, unsigned LLONG);
else
value = (long)va_arg (args, unsigned int);
fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
break;
case 'f':
if (cflags == DP_C_LDOUBLE)
fvalue = va_arg (args, LDOUBLE);
else
fvalue = va_arg (args, double);
/* um, floating point? */
fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
break;
case 'E':
flags |= DP_F_UP;
case 'e':
if (cflags == DP_C_LDOUBLE)
fvalue = va_arg (args, LDOUBLE);
else
fvalue = va_arg (args, double);
break;
case 'G':
flags |= DP_F_UP;
case 'g':
if (cflags == DP_C_LDOUBLE)
fvalue = va_arg (args, LDOUBLE);
else
fvalue = va_arg (args, double);
break;
case 'c':
dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
break;
case 's':
strvalue = va_arg (args, char *);
if (max == -1) {
max = strlen(strvalue);
}
if (min > 0 && max >= 0 && min > max) max = min;
fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
break;
case 'p':
strvalue = va_arg (args, void *);
fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
break;
case 'n':
if (cflags == DP_C_SHORT) {
short int *num;
num = va_arg (args, short int *);
*num = currlen;
} else if (cflags == DP_C_LONG) {
long int *num;
num = va_arg (args, long int *);
*num = (long int)currlen;
} else if (cflags == DP_C_LLONG) {
LLONG *num;
num = va_arg (args, LLONG *);
*num = (LLONG)currlen;
} else {
int *num;
num = va_arg (args, int *);
*num = currlen;
}
break;
case '%':
dopr_outch (buffer, &currlen, maxlen, ch);
break;
case 'w':
/* not supported yet, treat as next char */
ch = *format++;
break;
default:
/* Unknown, skip */
break;
}
ch = *format++;
state = DP_S_DEFAULT;
flags = cflags = min = 0;
max = -1;
break;
case DP_S_DONE:
break;
default:
/* hmm? */
break; /* some picky compilers need this */
}
}
if (maxlen != 0) {
if (currlen < maxlen - 1)
buffer[currlen] = '\0';
else if (maxlen > 0)
buffer[maxlen - 1] = '\0';
}
return currlen;
}
static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
char *value, int flags, int min, int max)
{
int padlen, strln; /* amount to pad */
int cnt = 0;
#ifdef DEBUG_SNPRINTF
printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
#endif
if (value == 0) {
value = "<NULL>";
}
for (strln = 0; value[strln]; ++strln); /* strlen */
padlen = min - strln;
if (padlen < 0)
padlen = 0;
if (flags & DP_F_MINUS)
padlen = -padlen; /* Left Justify */
while ((padlen > 0) && (cnt < max)) {
dopr_outch (buffer, currlen, maxlen, ' ');
--padlen;
++cnt;
}
while (*value && (cnt < max)) {
dopr_outch (buffer, currlen, maxlen, *value++);
++cnt;
}
while ((padlen < 0) && (cnt < max)) {
dopr_outch (buffer, currlen, maxlen, ' ');
++padlen;
++cnt;
}
}
/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
long value, int base, int min, int max, int flags)
{
int signvalue = 0;
unsigned long uvalue;
char convert[20];
int place = 0;
int spadlen = 0; /* amount to space pad */
int zpadlen = 0; /* amount to zero pad */
int caps = 0;
if (max < 0)
max = 0;
uvalue = value;
if(!(flags & DP_F_UNSIGNED)) {
if( value < 0 ) {
signvalue = '-';
uvalue = -value;
} else {
if (flags & DP_F_PLUS) /* Do a sign (+/i) */
signvalue = '+';
else if (flags & DP_F_SPACE)
signvalue = ' ';
}
}
if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
do {
convert[place++] =
(caps? "0123456789ABCDEF":"0123456789abcdef")
[uvalue % (unsigned)base ];
uvalue = (uvalue / (unsigned)base );
} while(uvalue && (place < 20));
if (place == 20) place--;
convert[place] = 0;
zpadlen = max - place;
spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
if (zpadlen < 0) zpadlen = 0;
if (spadlen < 0) spadlen = 0;
if (flags & DP_F_ZERO) {
zpadlen = MAX(zpadlen, spadlen);
spadlen = 0;
}
if (flags & DP_F_MINUS)
spadlen = -spadlen; /* Left Justifty */
#ifdef DEBUG_SNPRINTF
printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
zpadlen, spadlen, min, max, place);
#endif
/* Spaces */
while (spadlen > 0) {
dopr_outch (buffer, currlen, maxlen, ' ');
--spadlen;
}
/* Sign */
if (signvalue)
dopr_outch (buffer, currlen, maxlen, signvalue);
/* Zeros */
if (zpadlen > 0) {
while (zpadlen > 0) {
dopr_outch (buffer, currlen, maxlen, '0');
--zpadlen;
}
}
/* Digits */
while (place > 0)
dopr_outch (buffer, currlen, maxlen, convert[--place]);
/* Left Justified spaces */
while (spadlen < 0) {
dopr_outch (buffer, currlen, maxlen, ' ');
++spadlen;
}
}
static LDOUBLE abs_val(LDOUBLE value)
{
LDOUBLE result = value;
if (value < 0)
result = -value;
return result;
}
static LDOUBLE POW10(int exp)
{
LDOUBLE result = 1;
while (exp) {
result *= 10;
exp--;
}
return result;
}
static LLONG ROUND(LDOUBLE value)
{
LLONG intpart;
intpart = (LLONG)value;
value = value - intpart;
if (value >= 0.5) intpart++;
return intpart;
}
/* a replacement for modf that doesn't need the math library. Should
be portable, but slow */
static double my_modf(double x0, double *iptr)
{
int i;
long l;
double x = x0;
double f = 1.0;
for (i=0;i<100;i++) {
l = (long)x;
if (l <= (x+1) && l >= (x-1)) break;
x *= 0.1;
f *= 10.0;
}
if (i == 100) {
/* yikes! the number is beyond what we can handle. What do we do? */
(*iptr) = 0;
return 0;
}
if (i != 0) {
double i2;
double ret;
ret = my_modf(x0-l*f, &i2);
(*iptr) = l*f + i2;
return ret;
}
(*iptr) = l;
return x - (*iptr);
}
static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
LDOUBLE fvalue, int min, int max, int flags)
{
int signvalue = 0;
double ufvalue;
char iconvert[311];
char fconvert[311];
int iplace = 0;
int fplace = 0;
int padlen = 0; /* amount to pad */
int zpadlen = 0;
int caps = 0;
int index;
double intpart;
double fracpart;
double temp;
/*
* AIX manpage says the default is 0, but Solaris says the default
* is 6, and sprintf on AIX defaults to 6
*/
if (max < 0)
max = 6;
ufvalue = abs_val (fvalue);
if (fvalue < 0) {
signvalue = '-';
} else {
if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
signvalue = '+';
} else {
if (flags & DP_F_SPACE)
signvalue = ' ';
}
}
#if 0
if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
#endif
#if 0
if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
#endif
/*
* Sorry, we only support 16 digits past the decimal because of our
* conversion method
*/
if (max > 16)
max = 16;
/* We "cheat" by converting the fractional part to integer by
* multiplying by a factor of 10
*/
temp = ufvalue;
my_modf(temp, &intpart);
fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
if (fracpart >= POW10(max)) {
intpart++;
fracpart -= POW10(max);
}
/* Convert integer part */
do {
temp = intpart;
my_modf(intpart*0.1, &intpart);
temp = temp*0.1;
index = (int) ((temp -intpart +0.05)* 10.0);
/* index = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
/* printf ("%llf, %f, %x\n", temp, intpart, index); */
iconvert[iplace++] =
(caps? "0123456789ABCDEF":"0123456789abcdef")[index];
} while (intpart && (iplace < 311));
if (iplace == 311) iplace--;
iconvert[iplace] = 0;
/* Convert fractional part */
if (fracpart)
{
do {
temp = fracpart;
my_modf(fracpart*0.1, &fracpart);
temp = temp*0.1;
index = (int) ((temp -fracpart +0.05)* 10.0);
/* index = (int) ((((temp/10) -fracpart) +0.05) *10); */
/* printf ("%lf, %lf, %ld\n", temp, fracpart, index); */
fconvert[fplace++] =
(caps? "0123456789ABCDEF":"0123456789abcdef")[index];
} while(fracpart && (fplace < 311));
if (fplace == 311) fplace--;
}
fconvert[fplace] = 0;
/* -1 for decimal point, another -1 if we are printing a sign */
padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
zpadlen = max - fplace;
if (zpadlen < 0) zpadlen = 0;
if (padlen < 0)
padlen = 0;
if (flags & DP_F_MINUS)
padlen = -padlen; /* Left Justifty */
if ((flags & DP_F_ZERO) && (padlen > 0)) {
if (signvalue) {
dopr_outch (buffer, currlen, maxlen, signvalue);
--padlen;
signvalue = 0;
}
while (padlen > 0) {
dopr_outch (buffer, currlen, maxlen, '0');
--padlen;
}
}
while (padlen > 0) {
dopr_outch (buffer, currlen, maxlen, ' ');
--padlen;
}
if (signvalue)
dopr_outch (buffer, currlen, maxlen, signvalue);
while (iplace > 0)
dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
#ifdef DEBUG_SNPRINTF
printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
#endif
/*
* Decimal point. This should probably use locale to find the correct
* char to print out.
*/
if (max > 0) {
dopr_outch (buffer, currlen, maxlen, '.');
while (fplace > 0)
dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
}
while (zpadlen > 0) {
dopr_outch (buffer, currlen, maxlen, '0');
--zpadlen;
}
while (padlen < 0) {
dopr_outch (buffer, currlen, maxlen, ' ');
++padlen;
}
}
static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
{
if (*currlen < maxlen) {
buffer[(*currlen)] = c;
}
(*currlen)++;
}
#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
{
return dopr(str, count, fmt, args);
}
#endif
#if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
int snprintf(char *str,size_t count,const char *fmt,...)
{
size_t ret;
va_list ap;
va_start(ap, fmt);
ret = vsnprintf(str, count, fmt, ap);
va_end(ap);
return ret;
}
#endif
#endif
#ifndef HAVE_VASPRINTF
int vasprintf(char **ptr, const char *format, va_list ap)
{
int ret;
ret = vsnprintf(NULL, 0, format, ap);
if (ret <= 0) return ret;
(*ptr) = (char *)malloc(ret+1);
if (!*ptr) return -1;
ret = vsnprintf(*ptr, ret+1, format, ap);
return ret;
}
#endif
#ifndef HAVE_ASPRINTF
int asprintf(char **ptr, const char *format, ...)
{
va_list ap;
int ret;
va_start(ap, format);
ret = vasprintf(ptr, format, ap);
va_end(ap);
return ret;
}
#endif
#ifdef TEST_SNPRINTF
int sprintf(char *str,const char *fmt,...);
int main (void)
{
char buf1[1024];
char buf2[1024];
char *fp_fmt[] = {
"%1.1f",
"%-1.5f",
"%1.5f",
"%123.9f",
"%10.5f",
"% 10.5f",
"%+22.9f",
"%+4.9f",
"%01.3f",
"%4f",
"%3.1f",
"%3.2f",
"%.0f",
"%f",
"-16.16f",
NULL
};
double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
0.9996, 1.996, 4.136, 0};
char *int_fmt[] = {
"%-1.5d",
"%1.5d",
"%123.9d",
"%5.5d",
"%10.5d",
"% 10.5d",
"%+22.33d",
"%01.3d",
"%4d",
"%d",
NULL
};
long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
char *str_fmt[] = {
"10.5s",
"5.10s",
"10.1s",
"0.10s",
"10.0s",
"1.10s",
"%s",
"%.1s",
"%.10s",
"%10s",
NULL
};
char *str_vals[] = {"hello", "a", "", "a longer string", NULL};
int x, y;
int fail = 0;
int num = 0;
printf ("Testing snprintf format codes against system sprintf...\n");
for (x = 0; fp_fmt[x] ; x++) {
for (y = 0; fp_nums[y] != 0 ; y++) {
int l1 = snprintf(NULL, 0, fp_fmt[x], fp_nums[y]);
int l2 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
sprintf (buf2, fp_fmt[x], fp_nums[y]);
if (strcmp (buf1, buf2)) {
printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",
fp_fmt[x], buf1, buf2);
fail++;
}
if (l1 != l2) {
printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, fp_fmt[x]);
fail++;
}
num++;
}
}
for (x = 0; int_fmt[x] ; x++) {
for (y = 0; int_nums[y] != 0 ; y++) {
int l1 = snprintf(NULL, 0, int_fmt[x], int_nums[y]);
int l2 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
sprintf (buf2, int_fmt[x], int_nums[y]);
if (strcmp (buf1, buf2)) {
printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",
int_fmt[x], buf1, buf2);
fail++;
}
if (l1 != l2) {
printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, int_fmt[x]);
fail++;
}
num++;
}
}
for (x = 0; str_fmt[x] ; x++) {
for (y = 0; str_vals[y] != 0 ; y++) {
int l1 = snprintf(NULL, 0, str_fmt[x], str_vals[y]);
int l2 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]);
sprintf (buf2, str_fmt[x], str_vals[y]);
if (strcmp (buf1, buf2)) {
printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n",
str_fmt[x], buf1, buf2);
fail++;
}
if (l1 != l2) {
printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, str_fmt[x]);
fail++;
}
num++;
}
}
printf ("%d tests failed out of %d.\n", fail, num);
printf("seeing how many digits we support\n");
{
double v0 = 0.12345678901234567890123456789012345678901;
for (x=0; x<100; x++) {
snprintf(buf1, sizeof(buf1), "%1.1f", v0*pow(10, x));
sprintf(buf2, "%1.1f", v0*pow(10, x));
if (strcmp(buf1, buf2)) {
printf("we seem to support %d digits\n", x-1);
break;
}
}
}
return 0;
}
#endif /* SNPRINTF_TEST */

4601
lib/zlib.c
View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,632 +0,0 @@
/* $Id$ */
/*
* This file is derived from zlib.h and zconf.h from the zlib-0.95
* distribution by Jean-loup Gailly and Mark Adler, with some additions
* by Paul Mackerras to aid in implementing Deflate compression and
* decompression for PPP packets.
*/
/* zlib.h -- interface of the 'zlib' general purpose compression library
version 0.95, Aug 16th, 1995.
Copyright (C) 1995 Jean-loup Gailly and Mark Adler
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Jean-loup Gailly Mark Adler
gzip@prep.ai.mit.edu madler@alumni.caltech.edu
*/
#ifndef _ZLIB_H
#define _ZLIB_H
/* #include "zconf.h" */ /* included directly here */
/* zconf.h -- configuration of the zlib compression library
* Copyright (C) 1995 Jean-loup Gailly.
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* From: zconf.h,v 1.12 1995/05/03 17:27:12 jloup Exp */
/*
The library does not install any signal handler. It is recommended to
add at least a handler for SIGSEGV when decompressing; the library checks
the consistency of the input data whenever possible but may go nuts
for some forms of corrupted input.
*/
/*
* Compile with -DMAXSEG_64K if the alloc function cannot allocate more
* than 64k bytes at a time (needed on systems with 16-bit int).
* Compile with -DUNALIGNED_OK if it is OK to access shorts or ints
* at addresses which are not a multiple of their size.
* Under DOS, -DFAR=far or -DFAR=__far may be needed.
*/
#ifndef STDC
# if defined(MSDOS) || defined(__STDC__) || defined(__cplusplus)
# define STDC
# endif
#endif
#ifdef __MWERKS__ /* Metrowerks CodeWarrior declares fileno() in unix.h */
# include <unix.h>
#endif
/* Maximum value for memLevel in deflateInit2 */
#ifndef MAX_MEM_LEVEL
# ifdef MAXSEG_64K
# define MAX_MEM_LEVEL 8
# else
# define MAX_MEM_LEVEL 9
# endif
#endif
#ifndef FAR
# define FAR
#endif
/* Maximum value for windowBits in deflateInit2 and inflateInit2 */
#ifndef MAX_WBITS
# define MAX_WBITS 15 /* 32K LZ77 window */
#endif
/* The memory requirements for deflate are (in bytes):
1 << (windowBits+2) + 1 << (memLevel+9)
that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
plus a few kilobytes for small objects. For example, if you want to reduce
the default memory requirements from 256K to 128K, compile with
make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
Of course this will generally degrade compression (there's no free lunch).
The memory requirements for inflate are (in bytes) 1 << windowBits
that is, 32K for windowBits=15 (default value) plus a few kilobytes
for small objects.
*/
/* Type declarations */
#ifndef OF /* function prototypes */
# ifdef STDC
# define OF(args) args
# else
# define OF(args) ()
# endif
#endif
typedef unsigned char Byte; /* 8 bits */
typedef unsigned int uInt; /* 16 bits or more */
typedef int32 Long; /* 32 bits or more */
typedef uint32 uLong; /* 32 bits or more */
typedef Byte FAR Bytef;
typedef char FAR charf;
typedef int FAR intf;
typedef uInt FAR uIntf;
typedef uLong FAR uLongf;
#ifdef STDC
typedef void FAR *voidpf;
typedef void *voidp;
#else
typedef Byte FAR *voidpf;
typedef Byte *voidp;
#endif
/* end of original zconf.h */
#define ZLIB_VERSION "0.95P"
/*
The 'zlib' compression library provides in-memory compression and
decompression functions, including integrity checks of the uncompressed
data. This version of the library supports only one compression method
(deflation) but other algorithms may be added later and will have the same
stream interface.
For compression the application must provide the output buffer and
may optionally provide the input buffer for optimization. For decompression,
the application must provide the input buffer and may optionally provide
the output buffer for optimization.
Compression can be done in a single step if the buffers are large
enough (for example if an input file is mmap'ed), or can be done by
repeated calls of the compression function. In the latter case, the
application must provide more input and/or consume the output
(providing more output space) before each call.
*/
typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
typedef void (*free_func) OF((voidpf opaque, voidpf address, uInt nbytes));
struct internal_state;
typedef struct z_stream_s {
Bytef *next_in; /* next input byte */
uInt avail_in; /* number of bytes available at next_in */
uLong total_in; /* total nb of input bytes read so far */
Bytef *next_out; /* next output byte should be put there */
uInt avail_out; /* remaining free space at next_out */
uLong total_out; /* total nb of bytes output so far */
char *msg; /* last error message, NULL if no error */
struct internal_state FAR *state; /* not visible by applications */
alloc_func zalloc; /* used to allocate the internal state */
free_func zfree; /* used to free the internal state */
voidp opaque; /* private data object passed to zalloc and zfree */
Byte data_type; /* best guess about the data type: ascii or binary */
} z_stream;
/*
The application must update next_in and avail_in when avail_in has
dropped to zero. It must update next_out and avail_out when avail_out
has dropped to zero. The application must initialize zalloc, zfree and
opaque before calling the init function. All other fields are set by the
compression library and must not be updated by the application.
The opaque value provided by the application will be passed as the first
parameter for calls of zalloc and zfree. This can be useful for custom
memory management. The compression library attaches no meaning to the
opaque value.
zalloc must return Z_NULL if there is not enough memory for the object.
On 16-bit systems, the functions zalloc and zfree must be able to allocate
exactly 65536 bytes, but will not be required to allocate more than this
if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
pointers returned by zalloc for objects of exactly 65536 bytes *must*
have their offset normalized to zero. The default allocation function
provided by this library ensures this (see zutil.c). To reduce memory
requirements and avoid any allocation of 64K objects, at the expense of
compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
The fields total_in and total_out can be used for statistics or
progress reports. After compression, total_in holds the total size of
the uncompressed data and may be saved for use in the decompressor
(particularly if the decompressor wants to decompress everything in
a single step).
*/
/* constants */
#define Z_NO_FLUSH 0
#define Z_PARTIAL_FLUSH 1
#define Z_FULL_FLUSH 2
#define Z_SYNC_FLUSH 3 /* experimental: partial_flush + byte align */
#define Z_FINISH 4
#define Z_PACKET_FLUSH 5
#define Z_INSERT_ONLY 6 /* update hash table etc., produce no output */
/* See deflate() below for the usage of these constants */
#define Z_OK 0
#define Z_STREAM_END 1
#define Z_ERRNO (-1)
#define Z_STREAM_ERROR (-2)
#define Z_DATA_ERROR (-3)
#define Z_MEM_ERROR (-4)
#define Z_BUF_ERROR (-5)
/* error codes for the compression/decompression functions */
#define Z_BEST_SPEED 1
#define Z_BEST_COMPRESSION 9
#define Z_DEFAULT_COMPRESSION (-1)
/* compression levels */
#define Z_FILTERED 1
#define Z_HUFFMAN_ONLY 2
#define Z_DEFAULT_STRATEGY 0
#define Z_BINARY 0
#define Z_ASCII 1
#define Z_UNKNOWN 2
/* Used to set the data_type field */
#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
extern char *zlib_version;
/* The application can compare zlib_version and ZLIB_VERSION for consistency.
If the first character differs, the library code actually used is
not compatible with the zlib.h header file used by the application.
*/
/* basic functions */
extern int deflateInit OF((z_stream *strm, int level));
/*
Initializes the internal stream state for compression. The fields
zalloc, zfree and opaque must be initialized before by the caller.
If zalloc and zfree are set to Z_NULL, deflateInit updates them to
use default allocation functions.
The compression level must be Z_DEFAULT_COMPRESSION, or between 1 and 9:
1 gives best speed, 9 gives best compression. Z_DEFAULT_COMPRESSION requests
a default compromise between speed and compression (currently equivalent
to level 6).
deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
enough memory, Z_STREAM_ERROR if level is not a valid compression level.
msg is set to null if there is no error message. deflateInit does not
perform any compression: this will be done by deflate().
*/
extern int deflate OF((z_stream *strm, int flush));
/*
Performs one or both of the following actions:
- Compress more input starting at next_in and update next_in and avail_in
accordingly. If not all input can be processed (because there is not
enough room in the output buffer), next_in and avail_in are updated and
processing will resume at this point for the next call of deflate().
- Provide more output starting at next_out and update next_out and avail_out
accordingly. This action is forced if the parameter flush is non zero.
Forcing flush frequently degrades the compression ratio, so this parameter
should be set only when necessary (in interactive applications).
Some output may be provided even if flush is not set.
Before the call of deflate(), the application should ensure that at least
one of the actions is possible, by providing more input and/or consuming
more output, and updating avail_in or avail_out accordingly; avail_out
should never be zero before the call. The application can consume the
compressed output when it wants, for example when the output buffer is full
(avail_out == 0), or after each call of deflate().
If the parameter flush is set to Z_PARTIAL_FLUSH, the current compression
block is terminated and flushed to the output buffer so that the
decompressor can get all input data available so far. For method 9, a future
variant on method 8, the current block will be flushed but not terminated.
If flush is set to Z_FULL_FLUSH, the compression block is terminated, a
special marker is output and the compression dictionary is discarded; this
is useful to allow the decompressor to synchronize if one compressed block
has been damaged (see inflateSync below). Flushing degrades compression and
so should be used only when necessary. Using Z_FULL_FLUSH too often can
seriously degrade the compression. If deflate returns with avail_out == 0,
this function must be called again with the same value of the flush
parameter and more output space (updated avail_out), until the flush is
complete (deflate returns with non-zero avail_out).
If the parameter flush is set to Z_PACKET_FLUSH, the compression
block is terminated, and a zero-length stored block is output,
omitting the length bytes (the effect of this is that the 3-bit type
code 000 for a stored block is output, and the output is then
byte-aligned). This is designed for use at the end of a PPP packet.
In addition, if the current compression block contains all the data
since the last Z_PACKET_FLUSH, it is never output as a stored block.
If the current compression block output as a static or dynamic block
would not be at least `minCompression' bytes smaller than the
original data, then nothing is output for that block. (The type
code for the zero-length stored block is still output, resulting in
a single zero byte being output for the whole packet.)
`MinCompression' is a parameter to deflateInit2, or 0 if deflateInit
is used.
If the parameter flush is set to Z_FINISH, all pending input is processed,
all pending output is flushed and deflate returns with Z_STREAM_END if there
was enough output space; if deflate returns with Z_OK, this function must be
called again with Z_FINISH and more output space (updated avail_out) but no
more input data, until it returns with Z_STREAM_END or an error. After
deflate has returned Z_STREAM_END, the only possible operations on the
stream are deflateReset or deflateEnd.
Z_FINISH can be used immediately after deflateInit if all the compression
is to be done in a single step. In this case, avail_out must be at least
0.1% larger than avail_in plus 12 bytes. If deflate does not return
Z_STREAM_END, then it must be called again as described above.
deflate() may update data_type if it can make a good guess about
the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
binary. This field is only for information purposes and does not affect
the compression algorithm in any manner.
deflate() returns Z_OK if some progress has been made (more input
processed or more output produced), Z_STREAM_END if all input has been
consumed and all output has been produced (only when flush is set to
Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible.
*/
extern int deflateEnd OF((z_stream *strm));
/*
All dynamically allocated data structures for this stream are freed.
This function discards any unprocessed input and does not flush any
pending output.
deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
stream state was inconsistent. In the error case, msg may be set
but then points to a static string (which must not be deallocated).
*/
extern int inflateInit OF((z_stream *strm));
/*
Initializes the internal stream state for decompression. The fields
zalloc and zfree must be initialized before by the caller. If zalloc and
zfree are set to Z_NULL, inflateInit updates them to use default allocation
functions.
inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
enough memory. msg is set to null if there is no error message.
inflateInit does not perform any decompression: this will be done by
inflate().
*/
extern int inflate OF((z_stream *strm, int flush));
/*
Performs one or both of the following actions:
- Decompress more input starting at next_in and update next_in and avail_in
accordingly. If not all input can be processed (because there is not
enough room in the output buffer), next_in is updated and processing
will resume at this point for the next call of inflate().
- Provide more output starting at next_out and update next_out and avail_out
accordingly. inflate() always provides as much output as possible
(until there is no more input data or no more space in the output buffer).
Before the call of inflate(), the application should ensure that at least
one of the actions is possible, by providing more input and/or consuming
more output, and updating the next_* and avail_* values accordingly.
The application can consume the uncompressed output when it wants, for
example when the output buffer is full (avail_out == 0), or after each
call of inflate().
If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH,
inflate flushes as much output as possible to the output buffer. The
flushing behavior of inflate is not specified for values of the flush
parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the
current implementation actually flushes as much output as possible
anyway. For Z_PACKET_FLUSH, inflate checks that once all the input data
has been consumed, it is expecting to see the length field of a stored
block; if not, it returns Z_DATA_ERROR.
inflate() should normally be called until it returns Z_STREAM_END or an
error. However if all decompression is to be performed in a single step
(a single call of inflate), the parameter flush should be set to
Z_FINISH. In this case all pending input is processed and all pending
output is flushed; avail_out must be large enough to hold all the
uncompressed data. (The size of the uncompressed data may have been saved
by the compressor for this purpose.) The next operation on this stream must
be inflateEnd to deallocate the decompression state. The use of Z_FINISH
is never required, but can be used to inform inflate that a faster routine
may be used for the single inflate() call.
inflate() returns Z_OK if some progress has been made (more input
processed or more output produced), Z_STREAM_END if the end of the
compressed data has been reached and all uncompressed output has been
produced, Z_DATA_ERROR if the input data was corrupted, Z_STREAM_ERROR if
the stream structure was inconsistent (for example if next_in or next_out
was NULL), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no
progress is possible or if there was not enough room in the output buffer
when Z_FINISH is used. In the Z_DATA_ERROR case, the application may then
call inflateSync to look for a good compression block. */
extern int inflateEnd OF((z_stream *strm));
/*
All dynamically allocated data structures for this stream are freed.
This function discards any unprocessed input and does not flush any
pending output.
inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
was inconsistent. In the error case, msg may be set but then points to a
static string (which must not be deallocated).
*/
/* advanced functions */
/*
The following functions are needed only in some special applications.
*/
extern int deflateInit2 OF((z_stream *strm,
int level,
int method,
int windowBits,
int memLevel,
int strategy));
/*
This is another version of deflateInit with more compression options. The
fields next_in, zalloc and zfree must be initialized before by the caller.
The method parameter is the compression method. It must be 8 in this
version of the library. (Method 9 will allow a 64K history buffer and
partial block flushes.)
The windowBits parameter is the base two logarithm of the window size
(the size of the history buffer). It should be in the range 8..15 for this
version of the library (the value 16 will be allowed for method 9). Larger
values of this parameter result in better compression at the expense of
memory usage. The default value is 15 if deflateInit is used instead.
The memLevel parameter specifies how much memory should be allocated
for the internal compression state. memLevel=1 uses minimum memory but
is slow and reduces compression ratio; memLevel=9 uses maximum memory
for optimal speed. The default value is 8. See zconf.h for total memory
usage as a function of windowBits and memLevel.
The strategy parameter is used to tune the compression algorithm. Use
the value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data
produced by a filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman
encoding only (no string match). Filtered data consists mostly of small
values with a somewhat random distribution. In this case, the
compression algorithm is tuned to compress them better. The strategy
parameter only affects the compression ratio but not the correctness of
the compressed output even if it is not set appropriately.
The minCompression parameter specifies the minimum reduction in size
required for a compressed block to be output when Z_PACKET_FLUSH is
used (see the description of deflate above).
If next_in is not null, the library will use this buffer to hold also
some history information; the buffer must either hold the entire input
data, or have at least 1<<(windowBits+1) bytes and be writable. If next_in
is null, the library will allocate its own history buffer (and leave next_in
null). next_out need not be provided here but must be provided by the
application for the next call of deflate().
If the history buffer is provided by the application, next_in must
must never be changed by the application since the compressor maintains
information inside this buffer from call to call; the application
must provide more input only by increasing avail_in. next_in is always
reset by the library in this case.
deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
an invalid method). msg is set to null if there is no error message.
deflateInit2 does not perform any compression: this will be done by
deflate().
*/
extern int deflateCopy OF((z_stream *dest,
z_stream *source));
/*
Sets the destination stream as a complete copy of the source stream. If
the source stream is using an application-supplied history buffer, a new
buffer is allocated for the destination stream. The compressed output
buffer is always application-supplied. It's the responsibility of the
application to provide the correct values of next_out and avail_out for the
next call of deflate.
This function is useful when several compression strategies will be
tried, for example when there are several ways of pre-processing the input
data with a filter. The streams that will be discarded should then be freed
by calling deflateEnd. Note that deflateCopy duplicates the internal
compression state which can be quite large, so this strategy is slow and
can consume lots of memory.
deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
(such as zalloc being NULL). msg is left unchanged in both source and
destination.
*/
extern int deflateReset OF((z_stream *strm));
/*
This function is equivalent to deflateEnd followed by deflateInit,
but does not free and reallocate all the internal compression state.
The stream will keep the same compression level and any other attributes
that may have been set by deflateInit2.
deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
stream state was inconsistent (such as zalloc or state being NULL).
*/
extern int inflateInit2 OF((z_stream *strm,
int windowBits));
/*
This is another version of inflateInit with more compression options. The
fields next_out, zalloc and zfree must be initialized before by the caller.
The windowBits parameter is the base two logarithm of the maximum window
size (the size of the history buffer). It should be in the range 8..15 for
this version of the library (the value 16 will be allowed soon). The
default value is 15 if inflateInit is used instead. If a compressed stream
with a larger window size is given as input, inflate() will return with
the error code Z_DATA_ERROR instead of trying to allocate a larger window.
If next_out is not null, the library will use this buffer for the history
buffer; the buffer must either be large enough to hold the entire output
data, or have at least 1<<windowBits bytes. If next_out is null, the
library will allocate its own buffer (and leave next_out null). next_in
need not be provided here but must be provided by the application for the
next call of inflate().
If the history buffer is provided by the application, next_out must
never be changed by the application since the decompressor maintains
history information inside this buffer from call to call; the application
can only reset next_out to the beginning of the history buffer when
avail_out is zero and all output has been consumed.
inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
windowBits < 8). msg is set to null if there is no error message.
inflateInit2 does not perform any decompression: this will be done by
inflate().
*/
extern int inflateSync OF((z_stream *strm));
/*
Skips invalid compressed data until the special marker (see deflate()
above) can be found, or until all available input is skipped. No output
is provided.
inflateSync returns Z_OK if the special marker has been found, Z_BUF_ERROR
if no more input was provided, Z_DATA_ERROR if no marker has been found,
or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
case, the application may save the current current value of total_in which
indicates where valid compressed data was found. In the error case, the
application may repeatedly call inflateSync, providing more input each time,
until success or end of the input data.
*/
extern int inflateReset OF((z_stream *strm));
/*
This function is equivalent to inflateEnd followed by inflateInit,
but does not free and reallocate all the internal decompression state.
The stream will keep attributes that may have been set by inflateInit2.
inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
stream state was inconsistent (such as zalloc or state being NULL).
*/
extern int inflateIncomp OF((z_stream *strm));
/*
This function adds the data at next_in (avail_in bytes) to the output
history without performing any output. There must be no pending output,
and the decompressor must be expecting to see the start of a block.
Calling this function is equivalent to decompressing a stored block
containing the data at next_in (except that the data is not output).
*/
/* checksum functions */
/*
This function is not related to compression but is exported
anyway because it might be useful in applications using the
compression library.
*/
extern uLong adler32 OF((uLong adler, Bytef *buf, uInt len));
/*
Update a running Adler-32 checksum with the bytes buf[0..len-1] and
return the updated checksum. If buf is NULL, this function returns
the required initial value for the checksum.
An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
much faster. Usage example:
uLong adler = adler32(0L, Z_NULL, 0);
while (read_buffer(buffer, length) != EOF) {
adler = adler32(adler, buffer, length);
}
if (adler != original_adler) error();
*/
#ifndef _Z_UTIL_H
struct internal_state {int dummy;}; /* hack for buggy compilers */
#endif
#endif /* _ZLIB_H */

782
loadparm.c Normal file
View File

@@ -0,0 +1,782 @@
/* This is based on loadparm.c from Samba, written by Andrew Tridgell
and Karl Auer */
/* some fixes
*
* Copyright (C) 2001 by Martin Pool <mbp@samba.org>
*/
/*
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* Load parameters.
*
* This module provides suitable callback functions for the params
* module. It builds the internal table of service details which is
* then used by the rest of the server.
*
* To add a parameter:
*
* 1) add it to the global or service structure definition
* 2) add it to the parm_table
* 3) add it to the list of available functions (eg: using FN_GLOBAL_STRING())
* 4) If it's a global then initialise it in init_globals. If a local
* (ie. service) parameter then initialise it in the sDefault structure
*
*
* Notes:
* The configuration file is processed sequentially for speed. It is NOT
* accessed randomly as happens in 'real' Windows. For this reason, there
* is a fair bit of sequence-dependent code here - ie., code which assumes
* that certain things happen before others. In particular, the code which
* happens at the boundary between sections is delicately poised, so be
* careful!
*
*/
#include "rsync.h"
#define PTR_DIFF(p1,p2) ((ptrdiff_t)(((char *)(p1)) - (char *)(p2)))
#define strequal(a,b) (strcasecmp(a,b)==0)
#define BOOLSTR(b) ((b) ? "Yes" : "No")
typedef char pstring[1024];
#define pstrcpy(a,b) strlcpy(a,b,sizeof(pstring))
/* the following are used by loadparm for option lists */
typedef enum
{
P_BOOL,P_BOOLREV,P_CHAR,P_INTEGER,P_OCTAL,
P_STRING,P_GSTRING,P_ENUM,P_SEP
} parm_type;
typedef enum
{
P_LOCAL,P_GLOBAL,P_SEPARATOR,P_NONE
} parm_class;
struct enum_list {
int value;
char *name;
};
struct parm_struct
{
char *label;
parm_type type;
parm_class class;
void *ptr;
struct enum_list *enum_list;
unsigned flags;
};
#ifndef GLOBAL_NAME
#define GLOBAL_NAME "global"
#endif
/* some helpful bits */
#define pSERVICE(i) ServicePtrs[i]
#define iSERVICE(i) (*pSERVICE(i))
#define LP_SNUM_OK(iService) (((iService) >= 0) && ((iService) < iNumServices))
/*
* This structure describes global (ie., server-wide) parameters.
*/
typedef struct
{
char *motd_file;
char *log_file;
char *pid_file;
int syslog_facility;
char *socket_options;
} global;
static global Globals;
/*
* This structure describes a single service.
*/
typedef struct
{
char *name;
char *path;
char *comment;
char *lock_file;
BOOL read_only;
BOOL list;
BOOL use_chroot;
BOOL transfer_logging;
BOOL ignore_errors;
char *uid;
char *gid;
char *hosts_allow;
char *hosts_deny;
char *auth_users;
char *secrets_file;
BOOL strict_modes;
char *exclude;
char *exclude_from;
char *include;
char *include_from;
char *log_format;
char *refuse_options;
char *dont_compress;
int timeout;
int max_connections;
BOOL ignore_nonreadable;
} service;
/* This is a default service used to prime a services structure */
static service sDefault =
{
NULL, /* name */
NULL, /* path */
NULL, /* comment */
DEFAULT_LOCK_FILE, /* lock file */
True, /* read only */
True, /* list */
True, /* use chroot */
False, /* transfer logging */
False, /* ignore errors */
"nobody",/* uid */
"nobody",/* gid */
NULL, /* hosts allow */
NULL, /* hosts deny */
NULL, /* auth users */
NULL, /* secrets file */
True, /* strict modes */
NULL, /* exclude */
NULL, /* exclude from */
NULL, /* include */
NULL, /* include from */
"%o %h [%a] %m (%u) %f %l", /* log format */
NULL, /* refuse options */
"*.gz *.tgz *.zip *.z *.rpm *.deb *.iso *.bz2 *.tbz", /* dont compress */
0, /* timeout */
0, /* max connections */
False /* ignore nonreadable */
};
/* local variables */
static service **ServicePtrs = NULL;
static int iNumServices = 0;
static int iServiceIndex = 0;
static BOOL bInGlobalSection = True;
#define NUMPARAMETERS (sizeof(parm_table) / sizeof(struct parm_struct))
static struct enum_list enum_facilities[] = {
#ifdef LOG_AUTH
{ LOG_AUTH, "auth" },
#endif
#ifdef LOG_AUTHPRIV
{ LOG_AUTHPRIV, "authpriv" },
#endif
#ifdef LOG_CRON
{ LOG_CRON, "cron" },
#endif
#ifdef LOG_DAEMON
{ LOG_DAEMON, "daemon" },
#endif
#ifdef LOG_FTP
{ LOG_FTP, "ftp" },
#endif
#ifdef LOG_KERN
{ LOG_KERN, "kern" },
#endif
#ifdef LOG_LPR
{ LOG_LPR, "lpr" },
#endif
#ifdef LOG_MAIL
{ LOG_MAIL, "mail" },
#endif
#ifdef LOG_NEWS
{ LOG_NEWS, "news" },
#endif
#ifdef LOG_AUTH
{ LOG_AUTH, "security" },
#endif
#ifdef LOG_SYSLOG
{ LOG_SYSLOG, "syslog" },
#endif
#ifdef LOG_USER
{ LOG_USER, "user" },
#endif
#ifdef LOG_UUCP
{ LOG_UUCP, "uucp" },
#endif
#ifdef LOG_LOCAL0
{ LOG_LOCAL0, "local0" },
#endif
#ifdef LOG_LOCAL1
{ LOG_LOCAL1, "local1" },
#endif
#ifdef LOG_LOCAL2
{ LOG_LOCAL2, "local2" },
#endif
#ifdef LOG_LOCAL3
{ LOG_LOCAL3, "local3" },
#endif
#ifdef LOG_LOCAL4
{ LOG_LOCAL4, "local4" },
#endif
#ifdef LOG_LOCAL5
{ LOG_LOCAL5, "local5" },
#endif
#ifdef LOG_LOCAL6
{ LOG_LOCAL6, "local6" },
#endif
#ifdef LOG_LOCAL7
{ LOG_LOCAL7, "local7" },
#endif
{ -1, NULL }};
/* note that we do not initialise the defaults union - it is not allowed in ANSI C */
static struct parm_struct parm_table[] =
{
{"motd file", P_STRING, P_GLOBAL, &Globals.motd_file, NULL, 0},
{"syslog facility", P_ENUM, P_GLOBAL, &Globals.syslog_facility, enum_facilities,0},
{"socket options", P_STRING, P_GLOBAL, &Globals.socket_options,NULL, 0},
{"log file", P_STRING, P_GLOBAL, &Globals.log_file, NULL, 0},
{"pid file", P_STRING, P_GLOBAL, &Globals.pid_file, NULL, 0},
{"timeout", P_INTEGER, P_LOCAL, &sDefault.timeout, NULL, 0},
{"max connections", P_INTEGER, P_LOCAL, &sDefault.max_connections,NULL, 0},
{"name", P_STRING, P_LOCAL, &sDefault.name, NULL, 0},
{"comment", P_STRING, P_LOCAL, &sDefault.comment, NULL, 0},
{"lock file", P_STRING, P_LOCAL, &sDefault.lock_file, NULL, 0},
{"path", P_STRING, P_LOCAL, &sDefault.path, NULL, 0},
{"read only", P_BOOL, P_LOCAL, &sDefault.read_only, NULL, 0},
{"list", P_BOOL, P_LOCAL, &sDefault.list, NULL, 0},
{"use chroot", P_BOOL, P_LOCAL, &sDefault.use_chroot, NULL, 0},
{"ignore nonreadable",P_BOOL, P_LOCAL, &sDefault.ignore_nonreadable, NULL, 0},
{"uid", P_STRING, P_LOCAL, &sDefault.uid, NULL, 0},
{"gid", P_STRING, P_LOCAL, &sDefault.gid, NULL, 0},
{"hosts allow", P_STRING, P_LOCAL, &sDefault.hosts_allow, NULL, 0},
{"hosts deny", P_STRING, P_LOCAL, &sDefault.hosts_deny, NULL, 0},
{"auth users", P_STRING, P_LOCAL, &sDefault.auth_users, NULL, 0},
{"secrets file", P_STRING, P_LOCAL, &sDefault.secrets_file,NULL, 0},
{"strict modes", P_BOOL, P_LOCAL, &sDefault.strict_modes,NULL, 0},
{"exclude", P_STRING, P_LOCAL, &sDefault.exclude, NULL, 0},
{"exclude from", P_STRING, P_LOCAL, &sDefault.exclude_from,NULL, 0},
{"include", P_STRING, P_LOCAL, &sDefault.include, NULL, 0},
{"include from", P_STRING, P_LOCAL, &sDefault.include_from,NULL, 0},
{"transfer logging", P_BOOL, P_LOCAL, &sDefault.transfer_logging,NULL,0},
{"ignore errors", P_BOOL, P_LOCAL, &sDefault.ignore_errors,NULL,0},
{"log format", P_STRING, P_LOCAL, &sDefault.log_format, NULL, 0},
{"refuse options", P_STRING, P_LOCAL, &sDefault.refuse_options,NULL, 0},
{"dont compress", P_STRING, P_LOCAL, &sDefault.dont_compress,NULL, 0},
{NULL, P_BOOL, P_NONE, NULL, NULL, 0}
};
/***************************************************************************
Initialise the global parameter structure.
***************************************************************************/
static void init_globals(void)
{
memset(&Globals, 0, sizeof(Globals));
#ifdef LOG_DAEMON
Globals.syslog_facility = LOG_DAEMON;
#endif
}
/***************************************************************************
Initialise the sDefault parameter structure.
***************************************************************************/
static void init_locals(void)
{
}
/*
In this section all the functions that are used to access the
parameters from the rest of the program are defined
*/
#define FN_GLOBAL_STRING(fn_name,ptr) \
char *fn_name(void) {return(*(char **)(ptr) ? *(char **)(ptr) : "");}
#define FN_GLOBAL_BOOL(fn_name,ptr) \
BOOL fn_name(void) {return(*(BOOL *)(ptr));}
#define FN_GLOBAL_CHAR(fn_name,ptr) \
char fn_name(void) {return(*(char *)(ptr));}
#define FN_GLOBAL_INTEGER(fn_name,ptr) \
int fn_name(void) {return(*(int *)(ptr));}
#define FN_LOCAL_STRING(fn_name,val) \
char *fn_name(int i) {return((LP_SNUM_OK(i)&&pSERVICE(i)->val)?pSERVICE(i)->val : (sDefault.val?sDefault.val:""));}
#define FN_LOCAL_BOOL(fn_name,val) \
BOOL fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
#define FN_LOCAL_CHAR(fn_name,val) \
char fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
#define FN_LOCAL_INTEGER(fn_name,val) \
int fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
FN_GLOBAL_STRING(lp_motd_file, &Globals.motd_file)
FN_GLOBAL_STRING(lp_log_file, &Globals.log_file)
FN_GLOBAL_STRING(lp_pid_file, &Globals.pid_file)
FN_GLOBAL_STRING(lp_socket_options, &Globals.socket_options)
FN_GLOBAL_INTEGER(lp_syslog_facility, &Globals.syslog_facility)
FN_LOCAL_STRING(lp_name, name)
FN_LOCAL_STRING(lp_comment, comment)
FN_LOCAL_STRING(lp_path, path)
FN_LOCAL_STRING(lp_lock_file, lock_file)
FN_LOCAL_BOOL(lp_read_only, read_only)
FN_LOCAL_BOOL(lp_list, list)
FN_LOCAL_BOOL(lp_use_chroot, use_chroot)
FN_LOCAL_BOOL(lp_transfer_logging, transfer_logging)
FN_LOCAL_BOOL(lp_ignore_errors, ignore_errors)
FN_LOCAL_BOOL(lp_ignore_nonreadable, ignore_nonreadable)
FN_LOCAL_STRING(lp_uid, uid)
FN_LOCAL_STRING(lp_gid, gid)
FN_LOCAL_STRING(lp_hosts_allow, hosts_allow)
FN_LOCAL_STRING(lp_hosts_deny, hosts_deny)
FN_LOCAL_STRING(lp_auth_users, auth_users)
FN_LOCAL_STRING(lp_secrets_file, secrets_file)
FN_LOCAL_BOOL(lp_strict_modes, strict_modes)
FN_LOCAL_STRING(lp_exclude, exclude)
FN_LOCAL_STRING(lp_exclude_from, exclude_from)
FN_LOCAL_STRING(lp_include, include)
FN_LOCAL_STRING(lp_include_from, include_from)
FN_LOCAL_STRING(lp_log_format, log_format)
FN_LOCAL_STRING(lp_refuse_options, refuse_options)
FN_LOCAL_STRING(lp_dont_compress, dont_compress)
FN_LOCAL_INTEGER(lp_timeout, timeout)
FN_LOCAL_INTEGER(lp_max_connections, max_connections)
/* local prototypes */
static int strwicmp( char *psz1, char *psz2 );
static int map_parameter( char *parmname);
static BOOL set_boolean( BOOL *pb, char *parmvalue );
static int getservicebyname(char *name, service *pserviceDest);
static void copy_service( service *pserviceDest,
service *pserviceSource);
static BOOL do_parameter(char *parmname, char *parmvalue);
static BOOL do_section(char *sectionname);
/***************************************************************************
initialise a service to the defaults
***************************************************************************/
static void init_service(service *pservice)
{
memset((char *)pservice,0,sizeof(service));
copy_service(pservice,&sDefault);
}
/**
* Assign a copy of @p v to @p *s. Handles NULL strings. @p *v must
* be initialized when this is called, either to NULL or a malloc'd
* string.
*
* @fixme There is a small leak here in that sometimes the existing
* value will be dynamically allocated, and the old copy is lost.
* However, we can't always deallocate the old value, because in the
* case of sDefault, it points to a static string. It would be nice
* to have either all-strdup'd values, or to never need to free
* memory.
**/
static void string_set(char **s, const char *v)
{
if (!v) {
*s = NULL;
return;
}
*s = strdup(v);
if (!*s)
exit_cleanup(RERR_MALLOC);
}
/***************************************************************************
add a new service to the services array initialising it with the given
service
***************************************************************************/
static int add_a_service(service *pservice, char *name)
{
int i;
service tservice;
int num_to_alloc = iNumServices+1;
tservice = *pservice;
/* it might already exist */
if (name)
{
i = getservicebyname(name,NULL);
if (i >= 0)
return(i);
}
i = iNumServices;
ServicePtrs = (service **)Realloc(ServicePtrs,sizeof(service *)*num_to_alloc);
if (ServicePtrs)
pSERVICE(iNumServices) = (service *)malloc(sizeof(service));
if (!ServicePtrs || !pSERVICE(iNumServices))
return(-1);
iNumServices++;
init_service(pSERVICE(i));
copy_service(pSERVICE(i),&tservice);
if (name)
string_set(&iSERVICE(i).name,name);
return(i);
}
/***************************************************************************
Do a case-insensitive, whitespace-ignoring string compare.
***************************************************************************/
static int strwicmp(char *psz1, char *psz2)
{
/* if BOTH strings are NULL, return TRUE, if ONE is NULL return */
/* appropriate value. */
if (psz1 == psz2)
return (0);
else
if (psz1 == NULL)
return (-1);
else
if (psz2 == NULL)
return (1);
/* sync the strings on first non-whitespace */
while (1)
{
while (isspace(*psz1))
psz1++;
while (isspace(*psz2))
psz2++;
if (toupper(*psz1) != toupper(*psz2) || *psz1 == '\0' || *psz2 == '\0')
break;
psz1++;
psz2++;
}
return (*psz1 - *psz2);
}
/***************************************************************************
Map a parameter's string representation to something we can use.
Returns False if the parameter string is not recognised, else TRUE.
***************************************************************************/
static int map_parameter(char *parmname)
{
int iIndex;
if (*parmname == '-')
return(-1);
for (iIndex = 0; parm_table[iIndex].label; iIndex++)
if (strwicmp(parm_table[iIndex].label, parmname) == 0)
return(iIndex);
rprintf(FERROR, "Unknown Parameter encountered: \"%s\"\n", parmname);
return(-1);
}
/***************************************************************************
Set a boolean variable from the text value stored in the passed string.
Returns True in success, False if the passed string does not correctly
represent a boolean.
***************************************************************************/
static BOOL set_boolean(BOOL *pb, char *parmvalue)
{
BOOL bRetval;
bRetval = True;
if (strwicmp(parmvalue, "yes") == 0 ||
strwicmp(parmvalue, "true") == 0 ||
strwicmp(parmvalue, "1") == 0)
*pb = True;
else
if (strwicmp(parmvalue, "no") == 0 ||
strwicmp(parmvalue, "False") == 0 ||
strwicmp(parmvalue, "0") == 0)
*pb = False;
else
{
rprintf(FERROR, "Badly formed boolean in configuration file: \"%s\".\n",
parmvalue);
bRetval = False;
}
return (bRetval);
}
/***************************************************************************
Find a service by name. Otherwise works like get_service.
***************************************************************************/
static int getservicebyname(char *name, service *pserviceDest)
{
int iService;
for (iService = iNumServices - 1; iService >= 0; iService--)
if (strwicmp(iSERVICE(iService).name, name) == 0)
{
if (pserviceDest != NULL)
copy_service(pserviceDest, pSERVICE(iService));
break;
}
return (iService);
}
/***************************************************************************
Copy a service structure to another
***************************************************************************/
static void copy_service(service *pserviceDest,
service *pserviceSource)
{
int i;
for (i=0;parm_table[i].label;i++)
if (parm_table[i].ptr && parm_table[i].class == P_LOCAL) {
void *def_ptr = parm_table[i].ptr;
void *src_ptr =
((char *)pserviceSource) + PTR_DIFF(def_ptr,&sDefault);
void *dest_ptr =
((char *)pserviceDest) + PTR_DIFF(def_ptr,&sDefault);
switch (parm_table[i].type)
{
case P_BOOL:
case P_BOOLREV:
*(BOOL *)dest_ptr = *(BOOL *)src_ptr;
break;
case P_INTEGER:
case P_ENUM:
case P_OCTAL:
*(int *)dest_ptr = *(int *)src_ptr;
break;
case P_CHAR:
*(char *)dest_ptr = *(char *)src_ptr;
break;
case P_STRING:
string_set(dest_ptr,*(char **)src_ptr);
break;
default:
break;
}
}
}
/***************************************************************************
Process a parameter for a particular service number. If snum < 0
then assume we are in the globals
***************************************************************************/
static BOOL lp_do_parameter(int snum, char *parmname, char *parmvalue)
{
int parmnum, i;
void *parm_ptr=NULL; /* where we are going to store the result */
void *def_ptr=NULL;
parmnum = map_parameter(parmname);
if (parmnum < 0)
{
rprintf(FERROR, "IGNORING unknown parameter \"%s\"\n", parmname);
return(True);
}
def_ptr = parm_table[parmnum].ptr;
/* we might point at a service, the default service or a global */
if (snum < 0) {
parm_ptr = def_ptr;
} else {
if (parm_table[parmnum].class == P_GLOBAL) {
rprintf(FERROR, "Global parameter %s found in service section!\n",parmname);
return(True);
}
parm_ptr = ((char *)pSERVICE(snum)) + PTR_DIFF(def_ptr,&sDefault);
}
/* now switch on the type of variable it is */
switch (parm_table[parmnum].type)
{
case P_BOOL:
set_boolean(parm_ptr,parmvalue);
break;
case P_BOOLREV:
set_boolean(parm_ptr,parmvalue);
*(BOOL *)parm_ptr = ! *(BOOL *)parm_ptr;
break;
case P_INTEGER:
*(int *)parm_ptr = atoi(parmvalue);
break;
case P_CHAR:
*(char *)parm_ptr = *parmvalue;
break;
case P_OCTAL:
sscanf(parmvalue,"%o",(int *)parm_ptr);
break;
case P_STRING:
string_set(parm_ptr,parmvalue);
break;
case P_GSTRING:
strlcpy((char *)parm_ptr,parmvalue,sizeof(pstring));
break;
case P_ENUM:
for (i=0;parm_table[parmnum].enum_list[i].name;i++) {
if (strequal(parmvalue, parm_table[parmnum].enum_list[i].name)) {
*(int *)parm_ptr = parm_table[parmnum].enum_list[i].value;
break;
}
}
if (!parm_table[parmnum].enum_list[i].name) {
if (atoi(parmvalue) > 0)
*(int *)parm_ptr = atoi(parmvalue);
}
break;
case P_SEP:
break;
}
return(True);
}
/***************************************************************************
Process a parameter.
***************************************************************************/
static BOOL do_parameter(char *parmname, char *parmvalue)
{
return lp_do_parameter(bInGlobalSection?-2:iServiceIndex, parmname, parmvalue);
}
/***************************************************************************
Process a new section (service). At this stage all sections are services.
Later we'll have special sections that permit server parameters to be set.
Returns True on success, False on failure.
***************************************************************************/
static BOOL do_section(char *sectionname)
{
BOOL bRetval;
BOOL isglobal = (strwicmp(sectionname, GLOBAL_NAME) == 0);
bRetval = False;
/* if we were in a global section then do the local inits */
if (bInGlobalSection && !isglobal)
init_locals();
/* if we've just struck a global section, note the fact. */
bInGlobalSection = isglobal;
/* check for multiple global sections */
if (bInGlobalSection)
{
return(True);
}
/* if we have a current service, tidy it up before moving on */
bRetval = True;
if (iServiceIndex >= 0)
bRetval = True;
/* if all is still well, move to the next record in the services array */
if (bRetval)
{
/* We put this here to avoid an odd message order if messages are */
/* issued by the post-processing of a previous section. */
if ((iServiceIndex=add_a_service(&sDefault,sectionname)) < 0)
{
rprintf(FERROR,"Failed to add a new service\n");
return(False);
}
}
return (bRetval);
}
/***************************************************************************
Load the services array from the services file. Return True on success,
False on failure.
***************************************************************************/
BOOL lp_load(char *pszFname, int globals_only)
{
pstring n2;
BOOL bRetval;
bRetval = False;
bInGlobalSection = True;
init_globals();
pstrcpy(n2,pszFname);
/* We get sections first, so have to start 'behind' to make up */
iServiceIndex = -1;
bRetval = pm_process(n2, globals_only?NULL:do_section, do_parameter);
return (bRetval);
}
/***************************************************************************
return the max number of services
***************************************************************************/
int lp_numservices(void)
{
return(iNumServices);
}
/***************************************************************************
Return the number of the service with the given name, or -1 if it doesn't
exist. Note that this is a DIFFERENT ANIMAL from the internal function
getservicebyname()! This works ONLY if all services have been loaded, and
does not copy the found service.
***************************************************************************/
int lp_number(char *name)
{
int iService;
for (iService = iNumServices - 1; iService >= 0; iService--)
if (strequal(lp_name(iService), name))
break;
return (iService);
}

354
log.c Normal file
View File

@@ -0,0 +1,354 @@
/*
Copyright (C) Andrew Tridgell 1998
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
logging and utility functions
tridge, May 1998
*/
#include "rsync.h"
static FILE *logfile;
static int log_error_fd = -1;
static void logit(int priority, char *buf)
{
if (logfile) {
fprintf(logfile,"%s [%d] %s",
timestring(time(NULL)), (int)getpid(), buf);
fflush(logfile);
} else {
syslog(priority, "%s", buf);
}
}
void log_open(void)
{
static int initialised;
int options = LOG_PID;
time_t t;
char *logf;
if (initialised) return;
initialised = 1;
/* this looks pointless, but it is needed in order for the
C library on some systems to fetch the timezone info
before the chroot */
t = time(NULL);
localtime(&t);
/* optionally use a log file instead of syslog */
logf = lp_log_file();
if (logf && *logf) {
extern int orig_umask;
int old_umask = umask(022 | orig_umask);
logfile = fopen(logf, "a");
umask(old_umask);
return;
}
#ifdef LOG_NDELAY
options |= LOG_NDELAY;
#endif
#ifdef LOG_DAEMON
openlog("rsyncd", options, lp_syslog_facility());
#else
openlog("rsyncd", options);
#endif
#ifndef LOG_NDELAY
logit(LOG_INFO,"rsyncd started\n");
#endif
}
/* setup the error file descriptor - used when we are a server
that is receiving files */
void set_error_fd(int fd)
{
log_error_fd = fd;
}
/* this is the underlying (unformatted) rsync debugging function. Call
it with FINFO, FERROR or FLOG */
void rwrite(enum logcode code, char *buf, int len)
{
FILE *f=NULL;
extern int am_daemon;
extern int am_server;
extern int quiet;
/* recursion can happen with certain fatal conditions */
if (quiet && code == FINFO) return;
if (len < 0) exit_cleanup(RERR_MESSAGEIO);
buf[len] = 0;
if (code == FLOG) {
if (am_daemon) logit(LOG_INFO, buf);
return;
}
/* first try to pass it off the our sibling */
if (am_server && io_error_write(log_error_fd, code, buf, len)) {
return;
}
/* then try to pass it to the other end */
if (am_server && io_multiplex_write(code, buf, len)) {
return;
}
if (am_daemon) {
static int depth;
int priority = LOG_INFO;
if (code == FERROR) priority = LOG_WARNING;
if (depth) return;
depth++;
log_open();
logit(priority, buf);
depth--;
return;
}
if (code == FERROR) {
f = stderr;
}
if (code == FINFO) {
if (am_server)
f = stderr;
else
f = stdout;
}
if (!f) exit_cleanup(RERR_MESSAGEIO);
if (fwrite(buf, len, 1, f) != 1) exit_cleanup(RERR_MESSAGEIO);
if (buf[len-1] == '\r' || buf[len-1] == '\n') fflush(f);
}
/* this is the rsync debugging function. Call it with FINFO, FERROR or FLOG */
void rprintf(enum logcode code, const char *format, ...)
{
va_list ap;
char buf[1024];
int len;
va_start(ap, format);
len = vslprintf(buf, sizeof(buf), format, ap);
va_end(ap);
if (len > sizeof(buf)-1) exit_cleanup(RERR_MESSAGEIO);
rwrite(code, buf, len);
}
void rflush(enum logcode code)
{
FILE *f = NULL;
extern int am_daemon;
if (am_daemon) {
return;
}
if (code == FLOG) {
return;
}
if (code == FERROR) {
f = stderr;
}
if (code == FINFO) {
extern int am_server;
if (am_server)
f = stderr;
else
f = stdout;
}
if (!f) exit_cleanup(RERR_MESSAGEIO);
fflush(f);
}
/* a generic logging routine for send/recv, with parameter
substitiution */
static void log_formatted(enum logcode code,
char *format, char *op, struct file_struct *file,
struct stats *initial_stats)
{
extern int module_id;
extern char *auth_user;
char buf[1024];
char buf2[1024];
char *p, *s, *n;
int l;
extern struct stats stats;
extern int am_sender;
extern int am_daemon;
int64 b;
memset(buf,0,sizeof(buf));
strlcpy(buf, format, sizeof(buf));
for (s=&buf[0];
s && (p=strchr(s,'%')); ) {
n = NULL;
s = p + 1;
switch (p[1]) {
case 'h': if (am_daemon) n = client_name(0); break;
case 'a': if (am_daemon) n = client_addr(0); break;
case 'l':
slprintf(buf2,sizeof(buf2),"%.0f",
(double)file->length);
n = buf2;
break;
case 'p':
slprintf(buf2,sizeof(buf2),"%d",
(int)getpid());
n = buf2;
break;
case 'o': n = op; break;
case 'f':
slprintf(buf2, sizeof(buf2), "%s/%s",
file->basedir?file->basedir:"",
f_name(file));
clean_fname(buf2);
n = buf2;
if (*n == '/') n++;
break;
case 'm': n = lp_name(module_id); break;
case 't': n = timestring(time(NULL)); break;
case 'P': n = lp_path(module_id); break;
case 'u': n = auth_user; break;
case 'b':
if (am_sender) {
b = stats.total_written -
initial_stats->total_written;
} else {
b = stats.total_read -
initial_stats->total_read;
}
slprintf(buf2,sizeof(buf2),"%.0f", (double)b);
n = buf2;
break;
case 'c':
if (!am_sender) {
b = stats.total_written -
initial_stats->total_written;
} else {
b = stats.total_read -
initial_stats->total_read;
}
slprintf(buf2,sizeof(buf2),"%.0f", (double)b);
n = buf2;
break;
}
if (!n) continue;
l = strlen(n);
if (l + ((int)(s - &buf[0])) > sizeof(buf)) {
rprintf(FERROR,"buffer overflow expanding %%%c - exiting\n",
p[0]);
exit_cleanup(RERR_MESSAGEIO);
}
if (l != 2) {
memmove(s+(l-1), s+1, strlen(s+1)+1);
}
memcpy(p, n, l);
s = p+l;
}
rprintf(code,"%s\n", buf);
}
/* log the outgoing transfer of a file */
void log_send(struct file_struct *file, struct stats *initial_stats)
{
extern int module_id;
extern int am_server;
extern char *log_format;
if (lp_transfer_logging(module_id)) {
log_formatted(FLOG, lp_log_format(module_id), "send", file, initial_stats);
} else if (log_format && !am_server) {
log_formatted(FINFO, log_format, "send", file, initial_stats);
}
}
/* log the incoming transfer of a file */
void log_recv(struct file_struct *file, struct stats *initial_stats)
{
extern int module_id;
extern int am_server;
extern char *log_format;
if (lp_transfer_logging(module_id)) {
log_formatted(FLOG, lp_log_format(module_id), "recv", file, initial_stats);
} else if (log_format && !am_server) {
log_formatted(FINFO, log_format, "recv", file, initial_stats);
}
}
/* called when the transfer is interrupted for some reason */
void log_exit(int code, const char *file, int line)
{
if (code == 0) {
extern struct stats stats;
rprintf(FLOG,"wrote %.0f bytes read %.0f bytes total size %.0f\n",
(double)stats.total_written,
(double)stats.total_read,
(double)stats.total_size);
} else {
rprintf(FLOG,"transfer interrupted (code %d) at %s(%d)\n",
code, file, line);
}
}
/* log the incoming transfer of a file for interactive use, this
will be called at the end where the client was run
it i called when a file starts to be transferred
*/
void log_transfer(struct file_struct *file, const char *fname)
{
extern int verbose;
if (!verbose) return;
rprintf(FINFO,"%s\n", fname);
}

1414
main.c
View File

File diff suppressed because it is too large Load Diff

137
match.c
View File

@@ -29,18 +29,18 @@ extern int remote_version;
typedef unsigned short tag;
#define TABLESIZE (1<<16)
#define NULL_TAG ((tag)-1)
#define NULL_TAG (-1)
static int false_alarms;
static int tag_hits;
static int matches;
static int data_transfer;
static int64 data_transfer;
static int total_false_alarms;
static int total_tag_hits;
static int total_matches;
static int64 total_data_transfer;
extern struct stats stats;
struct target {
tag t;
@@ -49,14 +49,14 @@ struct target {
static struct target *targets;
static tag *tag_table;
static int *tag_table;
#define gettag2(s1,s2) (((s1) + (s2)) & 0xFFFF)
#define gettag(sum) gettag2((sum)&0xFFFF,(sum)>>16)
static int compare_targets(struct target *t1,struct target *t2)
{
return(t1->t - t2->t);
return((int)t1->t - (int)t2->t);
}
@@ -65,7 +65,7 @@ static void build_hash_table(struct sum_struct *s)
int i;
if (!tag_table)
tag_table = (tag *)malloc(sizeof(tag)*TABLESIZE);
tag_table = (int *)malloc(sizeof(tag_table[0])*TABLESIZE);
targets = (struct target *)malloc(sizeof(targets[0])*s->count);
if (!tag_table || !targets)
@@ -87,27 +87,26 @@ static void build_hash_table(struct sum_struct *s)
}
static off_t last_match;
static OFF_T last_match;
static void matched(int f,struct sum_struct *s,struct map_struct *buf,
off_t offset,int i)
OFF_T offset,int i)
{
off_t n = offset - last_match;
int j;
OFF_T n = offset - last_match;
OFF_T j;
if (verbose > 2 && i >= 0)
fprintf(FINFO,"match at %d last_match=%d j=%d len=%d n=%d\n",
(int)offset,(int)last_match,i,(int)s->sums[i].len,(int)n);
rprintf(FINFO,"match at %.0f last_match=%.0f j=%d len=%d n=%.0f\n",
(double)offset,(double)last_match,i,s->sums[i].len,(double)n);
send_token(f,i,buf,last_match,n,i==-1?0:s->sums[i].len);
send_token(f,i,buf,last_match,n,i<0?0:s->sums[i].len);
data_transfer += n;
if (n > 0)
write_flush(f);
if (i >= 0)
if (i >= 0) {
stats.matched_data += s->sums[i].len;
n += s->sums[i].len;
}
for (j=0;j<n;j+=CHUNK_SIZE) {
int n1 = MIN(CHUNK_SIZE,n-j);
@@ -119,39 +118,48 @@ static void matched(int f,struct sum_struct *s,struct map_struct *buf,
last_match = offset + s->sums[i].len;
else
last_match = offset;
if (buf) {
show_progress(last_match, buf->file_size);
if (i == -1) end_progress(buf->file_size);
}
}
static void hash_search(int f,struct sum_struct *s,
struct map_struct *buf,off_t len)
struct map_struct *buf,OFF_T len)
{
off_t offset;
int j,k;
int end;
OFF_T offset, end;
int j,k, last_i;
char sum2[SUM_LENGTH];
uint32 s1, s2, sum;
signed char *map;
schar *map;
/* last_i is used to encourage adjacent matches, allowing the RLL coding of the
output to work more efficiently */
last_i = -1;
if (verbose > 2)
fprintf(FINFO,"hash search b=%d len=%d\n",s->n,(int)len);
rprintf(FINFO,"hash search b=%d len=%.0f\n",s->n,(double)len);
k = MIN(len, s->n);
map = (signed char *)map_ptr(buf,0,k);
map = (schar *)map_ptr(buf,0,k);
sum = get_checksum1((char *)map, k);
s1 = sum & 0xFFFF;
s2 = sum >> 16;
if (verbose > 3)
fprintf(FINFO, "sum=%.8x k=%d\n", sum, k);
rprintf(FINFO, "sum=%.8x k=%d\n", sum, k);
offset = 0;
end = len + 1 - s->sums[s->count-1].len;
if (verbose > 3)
fprintf(FINFO,"hash search s->n=%d len=%d count=%d\n",
s->n,(int)len,s->count);
rprintf(FINFO,"hash search s->n=%d len=%.0f count=%d\n",
s->n,(double)len,s->count);
do {
tag t = gettag2(s1,s2);
@@ -159,7 +167,7 @@ static void hash_search(int f,struct sum_struct *s,
j = tag_table[t];
if (verbose > 4)
fprintf(FINFO,"offset=%d sum=%08x\n",(int)offset,sum);
rprintf(FINFO,"offset=%.0f sum=%08x\n",(double)offset,sum);
if (j == NULL_TAG) {
goto null_tag;
@@ -168,17 +176,20 @@ static void hash_search(int f,struct sum_struct *s,
sum = (s1 & 0xffff) | (s2 << 16);
tag_hits++;
for (; j<s->count && targets[j].t == t; j++) {
int i = targets[j].i;
int l, i = targets[j].i;
if (sum != s->sums[i].sum1) continue;
/* also make sure the two blocks are the same length */
l = MIN(s->n,len-offset);
if (l != s->sums[i].len) continue;
if (verbose > 3)
fprintf(FINFO,"potential match at %d target=%d %d sum=%08x\n",
(int)offset,j,i,sum);
rprintf(FINFO,"potential match at %.0f target=%d %d sum=%08x\n",
(double)offset,j,i,sum);
if (!done_csum2) {
int l = MIN(s->n,len-offset);
map = (signed char *)map_ptr(buf,offset,l);
map = (schar *)map_ptr(buf,offset,l);
get_checksum2((char *)map,l,sum2);
done_csum2 = 1;
}
@@ -187,11 +198,27 @@ static void hash_search(int f,struct sum_struct *s,
false_alarms++;
continue;
}
/* we've found a match, but now check to see
if last_i can hint at a better match */
for (j++; j<s->count && targets[j].t == t; j++) {
int i2 = targets[j].i;
if (i2 == last_i + 1) {
if (sum != s->sums[i2].sum1) break;
if (memcmp(sum2,s->sums[i2].sum2,csum_length) != 0) break;
/* we've found an adjacent match - the RLL coder
will be happy */
i = i2;
break;
}
}
last_i = i;
matched(f,s,buf,offset,i);
offset += s->sums[i].len - 1;
k = MIN((len-offset), s->n);
map = (signed char *)map_ptr(buf,offset,k);
map = (schar *)map_ptr(buf,offset,k);
sum = get_checksum1((char *)map, k);
s1 = sum & 0xFFFF;
s2 = sum >> 16;
@@ -201,7 +228,7 @@ static void hash_search(int f,struct sum_struct *s,
null_tag:
/* Trim off the first byte from the checksum */
map = (signed char *)map_ptr(buf,offset,k+1);
map = (schar *)map_ptr(buf,offset,k+1);
s1 -= map[0] + CHAR_OFFSET;
s2 -= k * (map[0]+CHAR_OFFSET);
@@ -212,7 +239,17 @@ static void hash_search(int f,struct sum_struct *s,
} else {
--k;
}
/* By matching early we avoid re-reading the
data 3 times in the case where a token
match comes a long way after last
match. The 3 reads are caused by the
running match, the checksum update and the
literal send. */
if (offset-last_match >= CHUNK_SIZE+s->n &&
(end-offset > CHUNK_SIZE)) {
matched(f,s,buf,offset - s->n, -2);
}
} while (++offset < end);
matched(f,s,buf,len,-1);
@@ -220,9 +257,10 @@ static void hash_search(int f,struct sum_struct *s,
}
void match_sums(int f,struct sum_struct *s,struct map_struct *buf,off_t len)
void match_sums(int f,struct sum_struct *s,struct map_struct *buf,OFF_T len)
{
char file_sum[MD4_SUM_LENGTH];
extern int write_batch; /* dw */
last_match = 0;
false_alarms = 0;
@@ -236,13 +274,19 @@ void match_sums(int f,struct sum_struct *s,struct map_struct *buf,off_t len)
build_hash_table(s);
if (verbose > 2)
fprintf(FINFO,"built hash table\n");
rprintf(FINFO,"built hash table\n");
hash_search(f,s,buf,len);
if (verbose > 2)
fprintf(FINFO,"done hash search\n");
rprintf(FINFO,"done hash search\n");
} else {
OFF_T j;
/* by doing this in pieces we avoid too many seeks */
for (j=0;j<(len-CHUNK_SIZE);j+=CHUNK_SIZE) {
int n1 = MIN(CHUNK_SIZE,(len-CHUNK_SIZE)-j);
matched(f,s,buf,j+n1,-2);
}
matched(f,s,buf,len,-1);
}
@@ -250,8 +294,10 @@ void match_sums(int f,struct sum_struct *s,struct map_struct *buf,off_t len)
if (remote_version >= 14) {
if (verbose > 2)
fprintf(FINFO,"sending file_sum\n");
rprintf(FINFO,"sending file_sum\n");
write_buf(f,file_sum,MD4_SUM_LENGTH);
if (write_batch) /* dw */
write_batch_delta_file(file_sum, MD4_SUM_LENGTH);
}
if (targets) {
@@ -260,13 +306,13 @@ void match_sums(int f,struct sum_struct *s,struct map_struct *buf,off_t len)
}
if (verbose > 2)
fprintf(FINFO, "false_alarms=%d tag_hits=%d matches=%d\n",
rprintf(FINFO, "false_alarms=%d tag_hits=%d matches=%d\n",
false_alarms, tag_hits, matches);
total_tag_hits += tag_hits;
total_false_alarms += false_alarms;
total_matches += matches;
total_data_transfer += data_transfer;
stats.literal_data += data_transfer;
}
void match_report(void)
@@ -274,8 +320,9 @@ void match_report(void)
if (verbose <= 1)
return;
fprintf(FINFO,
"total: matches=%d tag_hits=%d false_alarms=%d data=%ld\n",
rprintf(FINFO,
"total: matches=%d tag_hits=%d false_alarms=%d data=%.0f\n",
total_matches,total_tag_hits,
total_false_alarms,(long)total_data_transfer);
total_false_alarms,
(double)stats.literal_data);
}

263
md4.c
View File

@@ -1,263 +0,0 @@
/*
This code is from rfc1186.
It has been modified to use the SIVAL() macro to make it
byte order and length independent, so we don't need the LOWBYTEFIRST define
*/
/*
** ********************************************************************
** md4.c -- Implementation of MD4 Message Digest Algorithm **
** Updated: 2/16/90 by Ronald L. Rivest **
** (C) 1990 RSA Data Security, Inc. **
** ********************************************************************
*/
/*
** To use MD4:
** -- Include md4.h in your program
** -- Declare an MDstruct MD to hold the state of the digest
** computation.
** -- Initialize MD using MDbegin(&MD)
** -- For each full block (64 bytes) X you wish to process, call
** MDupdate(&MD,X,512)
** (512 is the number of bits in a full block.)
** -- For the last block (less than 64 bytes) you wish to process,
** MDupdate(&MD,X,n)
** where n is the number of bits in the partial block. A partial
** block terminates the computation, so every MD computation
** should terminate by processing a partial block, even if it
** has n = 0.
** -- The message digest is available in MD.buffer[0] ...
** MD.buffer[3]. (Least-significant byte of each word
** should be output first.)
** -- You can print out the digest using MDprint(&MD)
*/
#define TRUE 1
#define FALSE 0
/* Compile-time includes
*/
#include "rsync.h"
/* Compile-time declarations of MD4 "magic constants".
*/
#define I0 0x67452301 /* Initial values for MD buffer */
#define I1 0xefcdab89
#define I2 0x98badcfe
#define I3 0x10325476
#define C2 013240474631 /* round 2 constant = sqrt(2) in octal */
#define C3 015666365641 /* round 3 constant = sqrt(3) in octal */
/* C2 and C3 are from Knuth, The Art of Programming, Volume 2
** (Seminumerical Algorithms), Second Edition (1981), Addison-Wesley.
** Table 2, page 660.
*/
#define fs1 3 /* round 1 shift amounts */
#define fs2 7
#define fs3 11
#define fs4 19
#define gs1 3 /* round 2 shift amounts */
#define gs2 5
#define gs3 9
#define gs4 13
#define hs1 3 /* round 3 shift amounts */
#define hs2 9
#define hs3 11
#define hs4 15
/* Compile-time macro declarations for MD4.
** Note: The "rot" operator uses the variable "tmp".
** It assumes tmp is declared as unsigned int, so that the >>
** operator will shift in zeros rather than extending the sign bit.
*/
#define f(X,Y,Z) ((X&Y) | ((~X)&Z))
#define g(X,Y,Z) ((X&Y) | (X&Z) | (Y&Z))
#define h(X,Y,Z) (X^Y^Z)
#define rot(X,S) (tmp=X,(tmp<<S) | (tmp>>(32-S)))
#define ff(A,B,C,D,i,s) A = rot((A + f(B,C,D) + X[i]),s)
#define gg(A,B,C,D,i,s) A = rot((A + g(B,C,D) + X[i] + C2),s)
#define hh(A,B,C,D,i,s) A = rot((A + h(B,C,D) + X[i] + C3),s)
/* MDbegin(MDp)
** Initialize message digest buffer MDp.
** This is a user-callable routine.
*/
void
MDbegin(MDp)
MDptr MDp;
{ int i;
MDp->buffer[0] = I0;
MDp->buffer[1] = I1;
MDp->buffer[2] = I2;
MDp->buffer[3] = I3;
for (i=0;i<8;i++) MDp->count[i] = 0;
MDp->done = 0;
}
/* MDreverse(X)
** Reverse the byte-ordering of every int in X.
** Assumes X is an array of 16 ints.
** The macro revx reverses the byte-ordering of the next word of X.
*/
void MDreverse(X)
unsigned int32 *X;
{ register unsigned int32 t;
register unsigned int i;
for(i = 0; i < 16; i++) {
t = X[i];
SIVAL(X,i*4,t);
}
}
/* MDblock(MDp,X)
** Update message digest buffer MDp->buffer using 16-word data block X.
** Assumes all 16 words of X are full of data.
** Does not update MDp->count.
** This routine is not user-callable.
*/
static void
MDblock(MDp,X)
MDptr MDp;
unsigned int32 *X;
{
register unsigned int32 tmp, A, B, C, D;
MDreverse(X);
A = MDp->buffer[0];
B = MDp->buffer[1];
C = MDp->buffer[2];
D = MDp->buffer[3];
/* Update the message digest buffer */
ff(A , B , C , D , 0 , fs1); /* Round 1 */
ff(D , A , B , C , 1 , fs2);
ff(C , D , A , B , 2 , fs3);
ff(B , C , D , A , 3 , fs4);
ff(A , B , C , D , 4 , fs1);
ff(D , A , B , C , 5 , fs2);
ff(C , D , A , B , 6 , fs3);
ff(B , C , D , A , 7 , fs4);
ff(A , B , C , D , 8 , fs1);
ff(D , A , B , C , 9 , fs2);
ff(C , D , A , B , 10 , fs3);
ff(B , C , D , A , 11 , fs4);
ff(A , B , C , D , 12 , fs1);
ff(D , A , B , C , 13 , fs2);
ff(C , D , A , B , 14 , fs3);
ff(B , C , D , A , 15 , fs4);
gg(A , B , C , D , 0 , gs1); /* Round 2 */
gg(D , A , B , C , 4 , gs2);
gg(C , D , A , B , 8 , gs3);
gg(B , C , D , A , 12 , gs4);
gg(A , B , C , D , 1 , gs1);
gg(D , A , B , C , 5 , gs2);
gg(C , D , A , B , 9 , gs3);
gg(B , C , D , A , 13 , gs4);
gg(A , B , C , D , 2 , gs1);
gg(D , A , B , C , 6 , gs2);
gg(C , D , A , B , 10 , gs3);
gg(B , C , D , A , 14 , gs4);
gg(A , B , C , D , 3 , gs1);
gg(D , A , B , C , 7 , gs2);
gg(C , D , A , B , 11 , gs3);
gg(B , C , D , A , 15 , gs4);
hh(A , B , C , D , 0 , hs1); /* Round 3 */
hh(D , A , B , C , 8 , hs2);
hh(C , D , A , B , 4 , hs3);
hh(B , C , D , A , 12 , hs4);
hh(A , B , C , D , 2 , hs1);
hh(D , A , B , C , 10 , hs2);
hh(C , D , A , B , 6 , hs3);
hh(B , C , D , A , 14 , hs4);
hh(A , B , C , D , 1 , hs1);
hh(D , A , B , C , 9 , hs2);
hh(C , D , A , B , 5 , hs3);
hh(B , C , D , A , 13 , hs4);
hh(A , B , C , D , 3 , hs1);
hh(D , A , B , C , 11 , hs2);
hh(C , D , A , B , 7 , hs3);
hh(B , C , D , A , 15 , hs4);
MDp->buffer[0] += A;
MDp->buffer[1] += B;
MDp->buffer[2] += C;
MDp->buffer[3] += D;
}
/* MDupdate(MDp,X,count)
** Input: MDp -- an MDptr
** X -- a pointer to an array of unsigned characters.
** count -- the number of bits of X to use.
** (if not a multiple of 8, uses high bits of last byte.)
** Update MDp using the number of bits of X given by count.
** This is the basic input routine for an MD4 user.
** The routine completes the MD computation when count < 512, so
** every MD computation should end with one call to MDupdate with a
** count less than 512. A call with count 0 will be ignored if the
** MD has already been terminated (done != 0), so an extra call with
** count 0 can be given as a "courtesy close" to force termination
** if desired.
*/
void
MDupdate(MDp,X,count)
MDptr MDp;
unsigned char *X;
unsigned int count;
{ unsigned int32 i, tmp, bit, byte, mask;
unsigned char XX[64];
unsigned char *p;
/* return with no error if this is a courtesy close with count
** zero and MDp->done is true.
*/
if (count == 0 && MDp->done) return;
/* check to see if MD is already done and report error */
if (MDp->done)
{ fprintf(FERROR,"\nError: MDupdate MD already done."); return; }
/* Add count to MDp->count */
tmp = count;
p = MDp->count;
while (tmp)
{ tmp += *p;
*p++ = tmp;
tmp = tmp >> 8;
}
/* Process data */
if (count == 512)
{ /* Full block of data to handle */
MDblock(MDp,(unsigned int *)X);
}
else if (count > 512) /* Check for count too large */
{ fprintf(FERROR,"\nError: MDupdate called with illegal count value %d."
,count);
return;
}
else /* partial block -- must be last block so finish up */
{ /* Find out how many bytes and residual bits there are */
byte = count >> 3;
bit = count & 7;
/* Copy X into XX since we need to modify it */
for (i=0;i<=byte;i++) XX[i] = X[i];
for (i=byte+1;i<64;i++) XX[i] = 0;
/* Add padding '1' bit and low-order zeros in last byte */
mask = 1 << (7 - bit);
XX[byte] = (XX[byte] | mask) & ~( mask - 1);
/* If room for bit count, finish up with this block */
if (byte <= 55)
{ for (i=0;i<8;i++) XX[56+i] = MDp->count[i];
MDblock(MDp,(unsigned int32 *)XX);
}
else /* need to do two blocks to finish up */
{ MDblock(MDp,(unsigned int32 *)XX);
for (i=0;i<56;i++) XX[i] = 0;
for (i=0;i<8;i++) XX[56+i] = MDp->count[i];
MDblock(MDp,(unsigned int32 *)XX);
}
/* Set flag saying we're done with MD computation */
MDp->done = 1;
}
}
/*
** End of md4.c
*/

49
md4.h
View File

@@ -1,49 +0,0 @@
/*
This code is from rfc1186.
*/
/*
** ********************************************************************
** md4.h -- Header file for implementation of **
** MD4 Message Digest Algorithm **
** Updated: 2/13/90 by Ronald L. Rivest **
** (C) 1990 RSA Data Security, Inc. **
** ********************************************************************
*/
/* MDstruct is the data structure for a message digest computation.
*/
typedef struct {
unsigned int32 buffer[4]; /* Holds 4-word result of MD computation */
unsigned char count[8]; /* Number of bits processed so far */
unsigned int done; /* Nonzero means MD computation finished */
} MDstruct, *MDptr;
/* MDbegin(MD)
** Input: MD -- an MDptr
** Initialize the MDstruct prepatory to doing a message digest
** computation.
*/
extern void MDbegin();
/* MDupdate(MD,X,count)
** Input: MD -- an MDptr
** X -- a pointer to an array of unsigned characters.
** count -- the number of bits of X to use (an unsigned int).
** Updates MD using the first "count" bits of X.
** The array pointed to by X is not modified.
** If count is not a multiple of 8, MDupdate uses high bits of
** last byte.
** This is the basic input routine for a user.
** The routine terminates the MD computation when count < 512, so
** every MD computation should end with one call to MDupdate with a
** count less than 512. Zero is OK for a count.
*/
extern void MDupdate();
/*
** End of md4.h
*/

View File

@@ -19,11 +19,46 @@ BEGIN {
}
}
/^FN_LOCAL_BOOL/ {
split($0,a,"[,()]")
printf "BOOL %s(int );\n", a[2]
}
/^FN_LOCAL_STRING/ {
split($0,a,"[,()]")
printf "char *%s(int );\n", a[2]
}
/^FN_LOCAL_INT/ {
split($0,a,"[,()]")
printf "int %s(int );\n", a[2]
}
/^FN_LOCAL_CHAR/ {
split($0,a,"[,()]")
printf "char %s(int );\n", a[2]
}
/^FN_GLOBAL_BOOL/ {
split($0,a,"[,()]")
printf "BOOL %s(void);\n", a[2]
}
/^FN_GLOBAL_STRING/ {
split($0,a,"[,()]")
printf "char *%s(void);\n", a[2]
}
/^FN_GLOBAL_INT/ {
split($0,a,"[,()]")
printf "int %s(void);\n", a[2]
}
/^static|^extern/ || !/^[a-zA-Z]/ || /[;]/ {
next;
}
!/^off_t|^pid_t|^unsigned|^mode_t|^DIR|^user|^int|^char|^uint|^struct|^BOOL|^void|^time/ {
!/^OFF_T|^size_t|^off_t|^pid_t|^unsigned|^mode_t|^DIR|^user|^int|^char|^uint|^struct|^BOOL|^void|^time/ {
next;
}

719
options.c Normal file
View File

@@ -0,0 +1,719 @@
/* -*- c-file-style: "linux" -*-
Copyright (C) 1998-2001 by Andrew Tridgell <tridge@samba.org>
Copyright (C) 2000, 2001, 2002 by Martin Pool <mbp@samba.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "rsync.h"
#include "popt.h"
int make_backups = 0;
int whole_file = 0;
int copy_links = 0;
int preserve_links = 0;
int preserve_hard_links = 0;
int preserve_perms = 0;
int preserve_devices = 0;
int preserve_uid = 0;
int preserve_gid = 0;
int preserve_times = 0;
int update_only = 0;
int cvs_exclude = 0;
int dry_run=0;
int local_server=0;
int ignore_times=0;
int delete_mode=0;
int delete_excluded=0;
int one_file_system=0;
int remote_version=0;
int sparse_files=0;
int do_compression=0;
int am_root=0;
int orig_umask=0;
int relative_paths=0;
int numeric_ids = 0;
int force_delete = 0;
int io_timeout = 0;
int io_error = 0;
int read_only = 0;
int module_id = -1;
int am_server = 0;
int am_sender = 0;
int recurse = 0;
int am_daemon=0;
int do_stats=0;
int do_progress=0;
int keep_partial=0;
int safe_symlinks=0;
int copy_unsafe_links=0;
int block_size=BLOCK_SIZE;
int size_only=0;
int bwlimit=0;
int delete_after=0;
int only_existing=0;
int max_delete=0;
int ignore_errors=0;
#ifdef _WIN32
int modify_window=2;
#else
int modify_window=0;
#endif
int blocking_io=0;
/** Network address family. **/
#ifdef INET6
int default_af_hint = 0; /* Any protocol */
#else
int default_af_hint = AF_INET; /* Must use IPv4 */
#endif
/** Do not go into the background when run as --daemon. Good
* for debugging and required for running as a service on W32,
* or under Unix process-monitors. **/
int no_detach = 0;
int read_batch=0;
int write_batch=0;
char *backup_suffix = BACKUP_SUFFIX;
char *tmpdir = NULL;
char *compare_dest = NULL;
char *config_file = RSYNCD_CONF;
char *shell_cmd = NULL;
char *log_format = NULL;
char *password_file = NULL;
char *rsync_path = RSYNC_PATH;
char *backup_dir = NULL;
int rsync_port = RSYNC_PORT;
int verbose = 0;
int quiet = 0;
int always_checksum = 0;
int list_only = 0;
char *batch_ext = NULL;
static int modify_window_set;
/** Local address to bind. As a character string because it's
* interpreted by the IPv6 layer: should be a numeric IP4 or ip6
* address, or a hostname. **/
char *bind_address;
static void print_rsync_version(enum logcode f)
{
char const *got_socketpair = "no ";
char const *hardlinks = "no ";
char const *links = "no ";
char const *ipv6 = "no ";
STRUCT_STAT *dumstat;
#ifdef HAVE_SOCKETPAIR
got_socketpair = "";
#endif
#if SUPPORT_HARD_LINKS
hardlinks = "";
#endif
#if SUPPORT_LINKS
links = "";
#endif
#if INET6
ipv6 = "";
#endif
rprintf(f, "%s version %s protocol version %d\n",
RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION);
rprintf(f,
"Copyright (C) 1996-2002 by Andrew Tridgell and others\n");
rprintf(f, "<http://rsync.samba.org/>\n");
rprintf(f, "Capabilities: %d-bit files, %ssocketpairs, "
"%shard links, %ssymlinks, batchfiles, %sIPv6,\n",
(int) (sizeof(OFF_T) * 8),
got_socketpair, hardlinks, links, ipv6);
/* Note that this field may not have type ino_t. It depends
* on the complicated interaction between largefile feature
* macros. */
rprintf(f, " %d-bit system inums, %d-bit internal inums\n",
(int) (sizeof(dumstat->st_ino) * 8),
(int) (sizeof(INO64_T) * 8));
#ifdef NO_INT64
rprintf(f, "WARNING: no 64-bit integers on this platform!\n");
#endif
}
void usage(enum logcode F)
{
print_rsync_version(F);
rprintf(F,"rsync is a file transfer program capable of efficient remote update\nvia a fast differencing algorithm.\n\n");
rprintf(F,"Usage: rsync [OPTION]... SRC [SRC]... [USER@]HOST:DEST\n");
rprintf(F," or rsync [OPTION]... [USER@]HOST:SRC DEST\n");
rprintf(F," or rsync [OPTION]... SRC [SRC]... DEST\n");
rprintf(F," or rsync [OPTION]... [USER@]HOST::SRC [DEST]\n");
rprintf(F," or rsync [OPTION]... SRC [SRC]... [USER@]HOST::DEST\n");
rprintf(F," or rsync [OPTION]... rsync://[USER@]HOST[:PORT]/SRC [DEST]\n");
rprintf(F,"SRC on single-colon remote HOST will be expanded by remote shell\n");
rprintf(F,"SRC on server remote HOST may contain shell wildcards or multiple\n");
rprintf(F," sources separated by space as long as they have same top-level\n");
rprintf(F,"\nOptions\n");
rprintf(F," -v, --verbose increase verbosity\n");
rprintf(F," -q, --quiet decrease verbosity\n");
rprintf(F," -c, --checksum always checksum\n");
rprintf(F," -a, --archive archive mode\n");
rprintf(F," -r, --recursive recurse into directories\n");
rprintf(F," -R, --relative use relative path names\n");
rprintf(F," -b, --backup make backups (default %s suffix)\n",BACKUP_SUFFIX);
rprintf(F," --backup-dir make backups into this directory\n");
rprintf(F," --suffix=SUFFIX override backup suffix\n");
rprintf(F," -u, --update update only (don't overwrite newer files)\n");
rprintf(F," -l, --links copy symlinks as symlinks\n");
rprintf(F," -L, --copy-links copy the referent of symlinks\n");
rprintf(F," --copy-unsafe-links copy links outside the source tree\n");
rprintf(F," --safe-links ignore links outside the destination tree\n");
rprintf(F," -H, --hard-links preserve hard links\n");
rprintf(F," -p, --perms preserve permissions\n");
rprintf(F," -o, --owner preserve owner (root only)\n");
rprintf(F," -g, --group preserve group\n");
rprintf(F," -D, --devices preserve devices (root only)\n");
rprintf(F," -t, --times preserve times\n");
rprintf(F," -S, --sparse handle sparse files efficiently\n");
rprintf(F," -n, --dry-run show what would have been transferred\n");
rprintf(F," -W, --whole-file copy whole files, no incremental checks\n");
rprintf(F," -x, --one-file-system don't cross filesystem boundaries\n");
rprintf(F," -B, --block-size=SIZE checksum blocking size (default %d)\n",BLOCK_SIZE);
rprintf(F," -e, --rsh=COMMAND specify rsh replacement\n");
rprintf(F," --rsync-path=PATH specify path to rsync on the remote machine\n");
rprintf(F," -C, --cvs-exclude auto ignore files in the same way CVS does\n");
rprintf(F," --existing only update files that already exist\n");
rprintf(F," --delete delete files that don't exist on the sending side\n");
rprintf(F," --delete-excluded also delete excluded files on the receiving side\n");
rprintf(F," --delete-after delete after transferring, not before\n");
rprintf(F," --ignore-errors delete even if there are IO errors\n");
rprintf(F," --max-delete=NUM don't delete more than NUM files\n");
rprintf(F," --partial keep partially transferred files\n");
rprintf(F," --force force deletion of directories even if not empty\n");
rprintf(F," --numeric-ids don't map uid/gid values by user/group name\n");
rprintf(F," --timeout=TIME set IO timeout in seconds\n");
rprintf(F," -I, --ignore-times don't exclude files that match length and time\n");
rprintf(F," --size-only only use file size when determining if a file should be transferred\n");
rprintf(F," --modify-window=NUM Timestamp window (seconds) for file match (default=%d)\n",modify_window);
rprintf(F," -T --temp-dir=DIR create temporary files in directory DIR\n");
rprintf(F," --compare-dest=DIR also compare destination files relative to DIR\n");
rprintf(F," -P equivalent to --partial --progress\n");
rprintf(F," -z, --compress compress file data\n");
rprintf(F," --exclude=PATTERN exclude files matching PATTERN\n");
rprintf(F," --exclude-from=FILE exclude patterns listed in FILE\n");
rprintf(F," --include=PATTERN don't exclude files matching PATTERN\n");
rprintf(F," --include-from=FILE don't exclude patterns listed in FILE\n");
rprintf(F," --version print version number\n");
rprintf(F," --daemon run as a rsync daemon\n");
rprintf(F," --no-detach do not detach from the parent\n");
rprintf(F," --address=ADDRESS bind to the specified address\n");
rprintf(F," --config=FILE specify alternate rsyncd.conf file\n");
rprintf(F," --port=PORT specify alternate rsyncd port number\n");
rprintf(F," --blocking-io use blocking IO for the remote shell\n");
rprintf(F," --stats give some file transfer stats\n");
rprintf(F," --progress show progress during transfer\n");
rprintf(F," --log-format=FORMAT log file transfers using specified format\n");
rprintf(F," --password-file=FILE get password from FILE\n");
rprintf(F," --bwlimit=KBPS limit I/O bandwidth, KBytes per second\n");
rprintf(F," --read-batch=EXT read batch file\n");
rprintf(F," --write-batch write batch file\n");
rprintf(F," -h, --help show this help screen\n");
#ifdef INET6
rprintf(F," -4 prefer IPv4\n");
rprintf(F," -6 prefer IPv6\n");
#endif
rprintf(F,"\n");
rprintf(F,"\nPlease see the rsync(1) and rsyncd.conf(5) man pages for full documentation\n");
rprintf(F,"See http://rsync.samba.org/ for updates, bug reports, and answers\n");
}
enum {OPT_VERSION = 1000, OPT_SUFFIX, OPT_SENDER, OPT_SERVER, OPT_EXCLUDE,
OPT_EXCLUDE_FROM, OPT_DELETE, OPT_DELETE_EXCLUDED, OPT_NUMERIC_IDS,
OPT_RSYNC_PATH, OPT_FORCE, OPT_TIMEOUT, OPT_DAEMON, OPT_CONFIG, OPT_PORT,
OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_STATS, OPT_PARTIAL, OPT_PROGRESS,
OPT_COPY_UNSAFE_LINKS, OPT_SAFE_LINKS, OPT_COMPARE_DEST,
OPT_LOG_FORMAT, OPT_PASSWORD_FILE, OPT_SIZE_ONLY, OPT_ADDRESS,
OPT_DELETE_AFTER, OPT_EXISTING, OPT_MAX_DELETE, OPT_BACKUP_DIR,
OPT_IGNORE_ERRORS, OPT_BWLIMIT, OPT_BLOCKING_IO,
OPT_MODIFY_WINDOW, OPT_READ_BATCH, OPT_WRITE_BATCH};
static struct poptOption long_options[] = {
/* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
{"version", 0, POPT_ARG_NONE, 0, OPT_VERSION},
{"suffix", 0, POPT_ARG_STRING, &backup_suffix},
{"rsync-path", 0, POPT_ARG_STRING, &rsync_path},
{"password-file", 0, POPT_ARG_STRING, &password_file},
{"ignore-times", 'I', POPT_ARG_NONE, &ignore_times},
{"size-only", 0, POPT_ARG_NONE, &size_only},
{"modify-window", 0, POPT_ARG_INT, &modify_window, OPT_MODIFY_WINDOW},
{"one-file-system", 'x', POPT_ARG_NONE, &one_file_system},
{"delete", 0, POPT_ARG_NONE, &delete_mode},
{"existing", 0, POPT_ARG_NONE, &only_existing},
{"delete-after", 0, POPT_ARG_NONE, &delete_after},
{"delete-excluded", 0, POPT_ARG_NONE, 0, OPT_DELETE_EXCLUDED},
{"force", 0, POPT_ARG_NONE, &force_delete},
{"numeric-ids", 0, POPT_ARG_NONE, &numeric_ids},
{"exclude", 0, POPT_ARG_STRING, 0, OPT_EXCLUDE},
{"include", 0, POPT_ARG_STRING, 0, OPT_INCLUDE},
{"exclude-from", 0, POPT_ARG_STRING, 0, OPT_EXCLUDE_FROM},
{"include-from", 0, POPT_ARG_STRING, 0, OPT_INCLUDE_FROM},
{"safe-links", 0, POPT_ARG_NONE, &safe_symlinks},
{"help", 'h', POPT_ARG_NONE, 0, 'h'},
{"backup", 'b', POPT_ARG_NONE, &make_backups},
{"dry-run", 'n', POPT_ARG_NONE, &dry_run},
{"sparse", 'S', POPT_ARG_NONE, &sparse_files},
{"cvs-exclude", 'C', POPT_ARG_NONE, &cvs_exclude},
{"update", 'u', POPT_ARG_NONE, &update_only},
{"links", 'l', POPT_ARG_NONE, &preserve_links},
{"copy-links", 'L', POPT_ARG_NONE, &copy_links},
{"whole-file", 'W', POPT_ARG_NONE, &whole_file},
{"copy-unsafe-links", 0, POPT_ARG_NONE, &copy_unsafe_links},
{"perms", 'p', POPT_ARG_NONE, &preserve_perms},
{"owner", 'o', POPT_ARG_NONE, &preserve_uid},
{"group", 'g', POPT_ARG_NONE, &preserve_gid},
{"devices", 'D', POPT_ARG_NONE, &preserve_devices},
{"times", 't', POPT_ARG_NONE, &preserve_times},
{"checksum", 'c', POPT_ARG_NONE, &always_checksum},
{"verbose", 'v', POPT_ARG_NONE, 0, 'v'},
{"quiet", 'q', POPT_ARG_NONE, 0, 'q'},
{"archive", 'a', POPT_ARG_NONE, 0, 'a'},
{"server", 0, POPT_ARG_NONE, &am_server},
{"sender", 0, POPT_ARG_NONE, 0, OPT_SENDER},
{"recursive", 'r', POPT_ARG_NONE, &recurse},
{"relative", 'R', POPT_ARG_NONE, &relative_paths},
{"rsh", 'e', POPT_ARG_STRING, &shell_cmd},
{"block-size", 'B', POPT_ARG_INT, &block_size},
{"max-delete", 0, POPT_ARG_INT, &max_delete},
{"timeout", 0, POPT_ARG_INT, &io_timeout},
{"temp-dir", 'T', POPT_ARG_STRING, &tmpdir},
{"compare-dest", 0, POPT_ARG_STRING, &compare_dest},
/* TODO: Should this take an optional int giving the compression level? */
{"compress", 'z', POPT_ARG_NONE, &do_compression},
{"daemon", 0, POPT_ARG_NONE, &am_daemon},
{"no-detach", 0, POPT_ARG_NONE, &no_detach},
{"stats", 0, POPT_ARG_NONE, &do_stats},
{"progress", 0, POPT_ARG_NONE, &do_progress},
{"partial", 0, POPT_ARG_NONE, &keep_partial},
{"ignore-errors", 0, POPT_ARG_NONE, &ignore_errors},
{"blocking-io", 0, POPT_ARG_NONE, &blocking_io},
{0, 'P', POPT_ARG_NONE, 0, 'P'},
{"config", 0, POPT_ARG_STRING, &config_file},
{"port", 0, POPT_ARG_INT, &rsync_port},
{"log-format", 0, POPT_ARG_STRING, &log_format},
{"bwlimit", 0, POPT_ARG_INT, &bwlimit},
{"address", 0, POPT_ARG_STRING, &bind_address, 0},
{"backup-dir", 0, POPT_ARG_STRING, &backup_dir},
{"hard-links", 'H', POPT_ARG_NONE, &preserve_hard_links},
{"read-batch", 0, POPT_ARG_STRING, &batch_ext, OPT_READ_BATCH},
{"write-batch", 0, POPT_ARG_NONE, &write_batch},
#ifdef INET6
{0, '4', POPT_ARG_VAL, &default_af_hint, AF_INET },
{0, '6', POPT_ARG_VAL, &default_af_hint, AF_INET6 },
#endif
{0,0,0,0}
};
static char err_buf[100];
/* We store the option error message, if any, so that we can log the
connection attempt (which requires parsing the options), and then
show the error later on. */
void option_error(void)
{
if (err_buf[0]) {
rprintf(FLOG, "%s", err_buf);
rprintf(FERROR, "%s: %s", RSYNC_NAME, err_buf);
} else {
rprintf (FERROR, "Error parsing options: "
"option may be supported on client but not on server?\n");
rprintf (FERROR, RSYNC_NAME ": Error parsing options: "
"option may be supported on client but not on server?\n");
}
}
/* check to see if we should refuse this option */
static int check_refuse_options(char *ref, int opt)
{
int i, len;
char *p;
const char *name;
for (i=0; long_options[i].longName; i++) {
if (long_options[i].val == opt) break;
}
if (!long_options[i].longName) return 0;
name = long_options[i].longName;
len = strlen(name);
while ((p = strstr(ref,name))) {
if ((p==ref || p[-1]==' ') &&
(p[len] == ' ' || p[len] == 0)) {
snprintf(err_buf,sizeof(err_buf),
"The '%s' option is not supported by this server\n", name);
return 1;
}
ref += len;
}
return 0;
}
static int count_args(char const **argv)
{
int i = 0;
while (argv[i] != NULL)
i++;
return i;
}
/* Process command line arguments. Called on both local and remote.
* Returns if all options are OK, otherwise fills in err_buf and
* returns 0. */
int parse_arguments(int *argc, const char ***argv, int frommain)
{
int opt;
char *ref = lp_refuse_options(module_id);
poptContext pc;
/* TODO: Call poptReadDefaultConfig; handle errors. */
/* The context leaks in case of an error, but if there's a
* problem we always exit anyhow. */
pc = poptGetContext(RSYNC_NAME, *argc, *argv, long_options, 0);
while ((opt = poptGetNextOpt(pc)) != -1) {
if (ref) {
if (check_refuse_options(ref, opt)) return 0;
}
/* most options are handled automatically by popt;
* only special cases are returned and listed here. */
switch (opt) {
case OPT_VERSION:
print_rsync_version(FINFO);
exit_cleanup(0);
case OPT_MODIFY_WINDOW:
/* The value has already been set by popt, but
* we need to remember that we're using a
* non-default setting. */
modify_window_set = 1;
break;
case OPT_DELETE_EXCLUDED:
delete_excluded = 1;
delete_mode = 1;
break;
case OPT_EXCLUDE:
add_exclude(poptGetOptArg(pc), 0);
break;
case OPT_INCLUDE:
add_exclude(poptGetOptArg(pc), 1);
break;
case OPT_EXCLUDE_FROM:
add_exclude_file(poptGetOptArg(pc), 1, 0);
break;
case OPT_INCLUDE_FROM:
add_exclude_file(poptGetOptArg(pc), 1, 1);
break;
case 'h':
usage(FINFO);
exit_cleanup(0);
case 'H':
#if SUPPORT_HARD_LINKS
preserve_hard_links=1;
#else
/* FIXME: Don't say "server" if this is
* happening on the client. */
/* FIXME: Why do we have the duplicated
* rprintf? Everybody who gets this message
* ought to send it to the client and also to
* the logs. */
snprintf(err_buf,sizeof(err_buf),
"hard links are not supported on this %s\n",
am_server ? "server" : "client");
rprintf(FERROR,"ERROR: hard links not supported on this platform\n");
return 0;
#endif /* SUPPORT_HARD_LINKS */
break;
case 'v':
verbose++;
break;
case 'q':
if (frommain) quiet++;
break;
case 'a':
recurse=1;
#if SUPPORT_LINKS
preserve_links=1;
#endif
preserve_perms=1;
preserve_times=1;
preserve_gid=1;
preserve_uid=1;
preserve_devices=1;
break;
case OPT_SENDER:
if (!am_server) {
usage(FERROR);
exit_cleanup(RERR_SYNTAX);
}
am_sender = 1;
break;
case 'P':
do_progress = 1;
keep_partial = 1;
break;
case OPT_READ_BATCH:
/* The filename is stored in batch_ext for us by popt */
read_batch = 1;
break;
default:
/* FIXME: If --daemon is specified, then errors for later
* parameters seem to disappear. */
snprintf(err_buf, sizeof(err_buf),
"%s%s: %s\n",
am_server ? "on remote machine: " : "",
poptBadOption(pc, POPT_BADOPTION_NOALIAS),
poptStrerror(opt));
return 0;
}
}
*argv = poptGetArgs(pc);
if (*argv)
*argc = count_args(*argv);
else
*argc = 0;
return 1;
}
/* Construct a filtered list of options to pass through from the
* client to the server */
void server_options(char **args,int *argc)
{
int ac = *argc;
static char argstr[50];
static char bsize[30];
static char iotime[30];
static char mdelete[30];
static char mwindow[30];
static char bw[50];
static char fext[20];
static char wbatch[14];
int i, x;
args[ac++] = "--server";
if (!am_sender)
args[ac++] = "--sender";
x = 1;
argstr[0] = '-';
for (i=0;i<verbose;i++)
argstr[x++] = 'v';
/* the -q option is intentionally left out */
if (make_backups)
argstr[x++] = 'b';
if (update_only)
argstr[x++] = 'u';
if (dry_run)
argstr[x++] = 'n';
if (preserve_links)
argstr[x++] = 'l';
if (copy_links)
argstr[x++] = 'L';
if (whole_file)
argstr[x++] = 'W';
if (preserve_hard_links)
argstr[x++] = 'H';
if (preserve_uid)
argstr[x++] = 'o';
if (preserve_gid)
argstr[x++] = 'g';
if (preserve_devices)
argstr[x++] = 'D';
if (preserve_times)
argstr[x++] = 't';
if (preserve_perms)
argstr[x++] = 'p';
if (recurse)
argstr[x++] = 'r';
if (always_checksum)
argstr[x++] = 'c';
if (cvs_exclude)
argstr[x++] = 'C';
if (ignore_times)
argstr[x++] = 'I';
if (relative_paths)
argstr[x++] = 'R';
if (one_file_system)
argstr[x++] = 'x';
if (sparse_files)
argstr[x++] = 'S';
if (do_compression)
argstr[x++] = 'z';
/* this is a complete hack - blame Rusty
this is a hack to make the list_only (remote file list)
more useful */
if (list_only && !recurse)
argstr[x++] = 'r';
argstr[x] = 0;
if (x != 1) args[ac++] = argstr;
if (block_size != BLOCK_SIZE) {
snprintf(bsize,sizeof(bsize),"-B%d",block_size);
args[ac++] = bsize;
}
if (max_delete && am_sender) {
snprintf(mdelete,sizeof(mdelete),"--max-delete=%d",max_delete);
args[ac++] = mdelete;
}
if (write_batch) {
snprintf(wbatch,sizeof(wbatch),"--write-batch");
args[ac++] = wbatch;
}
if (batch_ext != NULL) {
snprintf(fext,sizeof(fext),"--read-batch=%s",batch_ext);
args[ac++] = fext;
}
if (io_timeout) {
snprintf(iotime,sizeof(iotime),"--timeout=%d",io_timeout);
args[ac++] = iotime;
}
if (bwlimit) {
snprintf(bw,sizeof(bw),"--bwlimit=%d",bwlimit);
args[ac++] = bw;
}
if (strcmp(backup_suffix, BACKUP_SUFFIX)) {
args[ac++] = "--suffix";
args[ac++] = backup_suffix;
}
if (delete_mode && !delete_excluded)
args[ac++] = "--delete";
if (delete_excluded)
args[ac++] = "--delete-excluded";
if (size_only)
args[ac++] = "--size-only";
if (modify_window_set) {
snprintf(mwindow,sizeof(mwindow),"--modify-window=%d",
modify_window);
args[ac++] = mwindow;
}
if (keep_partial)
args[ac++] = "--partial";
if (force_delete)
args[ac++] = "--force";
if (delete_after)
args[ac++] = "--delete-after";
if (ignore_errors)
args[ac++] = "--ignore-errors";
if (copy_unsafe_links)
args[ac++] = "--copy-unsafe-links";
if (safe_symlinks)
args[ac++] = "--safe-links";
if (numeric_ids)
args[ac++] = "--numeric-ids";
if (only_existing && am_sender)
args[ac++] = "--existing";
if (tmpdir) {
args[ac++] = "--temp-dir";
args[ac++] = tmpdir;
}
if (backup_dir && am_sender) {
/* only the receiver needs this option, if we are the sender
* then we need to send it to the receiver.
*/
args[ac++] = "--backup-dir";
args[ac++] = backup_dir;
}
if (compare_dest && am_sender) {
/* the server only needs this option if it is not the sender,
* and it may be an older version that doesn't know this
* option, so don't send it if client is the sender.
*/
args[ac++] = "--compare-dest";
args[ac++] = compare_dest;
}
*argc = ac;
}

84
packaging/lsb/rsync.spec Normal file
View File

@@ -0,0 +1,84 @@
Summary: Program for efficient remote updates of files.
Name: rsync
Version: 2.5.1
Release: 1
Copyright: GPL
Group: Applications/Networking
Source: ftp://samba.anu.edu.au/pub/rsync/rsync-2.5.1.tar.gz
URL: http://samba.anu.edu.au/rsync/
Packager: Andrew Tridgell <tridge@samba.anu.edu.au>
BuildRoot: /tmp/rsync
%description
rsync is a replacement for rcp that has many more features.
rsync uses the "rsync algorithm" which provides a very fast method for
bringing remote files into sync. It does this by sending just the
differences in the files across the link, without requiring that both
sets of files are present at one of the ends of the link beforehand.
A technical report describing the rsync algorithm is included with
this package.
%changelog
* Mon Sept 11 2000 John H Terpstra <jht@turbolinux.com>
Changed target paths to be Linux Standards Base compliant
* Mon Jan 25 1999 Stefan Hornburg <racke@linuxia.de>
quoted RPM_OPT_FLAGS for the sake of robustness
* Mon May 18 1998 Andrew Tridgell <tridge@samba.anu.edu.au>
reworked for auto-building when I release rsync (tridge@samba.anu.edu.au)
* Sat May 16 1998 John H Terpstra <jht@aquasoft.com.au>
Upgraded to Rsync 2.0.6
-new feature anonymous rsync
* Mon Apr 6 1998 Douglas N. Arnold <dna@math.psu.edu>
Upgrade to rsync version 1.7.2.
* Sun Mar 1 1998 Douglas N. Arnold <dna@math.psu.edu>
Built 1.6.9-1 based on the 1.6.3-2 spec file of John A. Martin.
Changes from 1.6.3-2 packaging: added latex and dvips commands
to create tech_report.ps.
* Mon Aug 25 1997 John A. Martin <jam@jamux.com>
Built 1.6.3-2 after finding no rsync-1.6.3-1.src.rpm although there
was an ftp://ftp.redhat.com/pub/contrib/alpha/rsync-1.6.3-1.alpha.rpm
showing no packager nor signature but giving
"Source RPM: rsync-1.6.3-1.src.rpm".
Changes from 1.6.2-1 packaging: added '$RPM_OPT_FLAGS' to make, strip
to '%build', removed '%prefix'.
* Thu Apr 10 1997 Michael De La Rue <miked@ed.ac.uk>
rsync-1.6.2-1 packaged. (This entry by jam to credit Michael for the
previous package(s).)
%prep
%setup
%build
./configure --prefix=/usr --mandir=/usr/share/man
make CFLAGS="$RPM_OPT_FLAGS"
strip rsync
%install
mkdir -p $RPM_BUILD_ROOT/usr/{bin,share/man/{man1,man5}}
install -m755 rsync $RPM_BUILD_ROOT/usr/bin
install -m644 rsync.1 $RPM_BUILD_ROOT/usr/share/man/man1
install -m644 rsyncd.conf.5 $RPM_BUILD_ROOT/usr/share/man/man5
%clean
rm -rf $RPM_BUILD_ROOT
%files
%attr(-,root,root) /usr/bin/rsync
%attr(-,root,root) /usr/share/man/man1/rsync.1
%attr(-,root,root) /usr/share/man/man5/rsyncd.conf.5
%attr(-,root,root) %doc tech_report.tex
%attr(-,root,root) %doc README
%attr(-,root,root) %doc COPYING

View File

@@ -0,0 +1,84 @@
Summary: Program for efficient remote updates of files.
Name: rsync
Version: PVERSION
Release: PRELEASE
Copyright: GPL
Group: Applications/Networking
Source: ftp://samba.anu.edu.au/pub/rsync/rsync-PVERSION.tar.gz
URL: http://samba.anu.edu.au/rsync/
Packager: Andrew Tridgell <tridge@samba.anu.edu.au>
BuildRoot: /tmp/rsync
%description
rsync is a replacement for rcp that has many more features.
rsync uses the "rsync algorithm" which provides a very fast method for
bringing remote files into sync. It does this by sending just the
differences in the files across the link, without requiring that both
sets of files are present at one of the ends of the link beforehand.
A technical report describing the rsync algorithm is included with
this package.
%changelog
* Mon Sept 11 2000 John H Terpstra <jht@turbolinux.com>
Changed target paths to be Linux Standards Base compliant
* Mon Jan 25 1999 Stefan Hornburg <racke@linuxia.de>
quoted RPM_OPT_FLAGS for the sake of robustness
* Mon May 18 1998 Andrew Tridgell <tridge@samba.anu.edu.au>
reworked for auto-building when I release rsync (tridge@samba.anu.edu.au)
* Sat May 16 1998 John H Terpstra <jht@aquasoft.com.au>
Upgraded to Rsync 2.0.6
-new feature anonymous rsync
* Mon Apr 6 1998 Douglas N. Arnold <dna@math.psu.edu>
Upgrade to rsync version 1.7.2.
* Sun Mar 1 1998 Douglas N. Arnold <dna@math.psu.edu>
Built 1.6.9-1 based on the 1.6.3-2 spec file of John A. Martin.
Changes from 1.6.3-2 packaging: added latex and dvips commands
to create tech_report.ps.
* Mon Aug 25 1997 John A. Martin <jam@jamux.com>
Built 1.6.3-2 after finding no rsync-1.6.3-1.src.rpm although there
was an ftp://ftp.redhat.com/pub/contrib/alpha/rsync-1.6.3-1.alpha.rpm
showing no packager nor signature but giving
"Source RPM: rsync-1.6.3-1.src.rpm".
Changes from 1.6.2-1 packaging: added '$RPM_OPT_FLAGS' to make, strip
to '%build', removed '%prefix'.
* Thu Apr 10 1997 Michael De La Rue <miked@ed.ac.uk>
rsync-1.6.2-1 packaged. (This entry by jam to credit Michael for the
previous package(s).)
%prep
%setup
%build
./configure --prefix=/usr --mandir=/usr/share/man
make CFLAGS="$RPM_OPT_FLAGS"
strip rsync
%install
mkdir -p $RPM_BUILD_ROOT/usr/{bin,share/man/{man1,man5}}
install -m755 rsync $RPM_BUILD_ROOT/usr/bin
install -m644 rsync.1 $RPM_BUILD_ROOT/usr/share/man/man1
install -m644 rsyncd.conf.5 $RPM_BUILD_ROOT/usr/share/man/man5
%clean
rm -rf $RPM_BUILD_ROOT
%files
%attr(-,root,root) /usr/bin/rsync
%attr(-,root,root) /usr/share/man/man1/rsync.1
%attr(-,root,root) /usr/share/man/man5/rsyncd.conf.5
%attr(-,root,root) %doc tech_report.tex
%attr(-,root,root) %doc README
%attr(-,root,root) %doc COPYING

View File

@@ -0,0 +1,81 @@
Summary: Program for efficient remote updates of files.
Name: rsync
Version: 2.5.1
Release: 1
Copyright: GPL
Group: Applications/Networking
Source: ftp://samba.anu.edu.au/pub/rsync/rsync-2.5.1.tar.gz
URL: http://samba.anu.edu.au/rsync/
Packager: Andrew Tridgell <tridge@samba.anu.edu.au>
BuildRoot: /tmp/rsync
%description
rsync is a replacement for rcp that has many more features.
rsync uses the "rsync algorithm" which provides a very fast method for
bringing remote files into sync. It does this by sending just the
differences in the files across the link, without requiring that both
sets of files are present at one of the ends of the link beforehand.
A technical report describing the rsync algorithm is included with
this package.
%changelog
* Mon Jan 25 1999 Stefan Hornburg <racke@linuxia.de>
quoted RPM_OPT_FLAGS for the sake of robustness
* Mon May 18 1998 Andrew Tridgell <tridge@samba.anu.edu.au>
reworked for auto-building when I release rsync (tridge@samba.anu.edu.au)
* Sat May 16 1998 John H Terpstra <jht@aquasoft.com.au>
Upgraded to Rsync 2.0.6
-new feature anonymous rsync
* Mon Apr 6 1998 Douglas N. Arnold <dna@math.psu.edu>
Upgrade to rsync version 1.7.2.
* Sun Mar 1 1998 Douglas N. Arnold <dna@math.psu.edu>
Built 1.6.9-1 based on the 1.6.3-2 spec file of John A. Martin.
Changes from 1.6.3-2 packaging: added latex and dvips commands
to create tech_report.ps.
* Mon Aug 25 1997 John A. Martin <jam@jamux.com>
Built 1.6.3-2 after finding no rsync-1.6.3-1.src.rpm although there
was an ftp://ftp.redhat.com/pub/contrib/alpha/rsync-1.6.3-1.alpha.rpm
showing no packager nor signature but giving
"Source RPM: rsync-1.6.3-1.src.rpm".
Changes from 1.6.2-1 packaging: added '$RPM_OPT_FLAGS' to make, strip
to '%build', removed '%prefix'.
* Thu Apr 10 1997 Michael De La Rue <miked@ed.ac.uk>
rsync-1.6.2-1 packaged. (This entry by jam to credit Michael for the
previous package(s).)
%prep
%setup
%build
./configure --prefix=/usr
make CFLAGS="$RPM_OPT_FLAGS"
strip rsync
%install
mkdir -p $RPM_BUILD_ROOT/usr/{bin,man/{man1,man5}}
install -m755 rsync $RPM_BUILD_ROOT/usr/bin
install -m644 rsync.1 $RPM_BUILD_ROOT/usr/man/man1
install -m644 rsyncd.conf.5 $RPM_BUILD_ROOT/usr/man/man5
%clean
rm -rf $RPM_BUILD_ROOT
%files
%attr(-,root,root) /usr/bin/rsync
%attr(-,root,root) /usr/man/man1/rsync.1
%attr(-,root,root) /usr/man/man5/rsyncd.conf.5
%attr(-,root,root) %doc tech_report.tex
%attr(-,root,root) %doc README
%attr(-,root,root) %doc COPYING

View File

@@ -0,0 +1,81 @@
Summary: Program for efficient remote updates of files.
Name: rsync
Version: PVERSION
Release: PRELEASE
Copyright: GPL
Group: Applications/Networking
Source: ftp://samba.anu.edu.au/pub/rsync/rsync-PVERSION.tar.gz
URL: http://samba.anu.edu.au/rsync/
Packager: Andrew Tridgell <tridge@samba.anu.edu.au>
BuildRoot: /tmp/rsync
%description
rsync is a replacement for rcp that has many more features.
rsync uses the "rsync algorithm" which provides a very fast method for
bringing remote files into sync. It does this by sending just the
differences in the files across the link, without requiring that both
sets of files are present at one of the ends of the link beforehand.
A technical report describing the rsync algorithm is included with
this package.
%changelog
* Mon Jan 25 1999 Stefan Hornburg <racke@linuxia.de>
quoted RPM_OPT_FLAGS for the sake of robustness
* Mon May 18 1998 Andrew Tridgell <tridge@samba.anu.edu.au>
reworked for auto-building when I release rsync (tridge@samba.anu.edu.au)
* Sat May 16 1998 John H Terpstra <jht@aquasoft.com.au>
Upgraded to Rsync 2.0.6
-new feature anonymous rsync
* Mon Apr 6 1998 Douglas N. Arnold <dna@math.psu.edu>
Upgrade to rsync version 1.7.2.
* Sun Mar 1 1998 Douglas N. Arnold <dna@math.psu.edu>
Built 1.6.9-1 based on the 1.6.3-2 spec file of John A. Martin.
Changes from 1.6.3-2 packaging: added latex and dvips commands
to create tech_report.ps.
* Mon Aug 25 1997 John A. Martin <jam@jamux.com>
Built 1.6.3-2 after finding no rsync-1.6.3-1.src.rpm although there
was an ftp://ftp.redhat.com/pub/contrib/alpha/rsync-1.6.3-1.alpha.rpm
showing no packager nor signature but giving
"Source RPM: rsync-1.6.3-1.src.rpm".
Changes from 1.6.2-1 packaging: added '$RPM_OPT_FLAGS' to make, strip
to '%build', removed '%prefix'.
* Thu Apr 10 1997 Michael De La Rue <miked@ed.ac.uk>
rsync-1.6.2-1 packaged. (This entry by jam to credit Michael for the
previous package(s).)
%prep
%setup
%build
./configure --prefix=/usr
make CFLAGS="$RPM_OPT_FLAGS"
strip rsync
%install
mkdir -p $RPM_BUILD_ROOT/usr/{bin,man/{man1,man5}}
install -m755 rsync $RPM_BUILD_ROOT/usr/bin
install -m644 rsync.1 $RPM_BUILD_ROOT/usr/man/man1
install -m644 rsyncd.conf.5 $RPM_BUILD_ROOT/usr/man/man5
%clean
rm -rf $RPM_BUILD_ROOT
%files
%attr(-,root,root) /usr/bin/rsync
%attr(-,root,root) /usr/man/man1/rsync.1
%attr(-,root,root) /usr/man/man5/rsyncd.conf.5
%attr(-,root,root) %doc tech_report.tex
%attr(-,root,root) %doc README
%attr(-,root,root) %doc COPYING

View File

@@ -0,0 +1,81 @@
Summary: Program for efficient remote updates of files.
Name: rsync
Version: 2.5.1
Release: 1
Copyright: GPL
Group: Applications/Networking
Source: ftp://samba.anu.edu.au/pub/rsync/rsync-2.5.1.tar.gz
URL: http://samba.anu.edu.au/rsync/
Packager: Andrew Tridgell <tridge@samba.anu.edu.au>
BuildRoot: /tmp/rsync
%description
rsync is a replacement for rcp that has many more features.
rsync uses the "rsync algorithm" which provides a very fast method for
bringing remote files into sync. It does this by sending just the
differences in the files across the link, without requiring that both
sets of files are present at one of the ends of the link beforehand.
A technical report describing the rsync algorithm is included with
this package.
%changelog
* Mon Jan 25 1999 Stefan Hornburg <racke@linuxia.de>
quoted RPM_OPT_FLAGS for the sake of robustness
* Mon May 18 1998 Andrew Tridgell <tridge@samba.anu.edu.au>
reworked for auto-building when I release rsync (tridge@samba.anu.edu.au)
* Sat May 16 1998 John H Terpstra <jht@aquasoft.com.au>
Upgraded to Rsync 2.0.6
-new feature anonymous rsync
* Mon Apr 6 1998 Douglas N. Arnold <dna@math.psu.edu>
Upgrade to rsync version 1.7.2.
* Sun Mar 1 1998 Douglas N. Arnold <dna@math.psu.edu>
Built 1.6.9-1 based on the 1.6.3-2 spec file of John A. Martin.
Changes from 1.6.3-2 packaging: added latex and dvips commands
to create tech_report.ps.
* Mon Aug 25 1997 John A. Martin <jam@jamux.com>
Built 1.6.3-2 after finding no rsync-1.6.3-1.src.rpm although there
was an ftp://ftp.redhat.com/pub/contrib/alpha/rsync-1.6.3-1.alpha.rpm
showing no packager nor signature but giving
"Source RPM: rsync-1.6.3-1.src.rpm".
Changes from 1.6.2-1 packaging: added '$RPM_OPT_FLAGS' to make, strip
to '%build', removed '%prefix'.
* Thu Apr 10 1997 Michael De La Rue <miked@ed.ac.uk>
rsync-1.6.2-1 packaged. (This entry by jam to credit Michael for the
previous package(s).)
%prep
%setup
%build
./configure --prefix=/usr
make CFLAGS="$RPM_OPT_FLAGS"
strip rsync
%install
mkdir -p $RPM_BUILD_ROOT/usr/{bin,man/{man1,man5}}
install -m755 rsync $RPM_BUILD_ROOT/usr/bin
install -m644 rsync.1* $RPM_BUILD_ROOT/usr/man/man1
install -m644 rsyncd.conf.5* $RPM_BUILD_ROOT/usr/man/man5
%clean
rm -rf $RPM_BUILD_ROOT
%files
%attr(-,root,root) /usr/bin/rsync
%attr(-,root,root) /usr/man/man1/rsync.1*
%attr(-,root,root) /usr/man/man5/rsyncd.conf.5*
%attr(-,root,root) %doc tech_report.tex
%attr(-,root,root) %doc README
%attr(-,root,root) %doc COPYING

View File

@@ -0,0 +1,81 @@
Summary: Program for efficient remote updates of files.
Name: rsync
Version: PVERSION
Release: PRELEASE
Copyright: GPL
Group: Applications/Networking
Source: ftp://samba.anu.edu.au/pub/rsync/rsync-PVERSION.tar.gz
URL: http://samba.anu.edu.au/rsync/
Packager: Andrew Tridgell <tridge@samba.anu.edu.au>
BuildRoot: /tmp/rsync
%description
rsync is a replacement for rcp that has many more features.
rsync uses the "rsync algorithm" which provides a very fast method for
bringing remote files into sync. It does this by sending just the
differences in the files across the link, without requiring that both
sets of files are present at one of the ends of the link beforehand.
A technical report describing the rsync algorithm is included with
this package.
%changelog
* Mon Jan 25 1999 Stefan Hornburg <racke@linuxia.de>
quoted RPM_OPT_FLAGS for the sake of robustness
* Mon May 18 1998 Andrew Tridgell <tridge@samba.anu.edu.au>
reworked for auto-building when I release rsync (tridge@samba.anu.edu.au)
* Sat May 16 1998 John H Terpstra <jht@aquasoft.com.au>
Upgraded to Rsync 2.0.6
-new feature anonymous rsync
* Mon Apr 6 1998 Douglas N. Arnold <dna@math.psu.edu>
Upgrade to rsync version 1.7.2.
* Sun Mar 1 1998 Douglas N. Arnold <dna@math.psu.edu>
Built 1.6.9-1 based on the 1.6.3-2 spec file of John A. Martin.
Changes from 1.6.3-2 packaging: added latex and dvips commands
to create tech_report.ps.
* Mon Aug 25 1997 John A. Martin <jam@jamux.com>
Built 1.6.3-2 after finding no rsync-1.6.3-1.src.rpm although there
was an ftp://ftp.redhat.com/pub/contrib/alpha/rsync-1.6.3-1.alpha.rpm
showing no packager nor signature but giving
"Source RPM: rsync-1.6.3-1.src.rpm".
Changes from 1.6.2-1 packaging: added '$RPM_OPT_FLAGS' to make, strip
to '%build', removed '%prefix'.
* Thu Apr 10 1997 Michael De La Rue <miked@ed.ac.uk>
rsync-1.6.2-1 packaged. (This entry by jam to credit Michael for the
previous package(s).)
%prep
%setup
%build
./configure --prefix=/usr
make CFLAGS="$RPM_OPT_FLAGS"
strip rsync
%install
mkdir -p $RPM_BUILD_ROOT/usr/{bin,man/{man1,man5}}
install -m755 rsync $RPM_BUILD_ROOT/usr/bin
install -m644 rsync.1* $RPM_BUILD_ROOT/usr/man/man1
install -m644 rsyncd.conf.5* $RPM_BUILD_ROOT/usr/man/man5
%clean
rm -rf $RPM_BUILD_ROOT
%files
%attr(-,root,root) /usr/bin/rsync
%attr(-,root,root) /usr/man/man1/rsync.1*
%attr(-,root,root) /usr/man/man5/rsyncd.conf.5*
%attr(-,root,root) %doc tech_report.tex
%attr(-,root,root) %doc README
%attr(-,root,root) %doc COPYING

558
params.c Normal file
View File

@@ -0,0 +1,558 @@
/*
This modules is based on the params.c module from Samba, written by Karl Auer
and much modifed by Christopher Hertel.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* -------------------------------------------------------------------------- **
*
* Module name: params
*
* -------------------------------------------------------------------------- **
*
* This module performs lexical analysis and initial parsing of a
* Windows-like parameter file. It recognizes and handles four token
* types: section-name, parameter-name, parameter-value, and
* end-of-file. Comments and line continuation are handled
* internally.
*
* The entry point to the module is function pm_process(). This
* function opens the source file, calls the Parse() function to parse
* the input, and then closes the file when either the EOF is reached
* or a fatal error is encountered.
*
* A sample parameter file might look like this:
*
* [section one]
* parameter one = value string
* parameter two = another value
* [section two]
* new parameter = some value or t'other
*
* The parameter file is divided into sections by section headers:
* section names enclosed in square brackets (eg. [section one]).
* Each section contains parameter lines, each of which consist of a
* parameter name and value delimited by an equal sign. Roughly, the
* syntax is:
*
* <file> :== { <section> } EOF
*
* <section> :== <section header> { <parameter line> }
*
* <section header> :== '[' NAME ']'
*
* <parameter line> :== NAME '=' VALUE '\n'
*
* Blank lines and comment lines are ignored. Comment lines are lines
* beginning with either a semicolon (';') or a pound sign ('#').
*
* All whitespace in section names and parameter names is compressed
* to single spaces. Leading and trailing whitespace is stipped from
* both names and values.
*
* Only the first equals sign in a parameter line is significant.
* Parameter values may contain equals signs, square brackets and
* semicolons. Internal whitespace is retained in parameter values,
* with the exception of the '\r' character, which is stripped for
* historic reasons. Parameter names may not start with a left square
* bracket, an equal sign, a pound sign, or a semicolon, because these
* are used to identify other tokens.
*
* -------------------------------------------------------------------------- **
*/
#include "rsync.h"
/* -------------------------------------------------------------------------- **
* Constants...
*/
#define BUFR_INC 1024
/* -------------------------------------------------------------------------- **
* Variables...
*
* bufr - pointer to a global buffer. This is probably a kludge,
* but it was the nicest kludge I could think of (for now).
* bSize - The size of the global buffer <bufr>.
*/
static char *bufr = NULL;
static int bSize = 0;
/* -------------------------------------------------------------------------- **
* Functions...
*/
static int EatWhitespace( FILE *InFile )
/* ------------------------------------------------------------------------ **
* Scan past whitespace (see ctype(3C)) and return the first non-whitespace
* character, or newline, or EOF.
*
* Input: InFile - Input source.
*
* Output: The next non-whitespace character in the input stream.
*
* Notes: Because the config files use a line-oriented grammar, we
* explicitly exclude the newline character from the list of
* whitespace characters.
* - Note that both EOF (-1) and the nul character ('\0') are
* considered end-of-file markers.
*
* ------------------------------------------------------------------------ **
*/
{
int c;
for( c = getc( InFile ); isspace( c ) && ('\n' != c); c = getc( InFile ) )
;
return( c );
} /* EatWhitespace */
static int EatComment( FILE *InFile )
/* ------------------------------------------------------------------------ **
* Scan to the end of a comment.
*
* Input: InFile - Input source.
*
* Output: The character that marks the end of the comment. Normally,
* this will be a newline, but it *might* be an EOF.
*
* Notes: Because the config files use a line-oriented grammar, we
* explicitly exclude the newline character from the list of
* whitespace characters.
* - Note that both EOF (-1) and the nul character ('\0') are
* considered end-of-file markers.
*
* ------------------------------------------------------------------------ **
*/
{
int c;
for( c = getc( InFile ); ('\n'!=c) && (EOF!=c) && (c>0); c = getc( InFile ) )
;
return( c );
} /* EatComment */
static int Continuation( char *line, int pos )
/* ------------------------------------------------------------------------ **
* Scan backards within a string to discover if the last non-whitespace
* character is a line-continuation character ('\\').
*
* Input: line - A pointer to a buffer containing the string to be
* scanned.
* pos - This is taken to be the offset of the end of the
* string. This position is *not* scanned.
*
* Output: The offset of the '\\' character if it was found, or -1 to
* indicate that it was not.
*
* ------------------------------------------------------------------------ **
*/
{
pos--;
while( (pos >= 0) && isspace(line[pos]) )
pos--;
return( ((pos >= 0) && ('\\' == line[pos])) ? pos : -1 );
} /* Continuation */
static BOOL Section( FILE *InFile, BOOL (*sfunc)(char *) )
/* ------------------------------------------------------------------------ **
* Scan a section name, and pass the name to function sfunc().
*
* Input: InFile - Input source.
* sfunc - Pointer to the function to be called if the section
* name is successfully read.
*
* Output: True if the section name was read and True was returned from
* <sfunc>. False if <sfunc> failed or if a lexical error was
* encountered.
*
* ------------------------------------------------------------------------ **
*/
{
int c;
int i;
int end;
char *func = "params.c:Section() -";
i = 0; /* <i> is the offset of the next free byte in bufr[] and */
end = 0; /* <end> is the current "end of string" offset. In most */
/* cases these will be the same, but if the last */
/* character written to bufr[] is a space, then <end> */
/* will be one less than <i>. */
c = EatWhitespace( InFile ); /* We've already got the '['. Scan */
/* past initial white space. */
while( (EOF != c) && (c > 0) )
{
/* Check that the buffer is big enough for the next character. */
if( i > (bSize - 2) )
{
bSize += BUFR_INC;
bufr = Realloc( bufr, bSize );
if( NULL == bufr )
{
rprintf(FERROR, "%s Memory re-allocation failure.", func);
return( False );
}
}
/* Handle a single character. */
switch( c )
{
case ']': /* Found the closing bracket. */
bufr[end] = '\0';
if( 0 == end ) /* Don't allow an empty name. */
{
rprintf(FERROR, "%s Empty section name in configuration file.\n", func );
return( False );
}
if( !sfunc( bufr ) ) /* Got a valid name. Deal with it. */
return( False );
(void)EatComment( InFile ); /* Finish off the line. */
return( True );
case '\n': /* Got newline before closing ']'. */
i = Continuation( bufr, i ); /* Check for line continuation. */
if( i < 0 )
{
bufr[end] = '\0';
rprintf(FERROR, "%s Badly formed line in configuration file: %s\n",
func, bufr );
return( False );
}
end = ( (i > 0) && (' ' == bufr[i - 1]) ) ? (i - 1) : (i);
c = getc( InFile ); /* Continue with next line. */
break;
default: /* All else are a valid name chars. */
if( isspace( c ) ) /* One space per whitespace region. */
{
bufr[end] = ' ';
i = end + 1;
c = EatWhitespace( InFile );
}
else /* All others copy verbatim. */
{
bufr[i++] = c;
end = i;
c = getc( InFile );
}
}
}
/* We arrive here if we've met the EOF before the closing bracket. */
rprintf(FERROR, "%s Unexpected EOF in the configuration file: %s\n", func, bufr );
return( False );
} /* Section */
static BOOL Parameter( FILE *InFile, BOOL (*pfunc)(char *, char *), int c )
/* ------------------------------------------------------------------------ **
* Scan a parameter name and value, and pass these two fields to pfunc().
*
* Input: InFile - The input source.
* pfunc - A pointer to the function that will be called to
* process the parameter, once it has been scanned.
* c - The first character of the parameter name, which
* would have been read by Parse(). Unlike a comment
* line or a section header, there is no lead-in
* character that can be discarded.
*
* Output: True if the parameter name and value were scanned and processed
* successfully, else False.
*
* Notes: This function is in two parts. The first loop scans the
* parameter name. Internal whitespace is compressed, and an
* equal sign (=) terminates the token. Leading and trailing
* whitespace is discarded. The second loop scans the parameter
* value. When both have been successfully identified, they are
* passed to pfunc() for processing.
*
* ------------------------------------------------------------------------ **
*/
{
int i = 0; /* Position within bufr. */
int end = 0; /* bufr[end] is current end-of-string. */
int vstart = 0; /* Starting position of the parameter value. */
char *func = "params.c:Parameter() -";
/* Read the parameter name. */
while( 0 == vstart ) /* Loop until we've found the start of the value. */
{
if( i > (bSize - 2) ) /* Ensure there's space for next char. */
{
bSize += BUFR_INC;
bufr = Realloc( bufr, bSize );
if( NULL == bufr )
{
rprintf(FERROR, "%s Memory re-allocation failure.", func) ;
return( False );
}
}
switch( c )
{
case '=': /* Equal sign marks end of param name. */
if( 0 == end ) /* Don't allow an empty name. */
{
rprintf(FERROR, "%s Invalid parameter name in config. file.\n", func );
return( False );
}
bufr[end++] = '\0'; /* Mark end of string & advance. */
i = end; /* New string starts here. */
vstart = end; /* New string is parameter value. */
bufr[i] = '\0'; /* New string is nul, for now. */
break;
case '\n': /* Find continuation char, else error. */
i = Continuation( bufr, i );
if( i < 0 )
{
bufr[end] = '\0';
rprintf(FERROR, "%s Ignoring badly formed line in configuration file: %s\n",
func, bufr );
return( True );
}
end = ( (i > 0) && (' ' == bufr[i - 1]) ) ? (i - 1) : (i);
c = getc( InFile ); /* Read past eoln. */
break;
case '\0': /* Shouldn't have EOF within param name. */
case EOF:
bufr[i] = '\0';
rprintf(FERROR, "%s Unexpected end-of-file at: %s\n", func, bufr );
return( True );
default:
if( isspace( c ) ) /* One ' ' per whitespace region. */
{
bufr[end] = ' ';
i = end + 1;
c = EatWhitespace( InFile );
}
else /* All others verbatim. */
{
bufr[i++] = c;
end = i;
c = getc( InFile );
}
}
}
/* Now parse the value. */
c = EatWhitespace( InFile ); /* Again, trim leading whitespace. */
while( (EOF !=c) && (c > 0) )
{
if( i > (bSize - 2) ) /* Make sure there's enough room. */
{
bSize += BUFR_INC;
bufr = Realloc( bufr, bSize );
if( NULL == bufr )
{
rprintf(FERROR, "%s Memory re-allocation failure.", func) ;
return( False );
}
}
switch( c )
{
case '\r': /* Explicitly remove '\r' because the older */
c = getc( InFile ); /* version called fgets_slash() which also */
break; /* removes them. */
case '\n': /* Marks end of value unless there's a '\'. */
i = Continuation( bufr, i );
if( i < 0 )
c = 0;
else
{
for( end = i; (end >= 0) && isspace(bufr[end]); end-- )
;
c = getc( InFile );
}
break;
default: /* All others verbatim. Note that spaces do */
bufr[i++] = c; /* not advance <end>. This allows trimming */
if( !isspace( c ) ) /* of whitespace at the end of the line. */
end = i;
c = getc( InFile );
break;
}
}
bufr[end] = '\0'; /* End of value. */
return( pfunc( bufr, &bufr[vstart] ) ); /* Pass name & value to pfunc(). */
} /* Parameter */
static BOOL Parse( FILE *InFile,
BOOL (*sfunc)(char *),
BOOL (*pfunc)(char *, char *) )
/* ------------------------------------------------------------------------ **
* Scan & parse the input.
*
* Input: InFile - Input source.
* sfunc - Function to be called when a section name is scanned.
* See Section().
* pfunc - Function to be called when a parameter is scanned.
* See Parameter().
*
* Output: True if the file was successfully scanned, else False.
*
* Notes: The input can be viewed in terms of 'lines'. There are four
* types of lines:
* Blank - May contain whitespace, otherwise empty.
* Comment - First non-whitespace character is a ';' or '#'.
* The remainder of the line is ignored.
* Section - First non-whitespace character is a '['.
* Parameter - The default case.
*
* ------------------------------------------------------------------------ **
*/
{
int c;
c = EatWhitespace( InFile );
while( (EOF != c) && (c > 0) )
{
switch( c )
{
case '\n': /* Blank line. */
c = EatWhitespace( InFile );
break;
case ';': /* Comment line. */
case '#':
c = EatComment( InFile );
break;
case '[': /* Section Header. */
if (!sfunc) return True;
if( !Section( InFile, sfunc ) )
return( False );
c = EatWhitespace( InFile );
break;
case '\\': /* Bogus backslash. */
c = EatWhitespace( InFile );
break;
default: /* Parameter line. */
if( !Parameter( InFile, pfunc, c ) )
return( False );
c = EatWhitespace( InFile );
break;
}
}
return( True );
} /* Parse */
static FILE *OpenConfFile( char *FileName )
/* ------------------------------------------------------------------------ **
* Open a configuration file.
*
* Input: FileName - The pathname of the config file to be opened.
*
* Output: A pointer of type (FILE *) to the opened file, or NULL if the
* file could not be opened.
*
* ------------------------------------------------------------------------ **
*/
{
FILE *OpenedFile;
char *func = "params.c:OpenConfFile() -";
if( NULL == FileName || 0 == *FileName )
{
rprintf(FERROR,"%s No configuration filename specified.\n", func);
return( NULL );
}
OpenedFile = fopen( FileName, "r" );
if( NULL == OpenedFile )
{
rprintf(FERROR,"%s Unable to open configuration file \"%s\":\n\t%s\n",
func, FileName, strerror(errno));
}
return( OpenedFile );
} /* OpenConfFile */
BOOL pm_process( char *FileName,
BOOL (*sfunc)(char *),
BOOL (*pfunc)(char *, char *) )
/* ------------------------------------------------------------------------ **
* Process the named parameter file.
*
* Input: FileName - The pathname of the parameter file to be opened.
* sfunc - A pointer to a function that will be called when
* a section name is discovered.
* pfunc - A pointer to a function that will be called when
* a parameter name and value are discovered.
*
* Output: TRUE if the file was successfully parsed, else FALSE.
*
* ------------------------------------------------------------------------ **
*/
{
int result;
FILE *InFile;
char *func = "params.c:pm_process() -";
InFile = OpenConfFile( FileName ); /* Open the config file. */
if( NULL == InFile )
return( False );
if( NULL != bufr ) /* If we already have a buffer */
result = Parse( InFile, sfunc, pfunc ); /* (recursive call), then just */
/* use it. */
else /* If we don't have a buffer */
{ /* allocate one, then parse, */
bSize = BUFR_INC; /* then free. */
bufr = (char *)malloc( bSize );
if( NULL == bufr )
{
rprintf(FERROR,"%s memory allocation failure.\n", func);
fclose(InFile);
return( False );
}
result = Parse( InFile, sfunc, pfunc );
free( bufr );
bufr = NULL;
bSize = 0;
}
fclose(InFile);
if( !result ) /* Generic failure. */
{
rprintf(FERROR,"%s Failed. Error returned from params.c:parse().\n", func);
return( False );
}
return( True ); /* Generic success. */
} /* pm_process */
/* -------------------------------------------------------------------------- */

9
popt/.cvsignore Normal file
View File

@@ -0,0 +1,9 @@
ID
Makefile
config.cache
config.h
config.log
config.status
dummy
rsync
zlib/dummy

43
popt/CHANGES Normal file
View File

@@ -0,0 +1,43 @@
1.3 ->
- heavy dose of const's
- poptParseArgvString() now NULL terminates the list
1.2.3 -> 1.3
- added support for single -
- misc bug fixes
- portability improvements
1.2.2 -> 1.2.3
- fixed memset() in help message generation (Dale Hawkins)
- added extern "C" stuff to popt.h for C++ compilers (Dale Hawkins)
- const'ified poptParseArgvString (Jeff Garzik)
1.2.1 -> 1.2.2
- fixed bug in chaind alias happens which seems to have only
affected --triggers in rpm
- added POPT_ARG_VAL
- popt.3 installed by default
1.2 -> 1.2.1
- added POPT_ARG_INTL_DOMAIN (Elliot Lee)
- updated Makefile's to be more GNUish (Elliot Lee)
1.1 -> 1.2
- added popt.3 man page (Robert Lynch)
- don't use mmap anymore (its lack of portability isn't worth the
trouble)
- added test script
- added support for exec
- removed support for *_POPT_ALIASES env variable -- it was a bad
idea
- reorganized into multiple source files
- added automatic help generation, POPT_AUTOHELP
- added table callbacks
- added table inclusion
- updated man page for new features
- added test scripts
1.0 -> 1.1
- moved to autoconf (Fred Fish)
- added STRERROR replacement (Norbert Warmuth)
- added const keywords (Bruce Perens)

22
popt/COPYING Normal file
View File

@@ -0,0 +1,22 @@
Copyright (c) 1998 Red Hat Software
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of the X Consortium shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from the X Consortium.

18
popt/README Normal file
View File

@@ -0,0 +1,18 @@
This is the popt command line option parsing library. While it is similiar
to getopt(3), it contains a number of enhancements, including:
1) popt is fully reentrant
2) popt can parse arbitrary argv[] style arrays while
getopt(2) makes this quite difficult
3) popt allows users to alias command line arguments
4) popt provides convience functions for parsting strings
into argv[] style arrays
popt is used by rpm, the Red Hat install program, and many other Red Hat
utilities, all of which provide excellent examples of how to use popt.
Complete documentation on popt is available in popt.ps (included in this
tarball), which is excerpted with permission from the book "Linux
Application Development" by Michael K. Johnson and Erik Troan (availble
from Addison Wesley in May, 1998).
Comments on popt should be addressed to ewt@redhat.com.

104
popt/config.log Normal file
View File

@@ -0,0 +1,104 @@
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
configure:592: checking host system type
configure:613: checking target system type
configure:631: checking build system type
configure:665: checking for a BSD compatible install
configure:718: checking whether build environment is sane
configure:775: checking whether make sets ${MAKE}
configure:821: checking for working aclocal
configure:834: checking for working autoconf
configure:847: checking for working automake
configure:860: checking for working autoheader
configure:873: checking for working makeinfo
configure:891: checking for gcc
configure:1004: checking whether the C compiler (gcc ) works
configure:1020: gcc -o conftest conftest.c 1>&5
configure:1046: checking whether the C compiler (gcc ) is a cross-compiler
configure:1051: checking whether we are using GNU C
configure:1079: checking whether gcc accepts -g
configure:1111: checking for POSIXized ISC
configure:1135: checking for gcc
configure:1248: checking whether the C compiler (gcc -g -O2 ) works
configure:1264: gcc -o conftest -g -O2 conftest.c 1>&5
configure:1290: checking whether the C compiler (gcc -g -O2 ) is a cross-compiler
configure:1295: checking whether we are using GNU C
configure:1323: checking whether gcc accepts -g
configure:1355: checking how to run the C preprocessor
configure:1436: checking whether gcc needs -traditional
configure:1485: checking for gcc option to accept ANSI C
configure:1564: checking for function prototypes
configure:1795: checking for ranlib
configure:1834: checking for ld used by GCC
configure:1896: checking if the linker (/usr/bin/ld) is GNU ld
configure:1912: checking for BSD-compatible nm
configure:1948: checking whether ln -s works
ltconfig:603: checking for object suffix
ltconfig:604: gcc -c -g -O2 conftest.c 1>&5
ltconfig:629: checking for executable suffix
ltconfig:630: gcc -o conftest -g -O2 conftest.c 1>&5
ltconfig:776: checking if gcc PIC flag -fPIC works
ltconfig:777: gcc -c -g -O2 -fPIC -DPIC conftest.c 1>&5
ltconfig:829: checking if gcc supports -c -o file.o
ltconfig:830: gcc -c -g -O2 -o out/conftest2.o conftest.c 1>&5
ltconfig:862: checking if gcc supports -c -o file.lo
ltconfig:863: gcc -c -g -O2 -c -o conftest.lo conftest.c 1>&5
ltconfig:914: checking if gcc supports -fno-rtti -fno-exceptions
ltconfig:915: gcc -c -g -O2 -fno-rtti -fno-exceptions -c conftest.c conftest.c 1>&5
ltconfig:958: checking if gcc static flag -static works
ltconfig:959: gcc -o conftest -g -O2 -static conftest.c 1>&5
GNU ld version 2.10.91 (with BFD 2.10.91.0.2)
ltconfig:1635: checking if global_symbol_pipe works
ltconfig:1636: gcc -c -g -O2 conftest.c 1>&5
ltconfig:1639: eval "/usr/bin/nm -B conftest.o | sed -n -e 's/^.*[ ]\([ABCDGISTW]\)[ ][ ]*\(\)\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2\3 \3/p' > conftest.nm"
ltconfig:1691: gcc -o conftest -g -O2 -fno-builtin -fno-rtti -fno-exceptions conftest.c conftstm.o 1>&5
configure:2150: checking for a BSD compatible install
configure:2231: checking for alloca.h
configure:2231: checking for libintl.h
configure:2231: checking for mcheck.h
configure:2231: checking for unistd.h
configure:2268: checking for /usr/ucblib in LIBS
configure:2284: checking for GNU xgettext
configure:2294: checking for strerror
configure:2294: checking for mtrace
configure:2347: checking for setreuid
configure:2438: checking for working const
configure:2513: checking for inline
configure:2553: checking for off_t
configure:2586: checking for size_t
configure:2621: checking for working alloca.h
configure:2654: checking for alloca
configure:2856: checking for unistd.h
configure:2895: checking for getpagesize
configure:2948: checking for working mmap
configure:3124: checking for argz.h
configure:3124: checking for limits.h
configure:3124: checking for locale.h
configure:3124: checking for nl_types.h
configure:3124: checking for malloc.h
configure:3124: checking for string.h
configure:3124: checking for unistd.h
configure:3124: checking for sys/param.h
configure:3164: checking for getcwd
configure:3164: checking for munmap
configure:3164: checking for putenv
configure:3164: checking for setenv
configure:3164: checking for setlocale
configure:3164: checking for strchr
configure:3164: checking for strcasecmp
configure:3164: checking for strdup
configure:3164: checking for __argz_count
configure:3164: checking for __argz_stringify
configure:3164: checking for __argz_next
configure:3283: checking for LC_MESSAGES
configure:3316: checking whether NLS is requested
configure:3336: checking whether included gettext is requested
configure:3355: checking for libintl.h
configure:3382: checking for gettext in libc
configure:3508: checking for msgfmt
configure:3542: checking for dcgettext
configure:3597: checking for gmsgfmt
configure:3633: checking for xgettext
configure:3673: gcc -o conftest -Wall -g -O2 conftest.c 1>&5
configure:4131: checking for catalogs to be installed

0
popt/dummy.in Normal file
View File

46
popt/findme.c Normal file
View File

@@ -0,0 +1,46 @@
/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING
file accompanying popt source distributions, available from
ftp://ftp.redhat.com/pub/code/popt */
#include "system.h"
#include "findme.h"
const char * findProgramPath(const char * argv0) {
char * path = getenv("PATH");
char * pathbuf;
char * start, * chptr;
char * buf, *local = NULL;
/* If there is a / in the argv[0], it has to be an absolute
path */
if (strchr(argv0, '/'))
return xstrdup(argv0);
if (!path) return NULL;
local = start = pathbuf = malloc(strlen(path) + 1);
buf = malloc(strlen(path) + strlen(argv0) + 2);
strcpy(pathbuf, path);
chptr = NULL;
do {
if ((chptr = strchr(start, ':')))
*chptr = '\0';
sprintf(buf, "%s/%s", start, argv0);
if (!access(buf, X_OK)) {
if (local) free(local);
return buf;
}
if (chptr)
start = chptr + 1;
else
start = NULL;
} while (start && *start);
free(buf);
if (local) free(local);
return NULL;
}

10
popt/findme.h Normal file
View File

@@ -0,0 +1,10 @@
/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING
file accompanying popt source distributions, available from
ftp://ftp.redhat.com/pub/code/popt */
#ifndef H_FINDME
#define H_FINDME
const char * findProgramPath(const char * argv0);
#endif

782
popt/popt.c Normal file
View File

@@ -0,0 +1,782 @@
/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING
file accompanying popt source distributions, available from
ftp://ftp.redhat.com/pub/code/popt */
#include "system.h"
#include "findme.h"
#include "poptint.h"
#ifndef HAVE_STRERROR
static char * strerror(int errno) {
extern int sys_nerr;
extern char * sys_errlist[];
if ((0 <= errno) && (errno < sys_nerr))
return sys_errlist[errno];
else
return POPT_("unknown errno");
}
#endif
void poptSetExecPath(poptContext con, const char * path, int allowAbsolute) {
if (con->execPath) xfree(con->execPath);
con->execPath = xstrdup(path);
con->execAbsolute = allowAbsolute;
}
static void invokeCallbacks(poptContext con, const struct poptOption * table,
int post) {
const struct poptOption * opt = table;
poptCallbackType cb;
while (opt->longName || opt->shortName || opt->arg) {
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
invokeCallbacks(con, opt->arg, post);
} else if (((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK) &&
((!post && (opt->argInfo & POPT_CBFLAG_PRE)) ||
( post && (opt->argInfo & POPT_CBFLAG_POST)))) {
cb = (poptCallbackType)opt->arg;
cb(con, post ? POPT_CALLBACK_REASON_POST : POPT_CALLBACK_REASON_PRE,
NULL, NULL, opt->descrip);
}
opt++;
}
}
poptContext poptGetContext(const char * name, int argc, const char ** argv,
const struct poptOption * options, int flags) {
poptContext con = malloc(sizeof(*con));
memset(con, 0, sizeof(*con));
con->os = con->optionStack;
con->os->argc = argc;
con->os->argv = argv;
con->os->argb = NULL;
if (!(flags & POPT_CONTEXT_KEEP_FIRST))
con->os->next = 1; /* skip argv[0] */
con->leftovers = calloc( (argc + 1), sizeof(char *) );
con->options = options;
con->aliases = NULL;
con->numAliases = 0;
con->flags = flags;
con->execs = NULL;
con->numExecs = 0;
con->finalArgvAlloced = argc * 2;
con->finalArgv = calloc( con->finalArgvAlloced, sizeof(*con->finalArgv) );
con->execAbsolute = 1;
con->arg_strip = NULL;
if (getenv("POSIXLY_CORRECT") || getenv("POSIX_ME_HARDER"))
con->flags |= POPT_CONTEXT_POSIXMEHARDER;
if (name)
con->appName = strcpy(malloc(strlen(name) + 1), name);
invokeCallbacks(con, con->options, 0);
return con;
}
static void cleanOSE(struct optionStackEntry *os)
{
if (os->nextArg) {
xfree(os->nextArg);
os->nextArg = NULL;
}
if (os->argv) {
xfree(os->argv);
os->argv = NULL;
}
if (os->argb) {
PBM_FREE(os->argb);
os->argb = NULL;
}
}
void poptResetContext(poptContext con) {
int i;
while (con->os > con->optionStack) {
cleanOSE(con->os--);
}
if (con->os->argb) {
PBM_FREE(con->os->argb);
con->os->argb = NULL;
}
con->os->currAlias = NULL;
con->os->nextCharArg = NULL;
con->os->nextArg = NULL;
con->os->next = 1; /* skip argv[0] */
con->numLeftovers = 0;
con->nextLeftover = 0;
con->restLeftover = 0;
con->doExec = NULL;
for (i = 0; i < con->finalArgvCount; i++) {
if (con->finalArgv[i]) {
xfree(con->finalArgv[i]);
con->finalArgv[i] = NULL;
}
}
con->finalArgvCount = 0;
if (con->arg_strip) {
PBM_FREE(con->arg_strip);
con->arg_strip = NULL;
}
}
/* Only one of longName, shortName may be set at a time */
static int handleExec(poptContext con, char * longName, char shortName) {
int i;
i = con->numExecs - 1;
if (longName) {
while (i >= 0 && (!con->execs[i].longName ||
strcmp(con->execs[i].longName, longName))) i--;
} else {
while (i >= 0 &&
con->execs[i].shortName != shortName) i--;
}
if (i < 0) return 0;
if (con->flags & POPT_CONTEXT_NO_EXEC)
return 1;
if (con->doExec == NULL) {
con->doExec = con->execs + i;
return 1;
}
/* We already have an exec to do; remember this option for next
time 'round */
if ((con->finalArgvCount + 1) >= (con->finalArgvAlloced)) {
con->finalArgvAlloced += 10;
con->finalArgv = realloc(con->finalArgv,
sizeof(*con->finalArgv) * con->finalArgvAlloced);
}
i = con->finalArgvCount++;
{ char *s = malloc((longName ? strlen(longName) : 0) + 3);
if (longName)
sprintf(s, "--%s", longName);
else
sprintf(s, "-%c", shortName);
con->finalArgv[i] = s;
}
return 1;
}
/* Only one of longName, shortName may be set at a time */
static int handleAlias(poptContext con, const char * longName, char shortName,
/*@keep@*/ const char * nextCharArg) {
int i;
if (con->os->currAlias && con->os->currAlias->longName && longName &&
!strcmp(con->os->currAlias->longName, longName))
return 0;
if (con->os->currAlias && shortName &&
shortName == con->os->currAlias->shortName)
return 0;
i = con->numAliases - 1;
if (longName) {
while (i >= 0 && (!con->aliases[i].longName ||
strcmp(con->aliases[i].longName, longName))) i--;
} else {
while (i >= 0 &&
con->aliases[i].shortName != shortName) i--;
}
if (i < 0) return 0;
if ((con->os - con->optionStack + 1) == POPT_OPTION_DEPTH)
return POPT_ERROR_OPTSTOODEEP;
if (nextCharArg && *nextCharArg)
con->os->nextCharArg = nextCharArg;
con->os++;
con->os->next = 0;
con->os->stuffed = 0;
con->os->nextArg = NULL;
con->os->nextCharArg = NULL;
con->os->currAlias = con->aliases + i;
poptDupArgv(con->os->currAlias->argc, con->os->currAlias->argv,
&con->os->argc, &con->os->argv);
con->os->argb = NULL;
return 1;
}
static void execCommand(poptContext con) {
const char ** argv;
int pos = 0;
const char * script = con->doExec->script;
argv = malloc(sizeof(*argv) *
(6 + con->numLeftovers + con->finalArgvCount));
if (!con->execAbsolute && strchr(script, '/')) return;
if (!strchr(script, '/') && con->execPath) {
char *s = malloc(strlen(con->execPath) + strlen(script) + 2);
sprintf(s, "%s/%s", con->execPath, script);
argv[pos] = s;
} else {
argv[pos] = script;
}
pos++;
argv[pos] = findProgramPath(con->os->argv[0]);
if (argv[pos]) pos++;
argv[pos++] = ";";
memcpy(argv + pos, con->finalArgv, sizeof(*argv) * con->finalArgvCount);
pos += con->finalArgvCount;
if (con->numLeftovers) {
argv[pos++] = "--";
memcpy(argv + pos, con->leftovers, sizeof(*argv) * con->numLeftovers);
pos += con->numLeftovers;
}
argv[pos++] = NULL;
#ifdef __hpux
setresuid(getuid(), getuid(),-1);
#else
/*
* XXX " ... on BSD systems setuid() should be preferred over setreuid()"
* XXX sez' Timur Bakeyev <mc@bat.ru>
* XXX from Norbert Warmuth <nwarmuth@privat.circular.de>
*/
#if defined(HAVE_SETUID)
setuid(getuid());
#elif defined (HAVE_SETREUID)
setreuid(getuid(), getuid()); /*hlauer: not portable to hpux9.01 */
#else
; /* Can't drop privileges */
#endif
#endif
execvp(argv[0], (char *const *)argv);
}
/*@observer@*/ static const struct poptOption *
findOption(const struct poptOption * table, const char * longName,
char shortName,
/*@out@*/ poptCallbackType * callback, /*@out@*/ const void ** callbackData,
int singleDash)
{
const struct poptOption * opt = table;
const struct poptOption * opt2;
const struct poptOption * cb = NULL;
/* This happens when a single - is given */
if (singleDash && !shortName && !*longName)
shortName = '-';
while (opt->longName || opt->shortName || opt->arg) {
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
opt2 = findOption(opt->arg, longName, shortName, callback,
callbackData, singleDash);
if (opt2) {
if (*callback && !*callbackData)
*callbackData = opt->descrip;
return opt2;
}
} else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK) {
cb = opt;
} else if (longName && opt->longName &&
(!singleDash || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) &&
!strcmp(longName, opt->longName)) {
break;
} else if (shortName && shortName == opt->shortName) {
break;
}
opt++;
}
if (!opt->longName && !opt->shortName) return NULL;
*callbackData = NULL;
*callback = NULL;
if (cb) {
*callback = (poptCallbackType)cb->arg;
if (!(cb->argInfo & POPT_CBFLAG_INC_DATA))
*callbackData = cb->descrip;
}
return opt;
}
static const char *findNextArg(poptContext con, unsigned argx, int delete)
{
struct optionStackEntry * os = con->os;
const char * arg;
do {
int i;
arg = NULL;
while (os->next == os->argc && os > con->optionStack) os--;
if (os->next == os->argc && os == con->optionStack) break;
for (i = os->next; i < os->argc; i++) {
if (os->argb && PBM_ISSET(i, os->argb)) continue;
if (*os->argv[i] == '-') continue;
if (--argx > 0) continue;
arg = os->argv[i];
if (delete) {
if (os->argb == NULL) os->argb = PBM_ALLOC(os->argc);
PBM_SET(i, os->argb);
}
break;
}
if (os > con->optionStack) os--;
} while (arg == NULL);
return arg;
}
static /*@only@*/ const char * expandNextArg(poptContext con, const char * s)
{
const char *a;
size_t alen;
char *t, *te;
size_t tn = strlen(s) + 1;
char c;
te = t = malloc(tn);;
while ((c = *s++) != '\0') {
switch (c) {
#if 0 /* XXX can't do this */
case '\\': /* escape */
c = *s++;
break;
#endif
case '!':
if (!(s[0] == '#' && s[1] == ':' && s[2] == '+'))
break;
if ((a = findNextArg(con, 1, 1)) == NULL)
break;
s += 3;
alen = strlen(a);
tn += alen;
*te = '\0';
t = realloc(t, tn);
te = t + strlen(t);
strncpy(te, a, alen); te += alen;
continue;
/*@notreached@*/ break;
default:
break;
}
*te++ = c;
}
*te = '\0';
t = realloc(t, strlen(t)+1); /* XXX memory leak, hard to plug */
return t;
}
static void poptStripArg(poptContext con, int which)
{
if(con->arg_strip == NULL) {
con->arg_strip = PBM_ALLOC(con->optionStack[0].argc);
}
PBM_SET(which, con->arg_strip);
}
/* returns 'val' element, -1 on last item, POPT_ERROR_* on error */
int poptGetNextOpt(poptContext con)
{
const struct poptOption * opt = NULL;
int done = 0;
/* looks a bit tricky to get rid of alloca properly in this fn */
#if HAVE_ALLOCA_H
#define ALLOCA(x) alloca(x)
#else
#define ALLOCA(x) malloc(x)
#endif
while (!done) {
const char * origOptString = NULL;
poptCallbackType cb = NULL;
const void * cbData = NULL;
const char * longArg = NULL;
int canstrip = 0;
while (!con->os->nextCharArg && con->os->next == con->os->argc
&& con->os > con->optionStack) {
cleanOSE(con->os--);
}
if (!con->os->nextCharArg && con->os->next == con->os->argc) {
invokeCallbacks(con, con->options, 1);
if (con->doExec) execCommand(con);
return -1;
}
/* Process next long option */
if (!con->os->nextCharArg) {
char * localOptString, * optString;
int thisopt;
if (con->os->argb && PBM_ISSET(con->os->next, con->os->argb)) {
con->os->next++;
continue;
}
thisopt=con->os->next;
origOptString = con->os->argv[con->os->next++];
if (con->restLeftover || *origOptString != '-') {
con->leftovers[con->numLeftovers++] = origOptString;
if (con->flags & POPT_CONTEXT_POSIXMEHARDER)
con->restLeftover = 1;
continue;
}
/* Make a copy we can hack at */
localOptString = optString =
strcpy(ALLOCA(strlen(origOptString) + 1),
origOptString);
if (!optString[0])
return POPT_ERROR_BADOPT;
if (optString[1] == '-' && !optString[2]) {
con->restLeftover = 1;
continue;
} else {
char *oe;
int singleDash;
optString++;
if (*optString == '-')
singleDash = 0, optString++;
else
singleDash = 1;
/* XXX aliases with arg substitution need "--alias=arg" */
if (handleAlias(con, optString, '\0', NULL))
continue;
if (handleExec(con, optString, '\0'))
continue;
/* Check for "--long=arg" option. */
for (oe = optString; *oe && *oe != '='; oe++)
;
if (*oe == '=') {
*oe++ = '\0';
/* XXX longArg is mapped back to persistent storage. */
longArg = origOptString + (oe - localOptString);
}
opt = findOption(con->options, optString, '\0', &cb, &cbData,
singleDash);
if (!opt && !singleDash)
return POPT_ERROR_BADOPT;
}
if (!opt) {
con->os->nextCharArg = origOptString + 1;
} else {
if(con->os == con->optionStack &&
opt->argInfo & POPT_ARGFLAG_STRIP) {
canstrip = 1;
poptStripArg(con, thisopt);
}
}
}
/* Process next short option */
if (con->os->nextCharArg) {
origOptString = con->os->nextCharArg;
con->os->nextCharArg = NULL;
if (handleAlias(con, NULL, *origOptString,
origOptString + 1)) {
origOptString++;
continue;
}
if (handleExec(con, NULL, *origOptString))
continue;
opt = findOption(con->options, NULL, *origOptString, &cb,
&cbData, 0);
if (!opt)
return POPT_ERROR_BADOPT;
origOptString++;
if (*origOptString)
con->os->nextCharArg = origOptString;
}
if (opt->arg && (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE) {
*((int *)opt->arg) = 1;
} else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL) {
if (opt->arg)
*((int *) opt->arg) = opt->val;
} else if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE) {
if (con->os->nextArg) {
xfree(con->os->nextArg);
con->os->nextArg = NULL;
}
if (longArg) {
con->os->nextArg = expandNextArg(con, longArg);
} else if (con->os->nextCharArg) {
con->os->nextArg = expandNextArg(con, con->os->nextCharArg);
con->os->nextCharArg = NULL;
} else {
while (con->os->next == con->os->argc &&
con->os > con->optionStack) {
cleanOSE(con->os--);
}
if (con->os->next == con->os->argc)
return POPT_ERROR_NOARG;
/* make sure this isn't part of a short arg or the
result of an alias expansion */
if(con->os == con->optionStack &&
opt->argInfo & POPT_ARGFLAG_STRIP &&
canstrip) {
poptStripArg(con, con->os->next);
}
con->os->nextArg = expandNextArg(con, con->os->argv[con->os->next++]);
}
if (opt->arg) {
long aLong;
char *end;
switch (opt->argInfo & POPT_ARG_MASK) {
case POPT_ARG_STRING:
/* XXX memory leak, hard to plug */
*((const char **) opt->arg) = xstrdup(con->os->nextArg);
break;
case POPT_ARG_INT:
case POPT_ARG_LONG:
aLong = strtol(con->os->nextArg, &end, 0);
if (!(end && *end == '\0'))
return POPT_ERROR_BADNUMBER;
if (aLong == LONG_MIN || aLong == LONG_MAX)
return POPT_ERROR_OVERFLOW;
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_LONG) {
*((long *) opt->arg) = aLong;
} else {
if (aLong > INT_MAX || aLong < INT_MIN)
return POPT_ERROR_OVERFLOW;
*((int *) opt->arg) = aLong;
}
break;
default:
fprintf(stdout, POPT_("option type (%d) not implemented in popt\n"),
opt->argInfo & POPT_ARG_MASK);
exit(EXIT_FAILURE);
}
}
}
if (cb)
cb(con, POPT_CALLBACK_REASON_OPTION, opt, con->os->nextArg, cbData);
else if (opt->val && ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL))
done = 1;
if ((con->finalArgvCount + 2) >= (con->finalArgvAlloced)) {
con->finalArgvAlloced += 10;
con->finalArgv = realloc(con->finalArgv,
sizeof(*con->finalArgv) * con->finalArgvAlloced);
}
{ char *s = malloc((opt->longName ? strlen(opt->longName) : 0) + 3);
if (opt->longName)
sprintf(s, "--%s", opt->longName);
else
sprintf(s, "-%c", opt->shortName);
con->finalArgv[con->finalArgvCount++] = s;
}
if (opt->arg && (opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE
&& (opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL) {
con->finalArgv[con->finalArgvCount++] = xstrdup(con->os->nextArg);
}
}
return opt->val;
}
const char * poptGetOptArg(poptContext con) {
const char * ret = con->os->nextArg;
con->os->nextArg = NULL;
return ret;
}
const char * poptGetArg(poptContext con) {
if (con->numLeftovers == con->nextLeftover) return NULL;
return con->leftovers[con->nextLeftover++];
}
const char * poptPeekArg(poptContext con) {
if (con->numLeftovers == con->nextLeftover) return NULL;
return con->leftovers[con->nextLeftover];
}
const char ** poptGetArgs(poptContext con) {
if (con->numLeftovers == con->nextLeftover) return NULL;
/* some apps like [like RPM ;-) ] need this NULL terminated */
con->leftovers[con->numLeftovers] = NULL;
return (con->leftovers + con->nextLeftover);
}
void poptFreeContext(poptContext con) {
int i;
poptResetContext(con);
if (con->os->argb) free(con->os->argb);
for (i = 0; i < con->numAliases; i++) {
if (con->aliases[i].longName) xfree(con->aliases[i].longName);
free(con->aliases[i].argv);
}
for (i = 0; i < con->numExecs; i++) {
if (con->execs[i].longName) xfree(con->execs[i].longName);
xfree(con->execs[i].script);
}
if (con->execs) xfree(con->execs);
free(con->leftovers);
free(con->finalArgv);
if (con->appName) xfree(con->appName);
if (con->aliases) free(con->aliases);
if (con->otherHelp) xfree(con->otherHelp);
if (con->execPath) xfree(con->execPath);
if (con->arg_strip) PBM_FREE(con->arg_strip);
free(con);
}
int poptAddAlias(poptContext con, struct poptAlias newAlias,
/*@unused@*/ int flags)
{
int aliasNum = con->numAliases++;
struct poptAlias * alias;
/* SunOS won't realloc(NULL, ...) */
if (!con->aliases)
con->aliases = malloc(sizeof(newAlias) * con->numAliases);
else
con->aliases = realloc(con->aliases,
sizeof(newAlias) * con->numAliases);
alias = con->aliases + aliasNum;
alias->longName = (newAlias.longName)
? strcpy(malloc(strlen(newAlias.longName) + 1), newAlias.longName)
: NULL;
alias->shortName = newAlias.shortName;
alias->argc = newAlias.argc;
alias->argv = newAlias.argv;
return 0;
}
const char * poptBadOption(poptContext con, int flags) {
struct optionStackEntry * os;
if (flags & POPT_BADOPTION_NOALIAS)
os = con->optionStack;
else
os = con->os;
return os->argv[os->next - 1];
}
#define POPT_ERROR_NOARG -10
#define POPT_ERROR_BADOPT -11
#define POPT_ERROR_OPTSTOODEEP -13
#define POPT_ERROR_BADQUOTE -15 /* only from poptParseArgString() */
#define POPT_ERROR_ERRNO -16 /* only from poptParseArgString() */
const char *const poptStrerror(const int error) {
switch (error) {
case POPT_ERROR_NOARG:
return POPT_("missing argument");
case POPT_ERROR_BADOPT:
return POPT_("unknown option");
case POPT_ERROR_OPTSTOODEEP:
return POPT_("aliases nested too deeply");
case POPT_ERROR_BADQUOTE:
return POPT_("error in paramter quoting");
case POPT_ERROR_BADNUMBER:
return POPT_("invalid numeric value");
case POPT_ERROR_OVERFLOW:
return POPT_("number too large or too small");
case POPT_ERROR_ERRNO:
return strerror(errno);
default:
return POPT_("unknown error");
}
}
int poptStuffArgs(poptContext con, const char ** argv) {
int argc;
if ((con->os - con->optionStack) == POPT_OPTION_DEPTH)
return POPT_ERROR_OPTSTOODEEP;
for (argc = 0; argv[argc]; argc++)
;
con->os++;
con->os->next = 0;
con->os->nextArg = NULL;
con->os->nextCharArg = NULL;
con->os->currAlias = NULL;
poptDupArgv(argc, argv, &con->os->argc, &con->os->argv);
con->os->argb = NULL;
con->os->stuffed = 1;
return 0;
}
const char * poptGetInvocationName(poptContext con) {
return con->os->argv[0];
}
int poptStrippedArgv(poptContext con, int argc, char **argv)
{
int i,j=1, numargs=argc;
for(i=1; i<argc; i++) {
if(PBM_ISSET(i, con->arg_strip)) {
numargs--;
}
}
for(i=1; i<argc; i++) {
if(PBM_ISSET(i, con->arg_strip)) {
continue;
} else {
if(j<numargs) {
argv[j++]=argv[i];
} else {
argv[j++]='\0';
}
}
}
return(numargs);
}

130
popt/popt.h Normal file
View File

@@ -0,0 +1,130 @@
/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING
file accompanying popt source distributions, available from
ftp://ftp.redhat.com/pub/code/popt */
#ifndef H_POPT
#define H_POPT
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h> /* for FILE * */
#define POPT_OPTION_DEPTH 10
#define POPT_ARG_NONE 0
#define POPT_ARG_STRING 1
#define POPT_ARG_INT 2
#define POPT_ARG_LONG 3
#define POPT_ARG_INCLUDE_TABLE 4 /* arg points to table */
#define POPT_ARG_CALLBACK 5 /* table-wide callback... must be
set first in table; arg points
to callback, descrip points to
callback data to pass */
#define POPT_ARG_INTL_DOMAIN 6 /* set the translation domain
for this table and any
included tables; arg points
to the domain string */
#define POPT_ARG_VAL 7 /* arg should take value val */
#define POPT_ARG_MASK 0x0000FFFF
#define POPT_ARGFLAG_ONEDASH 0x80000000 /* allow -longoption */
#define POPT_ARGFLAG_DOC_HIDDEN 0x40000000 /* don't show in help/usage */
#define POPT_ARGFLAG_STRIP 0x20000000 /* strip this arg from argv (only applies to long args) */
#define POPT_CBFLAG_PRE 0x80000000 /* call the callback before parse */
#define POPT_CBFLAG_POST 0x40000000 /* call the callback after parse */
#define POPT_CBFLAG_INC_DATA 0x20000000 /* use data from the include line,
not the subtable */
#define POPT_ERROR_NOARG -10
#define POPT_ERROR_BADOPT -11
#define POPT_ERROR_OPTSTOODEEP -13
#define POPT_ERROR_BADQUOTE -15 /* only from poptParseArgString() */
#define POPT_ERROR_ERRNO -16 /* only from poptParseArgString() */
#define POPT_ERROR_BADNUMBER -17
#define POPT_ERROR_OVERFLOW -18
/* poptBadOption() flags */
#define POPT_BADOPTION_NOALIAS (1 << 0) /* don't go into an alias */
/* poptGetContext() flags */
#define POPT_CONTEXT_NO_EXEC (1 << 0) /* ignore exec expansions */
#define POPT_CONTEXT_KEEP_FIRST (1 << 1) /* pay attention to argv[0] */
#define POPT_CONTEXT_POSIXMEHARDER (1 << 2) /* options can't follow args */
struct poptOption {
/*@observer@*/ /*@null@*/ const char * longName; /* may be NULL */
char shortName; /* may be '\0' */
int argInfo;
/*@shared@*/ /*@null@*/ void * arg; /* depends on argInfo */
int val; /* 0 means don't return, just update flag */
/*@shared@*/ /*@null@*/ const char * descrip; /* description for autohelp -- may be NULL */
/*@shared@*/ /*@null@*/ const char * argDescrip; /* argument description for autohelp */
};
struct poptAlias {
/*@owned@*/ /*@null@*/ const char * longName; /* may be NULL */
char shortName; /* may be '\0' */
int argc;
/*@owned@*/ const char ** argv; /* must be free()able */
};
extern struct poptOption poptHelpOptions[];
#define POPT_AUTOHELP { NULL, '\0', POPT_ARG_INCLUDE_TABLE, poptHelpOptions, \
0, "Help options", NULL },
typedef struct poptContext_s * poptContext;
#ifndef __cplusplus
typedef struct poptOption * poptOption;
#endif
enum poptCallbackReason { POPT_CALLBACK_REASON_PRE,
POPT_CALLBACK_REASON_POST,
POPT_CALLBACK_REASON_OPTION };
typedef void (*poptCallbackType)(poptContext con,
enum poptCallbackReason reason,
const struct poptOption * opt,
const char * arg, const void * data);
/*@only@*/ poptContext poptGetContext(/*@keep@*/ const char * name,
int argc, /*@keep@*/ const char ** argv,
/*@keep@*/ const struct poptOption * options, int flags);
void poptResetContext(poptContext con);
/* returns 'val' element, -1 on last item, POPT_ERROR_* on error */
int poptGetNextOpt(poptContext con);
/* returns NULL if no argument is available */
/*@observer@*/ /*@null@*/ const char * poptGetOptArg(poptContext con);
/* returns NULL if no more options are available */
/*@observer@*/ /*@null@*/ const char * poptGetArg(poptContext con);
/*@observer@*/ /*@null@*/ const char * poptPeekArg(poptContext con);
/*@observer@*/ /*@null@*/ const char ** poptGetArgs(poptContext con);
/* returns the option which caused the most recent error */
/*@observer@*/ const char * poptBadOption(poptContext con, int flags);
void poptFreeContext( /*@only@*/ poptContext con);
int poptStuffArgs(poptContext con, /*@keep@*/ const char ** argv);
int poptAddAlias(poptContext con, struct poptAlias alias, int flags);
int poptReadConfigFile(poptContext con, const char * fn);
/* like above, but reads /etc/popt and $HOME/.popt along with environment
vars */
int poptReadDefaultConfig(poptContext con, int useEnv);
/* argv should be freed -- this allows ', ", and \ quoting, but ' is treated
the same as " and both may include \ quotes */
int poptDupArgv(int argc, const char **argv,
/*@out@*/ int * argcPtr, /*@out@*/ const char *** argvPtr);
int poptParseArgvString(const char * s,
/*@out@*/ int * argcPtr, /*@out@*/ const char *** argvPtr);
/*@observer@*/ const char *const poptStrerror(const int error);
void poptSetExecPath(poptContext con, const char * path, int allowAbsolute);
void poptPrintHelp(poptContext con, FILE * f, int flags);
void poptPrintUsage(poptContext con, FILE * f, int flags);
void poptSetOtherOptionHelp(poptContext con, const char * text);
/*@observer@*/ const char * poptGetInvocationName(poptContext con);
/* shuffles argv pointers to remove stripped args, returns new argc */
int poptStrippedArgv(poptContext con, int argc, char **argv);
#ifdef __cplusplus
}
#endif
#endif

142
popt/poptconfig.c Normal file
View File

@@ -0,0 +1,142 @@
/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING
file accompanying popt source distributions, available from
ftp://ftp.redhat.com/pub/code/popt */
#include "system.h"
#include "poptint.h"
static void configLine(poptContext con, char * line) {
int nameLength = strlen(con->appName);
char * opt;
struct poptAlias alias;
char * entryType;
char * longName = NULL;
char shortName = '\0';
if (strncmp(line, con->appName, nameLength)) return;
line += nameLength;
if (!*line || !isspace(*line)) return;
while (*line && isspace(*line)) line++;
entryType = line;
while (!*line || !isspace(*line)) line++;
*line++ = '\0';
while (*line && isspace(*line)) line++;
if (!*line) return;
opt = line;
while (!*line || !isspace(*line)) line++;
*line++ = '\0';
while (*line && isspace(*line)) line++;
if (!*line) return;
if (opt[0] == '-' && opt[1] == '-')
longName = opt + 2;
else if (opt[0] == '-' && !opt[2])
shortName = opt[1];
if (!strcmp(entryType, "alias")) {
if (poptParseArgvString(line, &alias.argc, &alias.argv)) return;
alias.longName = longName, alias.shortName = shortName;
poptAddAlias(con, alias, 0);
} else if (!strcmp(entryType, "exec")) {
con->execs = realloc(con->execs,
sizeof(*con->execs) * (con->numExecs + 1));
if (longName)
con->execs[con->numExecs].longName = xstrdup(longName);
else
con->execs[con->numExecs].longName = NULL;
con->execs[con->numExecs].shortName = shortName;
con->execs[con->numExecs].script = xstrdup(line);
con->numExecs++;
}
}
int poptReadConfigFile(poptContext con, const char * fn) {
char * file=NULL, * chptr, * end;
char * buf=NULL, * dst;
int fd, rc;
int fileLength;
fd = open(fn, O_RDONLY);
if (fd < 0) {
if (errno == ENOENT)
return 0;
else
return POPT_ERROR_ERRNO;
}
fileLength = lseek(fd, 0, SEEK_END);
(void) lseek(fd, 0, 0);
file = malloc(fileLength + 1);
if (read(fd, file, fileLength) != fileLength) {
rc = errno;
close(fd);
errno = rc;
if (file) free(file);
return POPT_ERROR_ERRNO;
}
close(fd);
dst = buf = malloc(fileLength + 1);
chptr = file;
end = (file + fileLength);
while (chptr < end) {
switch (*chptr) {
case '\n':
*dst = '\0';
dst = buf;
while (*dst && isspace(*dst)) dst++;
if (*dst && *dst != '#') {
configLine(con, dst);
}
chptr++;
break;
case '\\':
*dst++ = *chptr++;
if (chptr < end) {
if (*chptr == '\n')
dst--, chptr++;
/* \ at the end of a line does not insert a \n */
else
*dst++ = *chptr++;
}
break;
default:
*dst++ = *chptr++;
break;
}
}
free(file);
free(buf);
return 0;
}
int poptReadDefaultConfig(poptContext con, /*@unused@*/ int useEnv) {
char * fn, * home;
int rc;
if (!con->appName) return 0;
rc = poptReadConfigFile(con, "/etc/popt");
if (rc) return rc;
if (getuid() != geteuid()) return 0;
if ((home = getenv("HOME"))) {
fn = malloc(strlen(home) + 20);
strcpy(fn, home);
strcat(fn, "/.popt");
rc = poptReadConfigFile(con, fn);
free(fn);
if (rc) return rc;
}
return 0;
}

301
popt/popthelp.c Normal file
View File

@@ -0,0 +1,301 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING
file accompanying popt source distributions, available from
ftp://ftp.redhat.com/pub/code/popt */
#include "system.h"
#include "poptint.h"
static void displayArgs(poptContext con,
/*@unused@*/ enum poptCallbackReason foo,
struct poptOption * key,
/*@unused@*/ const char * arg, /*@unused@*/ void * data) {
if (key->shortName== '?')
poptPrintHelp(con, stdout, 0);
else
poptPrintUsage(con, stdout, 0);
exit(0);
}
struct poptOption poptHelpOptions[] = {
{ NULL, '\0', POPT_ARG_CALLBACK, (void *)&displayArgs, '\0', NULL, NULL },
{ "help", '?', 0, NULL, '?', N_("Show this help message"), NULL },
{ "usage", '\0', 0, NULL, 'u', N_("Display brief usage message"), NULL },
{ NULL, '\0', 0, NULL, 0, NULL, NULL }
} ;
/*@observer@*/ /*@null@*/ static const char *const
getTableTranslationDomain(const struct poptOption *table)
{
const struct poptOption *opt;
for(opt = table;
opt->longName || opt->shortName || opt->arg;
opt++) {
if(opt->argInfo == POPT_ARG_INTL_DOMAIN)
return opt->arg;
}
return NULL;
}
/*@observer@*/ /*@null@*/ static const char *const
getArgDescrip(const struct poptOption * opt, const char *translation_domain)
{
if (!(opt->argInfo & POPT_ARG_MASK)) return NULL;
if (opt == (poptHelpOptions + 1) || opt == (poptHelpOptions + 2))
if (opt->argDescrip) return POPT_(opt->argDescrip);
if (opt->argDescrip) return D_(translation_domain, opt->argDescrip);
return POPT_("ARG");
}
static void singleOptionHelp(FILE * f, int maxLeftCol,
const struct poptOption * opt,
const char *translation_domain) {
int indentLength = maxLeftCol + 5;
int lineLength = 79 - indentLength;
const char * help = D_(translation_domain, opt->descrip);
int helpLength;
const char * ch;
char format[10];
char * left;
const char * argDescrip = getArgDescrip(opt, translation_domain);
left = malloc(maxLeftCol + 1);
*left = '\0';
if (opt->longName && opt->shortName)
sprintf(left, "-%c, --%s", opt->shortName, opt->longName);
else if (opt->shortName)
sprintf(left, "-%c", opt->shortName);
else if (opt->longName)
sprintf(left, "--%s", opt->longName);
if (!*left) return ;
if (argDescrip) {
strcat(left, "=");
strcat(left, argDescrip);
}
if (help)
fprintf(f," %-*s ", maxLeftCol, left);
else {
fprintf(f," %s\n", left);
goto out;
}
helpLength = strlen(help);
while (helpLength > lineLength) {
ch = help + lineLength - 1;
while (ch > help && !isspace(*ch)) ch--;
if (ch == help) break; /* give up */
while (ch > (help + 1) && isspace(*ch)) ch--;
ch++;
sprintf(format, "%%.%ds\n%%%ds", (int) (ch - help), indentLength);
fprintf(f, format, help, " ");
help = ch;
while (isspace(*help) && *help) help++;
helpLength = strlen(help);
}
if (helpLength) fprintf(f, "%s\n", help);
out:
free(left);
}
static int maxArgWidth(const struct poptOption * opt,
const char * translation_domain) {
int max = 0;
int this;
const char * s;
while (opt->longName || opt->shortName || opt->arg) {
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
this = maxArgWidth(opt->arg, translation_domain);
if (this > max) max = this;
} else if (!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
this = opt->shortName ? 2 : 0;
if (opt->longName) {
if (this) this += 2;
this += strlen(opt->longName) + 2;
}
s = getArgDescrip(opt, translation_domain);
if (s)
this += strlen(s) + 1;
if (this > max) max = this;
}
opt++;
}
return max;
}
static void singleTableHelp(FILE * f, const struct poptOption * table,
int left,
const char *translation_domain) {
const struct poptOption * opt;
const char *sub_transdom;
opt = table;
while (opt->longName || opt->shortName || opt->arg) {
if ((opt->longName || opt->shortName) &&
!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
singleOptionHelp(f, left, opt, translation_domain);
opt++;
}
opt = table;
while (opt->longName || opt->shortName || opt->arg) {
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
sub_transdom = getTableTranslationDomain(opt->arg);
if(!sub_transdom)
sub_transdom = translation_domain;
if (opt->descrip)
fprintf(f, "\n%s\n", D_(sub_transdom, opt->descrip));
singleTableHelp(f, opt->arg, left, sub_transdom);
}
opt++;
}
}
static int showHelpIntro(poptContext con, FILE * f) {
int len = 6;
const char * fn;
fprintf(f, POPT_("Usage:"));
if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) {
fn = con->optionStack->argv[0];
if (strchr(fn, '/')) fn = strchr(fn, '/') + 1;
fprintf(f, " %s", fn);
len += strlen(fn) + 1;
}
return len;
}
void poptPrintHelp(poptContext con, FILE * f, /*@unused@*/ int flags) {
int leftColWidth;
showHelpIntro(con, f);
if (con->otherHelp)
fprintf(f, " %s\n", con->otherHelp);
else
fprintf(f, " %s\n", POPT_("[OPTION...]"));
leftColWidth = maxArgWidth(con->options, NULL);
singleTableHelp(f, con->options, leftColWidth, NULL);
}
static int singleOptionUsage(FILE * f, int cursor,
const struct poptOption * opt,
const char *translation_domain) {
int len = 3;
char shortStr[2] = { '\0', '\0' };
const char * item = shortStr;
const char * argDescrip = getArgDescrip(opt, translation_domain);
if (opt->shortName) {
if (!(opt->argInfo & POPT_ARG_MASK))
return cursor; /* we did these already */
len++;
*shortStr = opt->shortName;
shortStr[1] = '\0';
} else if (opt->longName) {
len += 1 + strlen(opt->longName);
item = opt->longName;
}
if (len == 3) return cursor;
if (argDescrip)
len += strlen(argDescrip) + 1;
if ((cursor + len) > 79) {
fprintf(f, "\n ");
cursor = 7;
}
fprintf(f, " [-%s%s%s%s]", opt->shortName ? "" : "-", item,
argDescrip ? (opt->shortName ? " " : "=") : "",
argDescrip ? argDescrip : "");
return cursor + len + 1;
}
static int singleTableUsage(FILE * f, int cursor, const struct poptOption * table,
const char *translation_domain) {
const struct poptOption * opt;
opt = table;
while (opt->longName || opt->shortName || opt->arg) {
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN)
translation_domain = (const char *)opt->arg;
else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE)
cursor = singleTableUsage(f, cursor, opt->arg,
translation_domain);
else if ((opt->longName || opt->shortName) &&
!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
cursor = singleOptionUsage(f, cursor, opt, translation_domain);
opt++;
}
return cursor;
}
static int showShortOptions(const struct poptOption * opt, FILE * f,
char * str) {
char s[300]; /* this is larger then the ascii set, so
it should do just fine */
s[0] = '\0';
if (str == NULL) {
memset(s, 0, sizeof(s));
str = s;
}
while (opt->longName || opt->shortName || opt->arg) {
if (opt->shortName && !(opt->argInfo & POPT_ARG_MASK))
str[strlen(str)] = opt->shortName;
else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE)
showShortOptions(opt->arg, f, str);
opt++;
}
if (s != str || !*s)
return 0;
fprintf(f, " [-%s]", s);
return strlen(s) + 4;
}
void poptPrintUsage(poptContext con, FILE * f, /*@unused@*/ int flags) {
int cursor;
cursor = showHelpIntro(con, f);
cursor += showShortOptions(con->options, f, NULL);
singleTableUsage(f, cursor, con->options, NULL);
if (con->otherHelp) {
cursor += strlen(con->otherHelp) + 1;
if (cursor > 79) fprintf(f, "\n ");
fprintf(f, " %s", con->otherHelp);
}
fprintf(f, "\n");
}
void poptSetOtherOptionHelp(poptContext con, const char * text) {
if (con->otherHelp) xfree(con->otherHelp);
con->otherHelp = xstrdup(text);
}

87
popt/poptint.h Normal file
View File

@@ -0,0 +1,87 @@
/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING
file accompanying popt source distributions, available from
ftp://ftp.redhat.com/pub/code/popt */
#ifndef H_POPTINT
#define H_POPTINT
/* Bit mask macros. */
typedef unsigned int __pbm_bits;
#define __PBM_NBITS (8 * sizeof (__pbm_bits))
#define __PBM_IX(d) ((d) / __PBM_NBITS)
#define __PBM_MASK(d) ((__pbm_bits) 1 << ((d) % __PBM_NBITS))
typedef struct {
__pbm_bits bits[1];
} pbm_set;
#define __PBM_BITS(set) ((set)->bits)
#define PBM_ALLOC(d) calloc(__PBM_IX (d) + 1, sizeof(__pbm_bits))
#define PBM_FREE(s) free(s);
#define PBM_SET(d, s) (__PBM_BITS (s)[__PBM_IX (d)] |= __PBM_MASK (d))
#define PBM_CLR(d, s) (__PBM_BITS (s)[__PBM_IX (d)] &= ~__PBM_MASK (d))
#define PBM_ISSET(d, s) ((__PBM_BITS (s)[__PBM_IX (d)] & __PBM_MASK (d)) != 0)
struct optionStackEntry {
int argc;
/*@only@*/ const char ** argv;
/*@only@*/ pbm_set * argb;
int next;
/*@only@*/ const char * nextArg;
/*@keep@*/ const char * nextCharArg;
/*@dependent@*/ struct poptAlias * currAlias;
int stuffed;
};
struct execEntry {
const char * longName;
char shortName;
const char * script;
};
struct poptContext_s {
struct optionStackEntry optionStack[POPT_OPTION_DEPTH];
/*@dependent@*/ struct optionStackEntry * os;
/*@owned@*/ const char ** leftovers;
int numLeftovers;
int nextLeftover;
/*@keep@*/ const struct poptOption * options;
int restLeftover;
/*@only@*/ const char * appName;
/*@only@*/ struct poptAlias * aliases;
int numAliases;
int flags;
struct execEntry * execs;
int numExecs;
/*@only@*/ const char ** finalArgv;
int finalArgvCount;
int finalArgvAlloced;
/*@dependent@*/ struct execEntry * doExec;
/*@only@*/ const char * execPath;
int execAbsolute;
/*@only@*/ const char * otherHelp;
pbm_set * arg_strip;
};
#define xfree(_a) free((void *)_a)
#ifdef HAVE_LIBINTL_H
#include <libintl.h>
#endif
#if defined(HAVE_GETTEXT) && !defined(__LCLINT__)
#define _(foo) gettext(foo)
#else
#define _(foo) (foo)
#endif
#if defined(HAVE_DGETTEXT) && !defined(__LCLINT__)
#define D_(dom, str) dgettext(dom, str)
#define POPT_(foo) D_("popt", foo)
#else
#define POPT_(foo) (foo)
#define D_(dom, str) (str)
#endif
#define N_(foo) (foo)
#endif

102
popt/poptparse.c Normal file
View File

@@ -0,0 +1,102 @@
/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING
file accompanying popt source distributions, available from
ftp://ftp.redhat.com/pub/code/popt */
#include "system.h"
#define POPT_ARGV_ARRAY_GROW_DELTA 5
int poptDupArgv(int argc, const char **argv,
int * argcPtr, const char *** argvPtr)
{
size_t nb = (argc + 1) * sizeof(*argv);
const char ** argv2;
char * dst;
int i;
for (i = 0; i < argc; i++) {
if (argv[i] == NULL)
return POPT_ERROR_NOARG;
nb += strlen(argv[i]) + 1;
}
dst = malloc(nb);
argv2 = (void *) dst;
dst += (argc + 1) * sizeof(*argv);
for (i = 0; i < argc; i++) {
argv2[i] = dst;
dst += strlen(strcpy(dst, argv[i])) + 1;
}
argv2[argc] = NULL;
*argvPtr = argv2;
*argcPtr = argc;
return 0;
}
int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr)
{
const char * src;
char quote = '\0';
int argvAlloced = POPT_ARGV_ARRAY_GROW_DELTA;
const char ** argv = malloc(sizeof(*argv) * argvAlloced);
int argc = 0;
int buflen = strlen(s) + 1;
char *buf0 = calloc(buflen, 1);
char *buf = buf0;
argv[argc] = buf;
for (src = s; *src; src++) {
if (quote == *src) {
quote = '\0';
} else if (quote) {
if (*src == '\\') {
src++;
if (!*src) {
free(argv);
free(buf0);
return POPT_ERROR_BADQUOTE;
}
if (*src != quote) *buf++ = '\\';
}
*buf++ = *src;
} else if (isspace(*src)) {
if (*argv[argc]) {
buf++, argc++;
if (argc == argvAlloced) {
argvAlloced += POPT_ARGV_ARRAY_GROW_DELTA;
argv = realloc(argv, sizeof(*argv) * argvAlloced);
}
argv[argc] = buf;
}
} else switch (*src) {
case '"':
case '\'':
quote = *src;
break;
case '\\':
src++;
if (!*src) {
free(argv);
free(buf0);
return POPT_ERROR_BADQUOTE;
}
/*@fallthrough@*/
default:
*buf++ = *src;
break;
}
}
if (strlen(argv[argc])) {
argc++, buf++;
}
(void) poptDupArgv(argc, argv, argcPtr, argvPtr);
free(argv);
free(buf0);
return 0;
}

55
popt/system.h Normal file
View File

@@ -0,0 +1,55 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#if HAVE_MCHECK_H
#include <mcheck.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef __NeXT
/* access macros are not declared in non posix mode in unistd.h -
don't try to use posix on NeXTstep 3.3 ! */
#include <libc.h>
#endif
/* AIX requires this to be the first thing in the file. */
#ifndef __GNUC__
# if HAVE_ALLOCA_H
# include <alloca.h>
# else
# ifdef _AIX
#pragma alloca
# else
# ifndef alloca /* predefined by HP cc +Olibcalls */
char *alloca ();
# endif
# endif
# endif
#elif defined(__GNUC__) && defined(__STRICT_ANSI__)
#define alloca __builtin_alloca
#endif
/*@only@*/ char * xstrdup (const char *str);
#if HAVE_MCHECK_H && defined(__GNUC__)
#define vmefail() (fprintf(stderr, "virtual memory exhausted.\n"), exit(EXIT_FAILURE), NULL)
#define xstrdup(_str) (strcpy((malloc(strlen(_str)+1) ? : vmefail()), (_str)))
#else
#define xstrdup(_str) strdup(_str)
#endif /* HAVE_MCHECK_H && defined(__GNUC__) */
#include "popt.h"

509
receiver.c Normal file
View File

@@ -0,0 +1,509 @@
/*
Copyright (C) Andrew Tridgell 1996
Copyright (C) Paul Mackerras 1996
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "rsync.h"
extern int verbose;
extern int recurse;
extern int delete_mode;
extern int remote_version;
extern int csum_length;
extern struct stats stats;
extern int dry_run;
extern int am_server;
extern int relative_paths;
extern int preserve_hard_links;
extern int cvs_exclude;
extern int io_error;
extern char *tmpdir;
extern char *compare_dest;
extern int make_backups;
extern char *backup_suffix;
static struct delete_list {
dev_t dev;
INO_T inode;
} *delete_list;
static int dlist_len, dlist_alloc_len;
/* yuck! This function wouldn't have been necessary if I had the sorting
algorithm right. Unfortunately fixing the sorting algorithm would introduce
a backward incompatibility as file list indexes are sent over the link.
*/
static int delete_already_done(struct file_list *flist,int j)
{
int i;
STRUCT_STAT st;
if (link_stat(f_name(flist->files[j]), &st)) return 1;
for (i=0;i<dlist_len;i++) {
if (st.st_ino == delete_list[i].inode &&
st.st_dev == delete_list[i].dev)
return 1;
}
return 0;
}
static void add_delete_entry(struct file_struct *file)
{
if (dlist_len == dlist_alloc_len) {
dlist_alloc_len += 1024;
delete_list = (struct delete_list *)Realloc(delete_list, sizeof(delete_list[0])*dlist_alloc_len);
if (!delete_list) out_of_memory("add_delete_entry");
}
delete_list[dlist_len].dev = file->dev;
delete_list[dlist_len].inode = file->inode;
dlist_len++;
if (verbose > 3)
rprintf(FINFO,"added %s to delete list\n", f_name(file));
}
static void delete_one(struct file_struct *f)
{
if (!S_ISDIR(f->mode)) {
if (robust_unlink(f_name(f)) != 0) {
rprintf(FERROR,"unlink %s : %s\n",f_name(f),strerror(errno));
} else if (verbose) {
rprintf(FINFO,"deleting %s\n",f_name(f));
}
} else {
if (do_rmdir(f_name(f)) != 0) {
if (errno != ENOTEMPTY && errno != EEXIST)
rprintf(FERROR,"rmdir %s : %s\n",f_name(f),strerror(errno));
} else if (verbose) {
rprintf(FINFO,"deleting directory %s\n",f_name(f));
}
}
}
/* this deletes any files on the receiving side that are not present
on the sending side. For version 1.6.4 I have changed the behaviour
to match more closely what most people seem to expect of this option */
void delete_files(struct file_list *flist)
{
struct file_list *local_file_list;
int i, j;
char *name;
extern int module_id;
extern int ignore_errors;
extern int max_delete;
static int deletion_count;
if (cvs_exclude)
add_cvs_excludes();
if (io_error && !(lp_ignore_errors(module_id) || ignore_errors)) {
rprintf(FINFO,"IO error encountered - skipping file deletion\n");
return;
}
for (j=0;j<flist->count;j++) {
if (!S_ISDIR(flist->files[j]->mode) ||
!(flist->files[j]->flags & FLAG_DELETE)) continue;
if (remote_version < 19 &&
delete_already_done(flist, j)) continue;
name = strdup(f_name(flist->files[j]));
if (!(local_file_list = send_file_list(-1,1,&name))) {
free(name);
continue;
}
if (verbose > 1)
rprintf(FINFO,"deleting in %s\n", name);
for (i=local_file_list->count-1;i>=0;i--) {
if (max_delete && deletion_count > max_delete) break;
if (!local_file_list->files[i]->basename) continue;
if (remote_version < 19 &&
S_ISDIR(local_file_list->files[i]->mode))
add_delete_entry(local_file_list->files[i]);
if (-1 == flist_find(flist,local_file_list->files[i])) {
char *f = f_name(local_file_list->files[i]);
int k = strlen(f) - strlen(backup_suffix);
/* Hi Andrew, do we really need to play with backup_suffix here? */
if (make_backups && ((k <= 0) ||
(strcmp(f+k,backup_suffix) != 0))) {
(void) make_backup(f);
} else {
deletion_count++;
delete_one(local_file_list->files[i]);
}
}
}
flist_free(local_file_list);
free(name);
}
}
static int get_tmpname(char *fnametmp, char *fname)
{
char *f;
/* open tmp file */
if (tmpdir) {
f = strrchr(fname,'/');
if (f == NULL)
f = fname;
else
f++;
if (strlen(tmpdir)+strlen(f)+10 > MAXPATHLEN) {
rprintf(FERROR,"filename too long\n");
return 0;
}
slprintf(fnametmp,MAXPATHLEN, "%s/.%s.XXXXXX",tmpdir,f);
return 1;
}
f = strrchr(fname,'/');
if (strlen(fname)+9 > MAXPATHLEN) {
rprintf(FERROR,"filename too long\n");
return 0;
}
if (f) {
*f = 0;
slprintf(fnametmp,MAXPATHLEN,"%s/.%s.XXXXXX",
fname,f+1);
*f = '/';
} else {
slprintf(fnametmp,MAXPATHLEN,".%s.XXXXXX",fname);
}
return 1;
}
static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname,
OFF_T total_size)
{
int i;
unsigned int n,remainder,len,count;
OFF_T offset = 0;
OFF_T offset2;
char *data;
static char file_sum1[MD4_SUM_LENGTH];
static char file_sum2[MD4_SUM_LENGTH];
char *map=NULL;
count = read_int(f_in);
n = read_int(f_in);
remainder = read_int(f_in);
sum_init();
for (i=recv_token(f_in,&data); i != 0; i=recv_token(f_in,&data)) {
show_progress(offset, total_size);
if (i > 0) {
extern int cleanup_got_literal;
if (verbose > 3) {
rprintf(FINFO,"data recv %d at %.0f\n",
i,(double)offset);
}
stats.literal_data += i;
cleanup_got_literal = 1;
sum_update(data,i);
if (fd != -1 && write_file(fd,data,i) != i) {
rprintf(FERROR,"write failed on %s : %s\n",fname,strerror(errno));
exit_cleanup(RERR_FILEIO);
}
offset += i;
continue;
}
i = -(i+1);
offset2 = i*(OFF_T)n;
len = n;
if (i == count-1 && remainder != 0)
len = remainder;
stats.matched_data += len;
if (verbose > 3)
rprintf(FINFO,"chunk[%d] of size %d at %.0f offset=%.0f\n",
i,len,(double)offset2,(double)offset);
if (buf) {
map = map_ptr(buf,offset2,len);
see_token(map, len);
sum_update(map,len);
}
if (fd != -1 && write_file(fd,map,len) != len) {
rprintf(FERROR,"write failed on %s : %s\n",
fname,strerror(errno));
exit_cleanup(RERR_FILEIO);
}
offset += len;
}
end_progress(total_size);
if (fd != -1 && offset > 0 && sparse_end(fd) != 0) {
rprintf(FERROR,"write failed on %s : %s\n",
fname,strerror(errno));
exit_cleanup(RERR_FILEIO);
}
sum_end(file_sum1);
if (remote_version >= 14) {
read_buf(f_in,file_sum2,MD4_SUM_LENGTH);
if (verbose > 2) {
rprintf(FINFO,"got file_sum\n");
}
if (fd != -1 &&
memcmp(file_sum1,file_sum2,MD4_SUM_LENGTH) != 0) {
return 0;
}
}
return 1;
}
/* main routine for receiver process. Receiver process runs on the
same host as the generator process. */
int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
{
int fd1,fd2;
STRUCT_STAT st;
char *fname;
char fnametmp[MAXPATHLEN];
char *fnamecmp;
char fnamecmpbuf[MAXPATHLEN];
struct map_struct *buf;
int i;
struct file_struct *file;
int phase=0;
int recv_ok;
extern struct stats stats;
extern int preserve_perms;
extern int delete_after;
struct stats initial_stats;
if (verbose > 2) {
rprintf(FINFO,"recv_files(%d) starting\n",flist->count);
}
while (1) {
cleanup_disable();
i = read_int(f_in);
if (i == -1) {
if (phase==0 && remote_version >= 13) {
phase++;
csum_length = SUM_LENGTH;
if (verbose > 2)
rprintf(FINFO,"recv_files phase=%d\n",phase);
write_int(f_gen,-1);
continue;
}
break;
}
if (i < 0 || i >= flist->count) {
rprintf(FERROR,"Invalid file index %d in recv_files (count=%d)\n",
i, flist->count);
exit_cleanup(RERR_PROTOCOL);
}
file = flist->files[i];
fname = f_name(file);
stats.num_transferred_files++;
stats.total_transferred_size += file->length;
if (local_name)
fname = local_name;
if (dry_run) {
if (!am_server) {
log_transfer(file, fname);
}
continue;
}
initial_stats = stats;
if (verbose > 2)
rprintf(FINFO,"recv_files(%s)\n",fname);
fnamecmp = fname;
/* open the file */
fd1 = do_open(fnamecmp, O_RDONLY, 0);
if ((fd1 == -1) && (compare_dest != NULL)) {
/* try the file at compare_dest instead */
slprintf(fnamecmpbuf,MAXPATHLEN,"%s/%s",
compare_dest,fname);
fnamecmp = fnamecmpbuf;
fd1 = do_open(fnamecmp, O_RDONLY, 0);
}
if (fd1 != -1 && do_fstat(fd1,&st) != 0) {
rprintf(FERROR,"fstat %s : %s\n",fnamecmp,strerror(errno));
receive_data(f_in,NULL,-1,NULL,file->length);
close(fd1);
continue;
}
if (fd1 != -1 && !S_ISREG(st.st_mode)) {
rprintf(FERROR,"%s : not a regular file (recv_files)\n",fnamecmp);
receive_data(f_in,NULL,-1,NULL,file->length);
close(fd1);
continue;
}
if (fd1 != -1 && !preserve_perms) {
/* if the file exists already and we aren't perserving
presmissions then act as though the remote end sent
us the file permissions we already have */
file->mode = st.st_mode;
}
if (fd1 != -1 && st.st_size > 0) {
buf = map_file(fd1,st.st_size);
if (verbose > 2)
rprintf(FINFO,"recv mapped %s of size %.0f\n",fnamecmp,(double)st.st_size);
} else {
buf = NULL;
}
if (!get_tmpname(fnametmp,fname)) {
if (buf) unmap_file(buf);
if (fd1 != -1) close(fd1);
continue;
}
/* mktemp is deliberately used here instead of mkstemp.
because O_EXCL is used on the open, the race condition
is not a problem or a security hole, and we want to
control the access permissions on the created file. */
if (NULL == do_mktemp(fnametmp)) {
rprintf(FERROR,"mktemp %s failed\n",fnametmp);
receive_data(f_in,buf,-1,NULL,file->length);
if (buf) unmap_file(buf);
if (fd1 != -1) close(fd1);
continue;
}
/* we initially set the perms without the
setuid/setgid bits to ensure that there is no race
condition. They are then correctly updated after
the lchown. Thanks to snabb@epipe.fi for pointing
this out. We also set it initially without group
access because of a similar race condition. */
fd2 = do_open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,
file->mode & INITACCESSPERMS);
/* in most cases parent directories will already exist
because their information should have been previously
transferred, but that may not be the case with -R */
if (fd2 == -1 && relative_paths && errno == ENOENT &&
create_directory_path(fnametmp) == 0) {
fd2 = do_open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,
file->mode & INITACCESSPERMS);
}
if (fd2 == -1) {
rprintf(FERROR,"cannot create %s : %s\n",fnametmp,strerror(errno));
receive_data(f_in,buf,-1,NULL,file->length);
if (buf) unmap_file(buf);
if (fd1 != -1) close(fd1);
continue;
}
cleanup_set(fnametmp, fname, file, buf, fd1, fd2);
if (!am_server) {
log_transfer(file, fname);
}
/* recv file data */
recv_ok = receive_data(f_in,buf,fd2,fname,file->length);
log_recv(file, &initial_stats);
if (buf) unmap_file(buf);
if (fd1 != -1) {
close(fd1);
}
close(fd2);
if (verbose > 2)
rprintf(FINFO,"renaming %s to %s\n",fnametmp,fname);
finish_transfer(fname, fnametmp, file);
cleanup_disable();
if (!recv_ok) {
if (csum_length == SUM_LENGTH) {
rprintf(FERROR,"ERROR: file corruption in %s. File changed during transfer?\n",
fname);
} else {
if (verbose > 1)
rprintf(FINFO,"redoing %s(%d)\n",fname,i);
write_int(f_gen,i);
}
}
}
if (delete_after) {
if (recurse && delete_mode && !local_name && flist->count>0) {
delete_files(flist);
}
}
if (preserve_hard_links)
do_hard_links(flist);
/* now we need to fix any directory permissions that were
modified during the transfer */
for (i = 0; i < flist->count; i++) {
file = flist->files[i];
if (!file->basename || !S_ISDIR(file->mode)) continue;
recv_generator(local_name?local_name:f_name(file),flist,i,-1);
}
if (verbose > 2)
rprintf(FINFO,"recv_files finished\n");
return 0;
}

1181
rsync.c
View File

File diff suppressed because it is too large Load Diff

447
rsync.h
View File

@@ -17,18 +17,26 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define False 0
#define True 1
#define BLOCK_SIZE 700
#define RSYNC_RSH_ENV "RSYNC_RSH"
#define RSYNC_NAME "rsync"
#define RSYNCD_CONF "/etc/rsyncd.conf"
#define DEFAULT_LOCK_FILE "/var/run/rsyncd.lock"
#define URL_PREFIX "rsync://"
#define BACKUP_SUFFIX "~"
/* a non-zero CHAR_OFFSET makes the rolling sum stronger, but is
imcompatible with older versions :-( */
incompatible with older versions :-( */
#define CHAR_OFFSET 0
#define FILE_VALID 1
#define FLAG_DELETE (1<<0)
#define SAME_MODE (1<<1)
#define SAME_RDEV (1<<2)
#define SAME_UID (1<<3)
@@ -39,19 +47,25 @@
#define SAME_TIME (1<<7)
/* update this if you make incompatible changes */
#define PROTOCOL_VERSION 17
#define MIN_PROTOCOL_VERSION 11
#define PROTOCOL_VERSION 24
#define MIN_PROTOCOL_VERSION 15
#define MAX_PROTOCOL_VERSION 30
#define RSYNC_PORT 873
#define SPARSE_WRITE_SIZE (1024)
#define WRITE_SIZE (32*1024)
#define CHUNK_SIZE (32*1024)
#define MAX_MAP_SIZE (4*1024*1024)
#define MAX_MAP_SIZE (256*1024)
#define IO_BUFFER_SIZE (4092)
#define BLOCKING_TIMEOUT 10
#define MAX_ARGS 1000
#define FERROR stderr
#define FINFO (am_server?stderr:stdout)
#define MPLEX_BASE 7
enum logcode {FNONE=0, FERROR=1, FINFO=2, FLOG=3};
#include "errcode.h"
#include "config.h"
@@ -62,10 +76,18 @@
#endif
#include <sys/types.h>
#ifdef HAVE_GETOPT_LONG
#include <getopt.h>
#else
#include "lib/getopt.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#include <stddef.h>
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
@@ -83,10 +105,6 @@
#include <string.h>
#endif
#ifdef HAVE_COMPAT_H
#include <compat.h>
#endif
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
@@ -132,10 +150,6 @@
#endif
#include <errno.h>
#ifdef HAVE_MMAP
#include <sys/mman.h>
#endif
#ifdef HAVE_UTIME_H
#include <utime.h>
#endif
@@ -157,132 +171,20 @@
#include "lib/fnmatch.h"
#endif
#ifdef HAVE_GETOPT_LONG
#include <getopt.h>
#else
#include "lib/getopt.h"
#ifdef HAVE_GLOB_H
#include <glob.h>
#endif
/* these are needed for the uid/gid mapping code */
#include <pwd.h>
#include <grp.h>
#ifndef S_IFLNK
#define S_IFLNK 0120000
#endif
#ifndef S_ISLNK
#define S_ISLNK(mode) (((mode) & S_IFLNK) == S_IFLNK)
#endif
#ifndef uchar
#define uchar unsigned char
#endif
#ifndef int32
#if (SIZEOF_INT == 4)
#define int32 int
#elif (SIZEOF_LONG == 4)
#define int32 long
#elif (SIZEOF_SHORT == 4)
#define int32 short
#endif
#endif
#ifndef uint32
#define uint32 unsigned int32
#endif
#ifdef HAVE_LONGLONG
#define int64 long long
#else
#define int64 off_t
#endif
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
/* the length of the md4 checksum */
#define MD4_SUM_LENGTH 16
#define SUM_LENGTH 16
#ifndef MAXPATHLEN
#define MAXPATHLEN 1024
#endif
struct file_struct {
time_t modtime;
off_t length;
mode_t mode;
ino_t inode;
dev_t dev;
dev_t rdev;
uid_t uid;
gid_t gid;
char *basename;
char *dirname;
char *basedir;
char *link;
char *sum;
};
struct file_list {
int count;
int malloced;
struct file_struct **files;
};
struct sum_buf {
off_t offset; /* offset in file of this chunk */
int len; /* length of chunk of file */
int i; /* index of this chunk */
uint32 sum1; /* simple checksum */
char sum2[SUM_LENGTH]; /* checksum */
};
struct sum_struct {
off_t flength; /* total file length */
int count; /* how many chunks */
int remainder; /* flength % block_length */
int n; /* block_length */
struct sum_buf *sums; /* points to info for each chunk */
};
struct map_struct {
char *map,*p;
int fd,p_size,p_len;
off_t size, p_offset;
};
/* we need this function because of the silly way in which duplicate
entries are handled in the file lists - we can't change this
without breaking existing versions */
static inline int flist_up(struct file_list *flist, int i)
{
while (!flist->files[i]->basename) i++;
return i;
}
#include "byteorder.h"
#include "version.h"
#include "proto.h"
#include "md4.h"
#if !HAVE_STRERROR
extern char *sys_errlist[];
#define strerror(i) sys_errlist[i]
#endif
#ifndef HAVE_STRCHR
# define strchr index
# define strrchr rindex
#endif
#include <stdarg.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <syslog.h>
#include <sys/file.h>
#if HAVE_DIRENT_H
# include <dirent.h>
@@ -299,18 +201,199 @@ extern char *sys_errlist[];
# endif
#endif
#ifdef HAVE_COMPAT_H
#include <compat.h>
#endif
#define BOOL int
#ifndef uchar
#define uchar unsigned char
#endif
#if HAVE_UNSIGNED_CHAR
#define schar signed char
#else
#define schar char
#endif
#ifndef int32
#if (SIZEOF_INT == 4)
#define int32 int
#elif (SIZEOF_LONG == 4)
#define int32 long
#elif (SIZEOF_SHORT == 4)
#define int32 short
#else
/* I hope this works */
#define int32 int
#define LARGE_INT32
#endif
#endif
#ifndef uint32
#define uint32 unsigned int32
#endif
#if HAVE_OFF64_T
#define OFF_T off64_t
#define STRUCT_STAT struct stat64
#else
#define OFF_T off_t
#define STRUCT_STAT struct stat
#endif
#if HAVE_OFF64_T
#define int64 off64_t
#elif (SIZEOF_LONG == 8)
#define int64 long
#elif (SIZEOF_INT == 8)
#define int64 int
#elif HAVE_LONGLONG
#define int64 long long
#else
#define int64 off_t
#define NO_INT64
#endif
#if HAVE_SHORT_INO_T
#define INO_T uint32
#else
#define INO_T ino_t
#endif
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 256
#endif
/* the length of the md4 checksum */
#define MD4_SUM_LENGTH 16
#define SUM_LENGTH 16
#ifndef MAXPATHLEN
#define MAXPATHLEN 1024
#endif
#ifndef INADDR_NONE
#define INADDR_NONE 0xffffffff
#endif
struct file_struct {
unsigned flags;
time_t modtime;
OFF_T length;
mode_t mode;
INO_T inode;
dev_t dev;
dev_t rdev;
uid_t uid;
gid_t gid;
char *basename;
char *dirname;
char *basedir;
char *link;
char *sum;
};
#define ARENA_SIZE (32 * 1024)
struct string_area {
char *base;
char *end;
char *current;
struct string_area *next;
};
struct file_list {
int count;
int malloced;
struct file_struct **files;
struct string_area *string_area;
};
struct sum_buf {
OFF_T offset; /* offset in file of this chunk */
int len; /* length of chunk of file */
int i; /* index of this chunk */
uint32 sum1; /* simple checksum */
char sum2[SUM_LENGTH]; /* checksum */
};
struct sum_struct {
OFF_T flength; /* total file length */
size_t count; /* how many chunks */
size_t remainder; /* flength % block_length */
size_t n; /* block_length */
struct sum_buf *sums; /* points to info for each chunk */
};
struct map_struct {
char *p;
int fd,p_size,p_len;
OFF_T file_size, p_offset, p_fd_offset;
};
struct exclude_struct {
char *orig;
char *pattern;
int regular_exp;
int fnmatch_flags;
int include;
int directory;
int local;
};
struct stats {
int64 total_size;
int64 total_transferred_size;
int64 total_written;
int64 total_read;
int64 literal_data;
int64 matched_data;
int flist_size;
int num_files;
int num_transferred_files;
};
/* we need this function because of the silly way in which duplicate
entries are handled in the file lists - we can't change this
without breaking existing versions */
static inline int flist_up(struct file_list *flist, int i)
{
while (!flist->files[i]->basename) i++;
return i;
}
#include "byteorder.h"
#include "version.h"
#include "proto.h"
#include "lib/mdfour.h"
#if !HAVE_STRERROR
extern char *sys_errlist[];
#define strerror(i) sys_errlist[i]
#endif
#ifndef HAVE_STRCHR
# define strchr index
# define strrchr rindex
#endif
#ifndef HAVE_ERRNO_DECL
extern int errno;
#endif
#ifndef HAVE_BCOPY
#define bcopy(src,dest,n) memcpy(dest,src,n)
#endif
#ifndef HAVE_BZERO
#define bzero(buf,n) memset(buf,0,n)
#endif
#define SUPPORT_LINKS HAVE_READLINK
#define SUPPORT_HARD_LINKS HAVE_LINK
@@ -340,6 +423,18 @@ extern int errno;
#define S_IWUSR 0200
#endif
#ifndef _S_IFMT
#define _S_IFMT 0170000
#endif
#ifndef _S_IFLNK
#define _S_IFLNK 0120000
#endif
#ifndef S_ISLNK
#define S_ISLNK(mode) (((mode) & (_S_IFMT)) == (_S_IFLNK))
#endif
#ifndef S_ISBLK
#define S_ISBLK(mode) (((mode) & (_S_IFMT)) == (_S_IFBLK))
#endif
@@ -348,6 +443,22 @@ extern int errno;
#define S_ISCHR(mode) (((mode) & (_S_IFMT)) == (_S_IFCHR))
#endif
#ifndef S_ISSOCK
#ifdef _S_IFSOCK
#define S_ISSOCK(mode) (((mode) & (_S_IFMT)) == (_S_IFSOCK))
#else
#define S_ISSOCK(mode) (0)
#endif
#endif
#ifndef S_ISFIFO
#ifdef _S_IFIFO
#define S_ISFIFO(mode) (((mode) & (_S_IFMT)) == (_S_IFIFO))
#else
#define S_ISFIFO(mode) (0)
#endif
#endif
#ifndef S_ISDIR
#define S_ISDIR(mode) (((mode) & (_S_IFMT)) == (_S_IFDIR))
#endif
@@ -356,5 +467,51 @@ extern int errno;
#define S_ISREG(mode) (((mode) & (_S_IFMT)) == (_S_IFREG))
#endif
#define IS_DEVICE(mode) (S_ISCHR(mode) || S_ISBLK(mode))
/* work out what fcntl flag to use for non-blocking */
#ifdef O_NONBLOCK
# define NONBLOCK_FLAG O_NONBLOCK
#elif defined(SYSV)
# define NONBLOCK_FLAG O_NDELAY
#else
# define NONBLOCK_FLAG FNDELAY
#endif
#define IS_DEVICE(mode) (S_ISCHR(mode) || S_ISBLK(mode) || S_ISSOCK(mode) || S_ISFIFO(mode))
#ifndef ACCESSPERMS
#define ACCESSPERMS 0777
#endif
/* Initial mask on permissions given to temporary files. Mask off setuid
bits and group access because of potential race-condition security
holes, and mask other access because mode 707 is bizarre */
#define INITACCESSPERMS 0700
/* handler for null strings in printf format */
#define NS(s) ((s)?(s):"<NULL>")
/* use magic gcc attributes to catch format errors */
void rprintf(enum logcode , const char *, ...)
#ifdef __GNUC__
__attribute__ ((format (printf, 2, 3)))
#endif
;
#ifdef REPLACE_INET_NTOA
#define inet_ntoa rep_inet_ntoa
#endif
#ifndef HAVE_STRLCPY
size_t strlcpy(char *d, const char *s, size_t bufsize);
#endif
#ifndef HAVE_STRLCAT
size_t strlcat(char *d, const char *s, size_t bufsize);
#endif
#ifndef WEXITSTATUS
#define WEXITSTATUS(stat) ((int)(((stat)>>8)&0xFF))
#endif
#define exit_cleanup(code) _exit_cleanup(code, __FILE__, __LINE__)

986
rsync.yo Normal file
View File

@@ -0,0 +1,986 @@
mailto(rsync-bugs@samba.org)
manpage(rsync)(1)(14 Dec 2001)()()
manpagename(rsync)(faster, flexible replacement for rcp)
manpagesynopsis()
rsync [OPTION]... SRC [SRC]... [USER@]HOST:DEST
rsync [OPTION]... [USER@]HOST:SRC DEST
rsync [OPTION]... SRC [SRC]... DEST
rsync [OPTION]... [USER@]HOST::SRC [DEST]
rsync [OPTION]... SRC [SRC]... [USER@]HOST::DEST
rsync [OPTION]... rsync://[USER@]HOST[:PORT]/SRC [DEST]
manpagedescription()
rsync is a program that behaves in much the same way that rcp does,
but has many more options and uses the rsync remote-update protocol to
greatly speed up file transfers when the destination file already
exists.
The rsync remote-update protocol allows rsync to transfer just the
differences between two sets of files across the network link, using
an efficient checksum-search algorithm described in the technical
report that accompanies this package.
Some of the additional features of rsync are:
itemize(
it() support for copying links, devices, owners, groups and permissions
it() exclude and exclude-from options similar to GNU tar
it() a CVS exclude mode for ignoring the same files that CVS would ignore
it() can use any transparent remote shell, including rsh or ssh
it() does not require root privileges
it() pipelining of file transfers to minimize latency costs
it() support for anonymous or authenticated rsync servers (ideal for
mirroring)
)
manpagesection(GENERAL)
There are six different ways of using rsync. They are:
itemize(
it() for copying local files. This is invoked when neither
source nor destination path contains a : separator
it() for copying from the local machine to a remote machine using
a remote shell program as the transport (such as rsh or
ssh). This is invoked when the destination path contains a
single : separator.
it() for copying from a remote machine to the local machine
using a remote shell program. This is invoked when the source
contains a : separator.
it() for copying from a remote rsync server to the local
machine. This is invoked when the source path contains a ::
separator or a rsync:// URL.
it() for copying from the local machine to a remote rsync
server. This is invoked when the destination path contains a ::
separator.
it() for listing files on a remote machine. This is done the
same way as rsync transfers except that you leave off the
local destination.
)
Note that in all cases (other than listing) at least one of the source
and destination paths must be local.
manpagesection(SETUP)
See the file README for installation instructions.
Once installed you can use rsync to any machine that you can use rsh
to. rsync uses rsh for its communications, unless both the source and
destination are local.
You can also specify an alternative to rsh, either by using the -e
command line option, or by setting the RSYNC_RSH environment variable.
One common substitute is to use ssh, which offers a high degree of
security.
Note that rsync must be installed on both the source and destination
machines.
manpagesection(USAGE)
You use rsync in the same way you use rcp. You must specify a source
and a destination, one of which may be remote.
Perhaps the best way to explain the syntax is some examples:
quote(rsync *.c foo:src/)
this would transfer all files matching the pattern *.c from the
current directory to the directory src on the machine foo. If any of
the files already exist on the remote system then the rsync
remote-update protocol is used to update the file by sending only the
differences. See the tech report for details.
quote(rsync -avz foo:src/bar /data/tmp)
this would recursively transfer all files from the directory src/bar on the
machine foo into the /data/tmp/bar directory on the local machine. The
files are transferred in "archive" mode, which ensures that symbolic
links, devices, attributes, permissions, ownerships etc are preserved
in the transfer. Additionally, compression will be used to reduce the
size of data portions of the transfer.
quote(rsync -avz foo:src/bar/ /data/tmp)
a trailing slash on the source changes this behavior to transfer
all files from the directory src/bar on the machine foo into the
/data/tmp/. A trailing / on a source name means "copy the
contents of this directory". Without a trailing slash it means "copy
the directory". This difference becomes particularly important when
using the --delete option.
You can also use rsync in local-only mode, where both the source and
destination don't have a ':' in the name. In this case it behaves like
an improved copy command.
quote(rsync somehost.mydomain.com::)
this would list all the anonymous rsync modules available on the host
somehost.mydomain.com. (See the following section for more details.)
manpagesection(CONNECTING TO AN RSYNC SERVER)
It is also possible to use rsync without using rsh or ssh as the
transport. In this case you will connect to a remote rsync server
running on TCP port 873.
You may establish the connection via a web proxy by setting the
environment variable RSYNC_PROXY to a hostname:port pair pointing to
your web proxy. Note that your web proxy's configuration must allow
proxying to port 873.
Using rsync in this way is the same as using it with rsh or ssh except
that:
itemize(
it() you use a double colon :: instead of a single colon to
separate the hostname from the path.
it() the remote server may print a message of the day when you
connect.
it() if you specify no path name on the remote server then the
list of accessible paths on the server will be shown.
it() if you specify no local destination then a listing of the
specified files on the remote server is provided.
)
Some paths on the remote server may require authentication. If so then
you will receive a password prompt when you connect. You can avoid the
password prompt by setting the environment variable RSYNC_PASSWORD to
the password you want to use or using the --password-file option. This
may be useful when scripting rsync.
WARNING: On some systems environment variables are visible to all
users. On those systems using --password-file is recommended.
manpagesection(RUNNING AN RSYNC SERVER)
An rsync server is configured using a config file which by default is
called /etc/rsyncd.conf. Please see the rsyncd.conf(5) man page for more
information.
manpagesection(EXAMPLES)
Here are some examples of how I use rsync.
To backup my wife's home directory, which consists of large MS Word
files and mail folders, I use a cron job that runs
quote(rsync -Cavz . arvidsjaur:backup)
each night over a PPP link to a duplicate directory on my machine
"arvidsjaur".
To synchronize my samba source trees I use the following Makefile
targets:
quote( get:nl()
rsync -avuzb --exclude '*~' samba:samba/ .
put:nl()
rsync -Cavuzb . samba:samba/
sync: get put)
this allows me to sync with a CVS directory at the other end of the
link. I then do cvs operations on the remote machine, which saves a
lot of time as the remote cvs protocol isn't very efficient.
I mirror a directory between my "old" and "new" ftp sites with the
command
quote(rsync -az -e ssh --delete ~ftp/pub/samba/ nimbus:"~ftp/pub/tridge/samba")
this is launched from cron every few hours.
manpagesection(OPTIONS SUMMARY)
Here is a short summary of the options available in rsync. Please refer
to the detailed description below for a complete description.
verb(
-v, --verbose increase verbosity
-q, --quiet decrease verbosity
-c, --checksum always checksum
-a, --archive archive mode
-r, --recursive recurse into directories
-R, --relative use relative path names
-b, --backup make backups (default ~ suffix)
--backup-dir make backups into this directory
--suffix=SUFFIX override backup suffix
-u, --update update only (don't overwrite newer files)
-l, --links copy symlinks as symlinks
-L, --copy-links copy the referent of symlinks
--copy-unsafe-links copy links outside the source tree
--safe-links ignore links outside the destination tree
-H, --hard-links preserve hard links
-p, --perms preserve permissions
-o, --owner preserve owner (root only)
-g, --group preserve group
-D, --devices preserve devices (root only)
-t, --times preserve times
-S, --sparse handle sparse files efficiently
-n, --dry-run show what would have been transferred
-W, --whole-file copy whole files, no incremental checks
-x, --one-file-system don't cross filesystem boundaries
-B, --block-size=SIZE checksum blocking size (default 700)
-e, --rsh=COMMAND specify rsh replacement
--rsync-path=PATH specify path to rsync on the remote machine
-C, --cvs-exclude auto ignore files in the same way CVS does
--existing only update files that already exist
--delete delete files that don't exist on the sending side
--delete-excluded also delete excluded files on the receiving side
--delete-after delete after transferring, not before
--ignore-errors delete even if there are IO errors
--max-delete=NUM don't delete more than NUM files
--partial keep partially transferred files
--force force deletion of directories even if not empty
--numeric-ids don't map uid/gid values by user/group name
--timeout=TIME set IO timeout in seconds
-I, --ignore-times don't exclude files that match length and time
--size-only only use file size when determining if a file should be transferred
--modify-window=NUM Timestamp window (seconds) for file match (default=0)
-T --temp-dir=DIR create temporary files in directory DIR
--compare-dest=DIR also compare destination files relative to DIR
-P equivalent to --partial --progress
-z, --compress compress file data
--exclude=PATTERN exclude files matching PATTERN
--exclude-from=FILE exclude patterns listed in FILE
--include=PATTERN don't exclude files matching PATTERN
--include-from=FILE don't exclude patterns listed in FILE
--version print version number
--daemon run as a rsync daemon
--no-detach do not detach from the parent
--address=ADDRESS bind to the specified address
--config=FILE specify alternate rsyncd.conf file
--port=PORT specify alternate rsyncd port number
--blocking-io use blocking IO for the remote shell
--stats give some file transfer stats
--progress show progress during transfer
--log-format=FORMAT log file transfers using specified format
--password-file=FILE get password from FILE
--bwlimit=KBPS limit I/O bandwidth, KBytes per second
--read-batch=FILE read batch file
--write-batch write batch file
-h, --help show this help screen
)
manpageoptions()
rsync uses the GNU long options package. Many of the command line
options have two variants, one short and one long. These are shown
below, separated by commas. Some options only have a long variant.
The '=' for options that take a parameter is optional; whitespace
can be used instead.
startdit()
dit(bf(-h, --help)) Print a short help page describing the options
available in rsync
dit(bf(--version)) print the rsync version number and exit
dit(bf(-v, --verbose)) This option increases the amount of information you
are given during the transfer. By default, rsync works silently. A
single -v will give you information about what files are being
transferred and a brief summary at the end. Two -v flags will give you
information on what files are being skipped and slightly more
information at the end. More than two -v flags should only be used if
you are debugging rsync.
dit(bf(-q, --quiet)) This option decreases the amount of information you
are given during the transfer, notably suppressing information messages
from the remote server. This flag is useful when invoking rsync from
cron.
dit(bf(-I, --ignore-times)) Normally rsync will skip any files that are
already the same length and have the same time-stamp. This option turns
off this behavior.
dit(bf(--size-only)) Normally rsync will skip any files that are
already the same length and have the same time-stamp. With the
--size-only option files will be skipped if they have the same size,
regardless of timestamp. This is useful when starting to use rsync
after using another mirroring system which may not preserve timestamps
exactly.
dit(bf(--modify-window)) When comparing two timestamps rsync treats
the timestamps as being equal if they are within the value of
modify_window. This is normally zero, but you may find it useful to
set this to a larger value in some situations. In particular, when
transferring to/from FAT filesystems which cannot represent times with
a 1 second resolution this option is useful.
dit(bf(-c, --checksum)) This forces the sender to checksum all files using
a 128-bit MD4 checksum before transfer. The checksum is then
explicitly checked on the receiver and any files of the same name
which already exist and have the same checksum and size on the
receiver are skipped. This option can be quite slow.
dit(bf(-a, --archive)) This is equivalent to -rlptgoD. It is a quick
way of saying you want recursion and want to preserve almost
everything.
Note however that bf(-a) bf(does not preserve hardlinks), because
finding multiply-linked files is expensive. You must separately
specify bf(-H).
dit(bf(-r, --recursive)) This tells rsync to copy directories
recursively. If you don't specify this then rsync won't copy
directories at all.
dit(bf(-R, --relative)) Use relative paths. This means that the full path
names specified on the command line are sent to the server rather than
just the last parts of the filenames. This is particularly useful when
you want to send several different directories at the same time. For
example, if you used the command
verb(rsync foo/bar/foo.c remote:/tmp/)
then this would create a file called foo.c in /tmp/ on the remote
machine. If instead you used
verb(rsync -R foo/bar/foo.c remote:/tmp/)
then a file called /tmp/foo/bar/foo.c would be created on the remote
machine. The full path name is preserved.
dit(bf(-b, --backup)) With this option preexisting destination files are
renamed with a ~ extension as each file is transferred. You can
control the backup suffix using the --suffix option.
dit(bf(--backup-dir=DIR)) In combination with the --backup option, this
tells rsync to store all backups in the specified directory. This is
very useful for incremental backups.
dit(bf(--suffix=SUFFIX)) This option allows you to override the default
backup suffix used with the -b option. The default is a ~.
dit(bf(-u, --update)) This forces rsync to skip any files for which the
destination file already exists and has a date later than the source
file.
dit(bf(-l, --links)) When symlinks are encountered, recreate the
symlink on the destination.
dit(bf(-L, --copy-links)) When symlinks are encountered, the file that
they point to is copied, rather than the symlink.
dit(bf(--copy-unsafe-links)) This tells rsync to copy the referent of
symbolic links that point outside the source tree. Absolute symlinks
are also treated like ordinary files, and so are any symlinks in the
source path itself when --relative is used.
dit(bf(--safe-links)) This tells rsync to ignore any symbolic links
which point outside the destination tree. All absolute symlinks are
also ignored. Using this option in conjunction with --relative may
give unexpected results.
dit(bf(-H, --hard-links)) This tells rsync to recreate hard links on
the remote system to be the same as the local system. Without this
option hard links are treated like regular files.
Note that rsync can only detect hard links if both parts of the link
are in the list of files being sent.
This option can be quite slow, so only use it if you need it.
dit(bf(-W, --whole-file)) With this option the incremental rsync algorithm
is not used and the whole file is sent as-is instead. The transfer may be
faster if this option is used when the bandwidth between the source and
target machines is higher than the bandwidth to disk (especially when the
"disk" is actually a networked file system). This is the default when both
the source and target are on the local machine.
dit(bf(-p, --perms)) This option causes rsync to update the remote
permissions to be the same as the local permissions.
dit(bf(-o, --owner)) This option causes rsync to set the owner of the
destination file to be the same as the source file. On most systems,
only the super-user can set file ownership.
dit(bf(-g, --group)) This option causes rsync to set the group of the
destination file to be the same as the source file. If the receiving
program is not running as the super-user, only groups that the
receiver is a member of will be preserved (by group name, not group id
number).
dit(bf(-D, --devices)) This option causes rsync to transfer character and
block device information to the remote system to recreate these
devices. This option is only available to the super-user.
dit(bf(-t, --times)) This tells rsync to transfer modification times along
with the files and update them on the remote system. Note that if this
option is not used, the optimization that excludes files that have not been
modified cannot be effective; in other words, a missing -t or -a will
cause the next transfer to behave as if it used -I, and all files will have
their checksums compared and show up in log messages even if they haven't
changed.
dit(bf(-n, --dry-run)) This tells rsync to not do any file transfers,
instead it will just report the actions it would have taken.
dit(bf(-S, --sparse)) Try to handle sparse files efficiently so they take
up less space on the destination.
NOTE: Don't use this option when the destination is a Solaris "tmpfs"
filesystem. It doesn't seem to handle seeks over null regions
correctly and ends up corrupting the files.
dit(bf(-x, --one-file-system)) This tells rsync not to cross filesystem
boundaries when recursing. This is useful for transferring the
contents of only one filesystem.
dit(bf(--existing)) This tells rsync not to create any new files -
only update files that already exist on the destination.
dit(bf(--max-delete=NUM)) This tells rsync not to delete more than NUM
files or directories. This is useful when mirroring very large trees
to prevent disasters.
dit(bf(--delete)) This tells rsync to delete any files on the receiving
side that aren't on the sending side. Files that are excluded from
transfer are excluded from being deleted unless you use --delete-excluded.
This option has no effect if directory recursion is not selected.
This option can be dangerous if used incorrectly! It is a very good idea
to run first using the dry run option (-n) to see what files would be
deleted to make sure important files aren't listed.
If the sending side detects any IO errors then the deletion of any
files at the destination will be automatically disabled. This is to
prevent temporary filesystem failures (such as NFS errors) on the
sending side causing a massive deletion of files on the
destination. You can override this with the --ignore-errors option.
dit(bf(--delete-excluded)) In addition to deleting the files on the
receiving side that are not on the sending side, this tells rsync to also
delete any files on the receiving side that are excluded (see --exclude).
dit(bf(--delete-after)) By default rsync does file deletions before
transferring files to try to ensure that there is sufficient space on
the receiving filesystem. If you want to delete after transferring
then use the --delete-after switch.
dit(bf(--ignore-errors)) Tells --delete to go ahead and delete files
even when there are IO errors.
dit(bf(--force)) This options tells rsync to delete directories even if
they are not empty. This applies to both the --delete option and to
cases where rsync tries to copy a normal file but the destination
contains a directory of the same name.
Since this option was added, deletions were reordered to be done depth-first
so it is hardly ever needed anymore except in very obscure cases.
dit(bf(-B , --block-size=BLOCKSIZE)) This controls the block size used in
the rsync algorithm. See the technical report for details.
dit(bf(-e, --rsh=COMMAND)) This option allows you to choose an alternative
remote shell program to use for communication between the local and
remote copies of rsync. By default, rsync will use rsh, but you may
like to instead use ssh because of its high security.
You can also choose the remote shell program using the RSYNC_RSH
environment variable.
See also the --blocking-io option which is affected by this option.
dit(bf(--rsync-path=PATH)) Use this to specify the path to the copy of
rsync on the remote machine. Useful when it's not in your path. Note
that this is the full path to the binary, not just the directory that
the binary is in.
dit(bf(--exclude=PATTERN)) This option allows you to selectively exclude
certain files from the list of files to be transferred. This is most
useful in combination with a recursive transfer.
You may use as many --exclude options on the command line as you like
to build up the list of files to exclude.
See the section on exclude patterns for information on the syntax of
this option.
dit(bf(--exclude-from=FILE)) This option is similar to the --exclude
option, but instead it adds all exclude patterns listed in the file
FILE to the exclude list. Blank lines in FILE and lines starting with
';' or '#' are ignored.
dit(bf(--include=PATTERN)) This option tells rsync to not exclude the
specified pattern of filenames. This is useful as it allows you to
build up quite complex exclude/include rules.
See the section of exclude patterns for information on the syntax of
this option.
dit(bf(--include-from=FILE)) This specifies a list of include patterns
from a file.
dit(bf(-C, --cvs-exclude)) This is a useful shorthand for excluding a
broad range of files that you often don't want to transfer between
systems. It uses the same algorithm that CVS uses to determine if
a file should be ignored.
The exclude list is initialized to:
quote(RCS SCCS CVS CVS.adm RCSLOG cvslog.* tags TAGS .make.state
.nse_depinfo *~ #* .#* ,* *.old *.bak *.BAK *.orig *.rej .del-*
*.a *.o *.obj *.so *.Z *.elc *.ln core)
then files listed in a $HOME/.cvsignore are added to the list and any
files listed in the CVSIGNORE environment variable (space delimited).
Finally, any file is ignored if it is in the same directory as a
.cvsignore file and matches one of the patterns listed therein. See
the bf(cvs(1)) manual for more information.
dit(bf(--csum-length=LENGTH)) By default the primary checksum used in
rsync is a very strong 16 byte MD4 checksum. In most cases you will
find that a truncated version of this checksum is quite efficient, and
this will decrease the size of the checksum data sent over the link,
making things faster.
You can choose the number of bytes in the truncated checksum using the
--csum-length option. Any value less than or equal to 16 is valid.
Note that if you use this option then you run the risk of ending up
with an incorrect target file. The risk with a value of 16 is
microscopic and can be safely ignored (the universe will probably end
before it fails) but with smaller values the risk is higher.
Current versions of rsync actually use an adaptive algorithm for the
checksum length by default, using a 16 byte file checksum to determine
if a 2nd pass is required with a longer block checksum. Only use this
option if you have read the source code and know what you are doing.
dit(bf(-T, --temp-dir=DIR)) This option instructs rsync to use DIR as a
scratch directory when creating temporary copies of the files
transferred on the receiving side. The default behavior is to create
the temporary files in the receiving directory.
dit(bf(--compare-dest=DIR)) This option instructs rsync to use DIR on
the destination machine as an additional directory to compare destination
files against when doing transfers. This is useful for doing transfers to
a new destination while leaving existing files intact, and then doing a
flash-cutover when all files have been successfully transferred (for
example by moving directories around and removing the old directory,
although this requires also doing the transfer with -I to avoid skipping
files that haven't changed). This option increases the usefulness of
--partial because partially transferred files will remain in the new
temporary destination until they have a chance to be completed. If DIR is
a relative path, it is relative to the destination directory.
dit(bf(-z, --compress)) With this option, rsync compresses any data from
the files that it sends to the destination machine. This
option is useful on slow links. The compression method used is the
same method that gzip uses.
Note this this option typically achieves better compression ratios
that can be achieved by using a compressing remote shell, or a
compressing transport, as it takes advantage of the implicit
information sent for matching data blocks.
dit(bf(--numeric-ids)) With this option rsync will transfer numeric group
and user ids rather than using user and group names and mapping them
at both ends.
By default rsync will use the user name and group name to determine
what ownership to give files. The special uid 0 and the special group
0 are never mapped via user/group names even if the --numeric-ids
option is not specified.
If the source system is a daemon using chroot, or if a user or group
name does not exist on the destination system, then the numeric id
from the source system is used instead.
dit(bf(--timeout=TIMEOUT)) This option allows you to set a maximum IO
timeout in seconds. If no data is transferred for the specified time
then rsync will exit. The default is 0, which means no timeout.
dit(bf(--daemon)) This tells rsync that it is to run as a daemon. The
daemon may be accessed using the bf(host::module) or
bf(rsync://host/module/) syntax.
If standard input is a socket then rsync will assume that it is being
run via inetd, otherwise it will detach from the current terminal and
become a background daemon. The daemon will read the config file
(/etc/rsyncd.conf) on each connect made by a client and respond to
requests accordingly. See the rsyncd.conf(5) man page for more
details.
dit(bf(--no-detach)) When running as a daemon, this option instructs
rsync to not detach itself and become a background process. This
option is required when running as a service on Cygwin, and may also
be useful when rsync is supervised by a program such as
bf(daemontools) or AIX's bf(System Resource Controller).
bf(--no-detach) is also recommended when rsync is run under a
debugger. This option has no effect if rsync is run from inetd or
sshd.
dit(bf(--address)) By default rsync will bind to the wildcard address
when run as a daemon with the --daemon option or when connecting to a
rsync server. The --address option allows you to specify a specific IP
address (or hostname) to bind to. This makes virtual hosting possible
in conjunction with the --config option.
dit(bf(--config=FILE)) This specifies an alternate config file than
the default /etc/rsyncd.conf. This is only relevant when --daemon is
specified.
dit(bf(--port=PORT)) This specifies an alternate TCP port number to use
rather than the default port 873.
dit(bf(--blocking-io)) This tells rsync to use blocking IO when launching
a remote shell transport. If -e or --rsh are not specified or are set to
the default "rsh", this defaults to blocking IO, otherwise it defaults to
non-blocking IO. You may find the --blocking-io option is needed for some
remote shells that can't handle non-blocking IO. Ssh prefers blocking IO.
dit(bf(--log-format=FORMAT)) This allows you to specify exactly what the
rsync client logs to stdout on a per-file basis. The log format is
specified using the same format conventions as the log format option in
rsyncd.conf.
dit(bf(--stats)) This tells rsync to print a verbose set of statistics
on the file transfer, allowing you to tell how effective the rsync
algorithm is for your data.
dit(bf(--partial)) By default, rsync will delete any partially
transferred file if the transfer is interrupted. In some circumstances
it is more desirable to keep partially transferred files. Using the
--partial option tells rsync to keep the partial file which should
make a subsequent transfer of the rest of the file much faster.
dit(bf(--progress)) This option tells rsync to print information
showing the progress of the transfer. This gives a bored user
something to watch.
This option is normally combined with -v. Using this option without
the -v option will produce weird results on your display.
dit(bf(-P)) The -P option is equivalent to --partial --progress. I
found myself typing that combination quite often so I created an
option to make it easier.
dit(bf(--password-file)) This option allows you to provide a password
in a file for accessing a remote rsync server. Note that this option
is only useful when accessing a rsync server using the built in
transport, not when using a remote shell as the transport. The file
must not be world readable. It should contain just the password as a
single line.
dit(bf(--bwlimit=KBPS)) This option allows you to specify a maximum
transfer rate in kilobytes per second. This option is most effective when
using rsync with large files (several megabytes and up). Due to the nature
of rsync transfers, blocks of data are sent, then if rsync determines the
transfer was too fast, it will wait before sending the next data block. The
result is an average transfer rate equalling the specified limit. A value
of zero specifies no limit.
dit(bf(--read-batch)) Apply a previously generated change batch.
dit(bf(--write-batch)) Generate a set of files that can be transferred
as a batch update.
enddit()
manpagesection(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 encountered, 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.
Note also that the --include and --exclude options take one pattern
each. To add multiple patterns use the --include-from and
--exclude-from options or multiple --include and --exclude options.
The patterns can take several forms. The rules are:
itemize(
it() 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.
it() if the pattern ends with a / then it will only match a
directory, not a file, link or device.
it() 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.
it() if the pattern includes a double asterisk "**" then all wildcards in
the pattern will match slashes, otherwise they will stop at slashes.
it() if the pattern contains a / (not counting a trailing /) then it
is matched against the full filename, including any leading
directory. If the pattern doesn't 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.
it() 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.
it() 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.
it() 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 directories and never see the files below
them. To include all directories, use --include '*/' before the
--exclude '*'.
Here are some exclude/include examples:
itemize(
it() --exclude "*.o" would exclude all filenames matching *.o
it() --exclude "/foo" would exclude a file in the base directory called foo
it() --exclude "foo/" would exclude any directory called foo
it() --exclude "/foo/*/bar" would exclude any file called bar two
levels below a base directory called foo
it() --exclude "/foo/**/bar" would exclude any file called bar two
or more levels below a base directory called foo
it() --include "*/" --include "*.c" --exclude "*" would include all
directories and C source files
it() --include "foo/" --include "foo/bar.c" --exclude "*" would include
only foo/bar.c (the foo/ directory must be explicitly included or
it would be excluded by the "*")
)
manpagesection(BATCH MODE)
bf(Note:) Batch mode should be considered experimental in this version
of rsync. The interface or behaviour may change before it stabilizes.
The following call generates 4 files that encapsulate the information
for synchronizing the contents of bf(target_dir) with the updates found in
bf(src_dir)
quote(
$ rsync --write-batch [other rsync options here] \nl()
/somewhere/src_dir /somewhere/target_dir
)
The generated files are labeled with a common timestamp:
itemize(
it() bf(rsync_argvs.<timestamp>) command-line arguments
it() bf(rsync_flist.<timestamp>) rsync internal file metadata
it() bf(rsync_csums.<timestamp>) rsync checksums
it() bf(rsync_delta.<timestamp>) data blocks for file update & change
)
See bf(http://www.ils.unc.edu/i2dsi/unc_rsync+.html) for papers and technical
reports.
manpagesection(SYMBOLIC LINKS)
Three basic behaviours are possible when rsync encounters a symbolic
link in the source directory.
By default, symbolic links are not transferred at all. A message
"skipping non-regular" file is emitted for any symlinks that exist.
If bf(--links) is specified, then symlinks are recreated with the same
target on the destination. Note that bf(--archive) implies
bf(--links).
If bf(--copy-links) is specified, then symlinks are "collapsed" by
copying their referent, rather than the symlink.
rsync also distinguishes "safe" and "unsafe" symbolic links. An
example where this might be used is a web site mirror that wishes
ensure the rsync module they copy does not include symbolic links to
bf(/etc/passwd) in the public section of the site. Using
bf(--copy-unsafe-links) will cause any links to be copied as the file
they point to on the destination. Using bf(--safe-links) will cause
unsafe links to be ommitted altogether.
manpagesection(DIAGNOSTICS)
rsync occasionally produces error messages that may seem a little
cryptic. The one that seems to cause the most confusion is "protocol
version mismatch - is your shell clean?".
This message is usually caused by your startup scripts or remote shell
facility producing unwanted garbage on the stream that rsync is using
for its transport. The way to diagnose this problem is to run your
remote shell like this:
verb(
rsh remotehost /bin/true > out.dat
)
then look at out.dat. If everything is working correctly then out.dat
should be a zero length file. If you are getting the above error from
rsync then you will probably find that out.dat contains some text or
data. Look at the contents and try to work out what is producing
it. The most common cause is incorrectly configured shell startup
scripts (such as .cshrc or .profile) that contain output statements
for non-interactive logins.
If you are having trouble debugging include and exclude patterns, then
try specifying the -vv option. At this level of verbosity rsync will
show why each individual file is included or excluded.
manpagesection(EXIT VALUES)
startdit()
dit(bf(RERR_SYNTAX 1)) Syntax or usage error
dit(bf(RERR_PROTOCOL 2)) Protocol incompatibility
dit(bf(RERR_FILESELECT 3)) Errors selecting input/output files, dirs
dit(bf(RERR_UNSUPPORTED 4)) Requested action not supported: an attempt
was made to manipulate 64-bit files on a platform that cannot support
them; or an option was speciifed that is supported by the client and
not by the server.
dit(bf(RERR_SOCKETIO 10)) Error in socket IO
dit(bf(RERR_FILEIO 11)) Error in file IO
dit(bf(RERR_STREAMIO 12)) Error in rsync protocol data stream
dit(bf(RERR_MESSAGEIO 13)) Errors with program diagnostics
dit(bf(RERR_IPC 14)) Error in IPC code
dit(bf(RERR_SIGNAL 20)) Received SIGUSR1 or SIGINT
dit(bf(RERR_WAITCHILD 21)) Some error returned by waitpid()
dit(bf(RERR_MALLOC 22)) Error allocating core memory buffers
dit(bf(RERR_TIMEOUT 30)) Timeout in data send/receive
enddit()
manpagesection(ENVIRONMENT VARIABLES)
startdit()
dit(bf(CVSIGNORE)) The CVSIGNORE environment variable supplements any
ignore patterns in .cvsignore files. See the --cvs-exclude option for
more details.
dit(bf(RSYNC_RSH)) The RSYNC_RSH environment variable allows you to
override the default shell used as the transport for rsync. This can
be used instead of the -e option.
dit(bf(RSYNC_PROXY)) The RSYNC_PROXY environment variable allows you to
redirect your rsync client to use a web proxy when connecting to a
rsync daemon. You should set RSYNC_PROXY to a hostname:port pair.
dit(bf(RSYNC_PASSWORD)) Setting RSYNC_PASSWORD to the required
password allows you to run authenticated rsync connections to a rsync
daemon without user intervention. Note that this does not supply a
password to a shell transport such as ssh.
dit(bf(USER) or bf(LOGNAME)) The USER or LOGNAME environment variables
are used to determine the default username sent to a rsync server.
dit(bf(HOME)) The HOME environment variable is used to find the user's
default .cvsignore file.
enddit()
manpagefiles()
/etc/rsyncd.conf
manpageseealso()
rsyncd.conf(5)
manpagediagnostics()
manpagebugs()
times are transferred as unix time_t values
file permissions, devices etc are transferred as native numerical
values
see also the comments on the --delete option
Please report bugs! The rsync bug tracking system is online at
url(http://rsync.samba.org/rsync/)(http://rsync.samba.org/rsync/)
manpagesection(VERSION)
This man page is current for version 2.0 of rsync
manpagesection(CREDITS)
rsync is distributed under the GNU public license. See the file
COPYING for details.
A WEB site is available at
url(http://rsync.samba.org/)(http://rsync.samba.org/). The site
includes an FAQ-O-Matic which may cover questions unanswered by this
manual page.
The primary ftp site for rsync is
url(ftp://rsync.samba.org/pub/rsync)(ftp://rsync.samba.org/pub/rsync).
We would be delighted to hear from you if you like this program.
This program uses the excellent zlib compression library written by
Jean-loup Gailly and Mark Adler.
manpagesection(THANKS)
Thanks to Richard Brent, Brendan Mackay, Bill Waite, Stephen Rothwell
and David Bell for helpful suggestions, patches and testing of rsync.
I've probably missed some people, my apologies if I have.
Especial thanks also to: David Dykstra, Jos Backus, Sebastian Krahmer.
manpageauthor()
rsync was written by Andrew Tridgell <tridge@samba.org> and Paul
Mackerras.
rsync is now maintained by Martin Pool <mbp@samba.org>.
Mailing lists for support and development are available at
url(http://lists.samba.org)(lists.samba.org)
If you suspect you have found a security vulnerability in rsync,
please send it directly to Martin Pool and Andrew Tridgell. For other
enquiries, please use the mailing list.

469
rsync3.txt Normal file
View File

@@ -0,0 +1,469 @@
-*- indented-text -*-
Notes towards a new version of rsync
Martin Pool <mbp@samba.org>, September 2001.
Good things about the current implementation:
- Widely known and adopted.
- Fast/efficient, especially for moderately small sets of files over
slow links (transoceanic or modem.)
- Fairly reliable.
- The choice of runnning over a plain TCP socket or tunneling over
ssh.
- rsync operations are idempotent: you can always run the same
command twice to make sure it worked properly without any fear.
(Are there any exceptions?)
- Small changes to files cause small deltas.
- There is a way to evolve the protocol to some extent.
- rdiff and rsync --write-batch allow generation of standalone patch
sets. rsync+ is pretty cheesy, though. xdelta seems cleaner.
- Process triangle is creative, but seems to provoke OS bugs.
- "Morning-after property": you don't need to know anything on the
local machine about the state of the remote machine, or about
transfers that have been done in the past.
- You can easily push or pull simply by switching the order of
files.
- The "modules" system has some neat features compared to
e.g. Apache's per-directory configuration. In particular, because
you can set a userid and chroot directory, there is strong
protection between different modules. I haven't seen any calls
for a more flexible system.
Bad things about the current implementation:
- Persistent and hard-to-diagnose hang bugs remain
- Protocol is sketchily documented, tied to this implementation, and
hard to modify/extend
- Both the program and the protocol assume a single non-interactive
one-way transfer
- A list of all files are held in memory for the entire transfer,
which cripples scalability to large file trees
- Opening a new socket for every operation causes problems,
especially when running over SSH with password authentication.
- Renamed files are not handled: the old file is removed, and the
new file created from scratch.
- The versioning approach assumes that future versions of the
program know about all previous versions, and will do the right
thing.
- People always get confused about ':' vs '::'
- Error messages can be cryptic.
- Default behaviour is not intuitive: in too many cases rsync will
happily do nothing. Perhaps -a should be the default?
- People get confused by trailing slashes, though it's hard to think
of another reasonable way to make this necessary distinction
between a directory and its contents.
Protocol philosophy:
*The* big difference between protocols like HTTP, FTP, and NFS is
that their fundamental operations are "read this file", "delete
this file", and "make this directory", whereas rsync is "make this
directory like this one".
Questionable features:
These are neat, but not necessarily clean or worth preserving.
- The remote rsync can be wrapped by some other program, such as in
tridge's rsync-mail scripts. The general feature of sending and
retrieving mail over rsync is good, but this is perhaps not the
right way to implement it.
Desirable features:
These don't really require architectural changes; they're just
something to keep in mind.
- Synchronize ACLs and extended attributes
- Anonymous servers should be efficient
- Code should be portable to non-UNIX systems
- Should be possible to document the protocol in RFC form
- --dry-run option
- IPv6 support. Pretty straightforward.
- Allow the basis and destination files to be different. For
example, you could use this when you have a CD-ROM and want to
download an updated image onto a hard drive.
- Efficiently interrupt and restart a transfer. We can write a
checkpoint file that says where we're up to in the filesystem.
Alternatively, as long as transfers are idempotent, we can just
restart the whole thing. [NFSv4]
- Scripting support.
- Propagate atimes and do not modify them. This is very ugly on
Unix. It might be better to try to add O_NOATIME to kernels, and
call that.
- Unicode. Probably just use UTF-8 for everything.
- Open authentication system. Can we use PAM? Is SASL an adequate
mapping of PAM to the network, or useful in some other way?
- Resume interrupted transfers without the --partial flag. We need
to leave the temporary file behind, and then know to use it. This
leaves a risk of large temporary files accumulating, which is not
good. Perhaps it should be off by default.
- tcpwrappers support. Should be trivial; can already be done
through tcpd or inetd.
- Socks support built in. It's not clear this is any better than
just linking against the socks library, though.
- When run over SSH, invoke with predictable command-line arguments,
so that people can restrict what commands sshd will run. (Is this
really required?)
- Comparison mode: give a list of which files are new, gone, or
different. Set return code depending on whether anything has
changed.
- Internationalized messages (gettext?)
- Optionally use real regexps rather than globs?
- Show overall progress. Pretty hard to do, especially if we insist
on not scanning the directory tree up front.
Regression testing:
- Support automatic testing.
- Have hard internal timeouts against hangs.
- Be deterministic.
- Measure performance.
Hard links:
At the moment, we can recreate hard links, but it's a bit
inefficient: it depends on holding a list of all files in the tree.
Every time we see a file with a linkcount >1, we need to search for
another known name that has the same (fsid,inum) tuple. We could do
that more efficiently by keeping a list of only files with
linkcount>1, and removing files from that list as all their names
become known.
Command-line options:
We have rather a lot at the moment. We might get more if the tool
becomes more flexible. Do we need a .rc or configuration file?
That wouldn't really fit with its pattern of use: cp and tar don't
have them, though ssh does.
Scripting issues:
- Perhaps support multiple scripting languages: candidates include
Perl, Python, Tcl, Scheme (guile?), sh, ...
- Simply running a subprocess and looking at its stdout/exit code
might be sufficient, though it could also be pretty slow if it's
called often.
- There are security issues about running remote code, at least if
it's not running in the users own account. So we can either
disallow it, or use some kind of sandbox system.
- Python is a good language, but the syntax is not so good for
giving small fragments on the command line.
- Tcl is broken Lisp.
- Lots of sysadmins know Perl, though Perl can give some bizarre or
confusing errors. The built in stat operators and regexps might
be useful.
- Sadly probably not enough people know Scheme.
- sh is hard to embed.
Scripting hooks:
- Whether to transfer a file
- What basis file to use
- Logging
- Whether to allow transfers (for public servers)
- Authentication
- Locking
- Cache
- Generating backup path/name.
- Post-processing of backups, e.g. to do compression.
- After transfer, before replacement: so that we can spit out a diff
of what was changed, or kick off some kind of reconciliation
process.
VFS:
Rather than talking straight to the filesystem, rsyncd talks through
an internal API. Samba has one. Is it useful?
- Could be a tidy way to implement cached signatures.
- Keep files compressed on disk?
Interactive interface:
- Something like ncFTP, or integration into GNOME-vfs. Probably
hold a single socket connection open.
- Can either call us as a separate process, or as a library.
- The standalone process needs to produce output in a form easily
digestible by a calling program, like the --emacs feature some
have. Same goes for output: rpm outputs a series of hash symbols,
which are easier for a GUI to handle than "\r30% complete"
strings.
- Yow! emacs support. (You could probably build that already, of
course.) I'd like to be able to write a simple script on a remote
machine that rsyncs it to my workstation, edits it there, then
pushes it back up.
Pie-in-the-sky features:
These might have a severe impact on the protocol, and are not
clearly in our core requirements. It looks like in many of them
having scripting hooks will allow us
- Transport over UDP multicast. The hard part is handling multiple
destinations which have different basis files. We can look at
multicast-TFTP for inspiration.
- Conflict resolution. Possibly general scripting support will be
sufficient.
- Integrate with locking. It's hard to see a good general solution,
because Unix systems have several locking mechanisms, and grabbing
the lock from programs that don't expect it could cause deadlocks,
timeouts, or other problems. Scripting support might help.
- Replicate in place, rather than to a temporary file. This is
dangerous in the case of interruption, and it also means that the
delta can't refer to blocks that have already been overwritten.
On the other hand we could semi-trivially do this at first by
simply generating a delta with no copy instructions.
- Replicate block devices. Most of the difficulties here are to do
with replication in place, though on some systems we will also
have to do I/O on block boundaries.
- Peer to peer features. Flavour of the year. Can we think about
ways for clients to smoothly and voluntarily become servers for
content they receive?
- Imagine a situation where the destination has a much faster link
to the cloud than the source. In this case, Mojo Nation downloads
interleaved blocks from several slower servers. The general
situation might be a way for a master rsync process to farm out
tasks to several subjobs. In this particular case they'd need
different sockets. This might be related to multicast.
Unlikely features:
- Allow remote source and destination. If this can be cleanly
designed into the protocol, perhaps with the remote machine acting
as a kind of echo, then it's good. It's uncommon enough that we
don't want to shape the whole protocol around it, though.
In fact, in a triangle of machines there are two possibilities:
all traffic passes from remote1 to remote2 through local, or local
just sets up the transfer and then remote1 talks to remote2. FTP
supports the second but it's not clearly good. There are some
security problems with being able to instruct one machine to open
a connection to another.
In favour of evolving the protocol:
- Keeping compatibility with existing rsync servers will help with
adoption and testing.
- We should at the very least be able to fall back to the new
protocol.
- Error handling is not so good.
In favour of using a new protocol:
- Maintaining compatibility might soak up development time that
would better go into improving a new protocol.
- If we start from scratch, it can be documented as we go, and we
can avoid design decisions that make the protocol complex or
implementation-bound.
Error handling:
- Errors should come back reliably, and be clearly associated with
the particular file that caused the problem.
- Some errors ought to cause the whole transfer to abort; some are
just warnings. If any errors have occurred, then rsync ought to
return an error.
Concurrency:
- We want to keep the CPU, filesystem, and network as full as
possible as much of the time as possible.
- We can do nonblocking network IO, but not so for disk.
- It makes sense to on the destination be generating signatures and
applying patches at the same time.
- Can structure this with nonblocking, threads, separate processes,
etc.
Uses:
- Mirroring software distributions:
- Synchronizing laptop and desktop
- NFS filesystem migration/replication. See
http://www.ietf.org/proceedings/00jul/00july-133.htm#P24510_1276764
- Sync with PDA
- Network backup systems
- CVS filemover
Conflict resolution:
- Requires application-specific knowledge. We want to provide
policy, rather than mechanism.
- Possibly allowing two-way migration across a single connection
would be useful.
Moved files: <http://rsync.samba.org/cgi-bin/rsync.fom?file=44>
- There's no trivial way to detect renamed files, especially if they
move between directories.
- If we had a picture of the remote directory from last time on
either machine, then the inode numbers might give us a hint about
files which may have been renamed.
- Files that are renamed and not modified can be detected by
examining the directory listing, looking for files with the same
size/date as the origin.
Filesystem migration:
NFSv4 probably wants to migrate file locks, but that's not really
our problem.
Atomic updates:
The NFSv4 working group wants atomic migration. Most of the
responsibility for this lies on the NFS server or OS.
If migrating a whole tree, then we could do a nearly-atomic rename
at the end. This ties in to having separate basis and destination
files.
There's no way in Unix to replace a whole set of files atomically.
However, if we get them all onto the destination machine and then do
the updates quickly it would greatly reduce the window.
Scalability:
We should aim to work well on machines in use in a year or two.
That probably means transfers of many millions of files in one
batch, and gigabytes or terabytes of data.
For argument's sake: at the low end, we want to sync ten files for a
total of 10kb across a 1kB/s link. At the high end, we want to sync
1e9 files for 1TB of data across a 1GB/s link.
On the whole CPU usage is not normally a limiting factor, if only
because running over SSH burns a lot of cycles on encryption.
Perhaps have resource throttling without relying on rlimit.
Streaming:
A big attraction of rsync is that there are few round-trip delays:
basically only one to get started, and then everything is
pipelined. This is a problem with FTP, and NFS (at least up to
v3). NFSv4 can pipeline operations, but building on that is
probably a bit complicated.
Related work:
- mirror.pl http://freshmeat.net/project/mirror/
- ProFTPd
- Apache
- http://freshmeat.net/search/?site=Freshmeat&q=mirror&section=projects
- BitTorrent -- p2p mirroring
http://bitconjurer.org/BitTorrent/

480
rsyncd.conf.yo Normal file
View File

@@ -0,0 +1,480 @@
mailto(rsync-bugs@samba.org)
manpage(rsyncd.conf)(5)(12 Feb 1999)()()
manpagename(rsyncd.conf)(configuration file for rsync server)
manpagesynopsis()
rsyncd.conf
manpagedescription()
The rsyncd.conf file is the runtime configuration file for rsync when
run with the --daemon option. When run in this way rsync becomes a
rsync server listening on TCP port 873. Connections from rsync clients
are accepted for either anonymous or authenticated rsync sessions.
The rsyncd.conf file controls authentication, access, logging and
available modules.
manpagesection(FILE FORMAT)
The file consists of modules and parameters. A module begins with the
name of the module in square brackets and continues until the next
module begins. Modules contain parameters of the form 'name = value'.
The file is line-based - that is, each newline-terminated line represents
either a comment, a module name or a parameter.
Only the first equals sign in a parameter is significant. Whitespace before
or after the first equals sign is discarded. Leading, trailing and internal
whitespace in module and parameter names is irrelevant. Leading and
trailing whitespace in a parameter value is discarded. Internal whitespace
within a parameter value is retained verbatim.
Any line beginning with a hash (#) is ignored, as are lines containing
only whitespace.
Any line ending in a \ is "continued" on the next line in the
customary UNIX fashion.
The values following the equals sign in parameters are all either a string
(no quotes needed) or a boolean, which may be given as yes/no, 0/1 or
true/false. Case is not significant in boolean values, but is preserved
in string values.
manpagesection(LAUNCHING THE RSYNC DAEMON)
The rsync daemon is launched by specifying the --daemon option to
rsync.
The daemon must run with root privileges if you wish to use chroot, to
bind to a port numbered under 1024 (as is the default 873), or to set
file ownership. Otherwise, it must just have permission to read and
write the appropriate data, log, and lock files.
You can launch it either via inetd or as a stand-alone daemon. If run
as a daemon then just run the command "rsync --daemon" from a suitable
startup script.
When run via inetd you should add a line like this to /etc/services:
quote(rsync 873/tcp)
and a single line something like this to /etc/inetd.conf:
quote(rsync stream tcp nowait root /usr/bin/rsync rsyncd --daemon)
Replace "/usr/bin/rsync" with the path to where you have rsync installed on
your system. You will then need to send inetd a HUP signal to tell it to
reread its config file.
Note that you should not send the rsync server a HUP signal to force
it to reread the tt(/etc/rsyncd.conf). The file is re-read on each client
connection.
manpagesection(GLOBAL OPTIONS)
The first parameters in the file (before a [module] header) are the
global parameters.
You may also include any module parameters in the global part of the
config file in which case the supplied value will override the
default for that parameter.
startdit()
dit(bf(motd file)) The "motd file" option allows you to specify a
"message of the day" to display to clients on each connect. This
usually contains site information and any legal notices. The default
is no motd file.
dit(bf(log file)) The "log file" option tells the rsync daemon to log
messages to that file rather than using syslog. This is particularly
useful on systems (such as AIX) where syslog() doesn't work for
chrooted programs.
dit(bf(pid file)) The "pid file" option tells the rsync daemon to write
its process id to that file.
dit(bf(syslog facility)) The "syslog facility" option allows you to
specify the syslog facility name to use when logging messages from the
rsync server. You may use any standard syslog facility name which is
defined on your system. Common names are auth, authpriv, cron, daemon,
ftp, kern, lpr, mail, news, security, syslog, user, uucp, local0,
local1, local2, local3, local4, local5, local6 and local7. The default
is daemon.
dit(bf(socket options)) This option can provide endless fun for people
who like to tune their systems to the utmost degree. You can set all
sorts of socket options which may make transfers faster (or
slower!). Read the man page for the setsockopt() system call for
details on some of the options you may be able to set. By default no
special socket options are set.
enddit()
manpagesection(MODULE OPTIONS)
After the global options you should define a number of modules, each
module exports a directory tree as a symbolic name. Modules are
exported by specifying a module name in square brackets [module]
followed by the options for that module.
startdit()
dit(bf(comment)) The "comment" option specifies a description string
that is displayed next to the module name when clients obtain a list
of available modules. The default is no comment.
dit(bf(path)) The "path" option specifies the directory in the servers
filesystem to make available in this module. You must specify this option
for each module in tt(/etc/rsyncd.conf).
dit(bf(use chroot)) If "use chroot" is true, the rsync server will chroot
to the "path" before starting the file transfer with the client. This has
the advantage of extra protection against possible implementation security
holes, but it has the disadvantages of requiring super-user privileges and
of not being able to follow symbolic links outside of the new root path
when reading. When "use chroot" is false, for security reasons
symlinks may only be relative paths pointing to other files within the
root path, and leading slashes are removed from absolute paths. The
default for "use chroot" is true.
dit(bf(max connections)) The "max connections" option allows you to
specify the maximum number of simultaneous connections you will allow
to this module of your rsync server. Any clients connecting when the
maximum has been reached will receive a message telling them to try
later. The default is 0 which means no limit.
dit(bf(lock file)) The "lock file" option specifies the file to use to
support the "max connections" option. The rsync server uses record
locking on this file to ensure that the max connections limit is not
exceeded. The default is tt(/var/run/rsyncd.lock).
dit(bf(read only)) The "read only" option determines whether clients
will be able to upload files or not. If "read only" is true then any
attempted uploads will fail. If "read only" is false then uploads will
be possible if file permissions on the server allow them. The default
is for all modules to be read only.
dit(bf(list)) The "list" option determines if this module should be
listed when the client asks for a listing of available modules. By
setting this to false you can create hidden modules. The default is
for modules to be listable.
dit(bf(uid)) The "uid" option specifies the user name or user id that
file transfers to and from that module should take place as when the daemon
was run as root. In combination with the "gid" option this determines what
file permissions are available. The default is uid -2, which is normally
the user "nobody".
dit(bf(gid)) The "gid" option specifies the group name or group id that
file transfers to and from that module should take place as when the daemon
was run as root. This complements the "uid" option. The default is gid -2,
which is normally the group "nobody".
dit(bf(exclude)) The "exclude" option allows you to specify a space
separated list of patterns to add to the exclude list. This is
equivalent to the client specifying these patterns with the --exclude
option except that the exclude list is not passed to the client and
thus only apply on the server. Only one "exclude" option may be
specified, but you can use "-" and "+" before patterns to specify
exclude/include.
Note that this option is not designed with strong security in
mind, it is quite possible that a client may find a way to bypass this
exclude list. If you want to absolutely ensure that certain files
cannot be accessed then use the uid/gid options in combination with
file permissions.
dit(bf(exclude from)) The "exclude from" option specifies a filename
on the server that contains exclude patterns, one per line. This is
equivalent to the client specifying the --exclude-from option with a
equivalent file except that the resulting exclude patterns are not
passed to the client and thus only apply on the server. See also the
note about security for the exclude option above.
dit(bf(include)) The "include" option allows you to specify a space
separated list of patterns which rsync should not exclude. This is
equivalent to the client specifying these patterns with the --include
option. This is useful as it allows you to build up quite complex
exclude/include rules. Only one "include" option may be specified, but you
can use "+" and "-" before patterns to switch include/exclude.
See the section of exclude patterns in the rsync man page for information
on the syntax of this option.
dit(bf(include from)) The "include from" option specifies a filename
on the server that contains include patterns, one per line. This is
equivalent to the client specifying the --include-from option with a
equivalent file.
dit(bf(auth users)) The "auth users" option specifies a comma and
space separated list of usernames that will be allowed to connect to
this module. The usernames do not need to exist on the local
system. The usernames may also contain shell wildcard characters. If
"auth users" is set then the client will be challenged to supply a
username and password to connect to the module. A challenge response
authentication protocol is used for this exchange. The plain text
usernames are passwords are stored in the file specified by the
"secrets file" option. The default is for all users to be able to
connect without a password (this is called "anonymous rsync").
dit(bf(secrets file)) The "secrets file" option specifies the name of
a file that contains the username:password pairs used for
authenticating this module. This file is only consulted if the "auth
users" option is specified. The file is line based and contains
username:password pairs separated by a single colon. Any line starting
with a hash (#) is considered a comment and is skipped. The passwords
can contain any characters but be warned that many operating systems
limit the length of passwords that can be typed at the client end, so
you may find that passwords longer than 8 characters don't work.
There is no default for the "secrets file" option, you must choose a name
(such as tt(/etc/rsyncd.secrets)). The file must normally not be readable
by "other"; see "strict modes".
dit(bf(strict modes)) The "strict modes" option determines whether or not
the permissions on the secrets file will be checked. If "strict modes" is
true, then the secrets file must not be readable by any user id other
than the one that the rsync daemon is running under. If "strict modes" is
false, the check is not performed. The default is true. This option
was added to accommodate rsync running on the Windows operating system.
dit(bf(hosts allow)) The "hosts allow" option allows you to specify a
list of patterns that are matched against a connecting clients
hostname and IP address. If none of the patterns match then the
connection is rejected.
Each pattern can be in one of five forms:
itemize(
it() a dotted decimal IP address. In this case the incoming machines
IP address must match exactly.
it() a address/mask in the form a.b.c.d/n were n is the number of
one bits in in the netmask. All IP addresses which match the masked
IP address will be allowed in.
it() a address/mask in the form a.b.c.d/e.f.g.h where e.f.g.h is a
netmask in dotted decimal notation. All IP addresses which match the masked
IP address will be allowed in.
it() a hostname. The hostname as determined by a reverse lookup will
be matched (case insensitive) against the pattern. Only an exact
match is allowed in.
it() a hostname pattern using wildcards. These are matched using the
same rules as normal unix filename matching. If the pattern matches
then the client is allowed in.
)
You can also combine "hosts allow" with a separate "hosts deny"
option. If both options are specified then the "hosts allow" option s
checked first and a match results in the client being able to
connect. The "hosts deny" option is then checked and a match means
that the host is rejected. If the host does not match either the
"hosts allow" or the "hosts deny" patterns then it is allowed to
connect.
The default is no "hosts allow" option, which means all hosts can connect.
dit(bf(hosts deny)) The "hosts deny" option allows you to specify a
list of patterns that are matched against a connecting clients
hostname and IP address. If the pattern matches then the connection is
rejected. See the "hosts allow" option for more information.
The default is no "hosts deny" option, which means all hosts can connect.
dit(bf(ignore errors)) The "ignore errors" option tells rsyncd to
ignore IO errors on the server when deciding whether to run the delete
phase of the transfer. Normally rsync skips the --delete step if any
IO errors have occurred in order to prevent disasterous deletion due
to a temporary resource shortage or other IO error. In some cases this
test is counter productive so you can use this option to turn off this
behaviour.
dit(bf(ignore nonreadable)) This tells the rsync server to completely
ignore files that are not readable by the user. This is useful for
public archives that may have some non-readable files among the
directories, and the sysadmin doesn't want those files to be seen at all.
dit(bf(transfer logging)) The "transfer logging" option enables per-file
logging of downloads and uploads in a format somewhat similar to that
used by ftp daemons. If you want to customize the log formats look at
the log format option.
dit(bf(log format)) The "log format" option allows you to specify the
format used for logging file transfers when transfer logging is
enabled. The format is a text string containing embedded single
character escape sequences prefixed with a percent (%) character.
The prefixes that are understood are:
itemize(
it() %h for the remote host name
it() %a for the remote IP address
it() %l for the length of the file in bytes
it() %p for the process id of this rsync session
it() %o for the operation, which is either "send" or "recv"
it() %f for the filename
it() %P for the module path
it() %m for the module name
it() %t for the current date time
it() %u for the authenticated username (or the null string)
it() %b for the number of bytes actually transferred
it() %c when sending files this gives the number of checksum bytes
received for this file
)
The default log format is "%o %h [%a] %m (%u) %f %l", and a "%t [%p] "
is always added to the beginning when using the "log file" option.
A perl script called rsyncstats to summarize this format is included
in the rsync source code distribution.
dit(bf(timeout)) The "timeout" option allows you to override the
clients choice for IO timeout for this module. Using this option you
can ensure that rsync won't wait on a dead client forever. The timeout
is specified in seconds. A value of zero means no timeout and is the
default. A good choice for anonymous rsync servers may be 600 (giving
a 10 minute timeout).
dit(bf(refuse options)) The "refuse options" option allows you to
specify a space separated list of rsync command line options that will
be refused by your rsync server. The full names of the options must be
used (i.e., you must use "checksum" not "c" to disable checksumming).
When an option is refused, the server prints an error message and exits.
To prevent all compression, you can use "dont compress = *" (see below)
instead of "refuse options = compress" to avoid returning an error to a
client that requests compression.
dit(bf(dont compress)) The "dont compress" option allows you to select
filenames based on wildcard patterns that should not be compressed
during transfer. Compression is expensive in terms of CPU usage so it
is usually good to not try to compress files that won't compress well,
such as already compressed files.
The "dont compress" option takes a space separated list of
case-insensitive wildcard patterns. Any source filename matching one
of the patterns will not be compressed during transfer.
The default setting is verb(*.gz *.tgz *.zip *.z *.rpm *.deb *.iso *.bz2 *.tbz)
enddit()
manpagesection(AUTHENTICATION STRENGTH)
The authentication protocol used in rsync is a 128 bit MD4 based
challenge response system. Although I believe that no one has ever
demonstrated a brute-force break of this sort of system you should
realize that this is not a "military strength" authentication system.
It should be good enough for most purposes but if you want really top
quality security then I recommend that you run rsync over ssh.
Also note that the rsync server protocol does not currently provide any
encryption of the data that is transferred over the link. Only
authentication is provided. Use ssh as the transport if you want
encryption.
Future versions of rsync may support SSL for better authentication and
encryption, but that is still being investigated.
manpagesection(EXAMPLES)
A simple rsyncd.conf file that allow anonymous rsync to a ftp area at
tt(/home/ftp) would be:
verb(
[ftp]
path = /home/ftp
comment = ftp export area
)
A more sophisticated example would be:
uid = nobody nl()
gid = nobody nl()
use chroot = no nl()
max connections = 4 nl()
syslog facility = local5 nl()
pid file = /var/run/rsyncd.pid
verb([ftp]
path = /var/ftp/pub
comment = whole ftp area (approx 6.1 GB)
[sambaftp]
path = /var/ftp/pub/samba
comment = Samba ftp area (approx 300 MB)
[rsyncftp]
path = /var/ftp/pub/rsync
comment = rsync ftp area (approx 6 MB)
[sambawww]
path = /public_html/samba
comment = Samba WWW pages (approx 240 MB)
[cvs]
path = /data/cvs
comment = CVS repository (requires authentication)
auth users = tridge, susan
secrets file = /etc/rsyncd.secrets
)
The /etc/rsyncd.secrets file would look something like this:
tridge:mypass nl()
susan:herpass
manpagefiles()
/etc/rsyncd.conf
manpageseealso()
rsync(1)
manpagediagnostics()
manpagebugs()
The rsync server does not send all types of error messages to the
client. this means a client may be mystified as to why a transfer
failed. The error will have been logged by syslog on the server.
Please report bugs! The rsync bug tracking system is online at
url(http://rsync.samba.org/)(http://rsync.samba.org/)
manpagesection(VERSION)
This man page is current for version 2.0 of rsync
manpagesection(CREDITS)
rsync is distributed under the GNU public license. See the file
COPYING for details.
The primary ftp site for rsync is
url(ftp://rsync.samba.org/pub/rsync)(ftp://rsync.samba.org/pub/rsync).
A WEB site is available at
url(http://rsync.samba.org/)(http://rsync.samba.org/)
We would be delighted to hear from you if you like this program.
This program uses the zlib compression library written by Jean-loup
Gailly and Mark Adler.
manpagesection(THANKS)
Thanks to Warren Stanley for his original idea and patch for the rsync
server. Thanks to Karsten Thygesen for his many suggestions and
documentation!
manpageauthor()
rsync was written by Andrew Tridgell and Paul Mackerras. They may be
contacted via email at tridge@samba.org and
Paul.Mackerras@cs.anu.edu.au

26
rsyncsh.txt Normal file
View File

@@ -0,0 +1,26 @@
rsyncsh
Copyright (C) 2001 by Martin Pool
This is a quick hack to build an interactive shell around rsync, the
same way we have the ftp, lftp and ncftp programs for the FTP
protocol. The key application for this is connecting to a public
rsync server, such as rsync.kernel.org, change down through and list
directories, and finally pull down the file you want.
rsync is somewhat ill-at-ease as an interactive operation, since every
network connection is used to carry out exactly one operation. rsync
kind of "forks across the network" passing the options and filenames
to operate upon, and the connection is closed when the transfer is
complete. (This might be fixed in the future, either by adapting the
current protocol to allow chained operations over a single socket, or
by writing a new protocol that better supports interactive use.)
So, rsyncsh runs a new rsync command and opens a new socket for every
(network-based) command you type.
This has two consequences. Firstly, there is more command latency
than is really desirable. More seriously, if the connection cannot be
done automatically, because for example it uses SSH with a password,
then you will need to enter the password every time. We might even
fix this in the future, though, by having a way to automatically feed
the password to SSH if it's entered once.

247
runtests.sh Executable file
View File

@@ -0,0 +1,247 @@
#! /bin/sh
# Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version
# 2 as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
# rsync top-level test script -- this invokes all the other more
# detailed tests in order. This script can either be called by `make
# check' or `make installcheck'. `check' runs against the copies of
# the program and other files in the build directory, and
# `installcheck' against the installed copy of the program.
# In either case we need to also be able to find the source directory,
# since we read test scripts and possibly other information from
# there.
# Whenever possible, informational messages are written to stdout and
# error messages to stderr. They're separated out by the build farm
# display scripts.
# According to the GNU autoconf manual, the only valid place to set up
# directory locations is through Make, since users are allowed to (try
# to) change their mind on the Make command line. So, Make has to
# pass in all the values we need.
# For other configured settings we read ./config.sh, which tells us
# about shell commands on this machine and similar things.
# rsync_bin gives the location of the rsync binary. This is either
# builddir/rsync if we're testing an uninstalled copy, or
# install_prefix/bin/rsync if we're testing an installed copy. On the
# build farm rsync will be installed, but into a scratch /usr.
# srcdir gives the location of the source tree, which lets us find the
# build scripts. At the moment we assume we are invoked from the
# source directory.
# This script must be invoked from the build directory.
# A scratch directory, 'testtmp', is created in the build directory to
# hold working files.
# This script also uses the $loglevel environment variable. 1 is the
# default value, and 10 the most verbose. You can set this from the
# Make command line. It's also set by the build farm to give more
# detail for failing builds.
# NOTES FOR TEST CASES:
# Each test case runs in its own shell.
# Exit codes from tests:
# 1 tests failed
# 2 error in starting tests
# 77 this test skipped (random value unlikely to happen by chance, same as
# automake)
# HOWEVER, the overall exit code to the farm is different: we return
# the *number of tests that failed*, so that it will show up nicely in
# the overall summary.
# rsync.fns contains some general setup functions and definitions.
# NOTES ON PORTABILITY:
# Both this script and the Makefile have to be pretty conservative
# about which Unix features they use.
# We cannot count on Make exporting variables to commands, unless
# they're explicitly given on the command line.
# Also, we can't count on 'cp -a' or 'mkdir -p', although they're
# pretty handy.
# I think some of the GNU documentation suggests that we shouldn't
# rely on shell functions. However, the Bash manual seems to say that
# they're in POSIX 1003.2, and since the build farm relies on them
# they're probably working on most machines we really care about.
# You cannot use "function foo {" syntax, but must instead say "foo()
# {", or it breaks on FreeBSD.
# BSD machines tend not to have "head" or "seq".
# You cannot do "export VAR=VALUE" all on one line; the export must be
# separate from the assignment. (SCO SysV)
# STILL TO DO:
# We need a good protection against tests that hang indefinitely.
# Perhaps some combination of starting them in the background, wait,
# and kill?
# Perhaps we need a common way to cleanup tests. At the moment just
# clobbering the directory when we're done should be enough.
# If any of the targets fail, then (GNU?) Make returns 2, instead of
# the return code from the failing command. This is fine, but it
# means that the build farm just shows "2" for failed tests, not the
# number of tests that actually failed. For more details we might
# need to grovel through the log files to find a line saying how many
# failed.
set -e
. "./shconfig"
RUNSHFLAGS='-e'
if [ -n "$loglevel" ] && [ "$loglevel" -gt 8 ]
then
if set -x
then
# If it doesn't work the first time, don't keep trying.
RUNSHFLAGS="$RUNSHFLAGS -x"
fi
fi
echo "============================================================"
echo "$0 running in `pwd`"
echo " rsync_bin=$rsync_bin"
echo " srcdir=$srcdir"
if test ! -f $rsync_bin
then
echo "rsync_bin $rsync_bin is not a file" >&2
exit 2
fi
if test ! -d $srcdir
then
echo "srcdir $srcdir is not a directory" >&2
exit 2
fi
RSYNC="$rsync_bin"
export rsync_bin RSYNC
skipped=0
missing=0
passed=0
failed=0
# Prefix for scratch directory. We create separate directories for
# each test case, so that they can be left behind in case of failure
# to aid investigation.
scratchbase="`pwd`"/testtmp
echo " scratchbase=$scratchbase"
suitedir="$srcdir/testsuite"
export scratchdir suitedir
prep_scratch() {
[ -d "$scratchdir" ] && rm -rf "$scratchdir"
mkdir "$scratchdir"
return 0
}
discard_scratch() {
[ -d "$scratchdir" ] && rm -rf "$scratchdir"
return 0
}
if [ "x$whichtests" = x ]
then
whichtests="*.test"
fi
for testscript in $suitedir/$whichtests
do
testbase=`echo $testscript | sed 's!.*/!!' | sed -e 's/.test\$//'`
scratchdir="$scratchbase.$testbase"
prep_scratch
set +e
sh $RUNSHFLAGS "$testscript" >"$scratchdir/test.log" 2>&1
result=$?
set -e
case $result in
0)
echo "PASS $testbase"
passed=`expr $passed + 1`
discard_scratch
;;
77)
echo "SKIP $testbase"
skipped=`expr $skipped + 1`
discard_scratch
;;
78)
# It failed, but we expected that. don't dump out error logs,
# because most users won't want to see them. But do leave
# the working directory around.
echo "XFAIL $testbase"
failed=`expr $failed + 1`
;;
*)
echo "FAIL $testbase"
echo "----- $testbase failed: log follows"
cat "$scratchdir/test.log"
echo "----- $testbase log ends"
failed=`expr $failed + 1`
if [ "x$nopersist" = "xyes" ]
then
exit 1
fi
esac
done
echo '------------------------------------------------------------'
echo "----- overall results:"
echo " $passed passed"
[ "$failed" -gt 0 ] && echo " $failed failed"
[ "$skipped" -gt 0 ] && echo " $skipped skipped"
[ "$missing" -gt 0 ] && echo " $missing missing"
echo '------------------------------------------------------------'
# OK, so expr exits with 0 if the result is neither null nor zero; and
# 1 if the expression is null or zero. This is the opposite of what
# we want, and if we just call expr then this script will always fail,
# because -e is set.
result=`expr $failed + $missing || true`
echo "overall result is $result"
exit $result

293
sender.c Normal file
View File

@@ -0,0 +1,293 @@
/*
Copyright (C) Andrew Tridgell 1996
Copyright (C) Paul Mackerras 1996
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "rsync.h"
extern int verbose;
extern int remote_version;
extern int csum_length;
extern struct stats stats;
extern int io_error;
extern int dry_run;
extern int am_server;
/*
receive the checksums for a buffer
*/
static struct sum_struct *receive_sums(int f)
{
struct sum_struct *s;
int i;
OFF_T offset = 0;
s = (struct sum_struct *)malloc(sizeof(*s));
if (!s) out_of_memory("receive_sums");
s->count = read_int(f);
s->n = read_int(f);
s->remainder = read_int(f);
s->sums = NULL;
if (verbose > 3)
rprintf(FINFO,"count=%d n=%d rem=%d\n",
s->count,s->n,s->remainder);
if (s->count == 0)
return(s);
s->sums = (struct sum_buf *)malloc(sizeof(s->sums[0])*s->count);
if (!s->sums) out_of_memory("receive_sums");
for (i=0;i<s->count;i++) {
s->sums[i].sum1 = read_int(f);
read_buf(f,s->sums[i].sum2,csum_length);
s->sums[i].offset = offset;
s->sums[i].i = i;
if (i == s->count-1 && s->remainder != 0) {
s->sums[i].len = s->remainder;
} else {
s->sums[i].len = s->n;
}
offset += s->sums[i].len;
if (verbose > 3)
rprintf(FINFO,"chunk[%d] len=%d offset=%.0f sum1=%08x\n",
i,s->sums[i].len,(double)s->sums[i].offset,s->sums[i].sum1);
}
s->flength = offset;
return s;
}
void send_files(struct file_list *flist,int f_out,int f_in)
{
int fd = -1;
struct sum_struct *s;
struct map_struct *buf = NULL;
STRUCT_STAT st;
char fname[MAXPATHLEN];
int i;
struct file_struct *file;
int phase = 0;
extern struct stats stats;
struct stats initial_stats;
extern int write_batch; /* dw */
extern int read_batch; /* dw */
int checksums_match; /* dw */
int buff_len; /* dw */
char buff[CHUNK_SIZE]; /* dw */
int j; /* dw */
int done; /* dw */
if (verbose > 2)
rprintf(FINFO,"send_files starting\n");
while (1) {
int offset=0;
i = read_int(f_in);
if (i == -1) {
if (phase==0 && remote_version >= 13) {
phase++;
csum_length = SUM_LENGTH;
write_int(f_out,-1);
if (verbose > 2)
rprintf(FINFO,"send_files phase=%d\n",phase);
continue;
}
break;
}
if (i < 0 || i >= flist->count) {
rprintf(FERROR,"Invalid file index %d (count=%d)\n",
i, flist->count);
exit_cleanup(RERR_PROTOCOL);
}
file = flist->files[i];
stats.num_transferred_files++;
stats.total_transferred_size += file->length;
fname[0] = 0;
if (file->basedir) {
strlcpy(fname,file->basedir,MAXPATHLEN);
if (strlen(fname) == MAXPATHLEN-1) {
io_error = 1;
rprintf(FERROR, "send_files failed on long-named directory %s\n",
fname);
return;
}
strlcat(fname,"/",MAXPATHLEN);
offset = strlen(file->basedir)+1;
}
strlcat(fname,f_name(file),MAXPATHLEN);
if (verbose > 2)
rprintf(FINFO,"send_files(%d,%s)\n",i,fname);
if (dry_run) {
if (!am_server) {
log_transfer(file, fname+offset);
}
write_int(f_out,i);
continue;
}
initial_stats = stats;
s = receive_sums(f_in);
if (!s) {
io_error = 1;
rprintf(FERROR,"receive_sums failed\n");
return;
}
if (write_batch)
write_batch_csum_info(&i,flist->count,s);
if (!read_batch) {
fd = do_open(fname, O_RDONLY, 0);
if (fd == -1) {
io_error = 1;
rprintf(FERROR,"send_files failed to open %s: %s\n",
fname,strerror(errno));
free_sums(s);
continue;
}
/* map the local file */
if (do_fstat(fd,&st) != 0) {
io_error = 1;
rprintf(FERROR,"fstat failed : %s\n",strerror(errno));
free_sums(s);
close(fd);
return;
}
if (st.st_size > 0) {
buf = map_file(fd,st.st_size);
} else {
buf = NULL;
}
if (verbose > 2)
rprintf(FINFO,"send_files mapped %s of size %.0f\n",
fname,(double)st.st_size);
write_int(f_out,i);
if (write_batch)
write_batch_delta_file((char *)&i,sizeof(i));
write_int(f_out,s->count);
write_int(f_out,s->n);
write_int(f_out,s->remainder);
}
if (verbose > 2)
if (!read_batch)
rprintf(FINFO,"calling match_sums %s\n",fname);
if (!am_server) {
log_transfer(file, fname+offset);
}
set_compression(fname);
if (read_batch) { /* dw */
/* read checksums originally computed on sender side */
read_batch_csum_info(i, s, &checksums_match);
if (checksums_match) {
read_batch_delta_file( (char *) &j, sizeof(int) );
if (j != i) { /* if flist index entries don't match*/
rprintf(FINFO,"index mismatch in send_files\n");
rprintf(FINFO,"read index = %d flist ndx = %d\n",j,i);
close_batch_delta_file();
close_batch_csums_file();
exit_cleanup(1);
}
else {
write_int(f_out,j);
write_int(f_out,s->count);
write_int(f_out,s->n);
write_int(f_out,s->remainder);
done=0;
while (!done) {
read_batch_delta_file( (char *) &buff_len, sizeof(int) );
write_int(f_out,buff_len);
if (buff_len == 0) {
done = 1;
}
else {
if (buff_len > 0) {
read_batch_delta_file(buff, buff_len);
write_buf(f_out,buff,buff_len);
}
}
} /* end while */
read_batch_delta_file( buff, MD4_SUM_LENGTH);
write_buf(f_out, buff, MD4_SUM_LENGTH);
} /* j=i */
} else { /* not checksum match */
rprintf (FINFO,"readbatch & checksums don't match\n");
rprintf (FINFO,"filename=%s is being skipped\n",
fname);
continue;
}
} else {
match_sums(f_out,s,buf,st.st_size);
log_send(file, &initial_stats);
}
if (!read_batch) { /* dw */
if (buf) unmap_file(buf);
close(fd);
}
free_sums(s);
if (verbose > 2)
rprintf(FINFO,"sender finished %s\n",fname);
}
if (verbose > 2)
rprintf(FINFO,"send files finished\n");
match_report();
write_int(f_out,-1);
if (write_batch || read_batch) { /* dw */
close_batch_csums_file();
close_batch_delta_file();
}
}

12
shconfig.in Executable file
View File

@@ -0,0 +1,12 @@
#! /bin/sh
# config.sh.in
# This file is processed by config.status to produce config.status,
# containing autoconf-determined values needed by the test scripts.
ECHO_T="@ECHO_T@"
ECHO_N="@ECHO_N@"
ECHO_C="@ECHO_C@"
export ECHO_T ECHO_N ECHO_C

892
socket.c Normal file
View File

@@ -0,0 +1,892 @@
/* -*- c-file-style: "linux" -*-
rsync -- fast file replication program
Copyright (C) 1992-2001 by Andrew Tridgell <tridge@samba.org>
Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/**
* @file socket.c
*
* Socket functions used in rsync.
*
* This file is now converted to use the new-style getaddrinfo()
* interface, which supports IPv6 but is also supported on recent
* IPv4-only machines. On systems that don't have that interface, we
* emulate it using the KAME implementation.
**/
#include "rsync.h"
static const char default_name[] = "UNKNOWN";
/* Establish a proxy connection on an open socket to a web roxy by
* using the CONNECT method. */
static int establish_proxy_connection(int fd, char *host, int port)
{
char buffer[1024];
char *cp;
snprintf(buffer, sizeof(buffer), "CONNECT %s:%d HTTP/1.0\r\n\r\n", host, port);
if (write(fd, buffer, strlen(buffer)) != (int) strlen(buffer)) {
rprintf(FERROR, "failed to write to proxy: %s\n",
strerror(errno));
return -1;
}
for (cp = buffer; cp < &buffer[sizeof(buffer) - 1]; cp++) {
if (read(fd, cp, 1) != 1) {
rprintf(FERROR, "failed to read from proxy: %s\n",
strerror(errno));
return -1;
}
if (*cp == '\n')
break;
}
if (*cp != '\n')
cp++;
*cp-- = '\0';
if (*cp == '\r')
*cp = '\0';
if (strncmp(buffer, "HTTP/", 5) != 0) {
rprintf(FERROR, "bad response from proxy - %s\n",
buffer);
return -1;
}
for (cp = &buffer[5]; isdigit(*cp) || (*cp == '.'); cp++)
;
while (*cp == ' ')
cp++;
if (*cp != '2') {
rprintf(FERROR, "bad response from proxy - %s\n",
buffer);
return -1;
}
/* throw away the rest of the HTTP header */
while (1) {
for (cp = buffer; cp < &buffer[sizeof(buffer) - 1];
cp++) {
if (read(fd, cp, 1) != 1) {
rprintf(FERROR, "failed to read from proxy: %s\n",
strerror(errno));
return -1;
}
if (*cp == '\n')
break;
}
if ((cp > buffer) && (*cp == '\n'))
cp--;
if ((cp == buffer) && ((*cp == '\n') || (*cp == '\r')))
break;
}
return 0;
}
/**
* Try to set the local address for a newly-created socket. Return -1
* if this fails.
**/
int try_bind_local(int s,
int ai_family, int ai_socktype,
const char *bind_address)
{
int error;
struct addrinfo bhints, *bres_all, *r;
memset(&bhints, 0, sizeof(bhints));
bhints.ai_family = ai_family;
bhints.ai_socktype = ai_socktype;
bhints.ai_flags = AI_PASSIVE;
if ((error = getaddrinfo(bind_address, NULL, &bhints, &bres_all))) {
rprintf(FERROR, RSYNC_NAME ": getaddrinfo %s: %s\n",
bind_address, gai_strerror(error));
return -1;
}
for (r = bres_all; r; r = r->ai_next) {
if (bind(s, r->ai_addr, r->ai_addrlen) == -1)
continue;
return s;
}
/* no error message; there might be some problem that allows
* creation of the socket but not binding, perhaps if the
* machine has no ipv6 address of this name. */
return -1;
}
/**
* Open a socket to a tcp remote host with the specified port .
*
* Based on code from Warren. Proxy support by Stephen Rothwell.
* getaddrinfo() rewrite contributed by KAME.net.
*
* Now that we support IPv6 we need to look up the remote machine's
* address first, using @p af_hint to set a preference for the type
* of address. Then depending on whether it has v4 or v6 addresses we
* try to open a connection.
*
* The loop allows for machines with some addresses which may not be
* reachable, perhaps because we can't e.g. route ipv6 to that network
* but we can get ip4 packets through.
*
* @param bind_address Local address to use. Normally NULL to bind
* the wildcard address.
*
* @param af_hint Address family, e.g. AF_INET or AF_INET6.
**/
int open_socket_out(char *host, int port, const char *bind_address,
int af_hint)
{
int type = SOCK_STREAM;
int error;
int s;
struct addrinfo hints, *res0, *res;
char portbuf[10];
char *h;
int proxied = 0;
char buffer[1024];
char *cp;
/* if we have a RSYNC_PROXY env variable then redirect our
* connetcion via a web proxy at the given address. The format
* is hostname:port */
h = getenv("RSYNC_PROXY");
proxied = (h != NULL) && (*h != '\0');
if (proxied) {
strlcpy(buffer, h, sizeof(buffer));
cp = strchr(buffer, ':');
if (cp == NULL) {
rprintf(FERROR,
"invalid proxy specification: should be HOST:PORT\n");
return -1;
}
*cp++ = '\0';
strcpy(portbuf, cp);
h = buffer;
} else {
snprintf(portbuf, sizeof(portbuf), "%d", port);
h = host;
}
memset(&hints, 0, sizeof(hints));
hints.ai_family = af_hint;
hints.ai_socktype = type;
error = getaddrinfo(h, portbuf, &hints, &res0);
if (error) {
rprintf(FERROR, RSYNC_NAME ": getaddrinfo: %s %s: %s\n",
h, portbuf, gai_strerror(error));
return -1;
}
s = -1;
/* Try to connect to all addresses for this machine until we get
* through. It might e.g. be multi-homed, or have both IPv4 and IPv6
* addresses. We need to create a socket for each record, since the
* address record tells us what protocol to use to try to connect. */
for (res = res0; res; res = res->ai_next) {
s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (s < 0)
continue;
if (bind_address)
if (try_bind_local(s, res->ai_family, type,
bind_address) == -1) {
close(s);
s = -1;
continue;
}
if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
close(s);
s = -1;
continue;
}
if (proxied &&
establish_proxy_connection(s, host, port) != 0) {
close(s);
s = -1;
continue;
} else
break;
}
freeaddrinfo(res0);
if (s < 0) {
rprintf(FERROR, RSYNC_NAME ": failed to connect to %s: %s\n",
h, strerror(errno));
return -1;
}
return s;
}
/**
* Open an outgoing socket, but allow for it to be intercepted by
* $RSYNC_CONNECT_PROG, which will execute a program across a TCP
* socketpair rather than really opening a socket.
*
* We use this primarily in testing to detect TCP flow bugs, but not
* cause security problems by really opening remote connections.
*
* This is based on the Samba LIBSMB_PROG feature.
*
* @param bind_address Local address to use. Normally NULL to get the stack default.
**/
int open_socket_out_wrapped (char *host,
int port,
const char *bind_address,
int af_hint)
{
char *prog;
if ((prog = getenv ("RSYNC_CONNECT_PROG")) != NULL)
return sock_exec (prog);
else
return open_socket_out (host, port, bind_address,
af_hint);
}
/**
* Open a socket of the specified type, port and address for incoming data
*
* Try to be better about handling the results of getaddrinfo(): when
* opening an inbound socket, we might get several address results,
* e.g. for the machine's ipv4 and ipv6 name.
*
* If binding a wildcard, then any one of them should do. If an address
* was specified but it's insufficiently specific then that's not our
* fault.
*
* However, some of the advertized addresses may not work because e.g. we
* don't have IPv6 support in the kernel. In that case go on and try all
* addresses until one succeeds.
*
* @param bind_address Local address to bind, or NULL to allow it to
* default.
**/
static int open_socket_in(int type, int port, const char *bind_address,
int af_hint)
{
int one=1;
int s;
struct addrinfo hints, *all_ai, *resp;
char portbuf[10];
int error;
memset(&hints, 0, sizeof(hints));
hints.ai_family = af_hint;
hints.ai_socktype = type;
hints.ai_flags = AI_PASSIVE;
snprintf(portbuf, sizeof(portbuf), "%d", port);
error = getaddrinfo(bind_address, portbuf, &hints, &all_ai);
if (error) {
rprintf(FERROR, RSYNC_NAME ": getaddrinfo: bind address %s: %s\n",
bind_address, gai_strerror(error));
return -1;
}
/* We may not be able to create the socket, if for example the
* machine knows about IPv6 in the C library, but not in the
* kernel. */
for (resp = all_ai; resp; resp = resp->ai_next) {
s = socket(resp->ai_family, resp->ai_socktype,
resp->ai_protocol);
if (s == -1)
/* See if there's another address that will work... */
continue;
setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
(char *)&one, sizeof one);
/* now we've got a socket - we need to bind it */
if (bind(s, all_ai->ai_addr, all_ai->ai_addrlen) < 0) {
/* Nope, try another */
close(s);
continue;
}
return s;
}
rprintf(FERROR, RSYNC_NAME ": open inbound socket on port %d failed: "
"%s\n",
port,
strerror(errno));
freeaddrinfo(all_ai);
return -1;
}
/*
* Determine if a file descriptor is in fact a socket
*/
int is_a_socket(int fd)
{
int v;
socklen_t l;
l = sizeof(int);
/* Parameters to getsockopt, setsockopt etc are very
* unstandardized across platforms, so don't be surprised if
* there are compiler warnings on e.g. SCO OpenSwerver or AIX.
* It seems they all eventually get the right idea.
*
* Debian says: ``The fifth argument of getsockopt and
* setsockopt is in reality an int [*] (and this is what BSD
* 4.* and libc4 and libc5 have). Some POSIX confusion
* resulted in the present socklen_t. The draft standard has
* not been adopted yet, but glibc2 already follows it and
* also has socklen_t [*]. See also accept(2).''
*
* We now return to your regularly scheduled programming. */
return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0);
}
void start_accept_loop(int port, int (*fn)(int ))
{
int s;
extern char *bind_address;
extern int default_af_hint;
/* open an incoming socket */
s = open_socket_in(SOCK_STREAM, port, bind_address, default_af_hint);
if (s == -1)
exit_cleanup(RERR_SOCKETIO);
/* ready to listen */
if (listen(s, 5) == -1) {
close(s);
exit_cleanup(RERR_SOCKETIO);
}
/* now accept incoming connections - forking a new process
for each incoming connection */
while (1) {
fd_set fds;
int fd;
struct sockaddr_storage addr;
socklen_t addrlen = sizeof addr;
/* close log file before the potentially very long select so
file can be trimmed by another process instead of growing
forever */
log_close();
FD_ZERO(&fds);
FD_SET(s, &fds);
if (select(s+1, &fds, NULL, NULL, NULL) != 1) {
continue;
}
if(!FD_ISSET(s, &fds)) continue;
fd = accept(s,(struct sockaddr *)&addr,&addrlen);
if (fd == -1) continue;
signal(SIGCHLD, SIG_IGN);
/* we shouldn't have any children left hanging around
but I have had reports that on Digital Unix zombies
are produced, so this ensures that they are reaped */
#ifdef WNOHANG
while (waitpid(-1, NULL, WNOHANG) > 0);
#endif
if (fork()==0) {
close(s);
/* open log file in child before possibly giving
up privileges */
log_open();
_exit(fn(fd));
}
close(fd);
}
}
enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
struct
{
char *name;
int level;
int option;
int value;
int opttype;
} socket_options[] = {
{"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
{"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
{"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
#ifdef TCP_NODELAY
{"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
#endif
#ifdef IPTOS_LOWDELAY
{"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
#endif
#ifdef IPTOS_THROUGHPUT
{"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
#endif
#ifdef SO_SNDBUF
{"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
#endif
#ifdef SO_RCVBUF
{"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
#endif
#ifdef SO_SNDLOWAT
{"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
#endif
#ifdef SO_RCVLOWAT
{"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
#endif
#ifdef SO_SNDTIMEO
{"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
#endif
#ifdef SO_RCVTIMEO
{"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
#endif
{NULL,0,0,0,0}};
/****************************************************************************
set user socket options
****************************************************************************/
void set_socket_options(int fd, char *options)
{
char *tok;
if (!options || !*options) return;
options = strdup(options);
if (!options) out_of_memory("set_socket_options");
for (tok=strtok(options, " \t,"); tok; tok=strtok(NULL," \t,")) {
int ret=0,i;
int value = 1;
char *p;
int got_value = 0;
if ((p = strchr(tok,'='))) {
*p = 0;
value = atoi(p+1);
got_value = 1;
}
for (i=0;socket_options[i].name;i++)
if (strcmp(socket_options[i].name,tok)==0)
break;
if (!socket_options[i].name) {
rprintf(FERROR,"Unknown socket option %s\n",tok);
continue;
}
switch (socket_options[i].opttype) {
case OPT_BOOL:
case OPT_INT:
ret = setsockopt(fd,socket_options[i].level,
socket_options[i].option,(char *)&value,sizeof(int));
break;
case OPT_ON:
if (got_value)
rprintf(FERROR,"syntax error - %s does not take a value\n",tok);
{
int on = socket_options[i].value;
ret = setsockopt(fd,socket_options[i].level,
socket_options[i].option,(char *)&on,sizeof(int));
}
break;
}
if (ret != 0)
rprintf(FERROR, "failed to set socket option %s: %s\n", tok,
strerror(errno));
}
free(options);
}
/****************************************************************************
become a daemon, discarding the controlling terminal
****************************************************************************/
void become_daemon(void)
{
int i;
if (fork()) {
_exit(0);
}
/* detach from the terminal */
#ifdef HAVE_SETSID
setsid();
#else
#ifdef TIOCNOTTY
i = open("/dev/tty", O_RDWR);
if (i >= 0) {
ioctl(i, (int) TIOCNOTTY, (char *)0);
close(i);
}
#endif /* TIOCNOTTY */
#endif
/* make sure that stdin, stdout an stderr don't stuff things
up (library functions, for example) */
for (i=0;i<3;i++) {
close(i);
open("/dev/null", O_RDWR);
}
}
/**
* Return the IP addr of the client as a string
**/
char *client_addr(int fd)
{
struct sockaddr_storage ss;
socklen_t length = sizeof ss;
static char addr_buf[100];
static int initialised;
if (initialised) return addr_buf;
initialised = 1;
client_sockaddr(fd, &ss, &length);
getnameinfo((struct sockaddr *)&ss, length,
addr_buf, sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
return addr_buf;
}
static int get_sockaddr_family(const struct sockaddr_storage *ss)
{
return ((struct sockaddr *) ss)->sa_family;
}
/**
* Return the DNS name of the client.
*
* The name is statically cached so that repeated lookups are quick,
* so there is a limit of one lookup per customer.
*
* If anything goes wrong, including the name->addr->name check, then
* we just use "UNKNOWN", so you can use that value in hosts allow
* lines.
**/
char *client_name(int fd)
{
struct sockaddr_storage ss;
socklen_t ss_len = sizeof ss;
static char name_buf[100];
static char port_buf[100];
static int initialised;
if (initialised) return name_buf;
strcpy(name_buf, default_name);
initialised = 1;
client_sockaddr(fd, &ss, &ss_len);
if (!lookup_name(fd, &ss, ss_len, name_buf, sizeof name_buf, port_buf, sizeof port_buf))
check_name(fd, &ss, ss_len, name_buf, port_buf);
return name_buf;
}
/**
* Get the sockaddr for the client.
**/
void client_sockaddr(int fd,
struct sockaddr_storage *ss,
socklen_t *ss_len)
{
if (getpeername(fd, (struct sockaddr *) ss, ss_len)) {
/* FIXME: Can we really not continue? */
rprintf(FERROR, RSYNC_NAME ": getpeername on fd%d failed: %s\n",
fd, strerror(errno));
exit_cleanup(RERR_SOCKETIO);
}
#ifdef INET6
if (get_sockaddr_family(ss) == AF_INET6 &&
IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss)->sin6_addr)) {
/* OK, so ss is in the IPv6 family, but it is really
* an IPv4 address: something like
* "::ffff:10.130.1.2". If we use it as-is, then the
* reverse lookup might fail or perhaps something else
* bad might happen. So instead we convert it to an
* equivalent address in the IPv4 address family. */
struct sockaddr_in6 sin6;
struct sockaddr_in *sin;
memcpy(&sin6, ss, sizeof(sin6));
sin = (struct sockaddr_in *)ss;
memset(sin, 0, sizeof(*sin));
sin->sin_family = AF_INET;
*ss_len = sizeof(struct sockaddr_in);
#ifdef HAVE_SOCKADDR_LEN
sin->sin_len = *ss_len;
#endif
sin->sin_port = sin6.sin6_port;
/* There is a macro to extract the mapped part
* (IN6_V4MAPPED_TO_SINADDR ?), but it does not seem
* to be present in the Linux headers. */
memcpy(&sin->sin_addr, &sin6.sin6_addr.s6_addr[12],
sizeof(sin->sin_addr));
}
#endif
}
/**
* Look up a name from @p ss into @p name_buf.
**/
int lookup_name(int fd, const struct sockaddr_storage *ss,
socklen_t ss_len,
char *name_buf, size_t name_buf_len,
char *port_buf, size_t port_buf_len)
{
int name_err;
/* reverse lookup */
name_err = getnameinfo((struct sockaddr *) ss, ss_len,
name_buf, name_buf_len,
port_buf, port_buf_len,
NI_NAMEREQD | NI_NUMERICSERV);
if (name_err != 0) {
strcpy(name_buf, default_name);
rprintf(FERROR, RSYNC_NAME ": name lookup failed for %s: %s\n",
client_addr(fd),
gai_strerror(name_err));
return name_err;
}
return 0;
}
/* Do a forward lookup on name_buf and make sure it corresponds to ss
* -- otherwise we may be being spoofed. If we suspect we are, then
* we don't abort the connection but just emit a warning. */
int check_name(int fd,
const struct sockaddr_storage *ss,
socklen_t ss_len,
char *name_buf,
const char *port_buf)
{
struct addrinfo hints, *res, *res0;
int error;
int ss_family = get_sockaddr_family(ss);
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_flags = ss_family;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(name_buf, port_buf, &hints, &res0);
if (error) {
rprintf(FERROR,
RSYNC_NAME ": forward name lookup for %s:%s failed: %s\n",
name_buf, port_buf,
gai_strerror(error));
strcpy(name_buf, default_name);
return error;
}
/* We expect that one of the results will be the same as ss. */
for (res = res0; res; res = res->ai_next) {
if (res->ai_family != ss_family) {
rprintf(FERROR,
"check_name: response family %d != %d\n",
res->ai_family, ss_family);
continue;
}
if (res->ai_addrlen != ss_len) {
rprintf(FERROR,
"check_name: addrlen %d != %d\n",
res->ai_addrlen, ss_len);
continue;
}
if (memcmp(res->ai_addr, ss, res->ai_addrlen) == 0) {
rprintf(FERROR,
"check_name: %d bytes of address identical\n",
res->ai_addrlen);
break;
} else{
rprintf(FERROR,
"check_name: %d bytes of address NOT identical\n",
res->ai_addrlen);
}
}
if (!res0) {
/* We hit the end of the list without finding an
* address that was the same as ss. */
rprintf(FERROR, RSYNC_NAME
": no known address for \"%s\": "
"spoofed address?\n",
name_buf);
strcpy(name_buf, default_name);
}
if (res == NULL) {
/* We hit the end of the list without finding an
* address that was the same as ss. */
rprintf(FERROR, RSYNC_NAME
": %s is not a known address for \"%s\": "
"spoofed address?\n",
client_addr(fd),
name_buf);
strcpy(name_buf, default_name);
}
freeaddrinfo(res0);
return 0;
}
/*******************************************************************
this is like socketpair but uses tcp. It is used by the Samba
regression test code
The function guarantees that nobody else can attach to the socket,
or if they do that this function fails and the socket gets closed
returns 0 on success, -1 on failure
the resulting file descriptors are symmetrical
******************************************************************/
static int socketpair_tcp(int fd[2])
{
int listener;
struct sockaddr_in sock;
struct sockaddr_in sock2;
socklen_t socklen = sizeof(sock);
int connect_done = 0;
fd[0] = fd[1] = listener = -1;
memset(&sock, 0, sizeof(sock));
if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
memset(&sock2, 0, sizeof(sock2));
#ifdef HAVE_SOCK_SIN_LEN
sock2.sin_len = sizeof(sock2);
#endif
sock2.sin_family = PF_INET;
bind(listener, (struct sockaddr *)&sock2, sizeof(sock2));
if (listen(listener, 1) != 0) goto failed;
if (getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0) goto failed;
if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
set_nonblocking(fd[1]);
sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) == -1) {
if (errno != EINPROGRESS) goto failed;
} else {
connect_done = 1;
}
if ((fd[0] = accept(listener, (struct sockaddr *)&sock, &socklen)) == -1) goto failed;
close(listener);
if (connect_done == 0) {
if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) != 0
&& errno != EISCONN) goto failed;
}
set_blocking (fd[1]);
/* all OK! */
return 0;
failed:
if (fd[0] != -1) close(fd[0]);
if (fd[1] != -1) close(fd[1]);
if (listener != -1) close(listener);
return -1;
}
/**
* Run a program on a local tcp socket, so that we can talk to it's
* stdin and stdout. This is used to fake a connection to a daemon
* for testing -- not for the normal case of running SSH.
*
* @return a socket which is attached to a subprocess running
* "prog". stdin and stdout are attached. stderr is left attached to
* the original stderr
**/
int sock_exec(const char *prog)
{
int fd[2];
if (socketpair_tcp(fd) != 0) {
rprintf (FERROR, RSYNC_NAME
": socketpair_tcp failed (%s)\n",
strerror(errno));
return -1;
}
if (fork() == 0) {
close(fd[0]);
close(0);
close(1);
dup(fd[1]);
dup(fd[1]);
if (verbose > 3) {
/* Can't use rprintf because we've forked. */
fprintf (stderr,
RSYNC_NAME ": execute socket program \"%s\"\n",
prog);
}
exit (system (prog));
}
close (fd[1]);
return fd[0];
}

286
support/rsyncstats Executable file
View File

@@ -0,0 +1,286 @@
#! /usr/bin/perl
# ---------------------------------------------------------------------------
#
# USAGE: rsyncstats <options>
#
# OPTIONS:
# -f <filename> Use <filename> for the log file
# -h include report on hourly traffic
# -d include report on domain traffic
# -t report on total traffic by section
# -D <domain> report only on traffic from <domain>
# -l <depth> Depth of path detail for sections
# -s <section> Section to report on, For example: -s /pub will report
# only on paths under /pub
#
# This script parses the default logfile format produced by rsync when running
# as a daemon with transfer logging enabled. It is derived from the xferstats
# script that comes with wuftpd
#
# Andrew Tridgell, October 1998
# rsync-bugs@samba.org
#
# ---------------------------------------------------------------------------
# edit the next line to customize for your default log file
$usage_file = "/var/adm/rsyncd.log";
# Edit the following lines for default report settings.
# Entries defined here will be over-ridden by the command line.
$opt_h = 1;
$opt_d = 0;
$opt_t = 1;
$opt_l = 2;
require 'getopts.pl';
&Getopts('f:rahdD:l:s:');
if ($opt_r) { $real = 1;}
if ($opt_a) { $anon = 1;}
if ($real == 0 && $anon == 0) { $anon = 1; }
if ($opt_f) {$usage_file = $opt_f;}
open (LOG,$usage_file) || die "Error opening usage log file: $usage_file\n";
if ($opt_D) {print "Transfer Totals include the '$opt_D' domain only.\n";
print "All other domains are filtered out for this report.\n\n";}
if ($opt_s) {print "Transfer Totals include the '$opt_s' section only.\n";
print "All other sections are filtered out for this report.\n\n";}
line: while (<LOG>) {
@line = split;
$day = $line[0];
$time = $line[1];
$pid = $line[2];
$op = $line[3];
$host = $line[4];
$ip = $line[5];
$module = $line[6];
$user = $line[7];
$file = $line[8];
$bytes = $line[9];
next if ($#line != 9);
next if ($op != "send" && $op != "recv");
$daytime = $day;
$hour = substr($time,0,2);
$file = $module . "/" . $file;
$file =~ s|//|/|mg;
@path = split(/\//, $file);
$pathkey = "";
for ($i=0; $i <= $#path && $i <= $opt_l;$i++) {
$pathkey = $pathkey . "/" . $path[$i];
}
next if (substr($pathkey,0,length("$opt_s")) ne "$opt_s");
$host =~ tr/A-Z/a-z/;
@address = split(/\./, $host);
$domain = $address[$#address];
if ( int($address[0]) > 0 || $#address < 2 )
{ $domain = "unresolved"; }
if ($opt_D) {
next unless (substr($domain,0,length("$opt_D")) eq "$opt_D");
}
# printf ("c=%d day=%s bytes=%d file=%s path=%s\n",
# $#line, $daytime, $bytes, $file, $pathkey);
$xferfiles++; # total files sent
$xfertfiles++; # total files sent
$xferfiles{$daytime}++; # files per day
$groupfiles{$pathkey}++; # per-group accesses
$domainfiles{$domain}++;
$xferbytes{$daytime} += $bytes; # bytes per day
$domainbytes{$domain} += $bytes; # xmit bytes to domain
$xferbytes += $bytes; # total bytes sent
$groupbytes{$pathkey} += $bytes; # per-group bytes sent
$xfertfiles{$hour}++; # files per hour
$xfertbytes{$hour} += $bytes; # bytes per hour
$xfertbytes += $bytes; # total bytes sent
}
close LOG;
@syslist = keys(systemfiles);
@dates = sort datecompare keys(xferbytes);
if ($xferfiles == 0) {die "There was no data to process.\n";}
print "TOTALS FOR SUMMARY PERIOD ", $dates[0], " TO ", $dates[$#dates], "\n\n";
printf ("Files Transmitted During Summary Period %12.0f\n", $xferfiles);
printf ("Bytes Transmitted During Summary Period %12.0f\n", $xferbytes);
printf ("Systems Using Archives %12.0f\n\n", $#syslist+1);
printf ("Average Files Transmitted Daily %12.0f\n",
$xferfiles / ($#dates + 1));
printf ("Average Bytes Transmitted Daily %12.0f\n",
$xferbytes / ($#dates + 1));
format top1 =
Daily Transmission Statistics
Number Of Number of Percent Of Percent Of
Date Files Sent MB Sent Files Sent Bytes Sent
--------------- ---------- ----------- ---------- ----------
.
format line1 =
@<<<<<<<<<<<<<< @>>>>>>>>> @>>>>>>>>>> @>>>>>>> @>>>>>>>
$date, $nfiles, $nbytes/(1024*1024), $pctfiles, $pctbytes
.
$^ = top1;
$~ = line1;
foreach $date ( sort datecompare keys(xferbytes) ) {
$nfiles = $xferfiles{$date};
$nbytes = $xferbytes{$date};
$pctfiles = sprintf("%8.2f", 100*$xferfiles{$date} / $xferfiles);
$pctbytes = sprintf("%8.2f", 100*$xferbytes{$date} / $xferbytes);
write;
}
if ($opt_t) {
format top2 =
Total Transfers from each Archive Section (By bytes)
- Percent -
Archive Section NFiles MB Files Bytes
------------------------------------- ------- ----------- ----- -------
.
format line2 =
@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @>>>>>> @>>>>>>>>>> @>>>> @>>>>
$section, $files, $bytes/(1024*1024), $pctfiles, $pctbytes
.
$| = 1;
$- = 0;
$^ = top2;
$~ = line2;
foreach $section ( sort bytecompare keys(groupfiles) ) {
$files = $groupfiles{$section};
$bytes = $groupbytes{$section};
$pctbytes = sprintf("%8.2f", 100 * $groupbytes{$section} / $xferbytes);
$pctfiles = sprintf("%8.2f", 100 * $groupfiles{$section} / $xferfiles);
write;
}
if ( $xferfiles < 1 ) { $xferfiles = 1; }
if ( $xferbytes < 1 ) { $xferbytes = 1; }
}
if ($opt_d) {
format top3 =
Total Transfer Amount By Domain
Number Of Number of Percent Of Percent Of
Domain Name Files Sent MB Sent Files Sent Bytes Sent
----------- ---------- ------------ ---------- ----------
.
format line3 =
@<<<<<<<<<< @>>>>>>>>> @>>>>>>>>>>> @>>>>>>> @>>>>>>>
$domain, $files, $bytes/(1024*1024), $pctfiles, $pctbytes
.
$- = 0;
$^ = top3;
$~ = line3;
foreach $domain ( sort domnamcompare keys(domainfiles) ) {
if ( $domainsecs{$domain} < 1 ) { $domainsecs{$domain} = 1; }
$files = $domainfiles{$domain};
$bytes = $domainbytes{$domain};
$pctfiles = sprintf("%8.2f", 100 * $domainfiles{$domain} / $xferfiles);
$pctbytes = sprintf("%8.2f", 100 * $domainbytes{$domain} / $xferbytes);
write;
}
}
if ($opt_h) {
format top8 =
Hourly Transmission Statistics
Number Of Number of Percent Of Percent Of
Time Files Sent MB Sent Files Sent Bytes Sent
--------------- ---------- ----------- ---------- ----------
.
format line8 =
@<<<<<<<<<<<<<< @>>>>>>>>> @>>>>>>>>>> @>>>>>>> @>>>>>>>
$hour, $nfiles, $nbytes/(1024*1024), $pctfiles, $pctbytes
.
$| = 1;
$- = 0;
$^ = top8;
$~ = line8;
foreach $hour ( sort keys(xfertbytes) ) {
$nfiles = $xfertfiles{$hour};
$nbytes = $xfertbytes{$hour};
$pctfiles = sprintf("%8.2f", 100*$xfertfiles{$hour} / $xferfiles);
$pctbytes = sprintf("%8.2f", 100*$xfertbytes{$hour} / $xferbytes);
write;
}
}
exit(0);
sub datecompare {
$a gt $b;
}
sub domnamcompare {
$sdiff = length($a) - length($b);
($sdiff < 0) ? -1 : ($sdiff > 0) ? 1 : ($a lt $b) ? -1 : ($a gt $b) ? 1 : 0;
}
sub bytecompare {
$bdiff = $groupbytes{$b} - $groupbytes{$a};
($bdiff < 0) ? -1 : ($bdiff > 0) ? 1 : ($a lt $b) ? -1 : ($a gt $b) ? 1 : 0;
}
sub faccompare {
$fdiff = $fac{$b} - $fac{$a};
($fdiff < 0) ? -1 : ($fdiff > 0) ? 1 : ($a lt $b) ? -1 : ($a gt $b) ? 1 : 0;
}

107
syscall.c
View File

@@ -23,16 +23,22 @@
#include "rsync.h"
extern int dry_run;
extern int read_only;
extern int list_only;
#define CHECK_RO if (read_only || list_only) {errno = EROFS; return -1;}
int do_unlink(char *fname)
{
if (dry_run) return 0;
CHECK_RO
return unlink(fname);
}
int do_symlink(char *fname1, char *fname2)
{
if (dry_run) return 0;
CHECK_RO
return symlink(fname1, fname2);
}
@@ -40,6 +46,7 @@ int do_symlink(char *fname1, char *fname2)
int do_link(char *fname1, char *fname2)
{
if (dry_run) return 0;
CHECK_RO
return link(fname1, fname2);
}
#endif
@@ -47,6 +54,7 @@ int do_link(char *fname1, char *fname2)
int do_lchown(const char *path, uid_t owner, gid_t group)
{
if (dry_run) return 0;
CHECK_RO
return lchown(path, owner, group);
}
@@ -54,6 +62,7 @@ int do_lchown(const char *path, uid_t owner, gid_t group)
int do_mknod(char *pathname, mode_t mode, dev_t dev)
{
if (dry_run) return 0;
CHECK_RO
return mknod(pathname, mode, dev);
}
#endif
@@ -61,12 +70,23 @@ int do_mknod(char *pathname, mode_t mode, dev_t dev)
int do_rmdir(char *pathname)
{
if (dry_run) return 0;
CHECK_RO
return rmdir(pathname);
}
int do_open(char *pathname, int flags, mode_t mode)
{
if (dry_run) return -1;
if (flags != O_RDONLY) {
if (dry_run) return -1;
CHECK_RO
}
#ifdef O_BINARY
/* for Windows */
flags |= O_BINARY;
#endif
/* some systems can't handle a double / */
if (pathname[0] == '/' && pathname[1] == '/') pathname++;
return open(pathname, flags, mode);
}
@@ -74,6 +94,7 @@ int do_open(char *pathname, int flags, mode_t mode)
int do_chmod(const char *path, mode_t mode)
{
if (dry_run) return 0;
CHECK_RO
return chmod(path, mode);
}
#endif
@@ -81,17 +102,95 @@ int do_chmod(const char *path, mode_t mode)
int do_rename(char *fname1, char *fname2)
{
if (dry_run) return 0;
CHECK_RO
return rename(fname1, fname2);
}
int do_mkdir(char *fname, mode_t mode)
{
if (dry_run) return 0;
CHECK_RO
return mkdir(fname, mode);
}
char *do_mktemp(char *template)
/* like mkstemp but forces permissions */
int do_mkstemp(char *template, mode_t perms)
{
if (dry_run) return NULL;
return mktemp(template);
if (dry_run) return -1;
if (read_only) {errno = EROFS; return -1;}
#if defined(HAVE_SECURE_MKSTEMP) && defined(HAVE_FCHMOD)
{
int fd = mkstemp(template);
if (fd == -1) return -1;
if (fchmod(fd, perms) != 0) {
close(fd);
unlink(template);
return -1;
}
return fd;
}
#else
if (!mktemp(template)) return -1;
return do_open(template, O_RDWR|O_EXCL|O_CREAT, perms);
#endif
}
int do_stat(const char *fname, STRUCT_STAT *st)
{
#if HAVE_OFF64_T
return stat64(fname, st);
#else
return stat(fname, st);
#endif
}
#if SUPPORT_LINKS
int do_lstat(const char *fname, STRUCT_STAT *st)
{
#if HAVE_OFF64_T
return lstat64(fname, st);
#else
return lstat(fname, st);
#endif
}
#endif
int do_fstat(int fd, STRUCT_STAT *st)
{
#if HAVE_OFF64_T
return fstat64(fd, st);
#else
return fstat(fd, st);
#endif
}
OFF_T do_lseek(int fd, OFF_T offset, int whence)
{
#if HAVE_OFF64_T
off64_t lseek64();
return lseek64(fd, offset, whence);
#else
return lseek(fd, offset, whence);
#endif
}
#ifdef USE_MMAP
void *do_mmap(void *start, int len, int prot, int flags, int fd, OFF_T offset)
{
#if HAVE_OFF64_T
return mmap64(start, len, prot, flags, fd, offset);
#else
return mmap(start, len, prot, flags, fd, offset);
#endif
}
#endif
char *d_name(struct dirent *di)
{
#if HAVE_BROKEN_READDIR
return (di->d_name - 2);
#else
return di->d_name;
#endif
}

View File

@@ -31,7 +31,7 @@ Imagine you have two files, $A$ and $B$, and you wish to update $B$ to be
the same as $A$. The obvious method is to copy $A$ onto $B$.
Now imagine that the two files are on machines connected by a slow
communications link, for example a dial up IP link. If $A$ is large,
communications link, for example a dialup IP link. If $A$ is large,
copying $A$ onto $B$ will be slow. To make it faster you could
compress $A$ before sending it, but that will usually only gain a
factor of 2 to 4.
@@ -133,7 +133,7 @@ possible offsets within a file in a ``rolling'' fashion, with very
little computation at each point.
Despite its simplicity, this checksum was found to be quite adequate as
a first level check for a match of two file blocks. We have found in
a first-level check for a match of two file blocks. We have found in
practice that the probability of this checksum matching when the
blocks are not equal is quite low. This is important because the much
more expensive strong checksum must be calculated for each block where
@@ -158,16 +158,16 @@ contains a null value if no element of the list has that hash value.
At each offset in the file the 32-bit rolling checksum and its 16-bit
hash are calculated. If the hash table entry for that hash value is
not a null value, the second level check is invoked.
not a null value, the second-level check is invoked.
The second level check involves scanning the sorted checksum list
The second-level check involves scanning the sorted checksum list
starting with the entry pointed to by the hash table entry, looking
for an entry whose 32-bit rolling checksum matches the current value.
The scan terminates when it reaches an entry whose 16-bit hash
differs. If this search finds a match, the third level check is
differs. If this search finds a match, the third-level check is
invoked.
The third level check involves calculating the strong checksum for the
The third-level check involves calculating the strong checksum for the
current offset in the file and comparing it with the strong checksum
value in the current list entry. If the two strong checksums match,
we assume that we have found a block of $A$ which matches a block of
@@ -246,14 +246,14 @@ The columns in the table are as follows:
\begin{description}
\item [block size] The size in bytes of the checksummed blocks.
\item [matches] The number of times a block of $B$ was found in $A$.
\item [tag hits] The number of times the 16 bit hash of the rolling
\item [tag hits] The number of times the 16-bit hash of the rolling
checksum matched a hash of one of the checksums from $B$.
\item [false alarms] The number of times the 32 bit rolling checksum
\item [false alarms] The number of times the 32-bit rolling checksum
matched but the strong checksum didn't.
\item [data] The amount of file data transferred verbatim, in bytes.
\item [written] The total number of bytes written by $\alpha$
\item [written] The total number of bytes written by $\alpha$,
including protocol overheads. This is almost all file data.
\item [read] The total number of bytes read by $\alpha$ including
\item [read] The total number of bytes read by $\alpha$, including
protocol overheads. This is almost all checksum information.
\end{description}
@@ -269,7 +269,7 @@ case. Each pair of checksums consumes 20 bytes: 4 bytes for the
rolling checksum plus 16 bytes for the 128-bit MD4 checksum.
The number of false alarms was less than $1/1000$ of the number of
true matches, indicating that the 32 bit rolling checksum is quite
true matches, indicating that the 32-bit rolling checksum is quite
good at screening out false matches.
The number of tag hits indicates that the second level of the
@@ -305,6 +305,6 @@ diff between the two releases is 4155 lines long totalling 120 kB.
An implementation of rsync which provides a convenient interface
similar to the common UNIX command rcp has been written and is
available for download from ftp://samba.anu.edu.au/pub/rsync.
available for download from http://rsync.samba.org/
\end{document}

173
test.sh Executable file
View File

@@ -0,0 +1,173 @@
#!/bin/sh
# Copyright (C) 1998,1999 Philip Hands <phil@hands.com>
#
# This program is distributable under the terms of the GNU GPL (see COPYING)
#
# This is a simple test script that tests a few rsync
# features to make sure I haven't broken them before a release.
#
#
# check if we are running under debian-test, and change behaviour to suit
if test -n "${DEBIANTEST_LIB}" ; then
# make sure rsync is installed
test -e /usr/bin/rsync || exit 0
. ${DEBIANTEST_LIB}/functions.sh
Debian=1
else
cat <<EOF
This set of tests is not completely portable. It is intended for developers
not for end users. You may experience failures on some platforms that
do not indicate a problem with rsync.
EOF
RSYNC=`pwd`/rsync
runtest() {
echo -n "Test $1: "
eval "$2"
}
printmsg() {
echo ""
echo "**** ${1}^G ****"
echo ""
}
fi
TMP=/tmp/rsync-test.$$
FROM=${TMP}/from
TO=${TMP}/to
F1=text1
LOG=${TMP}/log
mkdir $TMP
mkdir $FROM
mkdir $TO
# set up test data
touch ${FROM}/empty
mkdir ${FROM}/emptydir
ps ax > ${FROM}/pslist
echo -n "This file has no trailing lf" > ${FROM}/nolf
ln -s nolf ${FROM}/nolf-symlink
# Gather some random text. We need files that will exist and be
# publicly readable on all platforms: hopefully this will work.
cat /etc/*tab /etc/services /etc/*.conf /etc/*rc > ${FROM}/${F1}
mkdir ${FROM}/dir
cp ${FROM}/${F1} ${FROM}/dir/
mkdir ${FROM}/dir/subdir
mkdir ${FROM}/dir/subdir/subsubdir
ls -ltr /etc > ${FROM}/dir/subdir/subsubdir/etc-ltr-list
mkdir ${FROM}/dir/subdir/subsubdir2
ls -lt /bin > ${FROM}/dir/subdir/subsubdir2/bin-lt-list
checkit() {
testnum=`expr 0${testnum} + 1`
log=${LOG}.${testnum}
failed=
echo "Running: \"$1\"" >${log}
echo "">>${log}
eval "$1" >>${log} 2>&1
status=$?
if [ $status != 0 ]; then
failed="YES";
fi
echo "-------------">>${log}
echo "check how the files compare with diff:">>${log}
echo "">>${log}
diff -ur $2 $3 >>${log} 2>&1 || failed=YES
echo "-------------">>${log}
echo "check how the directory listings compare with diff:">>${log}
echo "">>${log}
( cd $2 ; ls -laR ) > ${TMP}/ls-from 2>>${log}
( cd $3 ; ls -laR ) > ${TMP}/ls-to 2>>${log}
diff -u ${TMP}/ls-from ${TMP}/ls-to >>${log} 2>&1 || failed=YES
if [ -z "${failed}" ] ; then
test -z "${Debian}" && echo " done."
rm $log
return 0
else
if test -n "${Debian}" ; then
cat ${log}
rm ${log}
else
echo " FAILED (test # ${testnum} status=$status)."
fi
return 1
fi
}
checkforlogs() {
# skip it if we're under debian-test
if test -n "${Debian}" ; then return 0 ; fi
if [ -f $1 ] ; then
cat <<EOF
Failures have occured.
You can find the output of the tests in these files:
$@
Please hit <RETURN>
EOF
read input
else
rm -rf ${TMP}
echo ""
echo "Tests Completed Successfully :-)"
fi
}
# Main script starts here
runtest "basic operation" 'checkit "$RSYNC -av ${FROM}/ ${TO}" ${FROM}/ ${TO}'
ln ${FROM}/pslist ${FROM}/dir
runtest "hard links" 'checkit "$RSYNC -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
rm ${TO}/${F1}
runtest "one file" 'checkit "$RSYNC -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
echo "extra line" >> ${TO}/${F1}
runtest "extra data" 'checkit "$RSYNC -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
cp ${FROM}/${F1} ${TO}/ThisShouldGo
runtest " --delete" 'checkit "$RSYNC --delete -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
LONGDIR=${FROM}/This-is-a-directory-with-a-stupidly-long-name-created-in-an-attempt-to-provoke-an-error-found-in-2.0.11-that-should-hopefully-never-appear-again-if-this-test-does-its-job/This-is-a-directory-with-a-stupidly-long-name-created-in-an-attempt-to-provoke-an-error-found-in-2.0.11-that-should-hopefully-never-appear-again-if-this-test-does-its-job/This-is-a-directory-with-a-stupidly-long-name-created-in-an-attempt-to-provoke-an-error-found-in-2.0.11-that-should-hopefully-never-appear-again-if-this-test-does-its-job
mkdir -p ${LONGDIR}
date > ${LONGDIR}/1
ls -la / > ${LONGDIR}/2
runtest "long paths" 'checkit "$RSYNC --delete -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
if type ssh >/dev/null 2>&1; then
if [ "`ssh -o'BatchMode yes' localhost echo yes 2>/dev/null`" = "yes" ]; then
rm -rf ${TO}
runtest "ssh: basic test" 'checkit "$RSYNC -avH -e ssh --rsync-path=$RSYNC ${FROM}/ localhost:${TO}" ${FROM}/ ${TO}'
mv ${TO}/${F1} ${TO}/ThisShouldGo
runtest "ssh: renamed file" 'checkit "$RSYNC --delete -avH -e ssh --rsync-path=$RSYNC ${FROM}/ localhost:${TO}" ${FROM}/ ${TO}'
else
printmsg "Skipping SSH tests because ssh conection to localhost not authorised"
fi
else
printmsg "Skipping SSH tests because ssh is not in the path"
fi
rm -rf ${TO}
mkdir -p ${FROM}2/dir/subdir
cp -a ${FROM}/dir/subdir/subsubdir ${FROM}2/dir/subdir
cp ${FROM}/dir/* ${FROM}2/dir 2>/dev/null
runtest "excludes" 'checkit "$RSYNC -vv -Hlrt --delete --include /dir/ --include /dir/\* --include /dir/\*/subsubdir --include /dir/\*/subsubdir/\*\* --exclude \*\* ${FROM}/dir ${TO}" ${FROM}2/ ${TO}'
rm -r ${FROM}2
checkforlogs ${LOG}.?

5
testsuite/00-hello.test Normal file
View File

@@ -0,0 +1,5 @@
#! /bin/sh
echo $0 running
"$rsync_bin" --version || exit 1

7
testsuite/README Normal file
View File

@@ -0,0 +1,7 @@
This directory contains automatic test cases for rsync. You can run
them yourself if you want, preferably by doing "make check" in the
top-level source directory. (Not implemented yet.)
They also run automatically on the build farm, and you can see the
results on http://build.samba.org/. That's controlled by the file
./runlist.

32
testsuite/daemon.test Normal file
View File

@@ -0,0 +1,32 @@
#!/bin/sh
# Copyright (C) 2001 by Martin Pool <mbp@samba.org>
# This program is distributable under the terms of the GNU GPL (see
# COPYING)
# We don't really want to start the server listening, because that
# might interfere with the security or operation of the test machine.
# Instead we use the fake-connect feature to dynamically assign a pair
# of ports.
# Having started the server we try some basic operations against it:
# getting a list of module
# listing files in a module
# retrieving a module
# uploading to a module
# checking the log file
# password authentication
# TODO: Put the common framework in a common file, so that we can have
# subtests fail and keep going.
. "$suitedir/rsync.fns"
build_rsyncd_conf
RSYNC_CONNECT_PROG="$rsync_bin --config=$conf --daemon"
export RSYNC_CONNECT_PROG
$rsync_bin -v localhost::

57
testsuite/duplicates.test Normal file
View File

@@ -0,0 +1,57 @@
#! /bin/sh
# Copyright (C) 2002 by Martin Pool <mbp@samba.org>
# This program is distributable under the terms of the GNU GPL see
# COPYING).
# Test rsync handling of duplicate filenames.
# It's quite possible that the user might specify the same source file
# more than once on the command line, perhaps through shell variables
# or wildcard expansions. It might cause problems for rsync if the
# same name occurred more than once in the file list, because we might
# be trying to update the first copy and generate checksums for the
# second copy at the same time. See clean_flist() for the implementation.
# We don't need to worry about hardlinks or symlinks. Because we
# always rename-and-replace the new copy, they can't affect us.
# This test is not great, because it is a timing-dependent bug.
. $srcdir/testsuite/rsync.fns
echo "SKIP THIS FOR NOW; It's a known bug"
exit 77
set -x
# Build some hardlinks
fromdir="$scratchdir/from"
todir="$scratchdir/to"
mkdir "$fromdir"
name1="$fromdir/name1"
name2="$fromdir/name2"
echo "This is the file" > "$name1"
ln -s "$name1" "$name2" || fail "can't create symlink"
outfile="$scratchdir/rsync.out"
checkit "rsync -avv \"$fromdir/\" \"$fromdir/\" \"$fromdir/\" \"$fromdir/\" \"$fromdir/\" \"$fromdir/\" \"$fromdir/\" \"$fromdir/\" \"$fromdir/\" \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir" \
| tee "$outfile"
# Make sure each file was only copied once...
if [ `grep -c '^name1$' "$outfile"` != 1 ]
then
test_xfail "name1 was not copied exactly once"
fi
if [ `grep -c '^name2$' "$outfile"` != 1 ]
then
test_xfail "name2 was not copied exactly once"
fi
exit 0
# last [] may have failed but if we get here then we've won

30
testsuite/hands.test Normal file
View File

@@ -0,0 +1,30 @@
#!/bin/sh
# Copyright (C) 1998,1999 Philip Hands <phil@hands.com>
# Copyright (C) 2001 by Martin Pool <mbp@samba.org>
#
# This program is distributable under the terms of the GNU GPL (see COPYING)
. "$suitedir/rsync.fns"
hands_setup
# Main script starts here
runtest "basic operation" 'checkit "$RSYNC -av ${FROM}/ ${TO}" ${FROM}/ ${TO}'
ln ${FROM}/filelist ${FROM}/dir
runtest "hard links" 'checkit "$RSYNC -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
rm ${TO}/text
runtest "one file" 'checkit "$RSYNC -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
echo "extra line" >> ${TO}/text
runtest "extra data" 'checkit "$RSYNC -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
cp ${FROM}/text ${TO}/ThisShouldGo
runtest " --delete" 'checkit "$RSYNC --delete -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
checkforlogs ${LOG}.?
hands_cleanup

38
testsuite/hardlinks.test Normal file
View File

@@ -0,0 +1,38 @@
#! /bin/sh
# Copyright (C) 2002 by Martin Pool <mbp@samba.org>
# This program is distributable under the terms of the GNU GPL (see
# COPYING).
# Test rsync handling of hardlinks. By default (in 2.5.1) rsync does
# not detect symlinks and they get split into different files. If you
# specify -H, then hard links are detected and recreated as hardlinks
# on the other end.
. $srcdir/testsuite/rsync.fns
set -x
# Build some hardlinks
fromdir="$scratchdir/from"
todir="$scratchdir/to"
# TODO: Need to test whether hardlinks are possible on this OS/filesystem
mkdir "$fromdir"
name1="$fromdir/name1"
name2="$fromdir/name2"
name3="$fromdir/name3"
name4="$fromdir/name4"
echo "This is the file" > "$name1"
ln "$name1" "$name2" || fail "Can't create hardlink"
ln "$name2" "$name3" || fail "Can't create hardlink"
cp "$name2" "$name4" || fail "Can't copy file"
checkit "rsync -aHvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
exit 0
# last [] may have failed but if we get here then we've won

19
testsuite/longdir.test Normal file
View File

@@ -0,0 +1,19 @@
#!/bin/sh
# Copyright (C) 1998,1999 Philip Hands <phil@hands.com>
# Copyright (C) 2001 by Martin Pool <mbp@samba.org>
#
# This program is distributable under the terms of the GNU GPL (see COPYING)
. "$suitedir/rsync.fns"
# set -x
hands_setup
LONGDIR=${FROM}/This-is-a-directory-with-a-stupidly-long-name-created-in-an-attempt-to-provoke-an-error-found-in-2.0.11-that-should-hopefully-never-appear-again-if-this-test-does-its-job/This-is-a-directory-with-a-stupidly-long-name-created-in-an-attempt-to-provoke-an-error-found-in-2.0.11-that-should-hopefully-never-appear-again-if-this-test-does-its-job/This-is-a-directory-with-a-stupidly-long-name-created-in-an-attempt-to-provoke-an-error-found-in-2.0.11-that-should-hopefully-never-appear-again-if-this-test-does-its-job
makepath ${LONGDIR}
date > ${LONGDIR}/1
ls -la / > ${LONGDIR}/2
checkit "$RSYNC --delete -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}

234
testsuite/rsync.fns Normal file
View File

@@ -0,0 +1,234 @@
#! /bin/sh
# Copyright (C) 2001 by Martin Pool <mbp@samba.org>
# General-purpose test functions for rsync.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version
# 2 as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
TMP="$scratchdir"
FROM=${TMP}/from
TO=${TMP}/to
LOG=${TMP}/log
RSYNC="$rsync_bin"
runtest() {
echo $ECHO_N "Test $1: $ECHO_C"
if eval "$2"
then
echo "${ECHO_T} done."
return 0
else
echo "${ECHO_T} failed!"
return 1
fi
}
printmsg() {
echo "$1"
}
rsync_ls_lR() {
find "$@" -print | sort | xargs $TLS
}
####################
# Build test directories TO and FROM, with FROM full of files.
hands_setup() {
# Clean before creation
rm -rf $FROM
rm -rf $TO
[ -d $TMP ] || mkdir $TMP
[ -d $FROM ] || mkdir $FROM
[ -d $TO ] || mkdir $TO
# On some BSD systems, the umask affects the mode of created
# symlinks, even though the mode apparently has no effect on how
# the links behave in the future, and it cannot be changed using
# chmod! rsync always sets its umask to 000 so that it can
# accurately recreate permissions, but this script is probably run
# with a different umask.
# This causes a little problem that "ls -l" of the two will not be
# the same. So, we need to set our umask before doing any creations.
# set up test data
touch ${FROM}/empty
mkdir ${FROM}/emptydir
# a hundred lines of text or so
rsync_ls_lR "${srcdir}" > ${FROM}/filelist
# This might fail on systems that don't have -n
echo $ECHO_N "This file has no trailing lf$ECHO_C" > ${FROM}/nolf
umask 0
ln -s nolf ${FROM}/nolf-symlink
umask 022
cat $srcdir/*.c > ${FROM}/text
mkdir ${FROM}/dir
cp ${FROM}/text ${FROM}/dir
mkdir ${FROM}/dir/subdir
mkdir ${FROM}/dir/subdir/subsubdir
ls -ltr /etc > ${FROM}/dir/subdir/subsubdir/etc-ltr-list
mkdir ${FROM}/dir/subdir/subsubdir2
ls -lt /bin > ${FROM}/dir/subdir/subsubdir2/bin-lt-list
# echo testing head:
# ls -lR ${srcdir} | head -10 || echo failed
}
hands_cleanup() {
rm -r "$TMP"
}
####################
# Many machines do not have "mkdir -p", so we have to build up long paths.
# How boring.
makepath () {
echo " makepath $1"
p="$1"
(
# Absolut Unix.
if echo $p | grep '^/' >/dev/null
then
cd /
fi
# This will break if $1 contains a space.
for c in `echo $p | tr '/' ' '`
do
if [ -d "$c" ] || mkdir "$c"
then
cd "$c" || return $?
else
echo "failed to create $c" >&2; return $?
fi
done
)
}
###########################
# Run a test (in '$1') then compare directories $2 and $3 to see if
# there are any difference. If there are, explain them.
checkit() {
failed=
# We can just write everything to stdout/stderr, because the
# wrapper hides it unless there is a problem.
echo "Running: \"$1\""
eval "$1"
status=$?
if [ $status != 0 ]; then
failed="YES";
fi
echo "-------------"
echo "check how the files compare with diff:"
echo ""
diff -cr $2 $3 || failed=YES
echo "-------------"
echo "check how the directory listings compare with diff:"
echo ""
( cd "$2" && rsync_ls_lR . ) > ${TMP}/ls-from
( cd "$3" && rsync_ls_lR . ) > ${TMP}/ls-to
diff -c ${TMP}/ls-from ${TMP}/ls-to || failed=YES
if [ -z "${failed}" ] ; then
return 0
else
return 1
fi
}
# In fact, we need a more general feature of capturing all stderr/log files,
# and dumping them if something goes wrong.
checkforlogs() {
# skip it if we're under debian-test
if test -n "${Debian}" ; then return 0 ; fi
if [ -f $1 -a -s $1 ] ; then
echo "Failures have occurred. $1 follows:" >&2
cat $1 >&2
exit 1
fi
}
build_rsyncd_conf() {
# Build an appropriate configuration file
conf="$scratchdir/test-rsyncd.conf"
echo "building configuration $conf"
port=2612
pidfile="$scratchdir/rsyncd.pid"
logfile="$scratchdir/rsyncd.log"
cat >$conf <<EOF
# rsyncd configuration file autogenerated by $0
pid file = $pidfile
use chroot = no
hosts allow = localhost, 127.0.0.1
log file = $logfile
[test-from] = $scratchdir/daemon-from/
read only = yes
[test-to] = $scratchdir/daemon-to/
read only = no
EOF
}
build_symlinks() {
fromdir="$scratchdir/from"
todir="$scratchdir/to"
mkdir "$fromdir"
date >"$fromdir/referent"
ln -s referent "$fromdir/relative"
ln -s "$fromdir/referent" "$fromdir/absolute"
ln -s nonexistent "$fromdir/dangling"
ln -s "$srcdir/rsync.c" "$fromdir/unsafe"
}
test_fail() {
echo "$@" >&2
exit 1
}
# It failed, but we expected that. don't dump out error logs,
# because most users won't want to see them. But do leave
# the working directory around.
test_xfail() {
echo "$@" >&2
exit 78
}
# be reproducible
umask 077

33
testsuite/ssh-basic.test Normal file
View File

@@ -0,0 +1,33 @@
#!/bin/sh
# Copyright (C) 1998,1999 Philip Hands <phil@hands.com>
# Copyright (C) 2001 by Martin Pool <mbp@samba.org>
# This program is distributable under the terms of the GNU GPL (see
# COPYING)
# This script tests ssh, if possible. It's called by runtests.sh
. "$suitedir/rsync.fns"
if [ "x$rsync_enable_ssh_tests" != xyes ]
then
echo "Skipping SSH tests because \$rsync_enable_ssh_tests is not set"
exit 77
fi
if ! type ssh >/dev/null ; then
echo "Skipping SSH tests because ssh is not in the path"
exit 77
fi
if ! [ "`ssh -o'BatchMode yes' localhost echo yes`" = "yes" ]; then
echo "Skipping SSH tests because ssh conection to localhost not authorised"
exit 77
fi
runtest "ssh: basic test" 'checkit "$RSYNC -avH -e ssh --rsync-path=$RSYNC ${FROM}/ localhost:${TO}" ${FROM}/ ${TO}'
mv ${TO}/${F1} ${TO}/ThisShouldGo
runtest "ssh: renamed file" 'checkit "$RSYNC --delete -avH -e ssh --rsync-path=$RSYNC ${FROM}/ localhost:${TO}" ${FROM}/ ${TO}'

View File

@@ -0,0 +1,29 @@
#! /bin/sh
# Copyright (C) 2001 by Martin Pool <mbp@samba.org>
# This program is distributable under the terms of the GNU GPL (see
# COPYING).
# Test rsync's somewhat over-featured symlink control: the default
# behaviour is that symlinks should not be copied at all.
. $srcdir/testsuite/rsync.fns
set -x
build_symlinks || test_fail "failed to build symlinks"
# Copy recursively, but without -l or -L or -a, and all the symlinks
# should be missing.
"$rsync_bin" -r "$fromdir/" "$todir" || test_fail "rsync returned $?"
[ -f "${todir}/referent" ] || test_fail "referent was not copied"
[ -d "${todir}/from" ] && test_fail "extra level of directories"
[ -L "${todir}/dangling" ] && test_fail "dangling symlink was copied"
[ -L "${todir}/relative" ] && test_fail "relative symlink was copied"
[ -L "${todir}/absolute" ] && test_fail "absolute symlink was copied"
exit 0
# last [] may have failed but if we get here then we've one

141
tls.c Normal file
View File

@@ -0,0 +1,141 @@
/* -*- c-file-style: "linux" -*-
*
* Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/**
* \section tls
*
* tls -- Trivial recursive ls, for comparing two directories after
* running an rsync.
*
* The problem with using the system's own ls is that some features
* have little quirks that make directories look different when for
* our purposes they're the same -- for example, the BSD braindamage
* about setting the mode on symlinks based on your current umask.
*
* All the filenames must be given on the command line -- tls does not
* even read directories, let alone recurse. The typical usage is
* "find|sort|xargs tls".
*
* The format is not exactly the same as any particular Unix ls(1).
*
* A key requirement for this program is that the output be "very
* reproducible." So we mask away information that can accidentally
* change.
**/
#include "rsync.h"
#define PROGRAM "tls"
/* These are to make syscall.o shut up. */
int dry_run = 0;
int read_only = 1;
int list_only = 0;
static void failed (char const *what,
char const *where)
{
fprintf (stderr, PROGRAM ": %s %s: %s\n",
what, where, strerror (errno));
exit (1);
}
static void list_file (const char *fname)
{
struct stat buf;
char permbuf[PERMSTRING_SIZE];
struct tm *mt;
char datebuf[50];
char linkbuf[4096];
if (do_lstat(fname, &buf) == -1)
failed ("stat", fname);
/* The size of anything but a regular file is probably not
* worth thinking about. */
if (!S_ISREG(buf.st_mode))
buf.st_size = 0;
/* On some BSD platforms the mode bits of a symlink are
* undefined. Also it tends not to be possible to reset a
* symlink's mtime, so we have to ignore it too. */
if (S_ISLNK(buf.st_mode)) {
int len;
buf.st_mode &= ~0777;
buf.st_mtime = (time_t)0;
buf.st_uid = buf.st_gid = 0;
strcpy(linkbuf, " -> ");
/* const-cast required for silly UNICOS headers */
len = readlink((char *) fname, linkbuf+4, sizeof(linkbuf) - 4);
if (len == -1)
failed("readlink", fname);
else
/* it's not nul-terminated */
linkbuf[4+len] = 0;
} else {
linkbuf[0] = 0;
}
permstring(permbuf, buf.st_mode);
if (buf.st_mtime) {
mt = gmtime(&buf.st_mtime);
sprintf(datebuf, "%04d-%02d-%02d %02d:%02d:%02d",
mt->tm_year + 1900,
mt->tm_mon + 1,
mt->tm_mday,
mt->tm_hour,
mt->tm_min,
mt->tm_sec);
} else {
strcpy(datebuf, " ");
}
/* TODO: Perhaps escape special characters in fname? */
/* NB: need to pass size as a double because it might be be
* too large for a long. */
printf("%s %12.0f %6d.%-6d %6d %s %s%s\n",
permbuf, (double) buf.st_size,
buf.st_uid, buf.st_gid,
buf.st_nlink,
datebuf, fname, linkbuf);
}
int main (int argc, char *argv[])
{
if (argc < 2) {
fprintf (stderr, "usage: " PROGRAM " DIR ...\n"
"Trivial file listing program for portably checking rsync\n");
return 1;
}
for (argv++; *argv; argv++) {
list_file (*argv);
}
return 0;
}

648
token.c
View File

@@ -18,68 +18,105 @@
*/
#include "rsync.h"
#include "lib/zlib.h"
#include "zlib/zlib.h"
extern int do_compression;
static int compression_level = Z_DEFAULT_COMPRESSION;
/* determine the compression level based on a wildcard filename list */
void set_compression(char *fname)
{
extern int module_id;
char *dont;
char *tok;
if (!do_compression) return;
compression_level = Z_DEFAULT_COMPRESSION;
dont = lp_dont_compress(module_id);
if (!dont || !*dont) return;
if ((dont[0] == '*') && (!dont[1])) {
/* an optimization to skip the rest of this routine */
compression_level = 0;
return;
}
dont = strdup(dont);
fname = strdup(fname);
if (!dont || !fname) return;
strlower(dont);
strlower(fname);
for (tok=strtok(dont," ");tok;tok=strtok(NULL," ")) {
if (fnmatch(tok, fname, 0) == 0) {
compression_level = 0;
break;
}
}
free(dont);
free(fname);
}
/* non-compressing recv token */
static int simple_recv_token(int f,char **data)
{
static int residue;
static char *buf;
int n;
static int residue;
static char *buf;
int n;
if (!buf) {
buf = (char *)malloc(CHUNK_SIZE);
if (!buf) out_of_memory("simple_recv_token");
}
if (!buf) {
buf = (char *)malloc(CHUNK_SIZE);
if (!buf) out_of_memory("simple_recv_token");
}
if (residue == 0) {
int i = read_int(f);
if (i <= 0) return i;
residue = i;
}
if (residue == 0) {
int i = read_int(f);
if (i <= 0) return i;
residue = i;
}
*data = buf;
n = MIN(CHUNK_SIZE,residue);
residue -= n;
read_buf(f,buf,n);
return n;
*data = buf;
n = MIN(CHUNK_SIZE,residue);
residue -= n;
read_buf(f,buf,n);
return n;
}
/* non-compressing send token */
static void simple_send_token(int f,int token,
struct map_struct *buf,int offset,int n)
struct map_struct *buf,OFF_T offset,int n)
{
if (n > 0) {
int l = 0;
while (l < n) {
int n1 = MIN(CHUNK_SIZE,n-l);
write_int(f,n1);
write_buf(f,map_ptr(buf,offset+l,n1),n1);
l += n1;
}
}
write_int(f,-(token+1));
extern int write_batch; /* dw */
int hold_int; /* dw */
if (n > 0) {
int l = 0;
while (l < n) {
int n1 = MIN(CHUNK_SIZE,n-l);
write_int(f,n1);
write_buf(f,map_ptr(buf,offset+l,n1),n1);
if (write_batch) {
write_batch_delta_file( (char *) &n1, sizeof(int) );
write_batch_delta_file(map_ptr(buf,offset+l,n1),n1);
}
l += n1;
}
}
/* a -2 token means to send data only and no token */
if (token != -2) {
write_int(f,-(token+1));
if (write_batch) {
hold_int = -(token+1);
write_batch_delta_file( (char *) &hold_int, sizeof(int) );
}
}
}
/* Memory allocation/freeing routines, called by zlib stuff. */
static void *
z_alloc(void *opaque, uInt items, uInt size)
{
return malloc(items * size);
}
static void
z_free(void *opaque, void *adrs, uInt nbytes)
{
free(adrs);
}
/* Flag bytes in compressed stream are encoded as follows: */
#define END_FLAG 0 /* that's all folks */
#define TOKEN_LONG 0x20 /* followed by 32-bit token number */
@@ -104,102 +141,153 @@ static char *obuf;
/* Send a deflated token */
static void
send_deflated_token(int f, int token,
struct map_struct *buf, int offset, int nb, int toklen)
struct map_struct *buf, OFF_T offset, int nb, int toklen)
{
int n, r;
static int init_done;
int n, r;
static int init_done, flush_pending;
extern int write_batch; /* dw */
char temp_byte; /* dw */
if (last_token == -1) {
/* initialization */
if (!init_done) {
tx_strm.next_in = NULL;
tx_strm.zalloc = z_alloc;
tx_strm.zfree = z_free;
if (deflateInit2(&tx_strm, Z_DEFAULT_COMPRESSION, 8,
-15, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
fprintf(FERROR, "compression init failed\n");
exit_cleanup(1);
}
if ((obuf = malloc(MAX_DATA_COUNT+2)) == NULL)
out_of_memory("send_deflated_token");
init_done = 1;
} else
deflateReset(&tx_strm);
run_start = token;
last_run_end = 0;
if (last_token == -1) {
/* initialization */
if (!init_done) {
tx_strm.next_in = NULL;
tx_strm.zalloc = NULL;
tx_strm.zfree = NULL;
if (deflateInit2(&tx_strm, compression_level,
Z_DEFLATED, -15, 8,
Z_DEFAULT_STRATEGY) != Z_OK) {
rprintf(FERROR, "compression init failed\n");
exit_cleanup(RERR_STREAMIO);
}
if ((obuf = malloc(MAX_DATA_COUNT+2)) == NULL)
out_of_memory("send_deflated_token");
init_done = 1;
} else
deflateReset(&tx_strm);
last_run_end = 0;
run_start = token;
flush_pending = 0;
} else if (nb != 0 || token != last_token + 1
|| token >= run_start + 65536) {
/* output previous run */
r = run_start - last_run_end;
n = last_token - run_start;
if (r >= 0 && r <= 63) {
write_byte(f, (n==0? TOKEN_REL: TOKENRUN_REL) + r);
} else {
write_byte(f, (n==0? TOKEN_LONG: TOKENRUN_LONG));
write_int(f, run_start);
}
if (n != 0) {
write_byte(f, n);
write_byte(f, n >> 8);
}
last_run_end = last_token;
run_start = token;
}
} else if (last_token == -2) {
run_start = token;
last_token = token;
if (nb != 0) {
/* deflate the data starting at offset */
tx_strm.avail_in = 0;
tx_strm.avail_out = 0;
do {
if (tx_strm.avail_in == 0 && nb != 0) {
/* give it some more input */
n = MIN(nb, CHUNK_SIZE);
tx_strm.next_in = (Bytef *)map_ptr(buf, offset, n);
tx_strm.avail_in = n;
nb -= n;
offset += n;
}
if (tx_strm.avail_out == 0) {
tx_strm.next_out = (Bytef *)(obuf + 2);
tx_strm.avail_out = MAX_DATA_COUNT;
}
r = deflate(&tx_strm, nb? Z_NO_FLUSH: Z_PACKET_FLUSH);
if (r != Z_OK) {
fprintf(FERROR, "deflate returned %d\n", r);
exit_cleanup(1);
}
if (nb == 0 || tx_strm.avail_out == 0) {
n = MAX_DATA_COUNT - tx_strm.avail_out;
if (n > 0) {
obuf[0] = DEFLATED_DATA + (n >> 8);
obuf[1] = n;
write_buf(f, obuf, n+2);
} else if (nb != 0 || token != last_token + 1
|| token >= run_start + 65536) {
/* output previous run */
r = run_start - last_run_end;
n = last_token - run_start;
if (r >= 0 && r <= 63) {
write_byte(f, (n==0? TOKEN_REL: TOKENRUN_REL) + r);
if (write_batch) { /* dw */
temp_byte = (char)( (n==0? TOKEN_REL: TOKENRUN_REL) + r);
write_batch_delta_file(&temp_byte,sizeof(char));
}
} else {
write_byte(f, (n==0? TOKEN_LONG: TOKENRUN_LONG));
write_int(f, run_start);
if (write_batch) { /* dw */
temp_byte = (char)(n==0? TOKEN_LONG: TOKENRUN_LONG);
write_batch_delta_file(&temp_byte,sizeof(temp_byte));
write_batch_delta_file((char *)&run_start,sizeof(run_start));
}
}
}
} while (nb != 0 || tx_strm.avail_out == 0);
}
if (token != -1) {
/* add the data in the current block to the compressor's
history and hash table */
tx_strm.next_in = (Bytef *)map_ptr(buf, offset, toklen);
tx_strm.avail_in = toklen;
tx_strm.next_out = NULL;
tx_strm.avail_out = 2 * toklen;
r = deflate(&tx_strm, Z_INSERT_ONLY);
if (r != Z_OK || tx_strm.avail_in != 0) {
fprintf(FERROR, "deflate on token returned %d (%d bytes left)\n",
r, tx_strm.avail_in);
exit_cleanup(1);
if (n != 0) {
write_byte(f, n);
write_byte(f, n >> 8);
if (write_batch) { /* dw */
write_batch_delta_file((char *)&n,sizeof(char));
temp_byte = (char) n >> 8;
write_batch_delta_file(&temp_byte,sizeof(temp_byte));
}
}
last_run_end = last_token;
run_start = token;
}
} else {
/* end of file - clean up */
write_byte(f, END_FLAG);
}
last_token = token;
if (nb != 0 || flush_pending) {
/* deflate the data starting at offset */
int flush = Z_NO_FLUSH;
tx_strm.avail_in = 0;
tx_strm.avail_out = 0;
do {
if (tx_strm.avail_in == 0 && nb != 0) {
/* give it some more input */
n = MIN(nb, CHUNK_SIZE);
tx_strm.next_in = (Bytef *)
map_ptr(buf, offset, n);
tx_strm.avail_in = n;
nb -= n;
offset += n;
}
if (tx_strm.avail_out == 0) {
tx_strm.next_out = (Bytef *)(obuf + 2);
tx_strm.avail_out = MAX_DATA_COUNT;
if (flush != Z_NO_FLUSH) {
/*
* We left the last 4 bytes in the
* buffer, in case they are the
* last 4. Move them to the front.
*/
memcpy(tx_strm.next_out,
obuf+MAX_DATA_COUNT-2, 4);
tx_strm.next_out += 4;
tx_strm.avail_out -= 4;
}
}
if (nb == 0 && token != -2)
flush = Z_SYNC_FLUSH;
r = deflate(&tx_strm, flush);
if (r != Z_OK) {
rprintf(FERROR, "deflate returned %d\n", r);
exit_cleanup(RERR_STREAMIO);
}
if (nb == 0 || tx_strm.avail_out == 0) {
n = MAX_DATA_COUNT - tx_strm.avail_out;
if (flush != Z_NO_FLUSH) {
/*
* We have to trim off the last 4
* bytes of output when flushing
* (they are just 0, 0, ff, ff).
*/
n -= 4;
}
if (n > 0) {
obuf[0] = DEFLATED_DATA + (n >> 8);
obuf[1] = n;
write_buf(f, obuf, n+2);
if (write_batch) /* dw */
write_batch_delta_file(obuf,n+2);
}
}
} while (nb != 0 || tx_strm.avail_out == 0);
flush_pending = token == -2;
}
if (token == -1) {
/* end of file - clean up */
write_byte(f, END_FLAG);
if (write_batch) { /* dw */
temp_byte = END_FLAG;
write_batch_delta_file((char *)&temp_byte,sizeof(temp_byte));
}
} else if (token != -2) {
/* add the data in the current block to the compressor's
history and hash table */
tx_strm.next_in = (Bytef *) map_ptr(buf, offset, toklen);
tx_strm.avail_in = toklen;
tx_strm.next_out = (Bytef *) obuf;
tx_strm.avail_out = MAX_DATA_COUNT;
r = deflate(&tx_strm, Z_INSERT_ONLY);
if (r != Z_OK || tx_strm.avail_in != 0) {
rprintf(FERROR, "deflate on token returned %d (%d bytes left)\n",
r, tx_strm.avail_in);
exit_cleanup(RERR_STREAMIO);
}
}
}
@@ -219,131 +307,171 @@ static int rx_run;
static int
recv_deflated_token(int f, char **data)
{
int n, r, flag;
static int init_done;
static int saved_flag;
int n, r, flag;
static int init_done;
static int saved_flag;
for (;;) {
switch (recv_state) {
case r_init:
if (!init_done) {
rx_strm.next_out = NULL;
rx_strm.zalloc = z_alloc;
rx_strm.zfree = z_free;
if (inflateInit2(&rx_strm, -15) != Z_OK) {
fprintf(FERROR, "inflate init failed\n");
exit_cleanup(1);
}
if ((cbuf = malloc(MAX_DATA_COUNT)) == NULL
|| (dbuf = malloc(CHUNK_SIZE)) == NULL)
out_of_memory("recv_deflated_token");
init_done = 1;
} else {
inflateReset(&rx_strm);
}
recv_state = r_idle;
rx_token = 0;
break;
case r_idle:
case r_inflated:
if (saved_flag) {
flag = saved_flag & 0xff;
saved_flag = 0;
} else
flag = read_byte(f);
if ((flag & 0xC0) == DEFLATED_DATA) {
n = ((flag & 0x3f) << 8) + read_byte(f);
read_buf(f, cbuf, n);
rx_strm.next_in = (Bytef *)cbuf;
rx_strm.avail_in = n;
recv_state = r_inflating;
break;
}
if (recv_state == r_inflated) {
/* check previous inflated stuff ended correctly */
rx_strm.avail_in = 0;
rx_strm.next_out = (Bytef *)dbuf;
rx_strm.avail_out = CHUNK_SIZE;
r = inflate(&rx_strm, Z_PACKET_FLUSH);
n = CHUNK_SIZE - rx_strm.avail_out;
if (r != Z_OK) {
fprintf(FERROR, "inflate flush returned %d (%d bytes)\n",
r, n);
exit_cleanup(1);
}
if (n != 0) {
/* have to return some more data and
save the flag for later. */
saved_flag = flag + 0x10000;
if (rx_strm.avail_out != 0)
for (;;) {
switch (recv_state) {
case r_init:
if (!init_done) {
rx_strm.next_out = NULL;
rx_strm.zalloc = NULL;
rx_strm.zfree = NULL;
if (inflateInit2(&rx_strm, -15) != Z_OK) {
rprintf(FERROR, "inflate init failed\n");
exit_cleanup(RERR_STREAMIO);
}
if ((cbuf = malloc(MAX_DATA_COUNT)) == NULL
|| (dbuf = malloc(CHUNK_SIZE)) == NULL)
out_of_memory("recv_deflated_token");
init_done = 1;
} else {
inflateReset(&rx_strm);
}
recv_state = r_idle;
*data = dbuf;
return n;
rx_token = 0;
break;
case r_idle:
case r_inflated:
if (saved_flag) {
flag = saved_flag & 0xff;
saved_flag = 0;
} else
flag = read_byte(f);
if ((flag & 0xC0) == DEFLATED_DATA) {
n = ((flag & 0x3f) << 8) + read_byte(f);
read_buf(f, cbuf, n);
rx_strm.next_in = (Bytef *)cbuf;
rx_strm.avail_in = n;
recv_state = r_inflating;
break;
}
if (recv_state == r_inflated) {
/* check previous inflated stuff ended correctly */
rx_strm.avail_in = 0;
rx_strm.next_out = (Bytef *)dbuf;
rx_strm.avail_out = CHUNK_SIZE;
r = inflate(&rx_strm, Z_SYNC_FLUSH);
n = CHUNK_SIZE - rx_strm.avail_out;
/*
* Z_BUF_ERROR just means no progress was
* made, i.e. the decompressor didn't have
* any pending output for us.
*/
if (r != Z_OK && r != Z_BUF_ERROR) {
rprintf(FERROR, "inflate flush returned %d (%d bytes)\n",
r, n);
exit_cleanup(RERR_STREAMIO);
}
if (n != 0 && r != Z_BUF_ERROR) {
/* have to return some more data and
save the flag for later. */
saved_flag = flag + 0x10000;
*data = dbuf;
return n;
}
/*
* At this point the decompressor should
* be expecting to see the 0, 0, ff, ff bytes.
*/
if (!inflateSyncPoint(&rx_strm)) {
rprintf(FERROR, "decompressor lost sync!\n");
exit_cleanup(RERR_STREAMIO);
}
rx_strm.avail_in = 4;
rx_strm.next_in = (Bytef *)cbuf;
cbuf[0] = cbuf[1] = 0;
cbuf[2] = cbuf[3] = 0xff;
inflate(&rx_strm, Z_SYNC_FLUSH);
recv_state = r_idle;
}
if (flag == END_FLAG) {
/* that's all folks */
recv_state = r_init;
return 0;
}
/* here we have a token of some kind */
if (flag & TOKEN_REL) {
rx_token += flag & 0x3f;
flag >>= 6;
} else
rx_token = read_int(f);
if (flag & 1) {
rx_run = read_byte(f);
rx_run += read_byte(f) << 8;
recv_state = r_running;
}
return -1 - rx_token;
case r_inflating:
rx_strm.next_out = (Bytef *)dbuf;
rx_strm.avail_out = CHUNK_SIZE;
r = inflate(&rx_strm, Z_NO_FLUSH);
n = CHUNK_SIZE - rx_strm.avail_out;
if (r != Z_OK) {
rprintf(FERROR, "inflate returned %d (%d bytes)\n", r, n);
exit_cleanup(RERR_STREAMIO);
}
if (rx_strm.avail_in == 0)
recv_state = r_inflated;
if (n != 0) {
*data = dbuf;
return n;
}
break;
case r_running:
++rx_token;
if (--rx_run == 0)
recv_state = r_idle;
return -1 - rx_token;
}
recv_state = r_idle;
}
if (flag == END_FLAG) {
/* that's all folks */
recv_state = r_init;
return 0;
}
/* here we have a token of some kind */
if (flag & TOKEN_REL) {
rx_token += flag & 0x3f;
flag >>= 6;
} else
rx_token = read_int(f);
if (flag & 1) {
rx_run = read_byte(f);
rx_run += read_byte(f) << 8;
recv_state = r_running;
}
return -1 - rx_token;
case r_inflating:
rx_strm.next_out = (Bytef *)dbuf;
rx_strm.avail_out = CHUNK_SIZE;
r = inflate(&rx_strm, Z_NO_FLUSH);
n = CHUNK_SIZE - rx_strm.avail_out;
if (r != Z_OK) {
fprintf(FERROR, "inflate returned %d (%d bytes)\n", r, n);
exit_cleanup(1);
}
if (rx_strm.avail_in == 0)
recv_state = r_inflated;
if (n != 0) {
*data = dbuf;
return n;
}
break;
case r_running:
++rx_token;
if (--rx_run == 0)
recv_state = r_idle;
return -1 - rx_token;
}
}
}
/*
* put the data corresponding to a token that we've just returned
* from recv_deflated_token into the decompressor's history buffer.
*/
void
see_deflate_token(char *buf, int len)
static void see_deflate_token(char *buf, int len)
{
int r;
int r, blklen;
unsigned char hdr[5];
rx_strm.next_in = (Bytef *)buf;
rx_strm.avail_in = len;
r = inflateIncomp(&rx_strm);
if (r != Z_OK) {
fprintf(FERROR, "inflateIncomp returned %d\n", r);
exit_cleanup(1);
}
rx_strm.avail_in = 0;
blklen = 0;
hdr[0] = 0;
do {
if (rx_strm.avail_in == 0 && len != 0) {
if (blklen == 0) {
/* Give it a fake stored-block header. */
rx_strm.next_in = (Bytef *)hdr;
rx_strm.avail_in = 5;
blklen = len;
if (blklen > 0xffff)
blklen = 0xffff;
hdr[1] = blklen;
hdr[2] = blklen >> 8;
hdr[3] = ~hdr[1];
hdr[4] = ~hdr[2];
} else {
rx_strm.next_in = (Bytef *)buf;
rx_strm.avail_in = blklen;
len -= blklen;
blklen = 0;
}
}
rx_strm.next_out = (Bytef *)dbuf;
rx_strm.avail_out = CHUNK_SIZE;
r = inflate(&rx_strm, Z_SYNC_FLUSH);
if (r != Z_OK) {
rprintf(FERROR, "inflate (token) returned %d\n", r);
exit_cleanup(RERR_STREAMIO);
}
} while (len || rx_strm.avail_out == 0);
}
/*
@@ -351,14 +479,14 @@ see_deflate_token(char *buf, int len)
* If token == -1 then we have reached EOF
* If n == 0 then don't send a buffer
*/
void send_token(int f,int token,struct map_struct *buf,int offset,
void send_token(int f,int token,struct map_struct *buf,OFF_T offset,
int n,int toklen)
{
if (!do_compression) {
simple_send_token(f,token,buf,offset,n);
} else {
send_deflated_token(f, token, buf, offset, n, toklen);
}
if (!do_compression) {
simple_send_token(f,token,buf,offset,n);
} else {
send_deflated_token(f, token, buf, offset, n, toklen);
}
}
@@ -370,14 +498,14 @@ void send_token(int f,int token,struct map_struct *buf,int offset,
*/
int recv_token(int f,char **data)
{
int tok;
int tok;
if (!do_compression) {
tok = simple_recv_token(f,data);
} else {
tok = recv_deflated_token(f, data);
}
return tok;
if (!do_compression) {
tok = simple_recv_token(f,data);
} else {
tok = recv_deflated_token(f, data);
}
return tok;
}
/*
@@ -385,6 +513,6 @@ int recv_token(int f,char **data)
*/
void see_token(char *data, int toklen)
{
if (do_compression)
see_deflate_token(data, toklen);
if (do_compression)
see_deflate_token(data, toklen);
}

Some files were not shown because too many files have changed in this diff Show More