mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-05-25 15:25:30 -04:00
Compare commits
1052 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a6fd4c1c7 | ||
|
|
8395d24616 | ||
|
|
7d085960eb | ||
|
|
3884317181 | ||
|
|
089a2435f8 | ||
|
|
8ed16deb24 | ||
|
|
a577af9067 | ||
|
|
59af13651b | ||
|
|
787568f371 | ||
|
|
f0019fc506 | ||
|
|
9f639210ca | ||
|
|
deec574421 | ||
|
|
04657e42d5 | ||
|
|
1b88775534 | ||
|
|
7f6537557d | ||
|
|
518233ca79 | ||
|
|
bc72130d71 | ||
|
|
855decd3a7 | ||
|
|
0090cbdba6 | ||
|
|
73ff720972 | ||
|
|
c561e1378d | ||
|
|
aa2c47d835 | ||
|
|
536b84680b | ||
|
|
7508b795bf | ||
|
|
76ee1d18bf | ||
|
|
379bc86547 | ||
|
|
066696644f | ||
|
|
755bcd3722 | ||
|
|
1985aa9666 | ||
|
|
f4663a36da | ||
|
|
521e6fdcfc | ||
|
|
61ab574e38 | ||
|
|
660cb6a085 | ||
|
|
4274208833 | ||
|
|
34db05b421 | ||
|
|
1657be22a3 | ||
|
|
3636b9ffaa | ||
|
|
e3cd264571 | ||
|
|
69555b0943 | ||
|
|
522c05cf9a | ||
|
|
f0b4fdaf5e | ||
|
|
ac6ce98375 | ||
|
|
1b3cadaa39 | ||
|
|
61ca7d596c | ||
|
|
688d573295 | ||
|
|
ec6e0bf0c0 | ||
|
|
184dede92f | ||
|
|
d2cc0323fb | ||
|
|
3a1eefd331 | ||
|
|
824f1c7944 | ||
|
|
7bc8218d81 | ||
|
|
a405cda63c | ||
|
|
7afa3a4a48 | ||
|
|
c80b3d8c3f | ||
|
|
ef6122c622 | ||
|
|
75fb17b891 | ||
|
|
2abbf2498f | ||
|
|
b91b50c01f | ||
|
|
06891710f2 | ||
|
|
b765ec32b9 | ||
|
|
a70d070cc5 | ||
|
|
1f1fbe187e | ||
|
|
fc63847406 | ||
|
|
f58677d123 | ||
|
|
7ab1538861 | ||
|
|
7ad0f94de9 | ||
|
|
8af534a52c | ||
|
|
7447419266 | ||
|
|
5216de37a4 | ||
|
|
ccc0d1eb1d | ||
|
|
7fc0890881 | ||
|
|
b17f1d76c0 | ||
|
|
451b5fc969 | ||
|
|
1e678fcab1 | ||
|
|
48bcc6ee2b | ||
|
|
32734c7c3c | ||
|
|
aaf375d0a5 | ||
|
|
9680f811f6 | ||
|
|
bda41fa509 | ||
|
|
7ea84b6890 | ||
|
|
cc234d944a | ||
|
|
ac84096d1f | ||
|
|
a1cc591b29 | ||
|
|
da0405080e | ||
|
|
0c0a3e2dd3 | ||
|
|
ad301e487c | ||
|
|
b5ae4aba38 | ||
|
|
8d2aad49e3 | ||
|
|
bc2b4963a0 | ||
|
|
ee7118a816 | ||
|
|
95dd949c09 | ||
|
|
9326552e66 | ||
|
|
1e34e4b7cd | ||
|
|
06464f55e2 | ||
|
|
1b85e3f1a0 | ||
|
|
eac9dc63e3 | ||
|
|
30e8c8e1e4 | ||
|
|
d53d7795ee | ||
|
|
59c95e4243 | ||
|
|
f8a94f0de8 | ||
|
|
3b5f6214a6 | ||
|
|
542ad675b9 | ||
|
|
1e736b8ff7 | ||
|
|
a6d8c3f336 | ||
|
|
bb4aa89c10 | ||
|
|
09021eabb5 | ||
|
|
8d69d57113 | ||
|
|
eaa4c150ab | ||
|
|
a125c82ad2 | ||
|
|
93eff16a6a | ||
|
|
d2d9fe184d | ||
|
|
2d4ca358db | ||
|
|
39993af514 | ||
|
|
bef4934045 | ||
|
|
1312d9fc47 | ||
|
|
75aeac44e8 | ||
|
|
68f40ebba9 | ||
|
|
973007daac | ||
|
|
8060514230 | ||
|
|
b1a2f37a6e | ||
|
|
7c66b86028 | ||
|
|
cc248aae9b | ||
|
|
ca23c51aeb | ||
|
|
fca9a9b0f0 | ||
|
|
1ea15dbe05 | ||
|
|
8e34cd41f0 | ||
|
|
9ef1cc7cdf | ||
|
|
411acbbc2a | ||
|
|
32e83406c4 | ||
|
|
7e28fca126 | ||
|
|
e4ffb53900 | ||
|
|
7c2d381c28 | ||
|
|
bde47ca7c5 | ||
|
|
ea7f8108b0 | ||
|
|
98393ae2e2 | ||
|
|
759ac87019 | ||
|
|
a1e0e45e01 | ||
|
|
54170a084d | ||
|
|
1bbf83c07d | ||
|
|
ccd2b499ed | ||
|
|
1de50993a7 | ||
|
|
786c36876b | ||
|
|
8bd1a73e14 | ||
|
|
c7d692c3c3 | ||
|
|
f9b9e2f067 | ||
|
|
dafe63ca98 | ||
|
|
f49a7b227f | ||
|
|
f5e4eadb74 | ||
|
|
717eb9b883 | ||
|
|
5ba268efa8 | ||
|
|
25ff30e804 | ||
|
|
bdae761ee1 | ||
|
|
5af50297be | ||
|
|
32f761755e | ||
|
|
c4fea82ff9 | ||
|
|
6ded1170ac | ||
|
|
991f90f296 | ||
|
|
c979dad54a | ||
|
|
136ac7ecec | ||
|
|
3e8369b6dc | ||
|
|
a7dc44d27d | ||
|
|
07a874fd9b | ||
|
|
e35080cede | ||
|
|
ce8149b6fe | ||
|
|
a86179f429 | ||
|
|
56cf38ac98 | ||
|
|
b0f451eb3b | ||
|
|
d0829892c6 | ||
|
|
fdf88d7574 | ||
|
|
595f2d4d97 | ||
|
|
cae95647a4 | ||
|
|
a254fd9798 | ||
|
|
805edf9d7d | ||
|
|
eca2adb4b3 | ||
|
|
4eea7793ea | ||
|
|
67684d038d | ||
|
|
98b332edea | ||
|
|
e681e82066 | ||
|
|
08571358b1 | ||
|
|
8901a07fdb | ||
|
|
880da0072e | ||
|
|
a83600cc82 | ||
|
|
dd0628f85f | ||
|
|
e66dfd1879 | ||
|
|
bf2daeaf2d | ||
|
|
bd0ad74f4b | ||
|
|
79f671cc7c | ||
|
|
0f9c48b1d2 | ||
|
|
538ba24fd7 | ||
|
|
d37d8d7b69 | ||
|
|
f4a0483ab8 | ||
|
|
f5f95a38c4 | ||
|
|
3e7053ac59 | ||
|
|
420ef2c419 | ||
|
|
9fb3f7a9ab | ||
|
|
734a94a20c | ||
|
|
b44be3e944 | ||
|
|
fc0302cf07 | ||
|
|
4fdc39dde8 | ||
|
|
9a933bc2ce | ||
|
|
524dc9afd6 | ||
|
|
e4d709cbf8 | ||
|
|
48c1586cd1 | ||
|
|
7bd0cf5b8f | ||
|
|
fcb69e5cdc | ||
|
|
96557d23a3 | ||
|
|
4e5db0ad4a | ||
|
|
c81a32f071 | ||
|
|
6f2623fd69 | ||
|
|
b4235b3165 | ||
|
|
d25c0e42c7 | ||
|
|
0ecfbf27c3 | ||
|
|
fb4c98c2c8 | ||
|
|
cd8e38b13f | ||
|
|
b35d0d8e9a | ||
|
|
c948e309f2 | ||
|
|
d1f83bcc81 | ||
|
|
e0fde757fd | ||
|
|
25d34a5c80 | ||
|
|
610364e3a6 | ||
|
|
036e70b024 | ||
|
|
ac13ad106a | ||
|
|
bd9e9eccbd | ||
|
|
8ff9d697c9 | ||
|
|
62b68c8046 | ||
|
|
e4724e5c1c | ||
|
|
559e727bf7 | ||
|
|
126642b633 | ||
|
|
cca4e06786 | ||
|
|
2f1faea89b | ||
|
|
3d90ec146f | ||
|
|
1bc209b441 | ||
|
|
1433e6da69 | ||
|
|
f8f4c862e8 | ||
|
|
226df8e717 | ||
|
|
6c92af2067 | ||
|
|
54c7298ce4 | ||
|
|
642a979a27 | ||
|
|
e733c93423 | ||
|
|
ffdb58a51a | ||
|
|
c053133207 | ||
|
|
9098bbf3b3 | ||
|
|
68618b8810 | ||
|
|
e553d27f41 | ||
|
|
d092924c63 | ||
|
|
34027489e0 | ||
|
|
d1239eae92 | ||
|
|
331050969b | ||
|
|
259c3e72b0 | ||
|
|
8f7a38336d | ||
|
|
999dfffc9b | ||
|
|
527a51cec5 | ||
|
|
20c15aead5 | ||
|
|
fb859e5674 | ||
|
|
4f2dcb1714 | ||
|
|
64e74631e0 | ||
|
|
fba31efb74 | ||
|
|
435f1ed70d | ||
|
|
94f34ca10a | ||
|
|
b0633744fa | ||
|
|
c127e8aaec | ||
|
|
bf4e725d5d | ||
|
|
663717f465 | ||
|
|
12b159ac41 | ||
|
|
9299c8f0b4 | ||
|
|
dfef3f1099 | ||
|
|
fa3690f488 | ||
|
|
4acbfa2ade | ||
|
|
ef86d74736 | ||
|
|
118f39d45b | ||
|
|
77867907ed | ||
|
|
98c1b32565 | ||
|
|
7a176e87d5 | ||
|
|
79c9d8a180 | ||
|
|
7d8219327b | ||
|
|
4ac4bdbb38 | ||
|
|
f494f2864c | ||
|
|
017f22b47f | ||
|
|
dec41b556b | ||
|
|
be2961da2c | ||
|
|
914cc65c9d | ||
|
|
6479c2ed3f | ||
|
|
c1a04ecbfd | ||
|
|
69b06c50c4 | ||
|
|
6aaf8d8c10 | ||
|
|
4cf64834ed | ||
|
|
b8709f5046 | ||
|
|
24448f741f | ||
|
|
76533c52dc | ||
|
|
3ff984d7a7 | ||
|
|
7a52790b50 | ||
|
|
7b329a2d79 | ||
|
|
599dc93c64 | ||
|
|
8b54f00466 | ||
|
|
8469faef03 | ||
|
|
bceec82f35 | ||
|
|
ed521de525 | ||
|
|
d157de203a | ||
|
|
1bfbf40bd5 | ||
|
|
6d19c6742c | ||
|
|
a628b06977 | ||
|
|
6b2d24de2c | ||
|
|
e23d790fa7 | ||
|
|
2a5904a580 | ||
|
|
4610ac79c2 | ||
|
|
142f5be922 | ||
|
|
b17dd0c435 | ||
|
|
3669201179 | ||
|
|
a5c48193c7 | ||
|
|
4366275bab | ||
|
|
c579310a00 | ||
|
|
96553aa7ef | ||
|
|
2094283b80 | ||
|
|
4c631ac621 | ||
|
|
d96d3893dd | ||
|
|
b73b51a9e4 | ||
|
|
3c1edccb7b | ||
|
|
b23c290630 | ||
|
|
c7b562becf | ||
|
|
5648a81936 | ||
|
|
daa3d0e2da | ||
|
|
c9a66d41fe | ||
|
|
0ee1bd82c5 | ||
|
|
53e1f937bc | ||
|
|
604f343c49 | ||
|
|
e9c4c3018b | ||
|
|
db1babe6a9 | ||
|
|
f1abcc7a4c | ||
|
|
97e1254a2d | ||
|
|
89b0a3d963 | ||
|
|
3a79260d3a | ||
|
|
43a4dc1053 | ||
|
|
e53fe9a278 | ||
|
|
f5a95bb50b | ||
|
|
0e23e41d48 | ||
|
|
ac69049ec2 | ||
|
|
b2a2dd1154 | ||
|
|
31837783c0 | ||
|
|
d40fb72395 | ||
|
|
1c548d5e59 | ||
|
|
be59d0ec23 | ||
|
|
0bc467516a | ||
|
|
844f11f284 | ||
|
|
1cf1e7b3b4 | ||
|
|
18b72cc829 | ||
|
|
271f87e5d4 | ||
|
|
2e6c7f4549 | ||
|
|
6819304740 | ||
|
|
a795ab99c7 | ||
|
|
567e56313a | ||
|
|
9e95e92bdf | ||
|
|
be60c7b9d1 | ||
|
|
7d81641065 | ||
|
|
17d8573ef0 | ||
|
|
e2dd78f744 | ||
|
|
06b91d8eb9 | ||
|
|
9ec5422c37 | ||
|
|
1935e11c3c | ||
|
|
ec14031abd | ||
|
|
024a9bafbd | ||
|
|
27741d9fd9 | ||
|
|
e3bdb76326 | ||
|
|
9369576459 | ||
|
|
8a405c6ca1 | ||
|
|
94ad1c6477 | ||
|
|
6f039cc2ac | ||
|
|
6216ca2c70 | ||
|
|
c6e27b608e | ||
|
|
f76584a57c | ||
|
|
7bea78ced6 | ||
|
|
1264288cb5 | ||
|
|
0f0ea7f779 | ||
|
|
0b4af330ce | ||
|
|
6dd41b67fb | ||
|
|
1521eefb62 | ||
|
|
a036a0e818 | ||
|
|
7583ded808 | ||
|
|
78818f4465 | ||
|
|
7a49cb5667 | ||
|
|
23212669ac | ||
|
|
3ce0f9a653 | ||
|
|
d834adc14f | ||
|
|
b84ba8967a | ||
|
|
79845f2834 | ||
|
|
78ece130a4 | ||
|
|
bd37c66630 | ||
|
|
371d1c36b3 | ||
|
|
d0f821ad3d | ||
|
|
ded8347d6b | ||
|
|
c4a5c57dc3 | ||
|
|
404e813c52 | ||
|
|
90d0a8db38 | ||
|
|
956ff9ff72 | ||
|
|
1eca49c6ed | ||
|
|
34758d5c15 | ||
|
|
befbfe6115 | ||
|
|
900748fca1 | ||
|
|
87ee248169 | ||
|
|
bb7c4fa361 | ||
|
|
c613d37048 | ||
|
|
d52a22e4db | ||
|
|
6dfb45bcdf | ||
|
|
145794936f | ||
|
|
301c680fd7 | ||
|
|
d27cbec598 | ||
|
|
f5be54d6ab | ||
|
|
1e19f7ba5f | ||
|
|
db719fb0d7 | ||
|
|
b0d4f4c10e | ||
|
|
238d23d775 | ||
|
|
c019068f06 | ||
|
|
715d1f4504 | ||
|
|
4f092bee9f | ||
|
|
1bbd10fe07 | ||
|
|
088aac8597 | ||
|
|
81c652d5d2 | ||
|
|
d7761c1480 | ||
|
|
93689aa51a | ||
|
|
46e6ad492a | ||
|
|
97efa5c36c | ||
|
|
0b1ffe2755 | ||
|
|
8c35542d1f | ||
|
|
0e9480317d | ||
|
|
b695d088cf | ||
|
|
81dc5750ca | ||
|
|
d82434cf27 | ||
|
|
cd6058f3d4 | ||
|
|
9be3ba223c | ||
|
|
a261989cda | ||
|
|
7b5c3eb05e | ||
|
|
0feec72eee | ||
|
|
be8bd99aa4 | ||
|
|
355b8bcd73 | ||
|
|
d58e4c273c | ||
|
|
a217ad3095 | ||
|
|
3d6feada8a | ||
|
|
5f78da2025 | ||
|
|
a05e4fa512 | ||
|
|
2119a4c462 | ||
|
|
1d5a1da9f8 | ||
|
|
2e7d19945c | ||
|
|
5d2c5c4c73 | ||
|
|
8694312695 | ||
|
|
d9d6bc5278 | ||
|
|
ebed4c3af0 | ||
|
|
172875cf15 | ||
|
|
4d26e9e4f4 | ||
|
|
8f4455f296 | ||
|
|
2e1d43deb2 | ||
|
|
6780f72000 | ||
|
|
39e01d2d4b | ||
|
|
f75502950b | ||
|
|
974f27e7e9 | ||
|
|
af32f69eb0 | ||
|
|
0cd2f40764 | ||
|
|
0d95824995 | ||
|
|
bbc09ffba9 | ||
|
|
a4677968cf | ||
|
|
03b1cddc31 | ||
|
|
9c2dd04993 | ||
|
|
a84a93fafe | ||
|
|
5fdcc397b1 | ||
|
|
5664871e5f | ||
|
|
55d9e0fada | ||
|
|
929e3011c6 | ||
|
|
07d70ff560 | ||
|
|
58c2960960 | ||
|
|
00d943d513 | ||
|
|
71c780da06 | ||
|
|
3b18cba889 | ||
|
|
2974e20550 | ||
|
|
430d841a2c | ||
|
|
31ec50d7da | ||
|
|
5ad0e46f08 | ||
|
|
1b5814e338 | ||
|
|
255810c0d6 | ||
|
|
5d2640376e | ||
|
|
d02984bbb7 | ||
|
|
0f9555207a | ||
|
|
885448d74c | ||
|
|
b14545b3ff | ||
|
|
9a5a86734f | ||
|
|
d1d1505045 | ||
|
|
144ce1dc21 | ||
|
|
aa126974ba | ||
|
|
707de53457 | ||
|
|
10f83cf43d | ||
|
|
59ee743c5f | ||
|
|
d54765c442 | ||
|
|
91262d5d3e | ||
|
|
1c09c743b1 | ||
|
|
06ce139fcc | ||
|
|
fae5bb3183 | ||
|
|
6fe25398d6 | ||
|
|
909ce14fc4 | ||
|
|
935b920120 | ||
|
|
b31427cd4a | ||
|
|
e2e3379d79 | ||
|
|
6b1ef85dd8 | ||
|
|
92325ada0c | ||
|
|
1707e0f9e2 | ||
|
|
7ff701e816 | ||
|
|
2e3c141795 | ||
|
|
76f79ba748 | ||
|
|
9dd891bb28 | ||
|
|
99f106d1cf | ||
|
|
3816cae745 | ||
|
|
759c0627e1 | ||
|
|
e03dfae507 | ||
|
|
c7677b892a | ||
|
|
da7b63972d | ||
|
|
499957d9ba | ||
|
|
582250008b | ||
|
|
a9b31409d5 | ||
|
|
98355b8086 | ||
|
|
70ed474b38 | ||
|
|
4775934364 | ||
|
|
25f2cb3d6b | ||
|
|
154f9a3aca | ||
|
|
b9df3bf20c | ||
|
|
6abd193fe3 | ||
|
|
362099a512 | ||
|
|
fdfc3dc9f3 | ||
|
|
4937459225 | ||
|
|
be2f866b4c | ||
|
|
f08aacf7d6 | ||
|
|
4fa6112efe | ||
|
|
1623ba6889 | ||
|
|
766526c791 | ||
|
|
5c15e29f2b | ||
|
|
0413e1605f | ||
|
|
0e5a1f8352 | ||
|
|
e5a2b8544d | ||
|
|
736a6a291c | ||
|
|
6e69cff118 | ||
|
|
cf72f20426 | ||
|
|
d479210cee | ||
|
|
b781537597 | ||
|
|
ea1438dad8 | ||
|
|
d2e9d069b4 | ||
|
|
58379559cc | ||
|
|
b3e6c81565 | ||
|
|
a6a3c3df45 | ||
|
|
6e3d4c4045 | ||
|
|
ca60b701ee | ||
|
|
e24c0b98d7 | ||
|
|
f389ac80a9 | ||
|
|
50f2f002d9 | ||
|
|
9ec7528475 | ||
|
|
a8e2a43a09 | ||
|
|
eb06fa95e4 | ||
|
|
1db8b61de7 | ||
|
|
38c66db8d6 | ||
|
|
f8be7d4219 | ||
|
|
13e29995f5 | ||
|
|
7c583c7316 | ||
|
|
9fecec5e85 | ||
|
|
9e696bd468 | ||
|
|
6ab6d4bfc1 | ||
|
|
cb1bcc7ebb | ||
|
|
19ba7d6318 | ||
|
|
7753ca1f49 | ||
|
|
d52a796c39 | ||
|
|
60514d457c | ||
|
|
5bc00efe42 | ||
|
|
c45f3133bc | ||
|
|
fb47591de0 | ||
|
|
514d129c49 | ||
|
|
db843fc12d | ||
|
|
63787382d8 | ||
|
|
85d4d142d8 | ||
|
|
3cd2af41e4 | ||
|
|
b214eda4f0 | ||
|
|
0771727d41 | ||
|
|
a5d74a1876 | ||
|
|
23bf32f767 | ||
|
|
87a819edee | ||
|
|
27a1234874 | ||
|
|
51f289d1e6 | ||
|
|
d0d6dc61e8 | ||
|
|
d91c8c50d2 | ||
|
|
e20a4f84d6 | ||
|
|
bbd6f4ba8e | ||
|
|
2a951cd2f9 | ||
|
|
a538066d5a | ||
|
|
c10b0bdd50 | ||
|
|
431efc8979 | ||
|
|
2d6dbe290c | ||
|
|
c33e3e3967 | ||
|
|
71b3374bd5 | ||
|
|
de343e3cce | ||
|
|
384958ed3d | ||
|
|
1cd5beeb06 | ||
|
|
4c70e359d0 | ||
|
|
f9c3005bff | ||
|
|
9147074d8b | ||
|
|
7007bddaef | ||
|
|
2f8dc29182 | ||
|
|
6066594bbe | ||
|
|
40c0289176 | ||
|
|
acf1af0cd9 | ||
|
|
62791bdfa2 | ||
|
|
47f1218d69 | ||
|
|
1179355dab | ||
|
|
3d807132e4 | ||
|
|
42d0b4c280 | ||
|
|
d313ae7d23 | ||
|
|
28a69e25ea | ||
|
|
ad911a7ac3 | ||
|
|
5575de140d | ||
|
|
a5ce1eb1af | ||
|
|
76a78cd8bc | ||
|
|
0b25efc12a | ||
|
|
64cae087b6 | ||
|
|
b7cc59c503 | ||
|
|
7eb8d18a99 | ||
|
|
e7bf3e5e87 | ||
|
|
5aafd07b37 | ||
|
|
053f3a831d | ||
|
|
a2d2e5c047 | ||
|
|
dd3a922035 | ||
|
|
0e916c6038 | ||
|
|
87fcb63975 | ||
|
|
68b2cc5538 | ||
|
|
4dcf3697ff | ||
|
|
ea77525546 | ||
|
|
17d5a07ec2 | ||
|
|
3966b9c609 | ||
|
|
1c47fbd96b | ||
|
|
1691bdcafc | ||
|
|
6a5ef41fb3 | ||
|
|
09b6f4b00d | ||
|
|
7067b0aa28 | ||
|
|
112e731150 | ||
|
|
1336e41460 | ||
|
|
7c1b7890d3 | ||
|
|
dd0700b025 | ||
|
|
04d8e8b25f | ||
|
|
3723efcb1d | ||
|
|
054b40b6fa | ||
|
|
6773a7798f | ||
|
|
2d4c8e5945 | ||
|
|
087173c887 | ||
|
|
57835c00ad | ||
|
|
4ed886ae6e | ||
|
|
740819ef7b | ||
|
|
829230689e | ||
|
|
77ba4cc2f9 | ||
|
|
e94989fe4d | ||
|
|
c11b88061f | ||
|
|
647c5433f8 | ||
|
|
8f694072a5 | ||
|
|
9a689986c6 | ||
|
|
3174b31d96 | ||
|
|
4eb61975b7 | ||
|
|
76e26e1042 | ||
|
|
9069dfd005 | ||
|
|
2be5d2daad | ||
|
|
22cd0063e5 | ||
|
|
3d2e458a4d | ||
|
|
a57568d716 | ||
|
|
61f543cade | ||
|
|
b8771f9615 | ||
|
|
d5d4b28220 | ||
|
|
a037edaccd | ||
|
|
356bbb8351 | ||
|
|
1f0fa9318a | ||
|
|
15c1707887 | ||
|
|
9dec7aa9c1 | ||
|
|
bc3d7454e0 | ||
|
|
56901bc7c3 | ||
|
|
5c7f570b16 | ||
|
|
4f6e5fe323 | ||
|
|
7d682ffea7 | ||
|
|
cef40af209 | ||
|
|
a358449ab1 | ||
|
|
8ef6b72514 | ||
|
|
620bbabc61 | ||
|
|
7ef6aa6405 | ||
|
|
7ad1d4fd66 | ||
|
|
bf5c2bf604 | ||
|
|
b8fe70a516 | ||
|
|
06963d0fca | ||
|
|
b964901f7d | ||
|
|
b52c1d9d3a | ||
|
|
a24e12e6dd | ||
|
|
3c6cd53b23 | ||
|
|
4f69fe59c7 | ||
|
|
d2e02b7d96 | ||
|
|
a57873b710 | ||
|
|
30ce7e8a64 | ||
|
|
f0af1e5ec6 | ||
|
|
f7ca98bdc4 | ||
|
|
7df0935a51 | ||
|
|
f22ee86517 | ||
|
|
8f98c608b9 | ||
|
|
32c58f06e0 | ||
|
|
040f7b6595 | ||
|
|
d2476f0db3 | ||
|
|
952cf8f4f3 | ||
|
|
a138e47560 | ||
|
|
7d6916547f | ||
|
|
6cd7888e46 | ||
|
|
1d54358e52 | ||
|
|
4c80c473ed | ||
|
|
571a4b2654 | ||
|
|
501972bf72 | ||
|
|
99cdaff70d | ||
|
|
c36b5017b8 | ||
|
|
a4cf6bec19 | ||
|
|
0154b302ce | ||
|
|
ec99e9da81 | ||
|
|
e052b21f32 | ||
|
|
b2f0246498 | ||
|
|
c1659c79ef | ||
|
|
4a7cb3e8a8 | ||
|
|
0de40240bb | ||
|
|
d79c77caca | ||
|
|
2b106d0b3a | ||
|
|
8fef024528 | ||
|
|
6963e540db | ||
|
|
3ef526f5fa | ||
|
|
eecd22ff7b | ||
|
|
add7e8fb6b | ||
|
|
f6e09367a7 | ||
|
|
3aae15ecfb | ||
|
|
f5ad6eb18d | ||
|
|
7f1b717ac7 | ||
|
|
55bdb41632 | ||
|
|
7c06e407ec | ||
|
|
c13ad7ec47 | ||
|
|
d2094cc33d | ||
|
|
c3469aed19 | ||
|
|
232ce2b2c8 | ||
|
|
882582b307 | ||
|
|
ebaa0489b4 | ||
|
|
1a1c244dc3 | ||
|
|
320989b05d | ||
|
|
9d682a8dc1 | ||
|
|
37c3cf430d | ||
|
|
751411c40d | ||
|
|
6a46226b3a | ||
|
|
42e66aa24c | ||
|
|
5cb1f5c795 | ||
|
|
12b9c8409e | ||
|
|
e8ca590142 | ||
|
|
863dff5179 | ||
|
|
3fedd74ba2 | ||
|
|
78ffe4787f | ||
|
|
a4b4af889b | ||
|
|
d286ee98b9 | ||
|
|
42be591878 | ||
|
|
3a4c683f04 | ||
|
|
e7d29902a6 | ||
|
|
64bd756832 | ||
|
|
8642efd0d6 | ||
|
|
063393d62d | ||
|
|
7a55d06e0d | ||
|
|
6f82f7a6f6 | ||
|
|
33d213bb37 | ||
|
|
a426e396c4 | ||
|
|
fafeb69cb6 | ||
|
|
b9277bdb6a | ||
|
|
b53713d322 | ||
|
|
2f22174f21 | ||
|
|
d820215b35 | ||
|
|
ea4a03762a | ||
|
|
46ef7d1dc8 | ||
|
|
e340a8203e | ||
|
|
3459d319d1 | ||
|
|
09ec75a629 | ||
|
|
4df7868d39 | ||
|
|
bc888e05da | ||
|
|
26c7f120e6 | ||
|
|
5b7be6ee4a | ||
|
|
951351a537 | ||
|
|
0b21c485ec | ||
|
|
068a7221ce | ||
|
|
a4772a4dbc | ||
|
|
2ee91aedb1 | ||
|
|
d95447229b | ||
|
|
40ec33b604 | ||
|
|
35e3b2d555 | ||
|
|
aa9c2df9d9 | ||
|
|
f472cdf017 | ||
|
|
1dc587af1b | ||
|
|
aeb6292d0d | ||
|
|
7d91d5a619 | ||
|
|
7169bb4aa9 | ||
|
|
2db52650fc | ||
|
|
c1f62a573a | ||
|
|
08a740ff43 | ||
|
|
b67381d0dc | ||
|
|
07e9500818 | ||
|
|
c77cf82206 | ||
|
|
f8014b864e | ||
|
|
d58911fb37 | ||
|
|
b335d74565 | ||
|
|
3405fe45f4 | ||
|
|
095efec1d6 | ||
|
|
7ca6e85649 | ||
|
|
74be4fc399 | ||
|
|
3b4b1984ef | ||
|
|
6902ed178b | ||
|
|
fab9a9c547 | ||
|
|
376acbfad5 | ||
|
|
12458878c2 | ||
|
|
546434f867 | ||
|
|
ac2a1a449d | ||
|
|
e1bd49d6f3 | ||
|
|
ab94af5c6f | ||
|
|
c88ca682ef | ||
|
|
fc990e81cb | ||
|
|
e2ba16ccea | ||
|
|
76d4988d06 | ||
|
|
25ea348bd1 | ||
|
|
8ca5756339 | ||
|
|
029c171330 | ||
|
|
8f04bb36e7 | ||
|
|
b7334b4c31 | ||
|
|
a7f8404ecd | ||
|
|
6c65e14634 | ||
|
|
ddd491d45e | ||
|
|
5d78a10232 | ||
|
|
4d66e00afa | ||
|
|
531d06b824 | ||
|
|
c6a7f2f48a | ||
|
|
d4e4cbe105 | ||
|
|
41bd28fee3 | ||
|
|
a1a440c23e | ||
|
|
089e73f8d6 | ||
|
|
2c5548d25e | ||
|
|
65c2a918d4 | ||
|
|
8950ac03f8 | ||
|
|
26ef00bd3c | ||
|
|
efe3037cf5 | ||
|
|
f62c17e378 | ||
|
|
0f62178580 | ||
|
|
81c99202d3 | ||
|
|
3473b5b4d8 | ||
|
|
ba35824322 | ||
|
|
6afe7f23b0 | ||
|
|
19b27a485e | ||
|
|
ff81e809f4 | ||
|
|
fd2dd2aa23 | ||
|
|
82ed910630 | ||
|
|
90ba34e27c | ||
|
|
8ee3d639b2 | ||
|
|
0c5a792ac7 | ||
|
|
2af27ad9aa | ||
|
|
3b2b534567 | ||
|
|
3fa64fd008 | ||
|
|
b557c4c7eb | ||
|
|
0882faa2b2 | ||
|
|
3cd5eb3b3b | ||
|
|
4ff3d9d6b4 | ||
|
|
26c08b6c21 | ||
|
|
4db4149283 | ||
|
|
1ac15cd8ad | ||
|
|
b348deae3d | ||
|
|
18c71e96f8 | ||
|
|
f0f5767f15 | ||
|
|
15b7b73d7d | ||
|
|
e420b9d854 | ||
|
|
2855f61f4a | ||
|
|
2d1ebe9c72 | ||
|
|
c485a357cc | ||
|
|
5013576705 | ||
|
|
8886f8d0e6 | ||
|
|
fcb6d28d0b | ||
|
|
62402cb14b | ||
|
|
305ab1331b | ||
|
|
8212336aaa | ||
|
|
3e3dcd624f | ||
|
|
b30b3bb899 | ||
|
|
55b64e4b5e | ||
|
|
e411463442 | ||
|
|
660c6fbdaa | ||
|
|
ce6c7c6318 | ||
|
|
fa994de488 | ||
|
|
2348926995 | ||
|
|
735a816e54 | ||
|
|
a1b1b1da46 | ||
|
|
c3563c46ed | ||
|
|
0c80cd8ee9 | ||
|
|
b79f79e3aa | ||
|
|
af642a61b3 | ||
|
|
ef1aa91039 | ||
|
|
1960e2280c | ||
|
|
7c1b4daa6f | ||
|
|
7a24c346b0 | ||
|
|
64c2cf8fea | ||
|
|
81d538ce23 | ||
|
|
e327acece4 | ||
|
|
4e40377ac2 | ||
|
|
eeb1568fd5 | ||
|
|
0ba481368c | ||
|
|
38bf526fc5 | ||
|
|
bc363ea983 | ||
|
|
84f69dad19 | ||
|
|
4a13b9d57a | ||
|
|
a039749b4c | ||
|
|
15b84e142a | ||
|
|
45a8354004 | ||
|
|
c32d024071 | ||
|
|
205c27ac67 | ||
|
|
f5c2081302 | ||
|
|
e6c64e7933 | ||
|
|
a036580649 | ||
|
|
796d484b44 | ||
|
|
1f52f4c407 | ||
|
|
d567322fbc | ||
|
|
3ff1e677a1 | ||
|
|
ef325f0cf4 | ||
|
|
3d8810c928 | ||
|
|
d153974ee2 | ||
|
|
5b56cc19fb | ||
|
|
c48b22c858 | ||
|
|
65d0a49f5c | ||
|
|
6a48ca56eb | ||
|
|
a20aa42ac4 | ||
|
|
e92ee12893 | ||
|
|
5c66303ad6 | ||
|
|
27e3e9c906 | ||
|
|
f0b36a48c8 | ||
|
|
25cf88936f | ||
|
|
ae682c3e11 | ||
|
|
99994aef3e | ||
|
|
78043d1969 | ||
|
|
43e46b4cf6 | ||
|
|
9ec16c83be | ||
|
|
a24c687094 | ||
|
|
60cb2f9016 | ||
|
|
ac1a0994b6 | ||
|
|
f2cbf44ba5 | ||
|
|
dab552237e | ||
|
|
2201ba580e | ||
|
|
b7c33e3bde | ||
|
|
82980a2384 | ||
|
|
b6a30afc98 | ||
|
|
ed91f3e418 | ||
|
|
60c8d7bc7f | ||
|
|
5783c065ba | ||
|
|
adc19c987b | ||
|
|
3d38277706 | ||
|
|
64c704f0b9 | ||
|
|
69c6522734 | ||
|
|
0f8f98c8ff | ||
|
|
e384bfbdcb | ||
|
|
08e5094d7f | ||
|
|
4b3977bf00 | ||
|
|
c80ccabb0c | ||
|
|
ef5d23ebcd | ||
|
|
27b9a19be0 | ||
|
|
14175f1e77 | ||
|
|
269833af78 | ||
|
|
fca3ef06cd | ||
|
|
07a14ef8b2 | ||
|
|
21cde2888c | ||
|
|
4a7481889c | ||
|
|
0adb99b9dc | ||
|
|
36349ea0be | ||
|
|
ec3f7d1b61 | ||
|
|
f0359dd00d | ||
|
|
ef55c686bc | ||
|
|
5f7ce2041c | ||
|
|
328fcf113a | ||
|
|
24c857f1de | ||
|
|
a784e10d00 | ||
|
|
7eb6bf0397 | ||
|
|
49d6fdc036 | ||
|
|
8b35435f7c | ||
|
|
8ada751890 | ||
|
|
1a52e84874 | ||
|
|
53c5cbed23 | ||
|
|
4a81463880 | ||
|
|
09b7f5dbb1 | ||
|
|
6d7b6081ac | ||
|
|
31b7d79afe | ||
|
|
b2999e457f | ||
|
|
0f3203c312 | ||
|
|
a2edb26cd6 | ||
|
|
9bec528606 | ||
|
|
2f0e3b30a9 | ||
|
|
ff41a59f58 | ||
|
|
08f15335b5 | ||
|
|
bd36966bed | ||
|
|
f76933b149 | ||
|
|
378a074c82 | ||
|
|
c36cd31713 | ||
|
|
5e12ce1186 | ||
|
|
166aa72332 | ||
|
|
f9f6184f38 | ||
|
|
f625af9400 | ||
|
|
fc7952e7f3 | ||
|
|
cbce490e13 | ||
|
|
74a7f81d57 | ||
|
|
5b5591d8a8 | ||
|
|
c55f70218c | ||
|
|
6957ae33a9 | ||
|
|
8a5d6bba09 | ||
|
|
1d2c275fff | ||
|
|
d0fd26aa16 | ||
|
|
e20c5e9521 | ||
|
|
66203a982b | ||
|
|
b315601ce0 | ||
|
|
5f808dfbd7 | ||
|
|
0b73ca12fa | ||
|
|
03e2d0e329 | ||
|
|
182517e692 | ||
|
|
554e0a8dd0 | ||
|
|
b0f3f5784c | ||
|
|
3060d4aa1d | ||
|
|
1347d5126a | ||
|
|
5d1e1dcf4b | ||
|
|
74f5442401 | ||
|
|
c08bb0fb73 | ||
|
|
e30f065766 | ||
|
|
9dce9b45b3 | ||
|
|
60be6acf46 | ||
|
|
a5827a28d2 | ||
|
|
dcc875e41e | ||
|
|
128cf58433 | ||
|
|
7e0ca8e2f0 | ||
|
|
d79d1c69f7 | ||
|
|
a7d068abff | ||
|
|
7f931a0002 | ||
|
|
07b7c86c06 | ||
|
|
1f5c6343e6 | ||
|
|
290b615a16 | ||
|
|
57df171bc0 | ||
|
|
f08baea3dd | ||
|
|
2fb139c11b | ||
|
|
3420c8e6e0 | ||
|
|
b17bc22bb3 | ||
|
|
3adffb52e6 | ||
|
|
4df9f36841 | ||
|
|
5c9730a46c | ||
|
|
d9fcc198cf | ||
|
|
c831379436 | ||
|
|
d73ee7b70e | ||
|
|
cda2ae84b3 | ||
|
|
e7d6e0aa0c | ||
|
|
8c9fd200f9 | ||
|
|
79f118d859 | ||
|
|
7b10f91d8f | ||
|
|
3d19b4c83e | ||
|
|
79452d4693 | ||
|
|
cb13abfed0 | ||
|
|
0503f06089 | ||
|
|
f855a7d01a | ||
|
|
4c3b4b2557 |
32
.cvsignore
32
.cvsignore
@@ -1,21 +1,23 @@
|
||||
.ignore
|
||||
.cvsignore
|
||||
ID
|
||||
Makefile
|
||||
a
|
||||
b
|
||||
autom4te.cache
|
||||
confdefs.h
|
||||
config.cache
|
||||
config.h
|
||||
config.log
|
||||
config.status
|
||||
dist.tar.gz
|
||||
conftest.c
|
||||
conftest.log
|
||||
dox
|
||||
getgroups
|
||||
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
|
||||
trimslash
|
||||
t_unsafe
|
||||
zlib/dummy
|
||||
|
||||
187
Doxyfile
Normal file
187
Doxyfile
Normal file
@@ -0,0 +1,187 @@
|
||||
# Doxyfile 1.2.15
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# General configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
PROJECT_NAME = rsync
|
||||
PROJECT_NUMBER = HEAD
|
||||
OUTPUT_DIRECTORY = dox
|
||||
OUTPUT_LANGUAGE = English
|
||||
EXTRACT_ALL = YES
|
||||
EXTRACT_PRIVATE = YES
|
||||
EXTRACT_STATIC = YES
|
||||
EXTRACT_LOCAL_CLASSES = YES
|
||||
HIDE_UNDOC_MEMBERS = NO
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
FULL_PATH_NAMES = NO
|
||||
STRIP_FROM_PATH = *source
|
||||
INTERNAL_DOCS = YES
|
||||
STRIP_CODE_COMMENTS = NO
|
||||
CASE_SENSE_NAMES = YES
|
||||
SHORT_NAMES = NO
|
||||
HIDE_SCOPE_NAMES = YES
|
||||
VERBATIM_HEADERS = YES
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
JAVADOC_AUTOBRIEF = YES
|
||||
INHERIT_DOCS = YES
|
||||
INLINE_INFO = YES
|
||||
SORT_MEMBER_DOCS = NO
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
TAB_SIZE = 8
|
||||
GENERATE_TODOLIST = YES
|
||||
GENERATE_TESTLIST = YES
|
||||
GENERATE_BUGLIST = YES
|
||||
ALIASES =
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
SHOW_USED_FILES = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to warning and progress messages
|
||||
#---------------------------------------------------------------------------
|
||||
QUIET = NO
|
||||
WARNINGS = NO
|
||||
WARN_IF_UNDOCUMENTED = NO
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LOGFILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = .
|
||||
FILE_PATTERNS = *.c \
|
||||
*.h
|
||||
RECURSIVE = YES
|
||||
EXCLUDE = proto.h \
|
||||
zlib \
|
||||
popt
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS =
|
||||
EXAMPLE_PATH =
|
||||
EXAMPLE_PATTERNS =
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH =
|
||||
INPUT_FILTER =
|
||||
FILTER_SOURCE_FILES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to source browsing
|
||||
#---------------------------------------------------------------------------
|
||||
SOURCE_BROWSER = YES
|
||||
INLINE_SOURCES = YES
|
||||
REFERENCED_BY_RELATION = YES
|
||||
REFERENCES_RELATION = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
ALPHABETICAL_INDEX = YES
|
||||
COLS_IN_ALPHA_INDEX = 3
|
||||
IGNORE_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the HTML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = html
|
||||
HTML_FILE_EXTENSION = .html
|
||||
HTML_HEADER =
|
||||
HTML_FOOTER =
|
||||
HTML_STYLESHEET =
|
||||
HTML_ALIGN_MEMBERS = YES
|
||||
GENERATE_HTMLHELP = NO
|
||||
GENERATE_CHI = NO
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = NO
|
||||
DISABLE_INDEX = NO
|
||||
ENUM_VALUES_PER_LINE = 3
|
||||
GENERATE_TREEVIEW = NO
|
||||
TREEVIEW_WIDTH = 250
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the LaTeX output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_LATEX = NO
|
||||
LATEX_OUTPUT = latex
|
||||
LATEX_CMD_NAME = latex
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
COMPACT_LATEX = NO
|
||||
PAPER_TYPE = a4wide
|
||||
EXTRA_PACKAGES =
|
||||
LATEX_HEADER =
|
||||
PDF_HYPERLINKS = YES
|
||||
USE_PDFLATEX = YES
|
||||
LATEX_BATCHMODE = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the RTF output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_RTF = NO
|
||||
RTF_OUTPUT = rtf
|
||||
COMPACT_RTF = NO
|
||||
RTF_HYPERLINKS = NO
|
||||
RTF_STYLESHEET_FILE =
|
||||
RTF_EXTENSIONS_FILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the man page output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_MAN = NO
|
||||
MAN_OUTPUT = man
|
||||
MAN_EXTENSION = .3
|
||||
MAN_LINKS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the XML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_XML = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options for the AutoGen Definitions output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the preprocessor
|
||||
#---------------------------------------------------------------------------
|
||||
ENABLE_PREPROCESSING = NO
|
||||
MACRO_EXPANSION = NO
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
SEARCH_INCLUDES = YES
|
||||
INCLUDE_PATH =
|
||||
INCLUDE_FILE_PATTERNS =
|
||||
PREDEFINED =
|
||||
EXPAND_AS_DEFINED =
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::addtions related to external references
|
||||
#---------------------------------------------------------------------------
|
||||
TAGFILES =
|
||||
GENERATE_TAGFILE =
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = YES
|
||||
PERL_PATH = /usr/bin/perl
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
CLASS_DIAGRAMS = YES
|
||||
HAVE_DOT = YES
|
||||
CLASS_GRAPH = YES
|
||||
COLLABORATION_GRAPH = YES
|
||||
TEMPLATE_RELATIONS = YES
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
INCLUDE_GRAPH = YES
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
DOT_IMAGE_FORMAT = png
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
MAX_DOT_GRAPH_WIDTH = 1024
|
||||
MAX_DOT_GRAPH_HEIGHT = 1024
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::addtions related to the search engine
|
||||
#---------------------------------------------------------------------------
|
||||
SEARCHENGINE = NO
|
||||
CGI_NAME = search.cgi
|
||||
CGI_URL =
|
||||
DOC_URL =
|
||||
DOC_ABSPATH =
|
||||
BIN_ABSPATH = /usr/local/bin/
|
||||
EXT_DOC_PATHS =
|
||||
45
INSTALL
Normal file
45
INSTALL
Normal file
@@ -0,0 +1,45 @@
|
||||
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.
|
||||
|
||||
If you configure using --enable-maintainer-mode, then rsync will try
|
||||
to pop up an xterm on DISPLAY=:0 if it crashes. You might find this
|
||||
useful, but it should be turned off for production builds.
|
||||
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
||||
164
Makefile.in
164
Makefile.in
@@ -9,65 +9,124 @@ mandir=@mandir@
|
||||
LIBS=@LIBS@
|
||||
CC=@CC@
|
||||
CFLAGS=@CFLAGS@
|
||||
CPPFLAGS=@CPPFLAGS@
|
||||
EXEEXT=@EXEEXT@
|
||||
LDFLAGS=@LDFLAGS@
|
||||
|
||||
INSTALLCMD=@INSTALL@
|
||||
INSTALLMAN=@INSTALL@
|
||||
|
||||
srcdir=@srcdir@
|
||||
VPATH=$(srcdir)
|
||||
SHELL=/bin/sh
|
||||
|
||||
VERSION=@VERSION@
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .o
|
||||
|
||||
LIBOBJ=lib/getopt.o lib/fnmatch.o lib/compat.o lib/snprintf.o lib/mdfour.o
|
||||
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
|
||||
OBJS2=options.o flist.o io.o compat.o hlink.o token.o uidlist.o socket.o fileio.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 clientname.o
|
||||
OBJS3=progress.o pipe.o
|
||||
DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o
|
||||
OBJS=$(OBJS1) $(OBJS2) $(DAEMON_OBJ) $(LIBOBJ) $(ZLIBOBJ)
|
||||
popt_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \
|
||||
popt/popthelp.o popt/poptparse.o
|
||||
OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(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$(EXEEXT) tls$(EXEEXT) getgroups$(EXEEXT) \
|
||||
trimslash$(EXEEXT) t_unsafe$(EXEEXT)
|
||||
|
||||
# Objects for CHECK_PROGS to clean
|
||||
CHECK_OBJS=getgroups.o t_stub.o t_unsafe.o trimslash.o
|
||||
|
||||
# note that the -I. is needed to handle config.h when using VPATH
|
||||
.c.o:
|
||||
@OBJ_SAVE@
|
||||
$(CC) -I. -I$(srcdir) $(CFLAGS) -c $< @CC_SHOBJ_FLAG@
|
||||
$(CC) -I. -I$(srcdir) $(CFLAGS) $(CPPFLAGS) -c $< @CC_SHOBJ_FLAG@
|
||||
@OBJ_RESTORE@
|
||||
|
||||
all: rsync
|
||||
all: rsync$(EXEEXT)
|
||||
|
||||
man: rsync.1 rsyncd.conf.5
|
||||
|
||||
install: all
|
||||
-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
|
||||
-mkdir -p ${DESTDIR}${bindir}
|
||||
${INSTALLCMD} ${STRIP} -m 755 rsync$(EXEEXT) ${DESTDIR}${bindir}
|
||||
-mkdir -p ${DESTDIR}${mandir}/man1
|
||||
-mkdir -p ${DESTDIR}${mandir}/man5
|
||||
${INSTALLMAN} -m 644 $(srcdir)/rsync.1 ${DESTDIR}${mandir}/man1
|
||||
${INSTALLMAN} -m 644 $(srcdir)/rsyncd.conf.5 ${DESTDIR}${mandir}/man5
|
||||
|
||||
install-strip:
|
||||
$(MAKE) INSTALLCMD='$(INSTALLCMD) -s' install
|
||||
$(MAKE) STRIP='-s' install
|
||||
|
||||
rsync: $(OBJS)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o rsync $(OBJS) $(LIBS)
|
||||
rsync$(EXEEXT): $(OBJS)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
|
||||
|
||||
rsync.1: rsync.yo
|
||||
yodl2man -o rsync.1 rsync.yo
|
||||
$(OBJS): config.h
|
||||
|
||||
rsyncd.conf.5: rsyncd.conf.yo
|
||||
yodl2man -o rsyncd.conf.5 rsyncd.conf.yo
|
||||
tls$(EXEEXT): $(TLS_OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(TLS_OBJ) $(LIBS)
|
||||
|
||||
getgroups$(EXEEXT): getgroups.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ getgroups.o $(LIBS)
|
||||
|
||||
TRIMSLASH_OBJ = trimslash.o syscall.o
|
||||
trimslash$(EXEEXT): $(TRIMSLASH_OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(TRIMSLASH_OBJ) $(LIBS)
|
||||
|
||||
T_UNSAFE_OBJ = t_unsafe.o syscall.o util.o t_stub.o lib/compat.o lib/snprintf.o
|
||||
t_unsafe$(EXEEXT): $(T_UNSAFE_OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(T_UNSAFE_OBJ) $(LIBS)
|
||||
|
||||
# I don't like these rules because CVS can skew the timestamps and
|
||||
# produce spurious warnings, and also make "make install" fail if the
|
||||
# source directory can no longer be found. Since we don't rebuild
|
||||
# automatically they're kind of lame anyhow.
|
||||
|
||||
#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"
|
||||
|
||||
$(srcdir)/rsync.1: $(srcdir)/rsync.yo
|
||||
yodl2man -o $(srcdir)/rsync.1 $(srcdir)/rsync.yo
|
||||
|
||||
$(srcdir)/rsyncd.conf.5: $(srcdir)/rsyncd.conf.yo
|
||||
yodl2man -o $(srcdir)/rsyncd.conf.5 $(srcdir)/rsyncd.conf.yo
|
||||
|
||||
proto:
|
||||
cat *.c | awk -f mkproto.awk > proto.h
|
||||
cat $(srcdir)/*.c $(srcdir)/lib/compat.c | awk -f $(srcdir)/mkproto.awk > $(srcdir)/proto.h
|
||||
|
||||
clean:
|
||||
rm -f *~ $(OBJS) rsync
|
||||
clean: cleantests
|
||||
rm -f *~ $(OBJS) $(TLS_OBJ) $(CHECK_PROGS) $(CHECK_OBJS)
|
||||
|
||||
cleantests:
|
||||
rm -rf ./testtmp*
|
||||
|
||||
# We try to delete built files from both the source and build
|
||||
# directories, just in case somebody previously configured things in
|
||||
# the source directory.
|
||||
distclean: clean
|
||||
rm -f config.h config.cache config.status Makefile
|
||||
rm -f Makefile config.h config.status
|
||||
rm -f $(srcdir)/Makefile $(srcdir)/config.h $(srcdir)/config.status
|
||||
|
||||
rm -f config.cache config.log
|
||||
rm -f $(srcdir)/config.cache $(srcdir)/config.log
|
||||
|
||||
rm -f shconfig $(srcdir)/shconfig
|
||||
|
||||
# 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
|
||||
@@ -75,4 +134,59 @@ distclean: clean
|
||||
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
|
||||
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 TOOLDIR=`pwd` rsync_bin=`pwd`/rsync$(EXEEXT) 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 TOOLDIR=`pwd` rsync_bin="$(bindir)/rsync$(EXEEXT)" srcdir="$(srcdir)" $(srcdir)/runtests.sh
|
||||
|
||||
# TODO: Add 'dist' target; need to know which files will be included
|
||||
|
||||
# Run the SPLINT (Secure Programming Lint) tool. <www.splint.org>
|
||||
.PHONY: splint
|
||||
splint:
|
||||
splint +unixlib +gnuextensions -weak rsync.c
|
||||
|
||||
|
||||
rsync.dvi: doc/rsync.texinfo
|
||||
texi2dvi -o $@ $<
|
||||
|
||||
rsync.ps: rsync.dvi
|
||||
dvips -ta4 -o $@ $<
|
||||
|
||||
rsync.pdf: doc/rsync.texinfo
|
||||
texi2dvi -o $@ --pdf $<
|
||||
|
||||
|
||||
doxygen:
|
||||
cd $(srcdir) && rm dox/html/* && doxygen
|
||||
|
||||
# for maintainers only
|
||||
doxygen-upload:
|
||||
rsync -avzv $(srcdir)/dox/html/ --delete \
|
||||
samba.org:/home/httpd/html/rsync/doxygen/head/
|
||||
|
||||
91
NEWS
Normal file
91
NEWS
Normal file
@@ -0,0 +1,91 @@
|
||||
NEWS for rsync version 2.5.6, aka the dwd-between-jobs release
|
||||
Changes since version 2.5.5:
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
* The --delete-after option now implies --delete. (Wayne Davison)
|
||||
|
||||
* The --suffix option can now be used with --backup-dir. (Michael
|
||||
Zimmerman)
|
||||
|
||||
* Combining "::" syntax with the -rsh/-e option now uses the
|
||||
specified remote-shell as a transport to talk to a (newly-spawned)
|
||||
server-daemon. This allows someone to use daemon features, such
|
||||
as modules, over a secure protocol, such as ssh. (JD Paul)
|
||||
|
||||
* The rsync:// syntax for daemon connections is now accepted in the
|
||||
destination field.
|
||||
|
||||
* If the file name given to --include-from or --exclude-from is "-",
|
||||
rsync will read from standard input. (J.W. Schultz)
|
||||
|
||||
* New option --link-dest which is like --compare-dest except that
|
||||
unchanged files are hard-linked in to the destination directory.
|
||||
(J.W. Schultz)
|
||||
|
||||
* Don't report an error if an excluded file disappears during an
|
||||
rsync run. (Eugene Chupriyanov and Bo Kersey)
|
||||
|
||||
* Added .svn to --cvs-exclude list to support subversion. (Jon
|
||||
Middleton)
|
||||
|
||||
* Properly support IPv6 addresses in the rsyncd.conf "hosts allow"
|
||||
and "hosts deny" fields. (Hideaki Yoshifuji)
|
||||
|
||||
* Changed exclude file handling to permit DOS or MAC style line
|
||||
terminations. (J.W. Schultz)
|
||||
|
||||
* Ignore errors from chmod when -p/-a/--preserve-perms is not set.
|
||||
(Dave Dykstra)
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
* Fix "forward name lookup failed" errors on AIX 4.3.3. (John
|
||||
L. Allen, Martin Pool)
|
||||
|
||||
* Generate each file's rolling-checksum data as we send it, not
|
||||
in a separate (memory-eating) pass before hand. This prevents
|
||||
timeout errors on really large files. (Stefan Nehlsen)
|
||||
|
||||
* Fix compilation on Tru64. (Albert Chin, Zoong Pham)
|
||||
|
||||
* Better handling of some client-server errors. (Martin Pool)
|
||||
|
||||
* Fixed a crash that would occur when sending a list of files that
|
||||
contains a duplicate name (if it sorts to the end of the file
|
||||
list) and using --delete. (Wayne Davison)
|
||||
|
||||
* Fixed the file-name duplicate-removal code when dealing with multiple
|
||||
dups in a row. (Wayne Davison)
|
||||
|
||||
* Fixed a bug that caused rsync to lose the exit status of its child
|
||||
processes and sometimes return an exit code of 0 instead of showing
|
||||
an error. (David R. Staples, Dave Dykstra)
|
||||
|
||||
* Fixed bug in --copy-unsafe-links that caused it to be completely
|
||||
broken. (Dave Dykstra)
|
||||
|
||||
* Prevent infinite recursion in cleanup code under certain circumstances.
|
||||
(Sviatoslav Sviridov and Marc Espie)
|
||||
|
||||
* Fixed a bug that prevented rsync from creating intervening directories
|
||||
when --relative-paths/-R is set. (Craig Barratt)
|
||||
|
||||
* Prevent "Connection reset by peer" messages from Cygwin. (Randy O'Meara)
|
||||
|
||||
INTERNAL:
|
||||
|
||||
* Many code cleanups and improved internal documentation. (Martin
|
||||
Pool, Nelson Beebe)
|
||||
|
||||
* Portability fixes. (Dave Dykstra and Wayne Davison)
|
||||
|
||||
* More test cases. (Martin Pool)
|
||||
|
||||
* Some test-case fixes. (Brian Poole, Wayne Davison)
|
||||
|
||||
* Updated included popt to the latest vendor drop, version 1.6.4.
|
||||
(Jos Backus)
|
||||
|
||||
* Updated config.guess and config.sub to latest versions; this
|
||||
means rsync should build on more platforms. (Paul Green)
|
||||
296
OLDNEWS
Normal file
296
OLDNEWS
Normal file
@@ -0,0 +1,296 @@
|
||||
rsync 2.5.5 "Snowy River" (2 April 2002)
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
* With --progress, when a transfer is complete show the time taken;
|
||||
otherwise show expected time to complete. (Cameron Simpson)
|
||||
|
||||
* Make "make install-strip" works properly, and "make install"
|
||||
accepts a DESTDIR variable for help in building binary packages.
|
||||
(Peter Breitenlohner, Greg Louis)
|
||||
|
||||
* If configured with --enable-maintainer-mode, then on receipt of
|
||||
a fatal signal rsync will try to open an xterm running gdb,
|
||||
similarly to Samba's "panic action" or GNOME's bug-buddy.
|
||||
(Martin Pool)
|
||||
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
* Fix situation where failure to fork (e.g. because out of process
|
||||
slots) would cause rsync to kill all processes owned by the
|
||||
current user. Yes, really! (Paul Haas, Martin Pool)
|
||||
|
||||
* Fix test suite on Solaris. (Jos Backus, Martin Pool)
|
||||
|
||||
* Fix minor memory leak in socket code. (Dave Dykstra, Martin
|
||||
Pool.)
|
||||
|
||||
* Fix --whole-file problem that caused it to be the default even
|
||||
for remote connections. (Martin Pool, Frank Schulz)
|
||||
|
||||
* Work around bug in Mac OS X mkdir(2), which cannot handle
|
||||
trailing slashes.
|
||||
<http://www.opensource.apple.com/bugs/X/BSD%20Kernel/2734739.html>
|
||||
(Martin Pool)
|
||||
|
||||
* Improved network error handling. (Greg A. Woods)
|
||||
|
||||
|
||||
rsync 2.5.4 (13 March 2002)
|
||||
|
||||
"Imitation lizard skin"
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
* Additional fix for zlib double-free bug. (Martin Pool, Andrew
|
||||
Tridgell) (CVE CAN-2002-0059)
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
* Merge in changes from zlib 1.1.3 to zlib 1.1.4. (Jos Backus)
|
||||
(Note that rsync still uses a custom version of zlib; you can
|
||||
not just link against a system library. See zlib/README.rsync)
|
||||
|
||||
* Additional test cases for --compress. (Martin Pool)
|
||||
|
||||
|
||||
rsync 2.5.3 (11 March 2002)
|
||||
|
||||
"Happy 26"
|
||||
|
||||
SECURITY FIXES:
|
||||
|
||||
* Make sure that supplementary groups are removed from a server
|
||||
process after changing uid and gid. (Ethan Benson) (Debian bug
|
||||
#132272, CVE CAN-2002-0080)
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
* Fix zlib double-free bug. (Owen Taylor, Mark J Cox) (CVE
|
||||
CAN-2002-0059)
|
||||
|
||||
* Fixed problem that in many cases caused the error message
|
||||
unexpected read size of 0 in map_ptr
|
||||
and resulted in the wrong data being copied.
|
||||
|
||||
* Fixed compilation errors on some systems caused by the use of
|
||||
"unsigned int64" in rsync.h.
|
||||
|
||||
* Fixed problem on systems such as Sunos4 that do not support realloc
|
||||
on a NULL pointer; error was "out of memory in flist_expand".
|
||||
|
||||
* Fix for rsync server processes hanging around after the client
|
||||
unexpectedly disconnects. (Colin Walters) (Debian bug #128632)
|
||||
|
||||
* Cope with BSD systems on which mkdir() will not accept a trailing
|
||||
slash.
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
* Merge in changes from zlib 1.1.2 to zlib 1.1.3. (Note that
|
||||
rsync still uses a custom version of zlib; you can not just link
|
||||
against a system library. See zlib/README.rsync)
|
||||
|
||||
* Command to initiate connections is only shown with -vv, rather
|
||||
than -v as in 2.5.2. Output from plain -v is more similar to
|
||||
what was historically used so as not to break scripts that try
|
||||
to parse the output.
|
||||
|
||||
* Added --no-whole-file and --no-blocking-io options (Dave Dykstra)
|
||||
|
||||
* Made the --write-batch and --read-batch options actually work
|
||||
and added documentation in the man page (Jos Backus)
|
||||
|
||||
* If the daemon is unable to fork a child to accept a connection,
|
||||
print an error message. (Colin Walters)
|
||||
|
||||
rsync 2.5.2 (26 Jan 2002)
|
||||
|
||||
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.
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
* Fix possible string mangling in log files.
|
||||
|
||||
* Fix for setting local address of outgoing sockets.
|
||||
|
||||
* Better handling of hardlinks and devices on platforms with
|
||||
64-bit dev_t or ino_t.
|
||||
|
||||
* Name resolution on machines supporting IPv6 is improved.
|
||||
|
||||
* Fix for device nodes. (dann frazier) (Debian #129135)
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
* With -v, rsync now shows the command used to initiate an ssh/rsh
|
||||
connection.
|
||||
|
||||
* --statistics now shows memory heap usage on platforms that
|
||||
support mallinfo().
|
||||
|
||||
* "The Ted T'so school of program optimization": make progress
|
||||
visible and people will think it's faster. (With --progress,
|
||||
rsync will show you how many files it has seen as it builds the
|
||||
file_list, giving some indication that it has not hung.)
|
||||
|
||||
* Improvements to batch mode support. This is still experimental
|
||||
but testing would be welcome. (Jos Backus)
|
||||
|
||||
* New --ignore-existing option, patch previously distributed with
|
||||
Vipul's Razor. (Debian #124286)
|
||||
|
||||
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.
|
||||
119
README
119
README
@@ -18,83 +18,25 @@ this package.
|
||||
USAGE
|
||||
-----
|
||||
|
||||
Basically you use rsync just like rcp, but rsync has many additional options.
|
||||
Basically you use rsync just like rcp, but rsync has many additional
|
||||
options. To get a complete list of supported options type
|
||||
|
||||
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
|
||||
rsync --help
|
||||
|
||||
and see the manual for more information.
|
||||
|
||||
|
||||
SETUP
|
||||
-----
|
||||
|
||||
Rsync uses rsh or ssh for communication. It does not need to be setuid
|
||||
and requires no special privileges 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
|
||||
@@ -125,8 +67,7 @@ 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.org 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.org
|
||||
|
||||
@@ -135,15 +76,19 @@ BUG REPORTS
|
||||
-----------
|
||||
|
||||
If you have web access then please look at
|
||||
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.
|
||||
http://rsync.samba.org
|
||||
|
||||
If you don't have web access then mail bug reports to
|
||||
rsync-bugs@samba.org or (if you think it will be of interest to lots
|
||||
of people) send it to rsync@samba.org
|
||||
That page contains links to the current bug list, and information on
|
||||
how to report a bug well. You might also like to try searching the
|
||||
internet for the error message you've received, or looking in the
|
||||
mailing list archives at
|
||||
|
||||
http://mail-archive.com/rsync@lists.samba.org/
|
||||
|
||||
Please send bug reports to
|
||||
|
||||
rsync@lists.samba.org
|
||||
|
||||
|
||||
CVS TREE
|
||||
@@ -153,22 +98,24 @@ 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@cvs.samba.org:/cvsroot login
|
||||
cvs -d :pserver:cvs@pserver.samba.org:/cvsroot login
|
||||
Password: cvs
|
||||
|
||||
cvs -d :pserver:cvs@cvs.samba.org:/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.org
|
||||
paulus@cs.anu.edu.au
|
||||
http://www.fsf.org/licenses/gpl.html
|
||||
|
||||
|
||||
AVAILABILITY
|
||||
|
||||
815
TODO
Normal file
815
TODO
Normal file
@@ -0,0 +1,815 @@
|
||||
-*- indented-text -*-
|
||||
|
||||
BUGS ---------------------------------------------------------------
|
||||
|
||||
rsync-url barfs on upload
|
||||
|
||||
rsync foo rsync://localhost/transfer/
|
||||
|
||||
Fix the parser.
|
||||
|
||||
|
||||
There seems to be a bug with hardlinks
|
||||
|
||||
mbp/2 build$ ls -l /tmp/a /tmp/b -i
|
||||
/tmp/a:
|
||||
total 32
|
||||
2568307 -rw-rw-r-- 3 mbp mbp 29 Mar 25 17:30 a1
|
||||
2568307 -rw-rw-r-- 3 mbp mbp 29 Mar 25 17:30 a2
|
||||
2568307 -rw-rw-r-- 3 mbp mbp 29 Mar 25 17:30 a3
|
||||
2568310 -rw-rw-r-- 5 mbp mbp 29 Mar 25 17:30 a4
|
||||
2568310 -rw-rw-r-- 5 mbp mbp 29 Mar 25 17:30 a5
|
||||
2568310 -rw-rw-r-- 5 mbp mbp 29 Mar 25 17:30 b1
|
||||
2568310 -rw-rw-r-- 5 mbp mbp 29 Mar 25 17:30 b2
|
||||
2568310 -rw-rw-r-- 5 mbp mbp 29 Mar 25 17:30 b3
|
||||
|
||||
/tmp/b:
|
||||
total 32
|
||||
2568309 -rw-rw-r-- 3 mbp mbp 29 Mar 25 17:30 a1
|
||||
2568309 -rw-rw-r-- 3 mbp mbp 29 Mar 25 17:30 a2
|
||||
2568309 -rw-rw-r-- 3 mbp mbp 29 Mar 25 17:30 a3
|
||||
2568311 -rw-rw-r-- 5 mbp mbp 29 Mar 25 17:30 a4
|
||||
2568311 -rw-rw-r-- 5 mbp mbp 29 Mar 25 17:30 a5
|
||||
2568311 -rw-rw-r-- 5 mbp mbp 29 Mar 25 17:30 b1
|
||||
2568311 -rw-rw-r-- 5 mbp mbp 29 Mar 25 17:30 b2
|
||||
2568311 -rw-rw-r-- 5 mbp mbp 29 Mar 25 17:30 b3
|
||||
mbp/2 build$ rm -r /tmp/b && ./rsync -avH /tmp/a/ /tmp/b
|
||||
building file list ... done
|
||||
created directory /tmp/b
|
||||
./
|
||||
a1
|
||||
a4
|
||||
a2 => a1
|
||||
a3 => a2
|
||||
wrote 350 bytes read 52 bytes 804.00 bytes/sec
|
||||
total size is 232 speedup is 0.58
|
||||
mbp/2 build$ rm -r /tmp/b
|
||||
mbp/2 build$ ls -l /tmp/b
|
||||
ls: /tmp/b: No such file or directory
|
||||
mbp/2 build$ rm -r /tmp/b && ./rsync -avH /tmp/a/ /tmp/b
|
||||
rm: cannot remove `/tmp/b': No such file or directory
|
||||
mbp/2 build$ rm -f -r /tmp/b && ./rsync -avH /tmp/a/ /tmp/b
|
||||
building file list ... done
|
||||
created directory /tmp/b
|
||||
./
|
||||
a1
|
||||
a4
|
||||
a2 => a1
|
||||
a3 => a2
|
||||
wrote 350 bytes read 52 bytes 804.00 bytes/sec
|
||||
total size is 232 speedup is 0.58
|
||||
mbp/2 build$ ls -l /tmp/b
|
||||
total 32
|
||||
-rw-rw-r-- 3 mbp mbp 29 Mar 25 17:30 a1
|
||||
-rw-rw-r-- 3 mbp mbp 29 Mar 25 17:30 a2
|
||||
-rw-rw-r-- 3 mbp mbp 29 Mar 25 17:30 a3
|
||||
-rw-rw-r-- 5 mbp mbp 29 Mar 25 17:30 a4
|
||||
-rw-rw-r-- 5 mbp mbp 29 Mar 25 17:30 a5
|
||||
-rw-rw-r-- 5 mbp mbp 29 Mar 25 17:30 b1
|
||||
-rw-rw-r-- 5 mbp mbp 29 Mar 25 17:30 b2
|
||||
-rw-rw-r-- 5 mbp mbp 29 Mar 25 17:30 b3
|
||||
mbp/2 build$ ls -l /tmp/a
|
||||
total 32
|
||||
-rw-rw-r-- 3 mbp mbp 29 Mar 25 17:30 a1
|
||||
-rw-rw-r-- 3 mbp mbp 29 Mar 25 17:30 a2
|
||||
-rw-rw-r-- 3 mbp mbp 29 Mar 25 17:30 a3
|
||||
-rw-rw-r-- 5 mbp mbp 29 Mar 25 17:30 a4
|
||||
-rw-rw-r-- 5 mbp mbp 29 Mar 25 17:30 a5
|
||||
-rw-rw-r-- 5 mbp mbp 29 Mar 25 17:30 b1
|
||||
-rw-rw-r-- 5 mbp mbp 29 Mar 25 17:30 b2
|
||||
-rw-rw-r-- 5 mbp mbp 29 Mar 25 17:30 b3
|
||||
|
||||
|
||||
Progress indicator can produce corrupt output when transferring directories:
|
||||
|
||||
main/binary-arm/
|
||||
main/binary-arm/admin/
|
||||
main/binary-arm/base/
|
||||
main/binary-arm/comm/8.56kB/s 0:00:52
|
||||
main/binary-arm/devel/
|
||||
main/binary-arm/doc/
|
||||
main/binary-arm/editors/
|
||||
main/binary-arm/electronics/s 0:00:53
|
||||
main/binary-arm/games/
|
||||
main/binary-arm/graphics/
|
||||
main/binary-arm/hamradio/
|
||||
main/binary-arm/interpreters/
|
||||
main/binary-arm/libs/6.61kB/s 0:00:54
|
||||
main/binary-arm/mail/
|
||||
main/binary-arm/math/
|
||||
main/binary-arm/misc/
|
||||
|
||||
|
||||
lchmod
|
||||
I don't think we handle this properly on systems that don't have the
|
||||
call. Are there any such?
|
||||
|
||||
|
||||
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.
|
||||
|
||||
--no-blocking-io might be broken
|
||||
|
||||
in the same way as --no-whole-file; somebody needs to check.
|
||||
|
||||
Do not rely on having a group called "nobody"
|
||||
|
||||
http://www.linuxbase.org/spec/refspecs/LSB_1.1.0/gLSB/usernames.html
|
||||
|
||||
On Debian it's "nogroup"
|
||||
|
||||
Temporary file names can exceed max name length
|
||||
|
||||
Rsync creates temporary file names that are 10 characters longer
|
||||
than the length of the file being transferred. This creates
|
||||
problems for operating systems have fairly short maximum lengths
|
||||
(e.g., 32 characters for Stratus VOS). Even on operating systems
|
||||
with long max lengths it can still be a problem as it is perfectly
|
||||
reasonable to be using files with long names.
|
||||
|
||||
|
||||
DAEMON --------------------------------------------------------------
|
||||
|
||||
server-imposed bandwidth limits
|
||||
|
||||
rsyncd over ssh
|
||||
|
||||
There are already some patches to do this.
|
||||
|
||||
BitKeeper uses a server whose login shell is set to bkd. That's
|
||||
probably a reasonable approach.
|
||||
|
||||
|
||||
FEATURES ------------------------------------------------------------
|
||||
|
||||
|
||||
--dry-run is too dry
|
||||
|
||||
Mark Santcroos points out that -n fails to list files which have
|
||||
only metadata changes, though it probably should.
|
||||
|
||||
There may be a Debian bug about this as well.
|
||||
|
||||
|
||||
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.
|
||||
|
||||
|
||||
supplementary groups
|
||||
|
||||
Perhaps allow supplementary groups to be specified in rsyncd.conf;
|
||||
then make the first one the primary gid and all the rest be
|
||||
supplementary gids.
|
||||
|
||||
|
||||
File list structure in memory
|
||||
|
||||
Rather than one big array, perhaps have a tree in memory mirroring
|
||||
the directory tree.
|
||||
|
||||
This might make sorting much faster! (I'm not sure it's a big CPU
|
||||
problem, mind you.)
|
||||
|
||||
It might also reduce memory use in storing repeated directory names
|
||||
-- again I'm not sure this is a problem.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
||||
Handling IPv6 on old machines
|
||||
|
||||
The KAME IPv6 patch is nice in theory but has proved a bit of a
|
||||
nightmare in practice. The basic idea of their patch is that rsync
|
||||
is rewritten to use the new getaddrinfo()/getnameinfo() interface,
|
||||
rather than gethostbyname()/gethostbyaddr() as in rsync 2.4.6.
|
||||
Systems that don't have the new interface are handled by providing
|
||||
our own implementation in lib/, which is selectively linked in.
|
||||
|
||||
The problem with this is that it is really hard to get right on
|
||||
platforms that have a half-working implementation, so redefining
|
||||
these functions clashes with system headers, and leaving them out
|
||||
breaks. This affects at least OSF/1, RedHat 5, and Cobalt, which
|
||||
are moderately improtant.
|
||||
|
||||
Perhaps the simplest solution would be to have two different files
|
||||
implementing the same interface, and choose either the new or the
|
||||
old API. This is probably necessary for systems that e.g. have
|
||||
IPv6, but gethostbyaddr() can't handle it. The Linux manpage claims
|
||||
this is currently the case.
|
||||
|
||||
In fact, our internal sockets interface (things like
|
||||
open_socket_out(), etc) is much narrower than the getaddrinfo()
|
||||
interface, and so probably simpler to get right. In addition, the
|
||||
old code is known to work well on old machines.
|
||||
|
||||
We could drop the rather large lib/getaddrinfo files.
|
||||
|
||||
|
||||
Other IPv6 stuff:
|
||||
|
||||
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.
|
||||
|
||||
If we get an error writing to a socket, then we should perhaps
|
||||
continue trying to read to see if an error message comes across
|
||||
explaining why the socket is closed. I'm not sure if this would
|
||||
work, but it would certainly make our messages more helpful.
|
||||
|
||||
What happens if a directory is missing -x attributes. Do we lose
|
||||
our load? (Debian #28416) Probably fixed now, but a test case would
|
||||
be good.
|
||||
|
||||
|
||||
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.
|
||||
|
||||
Advantages:
|
||||
|
||||
- will automatically be up to date with bugfixes in zlib
|
||||
|
||||
- can leave it out for small rsync on e.g. recovery disks
|
||||
|
||||
- can use a shared library
|
||||
|
||||
- avoids people breaking rsync by trying to do this themselves and
|
||||
messing up
|
||||
|
||||
Should we ship zlib for systems that don't have it, or require
|
||||
people to install it separately?
|
||||
|
||||
Apparently this will make us incompatible with versions of rsync
|
||||
that use the patched version of rsync. Probably the simplest way to
|
||||
do this is to just disable gzip (with a warning) when talking to old
|
||||
versions.
|
||||
|
||||
|
||||
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.
|
||||
|
||||
If a child of the rsync daemon dies with a signal, we should notice
|
||||
that when we reap it and log a message.
|
||||
|
||||
Keep stderr and stdout properly separated (Debian #23626)
|
||||
|
||||
After we get the @RSYNCD greeting from the server, we know it's
|
||||
version but we have not yet sent the command line, so we could just
|
||||
remove the -z option if the server is too old.
|
||||
|
||||
For ssh invocation it's not so simple, because we actually use the
|
||||
command line to start the remote process. However, we only actually
|
||||
do compression in token.c, and we could therefore once we discover
|
||||
the remote version emit an error if it's too old. I'm not sure if
|
||||
that's a good tradeoff or not.
|
||||
|
||||
|
||||
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.
|
||||
|
||||
FAT support
|
||||
|
||||
rsync to a FAT partition on a Unix machine doesn't work very well at
|
||||
the moment. I think we get errors about invalid filenames and
|
||||
perhaps also trying to do atomic renames.
|
||||
|
||||
I guess the code to do this is currently #ifdef'd on Windows;
|
||||
perhaps we ought to intelligently fall back to it on Unix too.
|
||||
|
||||
|
||||
Better statistics:
|
||||
|
||||
<Rasmus> mbp: hey, how about an rsync option that just gives you the
|
||||
summary without the list of files? And perhaps gives more
|
||||
information like the number of new files, number of changed,
|
||||
deleted, etc. ? <mbp> Rasmus: nice idea <mbp> there is --stats
|
||||
<mbp> but at the moment it's very tridge-oriented <mbp> rather than
|
||||
user-friendly <mbp> it would be nice to improve it <mbp> that would
|
||||
also work well with --dryrun
|
||||
|
||||
TDB:
|
||||
|
||||
Rather than storing the file list in memory, store it in a TDB.
|
||||
|
||||
This *might* make memory usage lower while building the file list.
|
||||
|
||||
Hashtable lookup will mean files are not transmitted in order,
|
||||
though... hm.
|
||||
|
||||
This would neatly eliminate one of the major post-fork shared data
|
||||
structures.
|
||||
|
||||
|
||||
chmod:
|
||||
|
||||
On 12 Mar 2002, Dave Dykstra <dwd@bell-labs.com> wrote: > If we
|
||||
would add an option to do that functionality, I would vote for one >
|
||||
that was more general which could mask off any set of permission bits
|
||||
and > possibly add any set of bits. Perhaps a chmod-like syntax if it
|
||||
could be > implemented simply.
|
||||
|
||||
I think that would be good too. For example, people uploading files
|
||||
to a web server might like to say
|
||||
|
||||
rsync -avzP --chmod a+rX ./ sourcefrog.net:/home/www/sourcefrog/
|
||||
|
||||
Ideally the patch would implement as many of the gnu chmod semantics
|
||||
as possible. I think the mode parser should be a separate function
|
||||
that passes back something like (mask,set) description to the rest
|
||||
of the program. For bonus points there would be a test case for the
|
||||
parser.
|
||||
|
||||
Possibly also --chown
|
||||
|
||||
(Debian #23628)
|
||||
|
||||
|
||||
--diff
|
||||
|
||||
Allow people to specify the diff command. (Might want to use wdiff,
|
||||
gnudiff, etc.)
|
||||
|
||||
Just diff the temporary file with the destination file, and delete
|
||||
the tmp file rather than moving it into place.
|
||||
|
||||
Interaction with --partial.
|
||||
|
||||
Security interactions with daemon mode?
|
||||
|
||||
(Suggestion from david.e.sewell)
|
||||
|
||||
|
||||
Incorrect timestamps (Debian #100295)
|
||||
|
||||
A bit hard to believe, but apparently it happens.
|
||||
|
||||
|
||||
Check "refuse options works"
|
||||
|
||||
We need a test case for this...
|
||||
|
||||
Was this broken when we changed to popt?
|
||||
|
||||
|
||||
PERFORMANCE ----------------------------------------------------------
|
||||
|
||||
MD4 file_sum
|
||||
|
||||
If we're doing a local transfer, or using -W, then perhaps don't
|
||||
send the file checksum. If we're doing a local transfer, then
|
||||
calculating MD4 checksums uses 90% of CPU and is unlikely to be
|
||||
useful.
|
||||
|
||||
Indeed for transfers over zlib or ssh we can also rely on the
|
||||
transport to have quite strong protection against corruption.
|
||||
|
||||
Perhaps we should have an option to disable this, analogous to
|
||||
--whole-file, although it would default to disabled. The file
|
||||
checksum takes up a definite space in the protocol -- we can either
|
||||
set it to 0, or perhaps just leave it out.
|
||||
|
||||
MD4
|
||||
|
||||
Perhaps borrow an assembler MD4 from someone?
|
||||
|
||||
Make sure we call MD4 with properly-sized blocks whenever possible
|
||||
to avoid copying into the residue region?
|
||||
|
||||
String area code
|
||||
|
||||
Test whether this is actually faster than just using malloc(). If
|
||||
it's not (anymore), throw it out.
|
||||
|
||||
|
||||
PLATFORMS ------------------------------------------------------------
|
||||
|
||||
Win32
|
||||
|
||||
Don't detach, because this messes up --srvany.
|
||||
|
||||
http://sources.redhat.com/ml/cygwin/2001-08/msg00234.html
|
||||
|
||||
|
||||
DEVELOPMENT ----------------------------------------------------------
|
||||
|
||||
Splint
|
||||
|
||||
Build rsync with SPLINT to try to find security holes. Add
|
||||
annotations as necessary. Keep track of the number of warnings
|
||||
found initially, and see how many of them are real bugs, or real
|
||||
security bugs. Knowing the percentage of likely hits would be
|
||||
really interesting for other projects.
|
||||
|
||||
Torture test
|
||||
|
||||
Something that just keeps running rsync continuously over a data set
|
||||
likely to generate problems.
|
||||
|
||||
Cross-testing
|
||||
|
||||
Run current rsync versions against significant past releases.
|
||||
|
||||
Memory debugger
|
||||
|
||||
jra recommends Valgrind:
|
||||
|
||||
http://devel-home.kde.org/~sewardj/
|
||||
|
||||
Release script
|
||||
|
||||
Update spec files
|
||||
|
||||
Build tar file; upload
|
||||
|
||||
Send announcement to mailing list and c.o.l.a.
|
||||
|
||||
Make freshmeat announcement
|
||||
|
||||
Update web site
|
||||
|
||||
|
||||
|
||||
TESTING --------------------------------------------------------------
|
||||
|
||||
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 both up and down from the current release to
|
||||
all old versions.
|
||||
|
||||
We might need to omit broken old versions, or versions in which
|
||||
particular functionality is broken
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Test on kernel source
|
||||
|
||||
Download all versions of kernel; unpack, sync between them. Also
|
||||
sync between uncompressed tarballs. Compare directories after
|
||||
transfer.
|
||||
|
||||
Use local mode; ssh; daemon; --whole-file and --no-whole-file.
|
||||
|
||||
Use awk to pull out the 'speedup' number for each transfer. Make
|
||||
sure it is >= x.
|
||||
|
||||
|
||||
Test large files
|
||||
|
||||
Sparse and non-sparse
|
||||
|
||||
Mutator program
|
||||
|
||||
Insert bytes, delete bytes, swap blocks, ...
|
||||
|
||||
configure option to enable dangerous tests
|
||||
|
||||
If tests are skipped, say why.
|
||||
|
||||
Test daemon feature to disallow particular options.
|
||||
|
||||
Pipe program that makes slow/jerky connections.
|
||||
|
||||
Versions of read() and write() that corrupt the stream, or abruptly
|
||||
fail
|
||||
|
||||
Separate makefile target to run rough tests -- or perhaps just run
|
||||
them every time?
|
||||
|
||||
Test "refuse options" works
|
||||
|
||||
What about for --recursive?
|
||||
|
||||
If you specify an unrecognized option here, you should get an error.
|
||||
|
||||
|
||||
DOCUMENTATION --------------------------------------------------------
|
||||
|
||||
Update README
|
||||
|
||||
Keep list of open issues and todos on the web site
|
||||
|
||||
Update web site from CVS
|
||||
|
||||
|
||||
Perhaps redo manual as SGML
|
||||
|
||||
The man page is getting rather large, and there is more information
|
||||
that ought to be added.
|
||||
|
||||
TexInfo source is probably a dying format.
|
||||
|
||||
Linuxdoc looks like the most likely contender. I know DocBook is
|
||||
favoured by some people, but it's so bloody verbose, even with emacs
|
||||
support.
|
||||
|
||||
|
||||
BUILD FARM -----------------------------------------------------------
|
||||
|
||||
Add machines
|
||||
|
||||
Cygwin (on different versions of Win32?)
|
||||
|
||||
HP-UX variants (via HP?)
|
||||
|
||||
SCO
|
||||
|
||||
|
||||
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.
|
||||
|
||||
If a child of the rsync daemon dies with a signal, we should notice
|
||||
that when we reap it and log a message.
|
||||
|
||||
Keep stderr and stdout properly separated (Debian #23626)
|
||||
|
||||
Use a separate function for reporting errors; prefix it with
|
||||
"rsync:" or "rsync(remote)", or perhaps even "rsync(local
|
||||
generator): ".
|
||||
|
||||
verbose output
|
||||
|
||||
Indicate whether files are new, updated, or deleted
|
||||
|
||||
At end of transfer, show how many files were or were not transferred
|
||||
correctly.
|
||||
|
||||
-vv
|
||||
|
||||
Explain *why* every file is transferred or not (e.g. "local mtime
|
||||
123123 newer than 1283198")
|
||||
|
||||
|
||||
debugging of daemon
|
||||
|
||||
Add an rsyncd.conf parameter to turn on debugging on the server.
|
||||
|
||||
|
||||
|
||||
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
|
||||
|
||||
internationalization
|
||||
|
||||
Change to using gettext(). Probably need to ship this for platforms
|
||||
that don't have it.
|
||||
|
||||
Solicit translations.
|
||||
|
||||
Does anyone care? Before we bother modifying the code, we ought to
|
||||
get the manual translated first, because that's possibly more useful
|
||||
and at any rate demonstrates desire.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
RELATED PROJECTS -----------------------------------------------------
|
||||
|
||||
http://rsync.samba.org/rsync-and-debian/
|
||||
|
||||
rsyncable gzip patch
|
||||
|
||||
Exhaustive, tortuous testing
|
||||
|
||||
Cleanups?
|
||||
|
||||
rsyncsplit as alternative to real integration with gzip?
|
||||
|
||||
reverse rsync over HTTP Range
|
||||
|
||||
Goswin Brederlow suggested this on Debian; I think tridge and I
|
||||
talked about it previous in relation to rproxy.
|
||||
|
||||
|
||||
171
access.c
171
access.c
@@ -30,53 +30,166 @@ static int match_hostname(char *host, char *tok)
|
||||
return (fnmatch(tok, host, 0) == 0);
|
||||
}
|
||||
|
||||
static int match_binary(char *b1, char *b2, char *mask, int addrlen)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<addrlen; i++) {
|
||||
if ((b1[i]^b2[i])&mask[i]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void make_mask(char *mask, int plen, int addrlen) {
|
||||
int w, b;
|
||||
|
||||
w = plen >> 3;
|
||||
b = plen & 0x7;
|
||||
|
||||
if (w)
|
||||
memset(mask, 0xff, w);
|
||||
if (w < addrlen)
|
||||
mask[w] = 0xff & (0xff<<(8-b));
|
||||
if (w+1 < addrlen)
|
||||
memset(mask+w+1, 0, addrlen-w-1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int match_address(char *addr, char *tok)
|
||||
{
|
||||
char *p;
|
||||
unsigned long a, t, mask = (unsigned long)~0;
|
||||
struct addrinfo hints, *resa, *rest;
|
||||
int gai;
|
||||
int ret = 0;
|
||||
int addrlen = 0;
|
||||
#ifdef HAVE_STRTOL
|
||||
long int bits;
|
||||
#else
|
||||
int bits;
|
||||
#endif
|
||||
char mask[16];
|
||||
char *a = NULL, *t = NULL;
|
||||
|
||||
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);
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
#ifdef AI_NUMERICHOST
|
||||
hints.ai_flags = AI_NUMERICHOST;
|
||||
#endif
|
||||
|
||||
if (p) {
|
||||
*p = '/';
|
||||
}
|
||||
gai = getaddrinfo(addr, NULL, &hints, &resa);
|
||||
if (gai) return 0;
|
||||
|
||||
if (t == INADDR_NONE) {
|
||||
gai = getaddrinfo(tok, NULL, &hints, &rest);
|
||||
if (p)
|
||||
*p++ = '/';
|
||||
if (gai) {
|
||||
rprintf(FERROR,"malformed address %s\n", tok);
|
||||
freeaddrinfo(resa);
|
||||
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 || bits > 32) {
|
||||
rprintf(FERROR,"malformed mask in %s\n", tok);
|
||||
return 0;
|
||||
}
|
||||
mask &= (mask << (32-bits));
|
||||
}
|
||||
if (rest->ai_family != resa->ai_family) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
return ((a&mask) == (t&mask));
|
||||
switch(resa->ai_family) {
|
||||
case PF_INET:
|
||||
a = (char *)&((struct sockaddr_in *)resa->ai_addr)->sin_addr;
|
||||
t = (char *)&((struct sockaddr_in *)rest->ai_addr)->sin_addr;
|
||||
addrlen = 4;
|
||||
|
||||
break;
|
||||
|
||||
#ifdef INET6
|
||||
case PF_INET6:
|
||||
{
|
||||
struct sockaddr_in6 *sin6a, *sin6t;
|
||||
|
||||
sin6a = (struct sockaddr_in6 *)resa->ai_addr;
|
||||
sin6t = (struct sockaddr_in6 *)rest->ai_addr;
|
||||
|
||||
a = (char *)&sin6a->sin6_addr;
|
||||
t = (char *)&sin6t->sin6_addr;
|
||||
|
||||
addrlen = 16;
|
||||
|
||||
#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
|
||||
if (sin6t->sin6_scope_id &&
|
||||
sin6a->sin6_scope_id != sin6t->sin6_scope_id) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
rprintf(FERROR,"unknown family %u\n", rest->ai_family);
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bits = -1;
|
||||
if (p) {
|
||||
if (inet_pton(resa->ai_addr->sa_family, p, mask) <= 0) {
|
||||
#ifdef HAVE_STRTOL
|
||||
char *ep = NULL;
|
||||
#else
|
||||
unsigned char *pp;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STRTOL
|
||||
bits = strtol(p, &ep, 10);
|
||||
if (!*p || *ep) {
|
||||
rprintf(FERROR,"malformed mask in %s\n", tok);
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
#else
|
||||
for (pp = (unsigned char *)p; *pp; pp++) {
|
||||
if (!isascii(*pp) || !isdigit(*pp)) {
|
||||
rprintf(FERROR,"malformed mask in %s\n", tok);
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
bits = atoi(p);
|
||||
#endif
|
||||
if (bits == 0) {
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
if (bits < 0 || bits > (addrlen << 3)) {
|
||||
rprintf(FERROR,"malformed mask in %s\n", tok);
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bits = 128;
|
||||
}
|
||||
|
||||
if (bits >= 0)
|
||||
make_mask(mask, bits, addrlen);
|
||||
|
||||
ret = match_binary(a, t, mask, addrlen);
|
||||
|
||||
out:
|
||||
freeaddrinfo(resa);
|
||||
freeaddrinfo(rest);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int access_match(char *list, char *addr, char *host)
|
||||
|
||||
13
acconfig.h
13
acconfig.h
@@ -1,12 +1,11 @@
|
||||
#undef HAVE_BROKEN_READDIR
|
||||
#undef HAVE_ERRNO_DECL
|
||||
#undef HAVE_LONGLONG
|
||||
#undef HAVE_OFF64_T
|
||||
#undef HAVE_REMSH
|
||||
#undef HAVE_UNSIGNED_CHAR
|
||||
#undef HAVE_UTIMBUF
|
||||
#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_SOCKADDR_IN6_SCOPE_ID
|
||||
#undef HAVE_SOCKETPAIR
|
||||
|
||||
48
aclocal.m4
vendored
48
aclocal.m4
vendored
@@ -21,3 +21,51 @@ AC_DEFUN(AC_VALIDATE_CACHE_SYSTEM_TYPE, [
|
||||
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>])
|
||||
])
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright (C) Andrew Tridgell 1998
|
||||
/* -*- 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
|
||||
@@ -56,7 +57,7 @@ static void gen_challenge(char *addr, char *challenge)
|
||||
memset(input, 0, sizeof(input));
|
||||
|
||||
strlcpy((char *)input, addr, 17);
|
||||
gettimeofday(&tv, NULL);
|
||||
sys_gettimeofday(&tv);
|
||||
SIVAL(input, 16, tv.tv_sec);
|
||||
SIVAL(input, 20, tv.tv_usec);
|
||||
SIVAL(input, 24, getpid());
|
||||
@@ -85,7 +86,7 @@ static int get_secret(int module, char *user, char *secret, int len)
|
||||
if (fd == -1) return 0;
|
||||
|
||||
if (do_stat(fname, &st) == -1) {
|
||||
rprintf(FERROR,"stat(%s) : %s\n", fname, strerror(errno));
|
||||
rsyserr(FERROR, errno, "stat(%s)", fname);
|
||||
ok = 0;
|
||||
} else if (lp_strict_modes(module)) {
|
||||
if ((st.st_mode & 06) != 0) {
|
||||
@@ -104,8 +105,8 @@ static int get_secret(int module, char *user, char *secret, int len)
|
||||
|
||||
while (!found) {
|
||||
int i = 0;
|
||||
memset(line, 0, sizeof(line));
|
||||
while (i<(sizeof(line)-1)) {
|
||||
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);
|
||||
@@ -135,7 +136,6 @@ static int get_secret(int module, char *user, char *secret, int len)
|
||||
static char *getpassf(char *filename)
|
||||
{
|
||||
char buffer[100];
|
||||
int len=0;
|
||||
int fd=0;
|
||||
STRUCT_STAT st;
|
||||
int ok = 1;
|
||||
@@ -145,13 +145,13 @@ static char *getpassf(char *filename)
|
||||
if (!filename) return NULL;
|
||||
|
||||
if ( (fd=open(filename,O_RDONLY)) == -1) {
|
||||
rprintf(FERROR,"could not open password file \"%s\"\n",filename);
|
||||
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) {
|
||||
rprintf(FERROR,"stat(%s) : %s\n", filename, strerror(errno));
|
||||
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");
|
||||
@@ -170,7 +170,7 @@ static char *getpassf(char *filename)
|
||||
if (envpw) rprintf(FERROR,"RSYNC_PASSWORD environment variable ignored\n");
|
||||
|
||||
buffer[sizeof(buffer)-1]='\0';
|
||||
if ( (len=read(fd,buffer,sizeof(buffer)-1)) > 0)
|
||||
if (read(fd,buffer,sizeof(buffer)-1) > 0)
|
||||
{
|
||||
char *p = strtok(buffer,"\n\r");
|
||||
close(fd);
|
||||
@@ -203,7 +203,7 @@ static void generate_hash(char *in, char *challenge, char *out)
|
||||
|
||||
otherwise return username
|
||||
*/
|
||||
char *auth_server(int fd, int module, char *addr, char *leader)
|
||||
char *auth_server(int f_in, int f_out, int module, char *addr, char *leader)
|
||||
{
|
||||
char *users = lp_auth_users(module);
|
||||
char challenge[16];
|
||||
@@ -222,9 +222,9 @@ char *auth_server(int fd, int module, char *addr, char *leader)
|
||||
|
||||
base64_encode(challenge, 16, b64_challenge);
|
||||
|
||||
io_printf(fd,"%s%s\n", leader, b64_challenge);
|
||||
io_printf(f_out, "%s%s\n", leader, b64_challenge);
|
||||
|
||||
if (!read_line(fd, line, sizeof(line)-1)) {
|
||||
if (!read_line(f_in, line, sizeof(line)-1)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -234,12 +234,12 @@ char *auth_server(int fd, int module, char *addr, char *leader)
|
||||
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 (strcmp(tok, user) == 0) break;
|
||||
if (fnmatch(tok, user, 0) == 0) break;
|
||||
}
|
||||
free(users);
|
||||
|
||||
@@ -272,6 +272,9 @@ void auth_client(int fd, char *user, char *challenge)
|
||||
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: ");
|
||||
}
|
||||
|
||||
|
||||
297
backup.c
Normal file
297
backup.c
Normal file
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
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 int suffix_specified;
|
||||
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) +
|
||||
(suffix_specified ? strlen(backup_suffix) : 0) > (MAXPATHLEN - 1)) {
|
||||
rprintf (FERROR, "keep_backup filename too long\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (suffix_specified) {
|
||||
snprintf(keep_name, sizeof (keep_name), "%s/%s%s", backup_dir, fname, backup_suffix);
|
||||
} else {
|
||||
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));
|
||||
}
|
||||
|
||||
610
batch.c
Normal file
610
batch.c
Normal file
@@ -0,0 +1,610 @@
|
||||
/* -*- c-file-style: "linux" -*-
|
||||
|
||||
Weiss 1/1999
|
||||
Batch utilities for rsync.
|
||||
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#include <time.h>
|
||||
|
||||
extern char *batch_prefix;
|
||||
|
||||
struct file_list *batch_flist;
|
||||
|
||||
static char rsync_flist_file[] = ".rsync_flist";
|
||||
static char rsync_csums_file[] = ".rsync_csums";
|
||||
static char rsync_delta_file[] = ".rsync_delta";
|
||||
static char rsync_argvs_file[] = ".rsync_argvs";
|
||||
|
||||
static int fdb;
|
||||
static int fdb_delta;
|
||||
static int fdb_open;
|
||||
static int fdb_close;
|
||||
|
||||
void write_batch_flist_file(char *buff, int bytes_to_write)
|
||||
{
|
||||
char filename[MAXPATHLEN];
|
||||
|
||||
if (fdb_open) {
|
||||
/* Set up file extension */
|
||||
strlcpy(filename, batch_prefix, sizeof(filename));
|
||||
strlcat(filename, rsync_flist_file, sizeof(filename));
|
||||
|
||||
/*
|
||||
* Open batch flist file for writing;
|
||||
* create it if it doesn't exist
|
||||
*/
|
||||
fdb = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
|
||||
S_IREAD | S_IWRITE);
|
||||
if (fdb == -1) {
|
||||
rprintf(FERROR, "Batch file %s open error: %s\n",
|
||||
filename, 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",
|
||||
filename, 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];
|
||||
|
||||
SIVAL(b, 0, buf != NULL ? strlen(buf) : 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]; /* XXX */
|
||||
char buff2[MAXPATHLEN + 6];
|
||||
char filename[MAXPATHLEN];
|
||||
|
||||
/* Set up file extension */
|
||||
strlcpy(filename, batch_prefix, sizeof(filename));
|
||||
strlcat(filename, rsync_argvs_file, sizeof(filename));
|
||||
|
||||
/*
|
||||
* Open batch argvs file for writing;
|
||||
* create it if it doesn't exist
|
||||
*/
|
||||
fdb = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
|
||||
S_IREAD | S_IWRITE | S_IEXEC);
|
||||
if (fdb == -1) {
|
||||
rprintf(FERROR, "Batch file %s open error: %s\n",
|
||||
filename, 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) /* Skip source directory on cmdline */
|
||||
continue;
|
||||
/*
|
||||
* FIXME:
|
||||
* I think directly manipulating argv[] is probably bogus
|
||||
*/
|
||||
if (!strncmp(argv[i], "--write-batch",
|
||||
strlen("--write-batch"))) {
|
||||
/* Safer to change it here than script */
|
||||
/*
|
||||
* Change to --read-batch=prefix
|
||||
* to get ready for remote
|
||||
*/
|
||||
strlcat(buff, "--read-batch=", sizeof(buff));
|
||||
strlcat(buff, batch_prefix, sizeof(buff));
|
||||
} else
|
||||
if (i == argc - 1) {
|
||||
snprintf(buff2, sizeof(buff2), "${1:-%s}", argv[i]);
|
||||
strlcat(buff, buff2, 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",
|
||||
filename, strerror(errno));
|
||||
close(fdb);
|
||||
exit_cleanup(1);
|
||||
}
|
||||
close(fdb);
|
||||
}
|
||||
|
||||
struct file_list *create_flist_from_batch(void)
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
||||
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;
|
||||
char filename[MAXPATHLEN];
|
||||
|
||||
if (fdb_open) {
|
||||
/* Set up file extension */
|
||||
strlcpy(filename, batch_prefix, sizeof(filename));
|
||||
strlcat(filename, rsync_flist_file, sizeof(filename));
|
||||
|
||||
/* Open batch flist file for reading */
|
||||
fdb = do_open(filename, O_RDONLY, 0);
|
||||
if (fdb == -1) {
|
||||
rprintf(FERROR, "Batch file %s open error: %s\n",
|
||||
filename, strerror(errno));
|
||||
close(fdb);
|
||||
exit_cleanup(1);
|
||||
}
|
||||
fdb_open = 0;
|
||||
}
|
||||
|
||||
/* Read flist batch file */
|
||||
|
||||
switch (bytes_read = read(fdb, buff, len)) {
|
||||
case -1:
|
||||
rprintf(FERROR, "Batch file %s read error: %s\n",
|
||||
filename, strerror(errno));
|
||||
close(fdb);
|
||||
exit_cleanup(1);
|
||||
break;
|
||||
case 0: /* EOF */
|
||||
close(fdb);
|
||||
}
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
unsigned char read_batch_flags(void)
|
||||
{
|
||||
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;
|
||||
|
||||
/*
|
||||
* Keep these in sync with bytes_to_write assignment
|
||||
* in write_batch_flist_info()
|
||||
*/
|
||||
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;
|
||||
char filename[MAXPATHLEN];
|
||||
|
||||
if (fdb_open) {
|
||||
/* Set up file extension */
|
||||
strlcpy(filename, batch_prefix, sizeof(filename));
|
||||
strlcat(filename, rsync_csums_file, sizeof(filename));
|
||||
|
||||
/*
|
||||
* Open batch csums file for writing;
|
||||
* create it if it doesn't exist
|
||||
*/
|
||||
fdb = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
|
||||
S_IREAD | S_IWRITE);
|
||||
if (fdb == -1) {
|
||||
rprintf(FERROR, "Batch file %s open error: %s\n",
|
||||
filename, 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",
|
||||
filename, strerror(errno));
|
||||
close(fdb);
|
||||
exit_cleanup(1);
|
||||
}
|
||||
}
|
||||
|
||||
void close_batch_csums_file(void)
|
||||
{
|
||||
close(fdb);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write csum info to batch file
|
||||
*
|
||||
* @todo This will break if s->count is ever larger than maxint. The
|
||||
* batch code should probably be changed to consistently use the
|
||||
* variable-length integer routines, which is probably a compatible
|
||||
* change.
|
||||
**/
|
||||
void write_batch_csum_info(int *flist_entry, int flist_count,
|
||||
struct sum_struct *s)
|
||||
{
|
||||
size_t i;
|
||||
int int_count;
|
||||
extern int csum_length;
|
||||
|
||||
fdb_open = 1;
|
||||
|
||||
write_batch_csums_file(flist_entry, sizeof(int));
|
||||
int_count = s ? (int) s->count : 0;
|
||||
write_batch_csums_file(&int_count, sizeof int_count);
|
||||
|
||||
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;
|
||||
char filename[MAXPATHLEN];
|
||||
|
||||
if (fdb_open) {
|
||||
/* Set up file extension */
|
||||
strlcpy(filename, batch_prefix, sizeof(filename));
|
||||
strlcat(filename, rsync_csums_file, sizeof(filename));
|
||||
|
||||
/* Open batch flist file for reading */
|
||||
fdb = do_open(filename, O_RDONLY, 0);
|
||||
if (fdb == -1) {
|
||||
rprintf(FERROR, "Batch file %s open error: %s\n",
|
||||
filename, 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",
|
||||
filename, 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_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;
|
||||
char filename[MAXPATHLEN];
|
||||
|
||||
if (fdb_delta_open) {
|
||||
/* Set up file extension */
|
||||
strlcpy(filename, batch_prefix, sizeof(filename));
|
||||
strlcat(filename, rsync_delta_file, sizeof(filename));
|
||||
|
||||
/*
|
||||
* Open batch delta file for writing;
|
||||
* create it if it doesn't exist
|
||||
*/
|
||||
fdb_delta = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
|
||||
S_IREAD | S_IWRITE);
|
||||
if (fdb_delta == -1) {
|
||||
rprintf(FERROR, "Batch file %s open error: %s\n",
|
||||
filename, 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",
|
||||
filename, strerror(errno));
|
||||
close(fdb_delta);
|
||||
exit_cleanup(1);
|
||||
}
|
||||
}
|
||||
|
||||
void close_batch_delta_file(void)
|
||||
{
|
||||
close(fdb_delta);
|
||||
}
|
||||
|
||||
int read_batch_delta_file(char *buff, int len)
|
||||
{
|
||||
static int fdb_delta_open = 1;
|
||||
int bytes_read;
|
||||
char filename[MAXPATHLEN];
|
||||
|
||||
if (fdb_delta_open) {
|
||||
/* Set up file extension */
|
||||
strlcpy(filename, batch_prefix, sizeof(filename));
|
||||
strlcat(filename, rsync_delta_file, sizeof(filename));
|
||||
|
||||
/* Open batch flist file for reading */
|
||||
fdb_delta = do_open(filename, O_RDONLY, 0);
|
||||
if (fdb_delta == -1) {
|
||||
rprintf(FERROR, "Batch file %s open error: %s\n",
|
||||
filename, 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",
|
||||
filename, 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]);
|
||||
|
||||
}
|
||||
}
|
||||
14
checksum.c
14
checksum.c
@@ -91,9 +91,9 @@ void file_checksum(char *fname,char *sum,OFF_T size)
|
||||
char tmpchunk[CSUM_CHUNK];
|
||||
struct mdfour m;
|
||||
|
||||
memset(sum,0,csum_length);
|
||||
memset(sum,0,MD4_SUM_LENGTH);
|
||||
|
||||
fd = open(fname,O_RDONLY);
|
||||
fd = do_open(fname, O_RDONLY, 0);
|
||||
if (fd == -1) return;
|
||||
|
||||
buf = map_file(fd,size);
|
||||
@@ -140,7 +140,15 @@ void sum_init(void)
|
||||
sum_update(s,4);
|
||||
}
|
||||
|
||||
void sum_update(char *p,int len)
|
||||
/**
|
||||
* Feed data into an MD4 accumulator, md. The results may be
|
||||
* retrieved using sum_end(). md is used for different purposes at
|
||||
* different points during execution.
|
||||
*
|
||||
* @todo Perhaps get rid of md and just pass in the address each time.
|
||||
* Very slightly clearer and slower.
|
||||
**/
|
||||
void sum_update(char *p, int len)
|
||||
{
|
||||
int i;
|
||||
if (len + sumresidue < CSUM_CHUNK) {
|
||||
|
||||
91
cleanup.c
91
cleanup.c
@@ -1,6 +1,8 @@
|
||||
/*
|
||||
Copyright (C) Andrew Tridgell 1996
|
||||
/* -*- c-file-style: "linux" -*-
|
||||
|
||||
Copyright (C) 1996-2000 by Andrew Tridgell
|
||||
Copyright (C) Paul Mackerras 1996
|
||||
Copyright (C) 2002 by Martin Pool
|
||||
|
||||
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,9 +21,50 @@
|
||||
|
||||
#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 */
|
||||
/**
|
||||
* Close all open sockets and files, allowing a (somewhat) graceful
|
||||
* shutdown() of socket connections. This eliminates the abortive
|
||||
* TCP RST sent by a Winsock-based system when the close() occurs.
|
||||
**/
|
||||
void close_all()
|
||||
{
|
||||
#ifdef SHUTDOWN_ALL_SOCKETS
|
||||
int max_fd;
|
||||
int fd;
|
||||
int ret;
|
||||
struct stat st;
|
||||
|
||||
max_fd = sysconf(_SC_OPEN_MAX) - 1;
|
||||
for (fd = max_fd; fd >= 0; fd--) {
|
||||
ret = fstat(fd,&st);
|
||||
if (fstat(fd,&st) == 0) {
|
||||
if (is_a_socket(fd)) {
|
||||
ret = shutdown(fd, 2);
|
||||
}
|
||||
ret = close(fd);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @file cleanup.c
|
||||
*
|
||||
* Code for handling interrupted transfers. Depending on the @c
|
||||
* --partial option, we may either delete the temporary file, or go
|
||||
* ahead and overwrite the destination. This second behaviour only
|
||||
* occurs if we've sent literal data and therefore hopefully made
|
||||
* progress on the transfer.
|
||||
**/
|
||||
|
||||
/**
|
||||
* Set to True once literal data has been sent across the link for the
|
||||
* current file. (????)
|
||||
*
|
||||
* 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;
|
||||
@@ -32,13 +75,40 @@ static struct map_struct *cleanup_buf;
|
||||
static int cleanup_pid = 0;
|
||||
extern int io_error;
|
||||
|
||||
pid_t cleanup_child_pid = -1;
|
||||
|
||||
/**
|
||||
* Eventually calls exit(), passing @p code, therefore does not return.
|
||||
*
|
||||
* @param code one of the RERR_* codes from errcode.h.
|
||||
**/
|
||||
void _exit_cleanup(int code, const char *file, int line)
|
||||
{
|
||||
int ocode = code;
|
||||
extern int keep_partial;
|
||||
extern int log_got_error;
|
||||
static int inside_cleanup = 0;
|
||||
|
||||
if (code == 0 && io_error) code = RERR_FILEIO;
|
||||
if (inside_cleanup > 10) {
|
||||
/* prevent the occasional infinite recursion */
|
||||
return;
|
||||
}
|
||||
inside_cleanup++;
|
||||
|
||||
signal(SIGUSR1, SIG_IGN);
|
||||
signal(SIGUSR2, SIG_IGN);
|
||||
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO,"_exit_cleanup(code=%d, file=%s, line=%d): entered\n",
|
||||
code, file, line);
|
||||
|
||||
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;
|
||||
@@ -61,8 +131,17 @@ void _exit_cleanup(int code, const char *file, int line)
|
||||
}
|
||||
}
|
||||
|
||||
if (code == 0 && (io_error || log_got_error)) {
|
||||
code = RERR_PARTIAL;
|
||||
}
|
||||
|
||||
if (code) log_exit(code, file, line);
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"_exit_cleanup(code=%d, file=%s, line=%d): about to call exit(%d)\n",
|
||||
ocode, file, line, code);
|
||||
|
||||
close_all();
|
||||
exit(code);
|
||||
}
|
||||
|
||||
|
||||
364
clientname.c
Normal file
364
clientname.c
Normal file
@@ -0,0 +1,364 @@
|
||||
/* -*- 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 clientname.c
|
||||
*
|
||||
* Functions for looking up the remote name or addr of a socket.
|
||||
*
|
||||
* 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";
|
||||
extern int am_daemon;
|
||||
extern int am_server;
|
||||
|
||||
|
||||
/**
|
||||
* Return the IP addr of the client as a string
|
||||
**/
|
||||
char *client_addr(int fd)
|
||||
{
|
||||
struct sockaddr_storage ss;
|
||||
socklen_t length = sizeof ss;
|
||||
char *ssh_client, *p;
|
||||
int len;
|
||||
static char addr_buf[100];
|
||||
static int initialised;
|
||||
|
||||
if (initialised) return addr_buf;
|
||||
|
||||
initialised = 1;
|
||||
|
||||
if (am_server) {
|
||||
/* daemon over --rsh mode */
|
||||
strcpy(addr_buf, "0.0.0.0");
|
||||
if ((ssh_client = getenv("SSH_CLIENT")) != NULL) {
|
||||
/* truncate SSH_CLIENT to just IP address */
|
||||
p = strchr(ssh_client, ' ');
|
||||
if (p) {
|
||||
len = MIN((unsigned int) (p - ssh_client),
|
||||
sizeof(addr_buf) - 1);
|
||||
strncpy(addr_buf, ssh_client, len);
|
||||
*(addr_buf + len) = '\0';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
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.
|
||||
*
|
||||
* After translation from sockaddr to name we do a forward lookup to
|
||||
* make sure nobody is spoofing PTR records.
|
||||
**/
|
||||
char *client_name(int fd)
|
||||
{
|
||||
static char name_buf[100];
|
||||
static char port_buf[100];
|
||||
static int initialised;
|
||||
struct sockaddr_storage ss, *ssp;
|
||||
struct sockaddr_in sin;
|
||||
#ifdef INET6
|
||||
struct sockaddr_in6 sin6;
|
||||
#endif
|
||||
socklen_t ss_len;
|
||||
|
||||
if (initialised) return name_buf;
|
||||
|
||||
strcpy(name_buf, default_name);
|
||||
initialised = 1;
|
||||
|
||||
if (am_server) {
|
||||
/* daemon over --rsh mode */
|
||||
|
||||
char *addr = client_addr(fd);
|
||||
#ifdef INET6
|
||||
int dots = 0;
|
||||
char *p;
|
||||
|
||||
for (p = addr; *p && (dots <= 3); p++) {
|
||||
if (*p == '.')
|
||||
dots++;
|
||||
}
|
||||
if (dots > 3) {
|
||||
/* more than 4 parts to IP address, must be ipv6 */
|
||||
ssp = (struct sockaddr_storage *) &sin6;
|
||||
ss_len = sizeof sin6;
|
||||
memset(ssp, 0, ss_len);
|
||||
inet_pton(AF_INET6, addr, &sin6.sin6_addr);
|
||||
sin6.sin6_family = AF_INET6;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
ssp = (struct sockaddr_storage *) &sin;
|
||||
ss_len = sizeof sin;
|
||||
memset(ssp, 0, ss_len);
|
||||
inet_pton(AF_INET, addr, &sin.sin_addr);
|
||||
sin.sin_family = AF_INET;
|
||||
}
|
||||
|
||||
} else {
|
||||
ss_len = sizeof ss;
|
||||
ssp = &ss;
|
||||
|
||||
client_sockaddr(fd, &ss, &ss_len);
|
||||
|
||||
}
|
||||
|
||||
if (!lookup_name(fd, ssp, ss_len, name_buf, sizeof name_buf,
|
||||
port_buf, sizeof port_buf))
|
||||
check_name(fd, ssp, name_buf);
|
||||
|
||||
return name_buf;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the sockaddr for the client.
|
||||
*
|
||||
* If it comes in as an ipv4 address mapped into IPv6 format then we
|
||||
* convert it back to a regular IPv4.
|
||||
**/
|
||||
void client_sockaddr(int fd,
|
||||
struct sockaddr_storage *ss,
|
||||
socklen_t *ss_len)
|
||||
{
|
||||
memset(ss, 0, sizeof(*ss));
|
||||
|
||||
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.
|
||||
*
|
||||
* @param fd file descriptor for client socket.
|
||||
**/
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Compare an addrinfo from the resolver to a sockinfo.
|
||||
*
|
||||
* Like strcmp, returns 0 for identical.
|
||||
**/
|
||||
int compare_addrinfo_sockaddr(const struct addrinfo *ai,
|
||||
const struct sockaddr_storage *ss)
|
||||
{
|
||||
int ss_family = get_sockaddr_family(ss);
|
||||
const char fn[] = "compare_addrinfo_sockaddr";
|
||||
|
||||
if (ai->ai_family != ss_family) {
|
||||
rprintf(FERROR,
|
||||
"%s: response family %d != %d\n",
|
||||
fn, ai->ai_family, ss_family);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* The comparison method depends on the particular AF. */
|
||||
if (ss_family == AF_INET) {
|
||||
const struct sockaddr_in *sin1, *sin2;
|
||||
|
||||
sin1 = (const struct sockaddr_in *) ss;
|
||||
sin2 = (const struct sockaddr_in *) ai->ai_addr;
|
||||
|
||||
return memcmp(&sin1->sin_addr, &sin2->sin_addr,
|
||||
sizeof sin1->sin_addr);
|
||||
}
|
||||
#ifdef INET6
|
||||
else if (ss_family == AF_INET6) {
|
||||
const struct sockaddr_in6 *sin1, *sin2;
|
||||
|
||||
sin1 = (const struct sockaddr_in6 *) ss;
|
||||
sin2 = (const struct sockaddr_in6 *) ai->ai_addr;
|
||||
|
||||
if (ai->ai_addrlen < sizeof(struct sockaddr_in6)) {
|
||||
rprintf(FERROR,
|
||||
"%s: too short sockaddr_in6; length=%d\n",
|
||||
fn, ai->ai_addrlen);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (memcmp(&sin1->sin6_addr, &sin2->sin6_addr,
|
||||
sizeof sin1->sin6_addr))
|
||||
return 1;
|
||||
|
||||
#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
|
||||
if (sin1->sin6_scope_id != sin2->sin6_scope_id)
|
||||
return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#endif /* INET6 */
|
||||
else {
|
||||
/* don't know */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Do a forward lookup on @p name_buf and make sure it corresponds to
|
||||
* @p ss -- otherwise we may be being spoofed. If we suspect we are,
|
||||
* then we don't abort the connection but just emit a warning, and
|
||||
* change @p name_buf to be "UNKNOWN".
|
||||
*
|
||||
* We don't do anything with the service when checking the name,
|
||||
* because it doesn't seem that it could be spoofed in any way, and
|
||||
* getaddrinfo on random service names seems to cause problems on AIX.
|
||||
**/
|
||||
int check_name(int fd,
|
||||
const struct sockaddr_storage *ss,
|
||||
char *name_buf)
|
||||
{
|
||||
struct addrinfo hints, *res, *res0;
|
||||
int error;
|
||||
int ss_family = get_sockaddr_family(ss);
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = ss_family;
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
error = getaddrinfo(name_buf, NULL, &hints, &res0);
|
||||
if (error) {
|
||||
rprintf(FERROR,
|
||||
RSYNC_NAME ": forward name lookup for %s failed: %s\n",
|
||||
name_buf, gai_strerror(error));
|
||||
strcpy(name_buf, default_name);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/* Given all these results, we expect that one of them will be
|
||||
* the same as ss. The comparison is a bit complicated. */
|
||||
for (res = res0; res; res = res->ai_next) {
|
||||
if (!compare_addrinfo_sockaddr(res, ss))
|
||||
break; /* OK, identical */
|
||||
}
|
||||
|
||||
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);
|
||||
} else 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;
|
||||
}
|
||||
|
||||
387
clientserver.c
387
clientserver.c
@@ -1,22 +1,29 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
/* -*- c-file-style: "linux"; -*-
|
||||
*
|
||||
* Copyright (C) 1998-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.
|
||||
*/
|
||||
|
||||
/* the socket based protocol for setting up a connection wit rsyncd */
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* The socket based protocol for setting up a connection with
|
||||
* rsyncd.
|
||||
**/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
@@ -25,19 +32,34 @@ extern int read_only;
|
||||
extern int verbose;
|
||||
extern int rsync_port;
|
||||
char *auth_user;
|
||||
extern int sanitize_paths;
|
||||
|
||||
/**
|
||||
* Run a client connected to an rsyncd. The alternative to this
|
||||
* function for remote-shell connections is do_cmd().
|
||||
*
|
||||
* After negotiating which module to use and reading the server's
|
||||
* motd, this hands over to client_run(). Telling the server the
|
||||
* module will cause it to chroot/setuid/etc.
|
||||
*
|
||||
* Instead of doing a transfer, the client may at this stage instead
|
||||
* get a listing of remote modules and exit.
|
||||
*
|
||||
* @return -1 for error in startup, or the result of client_run().
|
||||
* Either way, it eventually gets passed to exit_cleanup().
|
||||
**/
|
||||
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];
|
||||
int fd, ret;
|
||||
char *p, *user=NULL;
|
||||
extern int remote_version;
|
||||
extern int am_sender;
|
||||
|
||||
extern char *bind_address;
|
||||
extern int default_af_hint;
|
||||
|
||||
/* this is redundant with code in start_inband_exchange(), but
|
||||
this short-circuits a problem before we open a socket, and
|
||||
the extra check won't hurt */
|
||||
if (*path == '/') {
|
||||
rprintf(FERROR,"ERROR: The remote path must start with a module name\n");
|
||||
rprintf(FERROR,"ERROR: The remote path must start with a module name not a /\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -48,15 +70,53 @@ int start_socket_client(char *host, char *path, int argc, char *argv[])
|
||||
*p = 0;
|
||||
}
|
||||
|
||||
if (!user) user = getenv("USER");
|
||||
if (!user) user = getenv("LOGNAME");
|
||||
|
||||
fd = open_socket_out(host, rsync_port);
|
||||
if (verbose >= 2) {
|
||||
/* FIXME: If we're going to use a socket program for
|
||||
* testing, then this message is wrong. We need to
|
||||
* say something like "(except really using %s)" */
|
||||
rprintf(FINFO, "opening tcp connection to %s port %d\n",
|
||||
host, rsync_port);
|
||||
}
|
||||
fd = open_socket_out_wrapped (host, rsync_port, bind_address,
|
||||
default_af_hint);
|
||||
if (fd == -1) {
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
}
|
||||
|
||||
server_options(sargs,&sargc);
|
||||
|
||||
ret = start_inband_exchange(user, path, fd, fd, argc);
|
||||
|
||||
return ret < 0? ret : client_run(fd, fd, -1, argc, argv);
|
||||
}
|
||||
|
||||
int start_inband_exchange(char *user, char *path, int f_in, int f_out, int argc)
|
||||
{
|
||||
int i;
|
||||
char *sargs[MAX_ARGS];
|
||||
int sargc = 0;
|
||||
char line[MAXPATHLEN];
|
||||
char *p;
|
||||
extern int remote_version;
|
||||
extern int kludge_around_eof;
|
||||
extern int am_sender;
|
||||
extern int daemon_over_rsh;
|
||||
extern int list_only;
|
||||
|
||||
if (argc == 0 && !am_sender)
|
||||
list_only = 1;
|
||||
|
||||
if (*path == '/') {
|
||||
rprintf(FERROR, "ERROR: The remote path must start with a module name\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!user) user = getenv("USER");
|
||||
if (!user) user = getenv("LOGNAME");
|
||||
|
||||
/* set daemon_over_rsh to false since we need to build the
|
||||
true set of args passed through the rsh/ssh connection;
|
||||
this is a no-op for direct-socket-connection mode */
|
||||
daemon_over_rsh = 0;
|
||||
server_options(sargs, &sargc);
|
||||
|
||||
sargs[sargc++] = ".";
|
||||
|
||||
@@ -65,113 +125,145 @@ int start_socket_client(char *host, char *path, int argc, char *argv[])
|
||||
|
||||
sargs[sargc] = NULL;
|
||||
|
||||
io_printf(fd,"@RSYNCD: %d\n", PROTOCOL_VERSION);
|
||||
io_printf(f_out, "@RSYNCD: %d\n", PROTOCOL_VERSION);
|
||||
|
||||
if (!read_line(fd, line, sizeof(line)-1)) {
|
||||
if (!read_line(f_in, line, sizeof(line)-1)) {
|
||||
rprintf(FERROR, "rsync: did not see server greeting\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sscanf(line,"@RSYNCD: %d", &remote_version) != 1) {
|
||||
/* note that read_line strips of \n or \r */
|
||||
rprintf(FERROR, "rsync: server sent \"%s\" rather than greeting\n",
|
||||
line);
|
||||
return -1;
|
||||
}
|
||||
|
||||
p = strchr(path,'/');
|
||||
if (p) *p = 0;
|
||||
io_printf(fd,"%s\n",path);
|
||||
io_printf(f_out, "%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 = list_only && (remote_version < 25);
|
||||
|
||||
while (1) {
|
||||
if (!read_line(fd, line, sizeof(line)-1)) {
|
||||
if (!read_line(f_in, line, sizeof(line)-1)) {
|
||||
rprintf(FERROR, "rsync: didn't get server startup line\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strncmp(line,"@RSYNCD: AUTHREQD ",18) == 0) {
|
||||
auth_client(fd, user, line+18);
|
||||
auth_client(f_out, user, line+18);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(line,"@RSYNCD: OK") == 0) break;
|
||||
rprintf(FINFO,"%s\n", line);
|
||||
|
||||
if (strcmp(line,"@RSYNCD: EXIT") == 0) {
|
||||
/* This is sent by recent versions of the
|
||||
* server to terminate the listing of modules.
|
||||
* We don't want to go on and transfer
|
||||
* anything; just exit. */
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (strncmp(line, "@ERROR", 6) == 0) {
|
||||
rprintf(FERROR,"%s\n", line);
|
||||
/* This is always fatal; the server will now
|
||||
* close the socket. */
|
||||
return RERR_STARTCLIENT;
|
||||
} else {
|
||||
rprintf(FINFO,"%s\n", line);
|
||||
}
|
||||
}
|
||||
kludge_around_eof = False;
|
||||
|
||||
for (i = 0; i < sargc; i++) {
|
||||
io_printf(f_out, "%s\n", sargs[i]);
|
||||
}
|
||||
io_printf(f_out, "\n");
|
||||
|
||||
if (remote_version < 23) {
|
||||
if (remote_version == 22 || (remote_version > 17 && !am_sender))
|
||||
io_start_multiplex_in(f_in);
|
||||
}
|
||||
|
||||
for (i=0;i<sargc;i++) {
|
||||
io_printf(fd,"%s\n", sargs[i]);
|
||||
}
|
||||
io_printf(fd,"\n");
|
||||
|
||||
if (remote_version > 17 && !am_sender)
|
||||
io_start_multiplex_in(fd);
|
||||
|
||||
return client_run(fd, fd, -1, argc, argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int rsync_module(int fd, int i)
|
||||
static int rsync_module(int f_in, int f_out, int i)
|
||||
{
|
||||
int argc=0;
|
||||
char *argv[MAX_ARGS];
|
||||
char **argp;
|
||||
char line[MAXPATHLEN];
|
||||
uid_t uid = (uid_t)-2;
|
||||
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 *addr = client_addr(f_in);
|
||||
char *host = client_name(f_in);
|
||||
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 am_server;
|
||||
extern int am_daemon;
|
||||
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, client_name(fd), client_addr(fd));
|
||||
io_printf(fd,"@ERROR: access denied to %s from %s (%s)\n",
|
||||
name, client_name(fd), client_addr(fd));
|
||||
name, host, addr);
|
||||
io_printf(f_out, "@ERROR: access denied to %s from %s (%s)\n",
|
||||
name, host, addr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (am_daemon && am_server) {
|
||||
rprintf(FINFO, "rsync allowed access on module %s from %s (%s)\n",
|
||||
name, host, addr);
|
||||
}
|
||||
|
||||
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",
|
||||
io_printf(f_out, "@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));
|
||||
io_printf(f_out, "@ERROR: max connections (%d) reached - try again later\n", lp_max_connections(i));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
auth_user = auth_server(fd, i, addr, "@RSYNCD: AUTHREQD ");
|
||||
auth_user = auth_server(f_in, f_out, 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);
|
||||
name, host, addr);
|
||||
io_printf(f_out, "@ERROR: auth failed on module %s\n", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
module_id = i;
|
||||
|
||||
if (lp_read_only(i))
|
||||
read_only = 1;
|
||||
|
||||
am_root = (getuid() == 0);
|
||||
|
||||
if (am_root) {
|
||||
p = lp_uid(i);
|
||||
if (!name_to_uid(p, &uid)) {
|
||||
if (!isdigit(*p)) {
|
||||
if (!isdigit(* (unsigned char *) p)) {
|
||||
rprintf(FERROR,"Invalid uid %s\n", p);
|
||||
io_printf(fd,"@ERROR: invalid uid\n");
|
||||
io_printf(f_out, "@ERROR: invalid uid %s\n", p);
|
||||
return -1;
|
||||
}
|
||||
uid = atoi(p);
|
||||
@@ -179,14 +271,21 @@ static int rsync_module(int fd, int i)
|
||||
|
||||
p = lp_gid(i);
|
||||
if (!name_to_gid(p, &gid)) {
|
||||
if (!isdigit(*p)) {
|
||||
if (!isdigit(* (unsigned char *) p)) {
|
||||
rprintf(FERROR,"Invalid gid %s\n", p);
|
||||
io_printf(fd,"@ERROR: invalid gid\n");
|
||||
io_printf(f_out, "@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);
|
||||
@@ -200,51 +299,84 @@ static int rsync_module(int fd, int i)
|
||||
p = lp_exclude(i);
|
||||
add_exclude_line(p);
|
||||
|
||||
log_open();
|
||||
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))) {
|
||||
rprintf(FERROR,"chroot %s failed\n", lp_path(i));
|
||||
io_printf(fd,"@ERROR: chroot failed\n");
|
||||
rsyserr(FERROR, errno, "chroot %s failed", lp_path(i));
|
||||
io_printf(f_out, "@ERROR: chroot failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!push_dir("/", 0)) {
|
||||
rprintf(FERROR,"chdir %s failed\n", lp_path(i));
|
||||
io_printf(fd,"@ERROR: chdir failed\n");
|
||||
rsyserr(FERROR, errno, "chdir %s failed\n", lp_path(i));
|
||||
io_printf(f_out, "@ERROR: chdir failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!push_dir(lp_path(i), 0)) {
|
||||
rprintf(FERROR,"chdir %s failed\n", lp_path(i));
|
||||
io_printf(fd,"@ERROR: chdir failed\n");
|
||||
rsyserr(FERROR, errno, "chdir %s failed\n", lp_path(i));
|
||||
io_printf(f_out, "@ERROR: chdir failed\n");
|
||||
return -1;
|
||||
}
|
||||
sanitize_paths = 1;
|
||||
}
|
||||
|
||||
if (am_root) {
|
||||
#ifdef HAVE_SETGROUPS
|
||||
/* Get rid of any supplementary groups this process
|
||||
* might have inheristed. */
|
||||
if (setgroups(0, NULL)) {
|
||||
rsyserr(FERROR, errno, "setgroups failed");
|
||||
io_printf(f_out, "@ERROR: setgroups failed\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* XXXX: You could argue that if the daemon is started
|
||||
* by a non-root user and they explicitly specify a
|
||||
* gid, then we should try to change to that gid --
|
||||
* this could be possible if it's already in their
|
||||
* supplementary groups. */
|
||||
|
||||
/* TODO: Perhaps we need to document that if rsyncd is
|
||||
* started by somebody other than root it will inherit
|
||||
* all their supplementary groups. */
|
||||
|
||||
if (setgid(gid)) {
|
||||
rprintf(FERROR,"setgid %d failed\n", gid);
|
||||
io_printf(fd,"@ERROR: setgid failed\n");
|
||||
rsyserr(FERROR, errno, "setgid %d failed", (int) gid);
|
||||
io_printf(f_out, "@ERROR: setgid failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setuid(uid)) {
|
||||
rprintf(FERROR,"setuid %d failed\n", uid);
|
||||
io_printf(fd,"@ERROR: setuid failed\n");
|
||||
rsyserr(FERROR, errno, "setuid %d failed", (int) uid);
|
||||
io_printf(f_out, "@ERROR: setuid failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
am_root = (getuid() == 0);
|
||||
}
|
||||
|
||||
io_printf(fd,"@RSYNCD: OK\n");
|
||||
io_printf(f_out, "@RSYNCD: OK\n");
|
||||
|
||||
argv[argc++] = "rsyncd";
|
||||
|
||||
while (1) {
|
||||
if (!read_line(fd, line, sizeof(line)-1)) {
|
||||
if (!read_line(f_in, line, sizeof(line)-1)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -262,7 +394,7 @@ static int rsync_module(int fd, int i)
|
||||
request = strdup(p);
|
||||
start_glob++;
|
||||
}
|
||||
glob_expand(name, argv, &argc, MAX_ARGS, !use_chroot);
|
||||
glob_expand(name, argv, &argc, MAX_ARGS);
|
||||
} else {
|
||||
argc++;
|
||||
}
|
||||
@@ -276,7 +408,7 @@ static int rsync_module(int fd, int i)
|
||||
}
|
||||
}
|
||||
|
||||
if (!use_chroot) {
|
||||
if (sanitize_paths) {
|
||||
/*
|
||||
* Note that this is applied to all parameters, whether or not
|
||||
* they are filenames, but no other legal parameters contain
|
||||
@@ -285,11 +417,12 @@ static int rsync_module(int fd, int i)
|
||||
* and which aren't.
|
||||
*/
|
||||
for (i = 1; i < argc; i++) {
|
||||
sanitize_path(argv[i]);
|
||||
sanitize_path(argv[i], NULL);
|
||||
}
|
||||
}
|
||||
|
||||
ret = parse_arguments(argc, argv, 0);
|
||||
argp = argv;
|
||||
ret = parse_arguments(&argc, (const char ***) &argp, 0);
|
||||
|
||||
if (request) {
|
||||
if (*auth_user) {
|
||||
@@ -304,20 +437,27 @@ static int rsync_module(int fd, int i)
|
||||
free(request);
|
||||
}
|
||||
|
||||
#if !TRIDGE
|
||||
#ifndef DEBUG
|
||||
/* don't allow the logs to be flooded too fast */
|
||||
if (verbose > 1) verbose = 1;
|
||||
#endif
|
||||
|
||||
argc -= optind;
|
||||
argp = argv + optind;
|
||||
optind = 0;
|
||||
|
||||
if (remote_version > 17 && am_sender)
|
||||
io_start_multiplex_out(fd);
|
||||
if (remote_version < 23) {
|
||||
if (remote_version == 22 || (remote_version > 17 && am_sender))
|
||||
io_start_multiplex_out(f_out);
|
||||
}
|
||||
|
||||
/* 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();
|
||||
option_error();
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
|
||||
if (lp_timeout(i)) {
|
||||
@@ -325,7 +465,7 @@ static int rsync_module(int fd, int i)
|
||||
io_timeout = lp_timeout(i);
|
||||
}
|
||||
|
||||
start_server(fd, fd, argc, argp);
|
||||
start_server(f_in, f_out, argc, argp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -336,32 +476,41 @@ 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
|
||||
/* this is called when a 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)
|
||||
int start_daemon(int f_in, int f_out)
|
||||
{
|
||||
char line[200];
|
||||
char *motd;
|
||||
int i = -1;
|
||||
extern char *config_file;
|
||||
extern int remote_version;
|
||||
extern int am_server;
|
||||
|
||||
if (!lp_load(config_file, 0)) {
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
set_socket_options(fd,"SO_KEEPALIVE");
|
||||
set_socket_options(fd,lp_socket_options());
|
||||
|
||||
log_init();
|
||||
|
||||
io_printf(fd,"@RSYNCD: %d\n", PROTOCOL_VERSION);
|
||||
if (!am_server) {
|
||||
set_socket_options(f_in, "SO_KEEPALIVE");
|
||||
set_socket_options(f_in, lp_socket_options());
|
||||
set_nonblocking(f_in);
|
||||
}
|
||||
|
||||
io_printf(f_out, "@RSYNCD: %d\n", PROTOCOL_VERSION);
|
||||
|
||||
motd = lp_motd_file();
|
||||
if (motd && *motd) {
|
||||
@@ -370,47 +519,47 @@ static int start_daemon(int fd)
|
||||
int len = fread(line, 1, sizeof(line)-1, f);
|
||||
if (len > 0) {
|
||||
line[len] = 0;
|
||||
io_printf(fd,"%s", line);
|
||||
io_printf(f_out, "%s", line);
|
||||
}
|
||||
}
|
||||
if (f) fclose(f);
|
||||
io_printf(fd,"\n");
|
||||
io_printf(f_out, "\n");
|
||||
}
|
||||
|
||||
if (!read_line(fd, line, sizeof(line)-1)) {
|
||||
if (!read_line(f_in, line, sizeof(line)-1)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sscanf(line,"@RSYNCD: %d", &remote_version) != 1) {
|
||||
io_printf(fd,"@ERROR: protocol startup error\n");
|
||||
io_printf(f_out, "@ERROR: protocol startup error\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (i == -1) {
|
||||
line[0] = 0;
|
||||
if (!read_line(fd, line, sizeof(line)-1)) {
|
||||
if (!read_line(f_in, line, sizeof(line)-1)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!*line || strcmp(line,"#list")==0) {
|
||||
send_listing(fd);
|
||||
send_listing(f_out);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*line == '#') {
|
||||
/* it's some sort of command that I don't understand */
|
||||
io_printf(fd,"@ERROR: Unknown command '%s'\n", line);
|
||||
io_printf(f_out, "@ERROR: Unknown command '%s'\n", line);
|
||||
return -1;
|
||||
}
|
||||
|
||||
i = lp_number(line);
|
||||
if (i == -1) {
|
||||
io_printf(fd,"@ERROR: Unknown module '%s'\n", line);
|
||||
io_printf(f_out, "@ERROR: Unknown module '%s'\n", line);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return rsync_module(fd, i);
|
||||
return rsync_module(f_in, f_out, i);
|
||||
}
|
||||
|
||||
|
||||
@@ -419,6 +568,7 @@ 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;
|
||||
@@ -431,21 +581,24 @@ int daemon_main(void)
|
||||
open("/dev/null", O_RDWR);
|
||||
}
|
||||
|
||||
set_nonblocking(STDIN_FILENO);
|
||||
|
||||
return start_daemon(STDIN_FILENO);
|
||||
return start_daemon(STDIN_FILENO, STDIN_FILENO);
|
||||
}
|
||||
|
||||
become_daemon();
|
||||
if (!no_detach)
|
||||
become_daemon();
|
||||
|
||||
if (!lp_load(config_file, 1)) {
|
||||
fprintf(stderr,"failed to load config file %s\n", config_file);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
log_open();
|
||||
log_init();
|
||||
|
||||
rprintf(FINFO,"rsyncd version %s starting\n",VERSION);
|
||||
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];
|
||||
@@ -455,10 +608,10 @@ int daemon_main(void)
|
||||
if ((fd = do_open(lp_pid_file(), O_WRONLY|O_CREAT|O_TRUNC,
|
||||
0666 & ~orig_umask)) == -1) {
|
||||
cleanup_set_pid(0);
|
||||
fprintf(stderr,"failed to create pid file %s\n", pid_file);
|
||||
rsyserr(FLOG, errno, "failed to create pid file %s", pid_file);
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
slprintf(pidbuf, sizeof(pidbuf), "%d\n", pid);
|
||||
snprintf(pidbuf, sizeof(pidbuf), "%d\n", pid);
|
||||
write(fd, pidbuf, strlen(pidbuf));
|
||||
close(fd);
|
||||
}
|
||||
|
||||
18
compat.c
18
compat.c
@@ -17,14 +17,16 @@
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/* compatability routines for older rsync protocol versions */
|
||||
/**
|
||||
* @file compat.c
|
||||
*
|
||||
* Compatibility routines for older rsync protocol versions.
|
||||
**/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
extern int am_server;
|
||||
|
||||
extern int csum_length;
|
||||
|
||||
extern int preserve_links;
|
||||
extern int preserve_perms;
|
||||
extern int preserve_devices;
|
||||
@@ -38,6 +40,9 @@ 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 (remote_version == 0) {
|
||||
@@ -57,12 +62,11 @@ void setup_protocol(int f_out,int f_in)
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "local_version=%d remote_version=%d\n",
|
||||
PROTOCOL_VERSION, remote_version);
|
||||
|
||||
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 {
|
||||
|
||||
1072
config.guess
vendored
1072
config.guess
vendored
File diff suppressed because it is too large
Load Diff
728
config.sub
vendored
728
config.sub
vendored
File diff suppressed because it is too large
Load Diff
646
configure.in
646
configure.in
@@ -1,20 +1,260 @@
|
||||
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)
|
||||
|
||||
# compile with optimisation and without debugging by default
|
||||
CFLAGS=${CFLAGS-"-O"}
|
||||
RSYNC_VERSION=2.5.6
|
||||
AC_SUBST(RSYNC_VERSION)
|
||||
AC_MSG_NOTICE([Configuring rsync $RSYNC_VERSION])
|
||||
|
||||
AC_CANONICAL_SYSTEM
|
||||
AC_VALIDATE_CACHE_SYSTEM_TYPE
|
||||
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_DEFINE([_GNU_SOURCE], 1,
|
||||
[Define _GNU_SOURCE so that we get all necessary prototypes])
|
||||
|
||||
if test "x$ac_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
|
||||
|
||||
|
||||
# Specifically, this turns on panic_action handling.
|
||||
AC_ARG_ENABLE(maintainer-mode,
|
||||
AC_HELP_STRING([--enable-maintainer-mode],
|
||||
[turn on extra debug features],
|
||||
[], []))
|
||||
if test x"$enable_maintainer_mode" = xyes
|
||||
then
|
||||
CFLAGS="$CFLAGS -DMAINTAINER_MODE"
|
||||
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", [location of rsync on remote machine])
|
||||
|
||||
AC_ARG_WITH(rsh,
|
||||
AC_HELP_STRING([--with-rsh=CMD], [set rsh command to CMD (default: \"remsh\" or \"rsh\")]))
|
||||
|
||||
AC_CHECK_PROG(HAVE_REMSH, remsh, 1, 0)
|
||||
AC_DEFINE_UNQUOTED(HAVE_REMSH, $HAVE_REMSH)
|
||||
AC_DEFINE_UNQUOTED(HAVE_REMSH, $HAVE_REMSH, [remote shell is remsh not rsh])
|
||||
|
||||
if test x"$with_rsh" != x
|
||||
then
|
||||
RSYNC_RSH="$with_rsh"
|
||||
elif test x"$HAVE_REMSH" = x1
|
||||
then
|
||||
RSYNC_RSH="remsh"
|
||||
else
|
||||
RSYNC_RSH="rsh"
|
||||
fi
|
||||
|
||||
AC_DEFINE_UNQUOTED(RSYNC_RSH, "$RSYNC_RSH", [default -e command])
|
||||
|
||||
# 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_MSG_CHECKING([whether to call shutdown on all sockets])
|
||||
case $host_os in
|
||||
*cygwin* ) AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(SHUTDOWN_ALL_SOCKETS, 1,
|
||||
[Define if sockets need to be shutdown])
|
||||
;;
|
||||
* ) AC_MSG_RESULT(no);;
|
||||
esac
|
||||
|
||||
AC_C_BIGENDIAN
|
||||
AC_HEADER_DIRENT
|
||||
@@ -22,8 +262,11 @@ 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)
|
||||
AC_CHECK_HEADERS(sys/filio.h string.h stdlib.h sys/socket.h sys/mode.h sys/un.h)
|
||||
AC_CHECK_HEADERS(glob.h mcheck.h sys/sysctl.h arpa/inet.h arpa/nameser.h)
|
||||
AC_CHECK_HEADERS(netdb.h)
|
||||
AC_CHECK_HEADERS(malloc.h)
|
||||
AC_CHECK_HEADERS(float.h)
|
||||
|
||||
AC_CHECK_SIZEOF(int)
|
||||
AC_CHECK_SIZEOF(long)
|
||||
@@ -38,119 +281,22 @@ AC_TYPE_OFF_T
|
||||
AC_TYPE_SIZE_T
|
||||
AC_TYPE_PID_T
|
||||
AC_TYPE_GETGROUPS
|
||||
AC_STRUCT_ST_RDEV
|
||||
AC_CHECK_TYPE(ino_t,unsigned)
|
||||
AC_CHECK_MEMBERS([struct stat.st_rdev])
|
||||
|
||||
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)
|
||||
fi
|
||||
|
||||
AC_FUNC_MEMCMP
|
||||
AC_FUNC_UTIME_NULL
|
||||
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 setsid glob strpbrk)
|
||||
AC_CHECK_FUNCS(strlcat strlcpy)
|
||||
|
||||
AC_CACHE_CHECK([for working fnmatch],rsync_cv_HAVE_FNMATCH,[
|
||||
AC_TRY_RUN([#include <fnmatch.h>
|
||||
main() { exit(fnmatch("*.o", "x.o", 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)
|
||||
fi
|
||||
|
||||
# sometimes getopt_long cannot parse same arguments twice
|
||||
# e.g. on certain versions of CygWin32
|
||||
AC_CACHE_CHECK([for working getopt_long],rsync_cv_HAVE_GETOPT_LONG,[
|
||||
AC_TRY_RUN([#include <getopt.h>
|
||||
main() {
|
||||
int i, x = 0; char *argv[] = { "x", "--xx" };
|
||||
struct option o[] = {{"xx", 0, 0, 1}, {0,0,0,0}};
|
||||
getopt_long(2, argv, "x", o, &i) == 1 ? x++ : 0; optind = 0;
|
||||
getopt_long(2, argv, "x", o, &i) == 1 ? x++ : 0;
|
||||
exit(x == 2 ? 0 : 1);
|
||||
}], rsync_cv_HAVE_GETOPT_LONG=yes,rsync_cv_HAVE_GETOPT_LONG=no,
|
||||
rsync_cv_HAVE_GETOPT_LONG=cross)])
|
||||
if test x"$rsync_cv_HAVE_GETOPT_LONG" = x"yes"; then
|
||||
AC_DEFINE(HAVE_GETOPT_LONG)
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for long long],rsync_cv_HAVE_LONGLONG,[
|
||||
AC_TRY_RUN([#include <stdio.h>
|
||||
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)
|
||||
fi
|
||||
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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; 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)
|
||||
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(0); }
|
||||
exit(1);}],
|
||||
rsync_cv_REPLACE_INET_NTOA=yes,rsync_cv_REPLACE_INET_NTOA=no,rsync_cv_REPLACE_INET_NTOA=cross)])
|
||||
if test x"$rsync_cv_REPLACE_INET_NTOA" = x"yes"; then
|
||||
AC_DEFINE(REPLACE_INET_NTOA)
|
||||
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
|
||||
@@ -179,11 +325,77 @@ if test x"$ac_cv_func_connect" = x"no"; then
|
||||
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)
|
||||
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))
|
||||
|
||||
# Irix 6.5 has getaddrinfo but not the corresponding defines, so use
|
||||
# builtin getaddrinfo if one of the defines don't exist
|
||||
AC_CACHE_CHECK([whether defines needed by getaddrinfo exist],
|
||||
rsync_cv_HAVE_GETADDR_DEFINES,[
|
||||
AC_EGREP_CPP(yes, [
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#ifdef AI_PASSIVE
|
||||
yes
|
||||
#endif],
|
||||
rsync_cv_HAVE_GETADDR_DEFINES=yes,
|
||||
rsync_cv_HAVE_GETADDR_DEFINES=no)])
|
||||
if test x"$rsync_cv_HAVE_GETADDR_DEFINES" = x"yes"; then
|
||||
# Tru64 UNIX has getaddrinfo() but has it renamed in libc as
|
||||
# something else so we must include <netdb.h> to get the
|
||||
# redefinition.
|
||||
AC_CHECK_FUNCS(getaddrinfo, ,
|
||||
[AC_MSG_CHECKING([for getaddrinfo by including <netdb.h>])
|
||||
AC_TRY_LINK([#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>],[getaddrinfo(NULL, NULL, NULL, NULL);],
|
||||
[AC_MSG_RESULT([yes])
|
||||
AC_DEFINE(HAVE_GETADDRINFO, 1,
|
||||
[Define if you have the `getaddrinfo' function.])],
|
||||
[AC_MSG_RESULT([no])
|
||||
AC_LIBOBJ(lib/getaddrinfo)])])
|
||||
AC_CHECK_FUNCS(getnameinfo, , AC_LIBOBJ(lib/getnameinfo))
|
||||
else
|
||||
AC_LIBOBJ(lib/getaddrinfo)
|
||||
AC_LIBOBJ(lib/getnameinfo)
|
||||
fi
|
||||
|
||||
|
||||
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))
|
||||
|
||||
AC_CHECK_MEMBER([struct sockaddr_in6.sin6_scope_id],
|
||||
[ AC_DEFINE(HAVE_SOCKADDR_IN6_SCOPE_ID) ],
|
||||
[],
|
||||
[
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
])
|
||||
|
||||
# if we can't find strcasecmp, look in -lresolv (for Unixware at least)
|
||||
#
|
||||
AC_CHECK_FUNCS(strcasecmp)
|
||||
@@ -191,6 +403,205 @@ 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_UTIME_NULL
|
||||
AC_FUNC_ALLOCA
|
||||
AC_CHECK_FUNCS(waitpid wait4 getcwd strdup strerror chown chmod mknod mkfifo)
|
||||
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 strtol mtrace mallinfo setgroups)
|
||||
|
||||
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", 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
|
||||
|
||||
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"
|
||||
if test x"$ALLOCA" != x
|
||||
then
|
||||
# this can be removed when/if we add an included alloca.c;
|
||||
# see autoconf documentation on AC_FUNC_ALLOCA
|
||||
AC_MSG_WARN([included libpopt will use malloc, not alloca (which wastes a small amount of memory)])
|
||||
fi
|
||||
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 = 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
|
||||
|
||||
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; 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_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
|
||||
#
|
||||
@@ -220,6 +631,11 @@ 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_OUTPUT(Makefile lib/dummy zlib/dummy)
|
||||
AC_MSG_RESULT()
|
||||
AC_MSG_RESULT([ rsync ${RSYNC_VERSION} configuration successful])
|
||||
AC_MSG_RESULT()
|
||||
|
||||
82
csprotocol.txt
Normal file
82
csprotocol.txt
Normal 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.
|
||||
2
doc/.cvsignore
Normal file
2
doc/.cvsignore
Normal file
@@ -0,0 +1,2 @@
|
||||
rsync.pdf
|
||||
rsync.ps
|
||||
20
doc/README-SGML
Normal file
20
doc/README-SGML
Normal file
@@ -0,0 +1,20 @@
|
||||
Handling the rsync SGML documentation
|
||||
|
||||
rsync documentation is now primarily in Docbook format. Docbook is an
|
||||
SGML/XML documentation format that is becoming standard on free
|
||||
operating systems. It's also used for Samba documentation.
|
||||
|
||||
The SGML files are source code that can be translated into various
|
||||
useful output formats, primarily PDF, HTML, Postscript and plain text.
|
||||
|
||||
To do this transformation on Debian, you should install the
|
||||
docbook-utils package. Having done that, you can say
|
||||
|
||||
docbook2pdf rsync.sgml
|
||||
|
||||
and so on.
|
||||
|
||||
On other systems you probably need James Clark's "sp" and "JadeTeX"
|
||||
packages. Work it out for yourself and send a note to the mailing
|
||||
list.
|
||||
|
||||
42
doc/profile.txt
Normal file
42
doc/profile.txt
Normal file
@@ -0,0 +1,42 @@
|
||||
Notes on rsync profiling
|
||||
|
||||
strlcpy is hot:
|
||||
|
||||
0.00 0.00 1/7735635 push_dir [68]
|
||||
0.00 0.00 1/7735635 pop_dir [71]
|
||||
0.00 0.00 1/7735635 send_file_list [15]
|
||||
0.01 0.00 18857/7735635 send_files [4]
|
||||
0.04 0.00 129260/7735635 send_file_entry [18]
|
||||
0.04 0.00 129260/7735635 make_file [20]
|
||||
0.04 0.00 141666/7735635 send_directory <cycle 1> [36]
|
||||
2.29 0.00 7316589/7735635 f_name [13]
|
||||
[14] 11.7 2.42 0.00 7735635 strlcpy [14]
|
||||
|
||||
|
||||
Here's the top few functions:
|
||||
|
||||
46.23 9.57 9.57 13160929 0.00 0.00 mdfour64
|
||||
14.78 12.63 3.06 13160929 0.00 0.00 copy64
|
||||
11.69 15.05 2.42 7735635 0.00 0.00 strlcpy
|
||||
10.05 17.13 2.08 41438 0.05 0.38 sum_update
|
||||
4.11 17.98 0.85 13159996 0.00 0.00 mdfour_update
|
||||
1.50 18.29 0.31 file_compare
|
||||
1.45 18.59 0.30 129261 0.00 0.01 send_file_entry
|
||||
1.23 18.84 0.26 2557585 0.00 0.00 f_name
|
||||
1.11 19.07 0.23 1483750 0.00 0.00 u_strcmp
|
||||
1.11 19.30 0.23 118129 0.00 0.00 writefd_unbuffered
|
||||
0.92 19.50 0.19 1085011 0.00 0.00 writefd
|
||||
0.43 19.59 0.09 156987 0.00 0.00 read_timeout
|
||||
0.43 19.68 0.09 129261 0.00 0.00 clean_fname
|
||||
0.39 19.75 0.08 32887 0.00 0.38 matched
|
||||
0.34 19.82 0.07 1 70.00 16293.92 send_files
|
||||
0.29 19.89 0.06 129260 0.00 0.00 make_file
|
||||
0.29 19.95 0.06 75430 0.00 0.00 read_unbuffered
|
||||
|
||||
|
||||
|
||||
mdfour could perhaps be made faster:
|
||||
|
||||
/* NOTE: This code makes no attempt to be fast! */
|
||||
|
||||
There might be an optimized version somewhere that we can borrow.
|
||||
351
doc/rsync.sgml
Normal file
351
doc/rsync.sgml
Normal file
@@ -0,0 +1,351 @@
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
|
||||
<book id="rsync">
|
||||
<bookinfo>
|
||||
<title>rsync</title>
|
||||
<copyright>
|
||||
<year>1996 -- 2002</year>
|
||||
<holder>Martin Pool</holder>
|
||||
<holder>Andrew Tridgell</holder>
|
||||
</copyright>
|
||||
<author>
|
||||
<firstname>Martin</firstname>
|
||||
<surname>Pool</surname>
|
||||
</author>
|
||||
</bookinfo>
|
||||
|
||||
<chapter>
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>rsync is a flexible program for efficiently copying files or
|
||||
directory trees.
|
||||
|
||||
<para>rsync has many options to select which files will be copied
|
||||
and how they are to be transferred. It may be used as an
|
||||
alternative to ftp, http, scp or rcp.
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
<para>Some of the additional features of rsync are:</para>
|
||||
|
||||
<itemizedlist>
|
||||
|
||||
<listitem>
|
||||
<para>support for copying links, devices, owners, groups and
|
||||
permissions
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
exclude and exclude-from options similar to GNU tar
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
a CVS exclude mode for ignoring the same files that CVS would ignore
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
can use any transparent remote shell, including rsh or ssh
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
does not require root privileges
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
pipelining of file transfers to minimize latency costs
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
support for anonymous or authenticated rsync servers (ideal for
|
||||
mirroring)
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</chapter>
|
||||
|
||||
|
||||
|
||||
<chapter>
|
||||
<title>Using rsync</title>
|
||||
<section>
|
||||
<title>
|
||||
Introductory example
|
||||
</title>
|
||||
|
||||
<para>
|
||||
Probably the most common case of rsync usage is to copy files
|
||||
to or from a remote machine using
|
||||
<application>ssh</application> as a network transport. In
|
||||
this situation rsync is a good alternative to
|
||||
<application>scp</application>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The most commonly used arguments for rsync are
|
||||
</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>-v</option></term>
|
||||
<listitem>
|
||||
<para>Be verbose. Primarily, display the name of each file as it is copied.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-a</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Reproduce the structure and attributes of the origin files as exactly
|
||||
as possible: this includes copying subdirectories, symlinks, special
|
||||
files, ownership and permissions. (@xref{Attributes to
|
||||
copy}.)
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
|
||||
|
||||
<para><option>-v </option>
|
||||
|
||||
<para><option>-z</option>
|
||||
Compress network traffic, using a modified version of the
|
||||
@command{zlib} library.</para>
|
||||
|
||||
<para><option>-P</option>
|
||||
Display a progress indicator while files are transferred. This should
|
||||
normally be ommitted if rsync is not run on a terminal.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<title>Local and remote</title>
|
||||
|
||||
<para>There are six different ways of using rsync. They
|
||||
are:</para>
|
||||
|
||||
|
||||
|
||||
<!-- one of (CALLOUTLIST GLOSSLIST ITEMIZEDLIST ORDEREDLIST SEGMENTEDLIST SIMPLELIST VARIABLELIST CAUTION IMPORTANT NOTE TIP WARNING LITERALLAYOUT PROGRAMLISTING PROGRAMLISTINGCO SCREEN SCREENCO SCREENSHOT SYNOPSIS CMDSYNOPSIS FUNCSYNOPSIS CLASSSYNOPSIS FIELDSYNOPSIS CONSTRUCTORSYNOPSIS DESTRUCTORSYNOPSIS METHODSYNOPSIS FORMALPARA PARA SIMPARA ADDRESS BLOCKQUOTE GRAPHIC GRAPHICCO MEDIAOBJECT MEDIAOBJECTCO INFORMALEQUATION INFORMALEXAMPLE INFORMALFIGURE INFORMALTABLE EQUATION EXAMPLE FIGURE TABLE MSGSET PROCEDURE SIDEBAR QANDASET ANCHOR BRIDGEHEAD REMARK HIGHLIGHTS ABSTRACT AUTHORBLURB EPIGRAPH INDEXTERM REFENTRY SECTION) -->
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
for copying local files. This is invoked when neither
|
||||
source nor destination path contains a @code{:} separator
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
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 @code{:} separator.
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
for copying from a remote machine to the local machine
|
||||
using a remote shell program. This is invoked when the source
|
||||
contains a @code{:} separator.
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
for copying from a remote rsync server to the local
|
||||
machine. This is invoked when the source path contains a @code{::}
|
||||
separator or a @code{rsync://} URL.
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
for copying from the local machine to a remote rsync
|
||||
server. This is invoked when the destination path contains a @code{::}
|
||||
separator.
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
for listing files on a remote machine. This is done the
|
||||
same way as rsync transfers except that you leave off the
|
||||
local destination.
|
||||
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<para>
|
||||
Note that in all cases (other than listing) at least one of the source
|
||||
and destination paths must be local.
|
||||
|
||||
<para>
|
||||
Any one invocation of rsync makes a copy in a single direction. rsync
|
||||
currently has no equivalent of @command{ftp}'s interactive mode.
|
||||
|
||||
@cindex @sc{nfs}
|
||||
@cindex network filesystems
|
||||
@cindex remote filesystems
|
||||
|
||||
<para>
|
||||
rsync's network protocol is generally faster at copying files than
|
||||
network filesystems such as @sc{nfs} or @sc{cifs}. It is better to
|
||||
run rsync on the file server either as a daemon or over ssh than
|
||||
running rsync giving the network directory.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
||||
|
||||
|
||||
|
||||
<chapter>
|
||||
<title>Frequently asked questions</title>
|
||||
|
||||
|
||||
<!-- one of (CALLOUTLIST GLOSSLIST ITEMIZEDLIST ORDEREDLIST SEGMENTEDLIST SIMPLELIST VARIABLELIST CAUTION IMPORTANT NOTE TIP WARNING LITERALLAYOUT PROGRAMLISTING PROGRAMLISTINGCO SCREEN SCREENCO SCREENSHOT SYNOPSIS CMDSYNOPSIS FUNCSYNOPSIS CLASSSYNOPSIS FIELDSYNOPSIS CONSTRUCTORSYNOPSIS DESTRUCTORSYNOPSIS METHODSYNOPSIS FORMALPARA PARA SIMPARA ADDRESS BLOCKQUOTE GRAPHIC GRAPHICCO MEDIAOBJECT MEDIAOBJECTCO INFORMALEQUATION INFORMALEXAMPLE INFORMALFIGURE INFORMALTABLE EQUATION EXAMPLE FIGURE TABLE MSGSET PROCEDURE SIDEBAR QANDASET ANCHOR BRIDGEHEAD REMARK HIGHLIGHTS ABSTRACT AUTHORBLURB EPIGRAPH INDEXTERM SECTION SIMPLESECT REFENTRY SECT1) -->
|
||||
<qandaset>
|
||||
<!-- one of (QANDADIV QANDAENTRY) -->
|
||||
|
||||
<qandaentry>
|
||||
<question>
|
||||
<!-- one of (CALLOUTLIST GLOSSLIST ITEMIZEDLIST ORDEREDLIST
|
||||
SEGMENTEDLIST SIMPLELIST VARIABLELIST CAUTION IMPORTANT NOTE
|
||||
TIP WARNING LITERALLAYOUT PROGRAMLISTING PROGRAMLISTINGCO
|
||||
SCREEN SCREENCO SCREENSHOT SYNOPSIS CMDSYNOPSIS FUNCSYNOPSIS
|
||||
CLASSSYNOPSIS FIELDSYNOPSIS CONSTRUCTORSYNOPSIS
|
||||
DESTRUCTORSYNOPSIS METHODSYNOPSIS FORMALPARA PARA SIMPARA
|
||||
ADDRESS BLOCKQUOTE GRAPHIC GRAPHICCO MEDIAOBJECT
|
||||
MEDIAOBJECTCO INFORMALEQUATION INFORMALEXAMPLE
|
||||
INFORMALFIGURE INFORMALTABLE EQUATION EXAMPLE FIGURE TABLE
|
||||
PROCEDURE ANCHOR BRIDGEHEAD REMARK HIGHLIGHTS INDEXTERM) -->
|
||||
<para>Are there mailing lists for rsync?
|
||||
</question>
|
||||
|
||||
<answer>
|
||||
<para>Yes, and you can subscribe and unsubscribe through a
|
||||
web interface at
|
||||
<ulink
|
||||
url="http://lists.samba.org/">http://lists.samba.org/</ulink>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If you are having trouble with the mailing list, please
|
||||
send mail to the administrator
|
||||
|
||||
<email>rsync-admin@lists.samba.org</email>
|
||||
|
||||
not to the list itself.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The mailing list archives are searchable. Use
|
||||
<ulink url="http://google.com/">Google</ulink> and prepend
|
||||
the search with <userinput>site:lists.samba.org
|
||||
rsync</userinput>, plus relevant keywords.
|
||||
</para>
|
||||
</answer>
|
||||
</qandaentry>
|
||||
|
||||
|
||||
<qandaentry>
|
||||
<question>
|
||||
<para>
|
||||
Why is rsync so much bigger when I build it with
|
||||
<command>gcc</command>?
|
||||
</para>
|
||||
</question>
|
||||
<answer>
|
||||
<para>
|
||||
On gcc, rsync builds by default with debug symbols
|
||||
included. If you strip both executables, they should end
|
||||
up about the same size. (Use <command>make
|
||||
install-strip</command>.)
|
||||
</para>
|
||||
</answer>
|
||||
</qandaentry>
|
||||
|
||||
|
||||
<qandaentry>
|
||||
<question>
|
||||
<para>Is rsync useful for a single large file like an ISO image?</para>
|
||||
</question>
|
||||
<answer>
|
||||
<para>
|
||||
Yes, but note the following:
|
||||
|
||||
<para>
|
||||
Background: A common use of rsync is to update a file (or set of files) in one location from a more
|
||||
correct or up-to-date copy in another location, taking advantage of portions of the files that are
|
||||
identical to speed up the process. (Note that rsync will transfer a file in its entirety if no copy
|
||||
exists at the destination.)
|
||||
|
||||
<para>
|
||||
(This discussion is written in terms of updating a local copy of a file from a correct file in a
|
||||
remote location, although rsync can work in either direction.)
|
||||
|
||||
<para>
|
||||
The file to be updated (the local file) must be in a destination directory that has enough space for
|
||||
two copies of the file. (In addition, keep an extra copy of the file to be updated in a different
|
||||
location for safety -- see the discussion (below) about rsync's behavior when the rsync process is
|
||||
interrupted before completion.)
|
||||
|
||||
<para>
|
||||
The local file must have the same name as the remote file being sync'd to (I think?). If you are
|
||||
trying to upgrade an iso from, for example, beta1 to beta2, rename the local file to the same name
|
||||
as the beta2 file. *(This is a useful thing to do -- only the changed portions will be
|
||||
transmitted.)*
|
||||
|
||||
<para>
|
||||
The extra copy of the local file kept in a different location is because of rsync's behavior if
|
||||
interrupted before completion:
|
||||
|
||||
<para>
|
||||
* If you specify the --partial option and rsync is interrupted, rsync will save the partially
|
||||
rsync'd file and throw away the original local copy. (The partially rsync'd file is correct but
|
||||
truncated.) If rsync is restarted, it will not have a local copy of the file to check for duplicate
|
||||
blocks beyond the section of the file that has already been rsync'd, thus the remainder of the rsync
|
||||
process will be a "pure transfer" of the file rather than taking advantage of the rsync algorithm.
|
||||
|
||||
<para>
|
||||
* If you don't specify the --partial option and rsync is interrupted, rsync will throw away the
|
||||
partially rsync'd file, and, when rsync is restarted starts the rsync process over from the
|
||||
beginning.
|
||||
|
||||
<para>
|
||||
Which of these is most desirable depends on the degree of commonality between the local and remote
|
||||
copies of the file *and how much progress was made before the interruption*.
|
||||
|
||||
<para>
|
||||
The ideal approach after an interruption would be to create a new file by taking the original file
|
||||
and deleting a portion equal in size to the portion already rsync'd and then appending *the
|
||||
remaining* portion to the portion of the file that has already been rsync'd. (There has been some
|
||||
discussion about creating an option to do this automatically.)
|
||||
|
||||
The --compare-dest option is useful when transferring multiple files, but is of no benefit in
|
||||
transferring a single file. (AFAIK)
|
||||
|
||||
*Other potentially useful information can be found at:
|
||||
-[3]http://twiki.org/cgi-bin/view/Wikilearn/RsyncingALargeFile
|
||||
|
||||
This answer, formatted with "real" bullets, can be found at:
|
||||
-[4]http://twiki.org/cgi-bin/view/Wikilearn/RsyncingALargeFileFAQ*
|
||||
|
||||
</para>
|
||||
</answer>
|
||||
</qandaentry>
|
||||
</qandaset>
|
||||
</chapter>
|
||||
|
||||
|
||||
<appendix>
|
||||
<title>Other Resources</title>
|
||||
|
||||
<para><ulink url="http://www.ccp14.ac.uk/ccp14admin/rsync/"></ulink></para>
|
||||
</appendix>
|
||||
</book>
|
||||
43
errcode.h
43
errcode.h
@@ -1,9 +1,33 @@
|
||||
/* error codes returned by rsync */
|
||||
/* -*- 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_OK 0
|
||||
#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_STARTCLIENT 5 /* error starting client-server protocol */
|
||||
|
||||
#define RERR_SOCKETIO 10 /* error in socket IO */
|
||||
#define RERR_FILEIO 11 /* error in file IO */
|
||||
@@ -14,5 +38,22 @@
|
||||
#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
|
||||
|
||||
226
exclude.c
226
exclude.c
@@ -1,25 +1,29 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
/* -*- c-file-style: "linux" -*-
|
||||
*
|
||||
* Copyright (C) 1996-2001 by Andrew Tridgell <tridge@samba.org>
|
||||
* Copyright (C) 1996 by Paul Mackerras
|
||||
* Copyright (C) 2002 by Martin Pool
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* 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/exclude cluestick added by Martin Pool <mbp@samba.org> */
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
extern int verbose;
|
||||
@@ -27,52 +31,8 @@ extern int delete_mode;
|
||||
|
||||
static struct exclude_struct **exclude_list;
|
||||
|
||||
/*
|
||||
* Optimization for special case when all included files are explicitly
|
||||
* listed without wildcards in the "exclude" list followed by a "- *"
|
||||
* to exclude the rest.
|
||||
* Contributed by Dave Dykstra <dwd@bell-labs.com>
|
||||
*/
|
||||
static int only_included_files = 1;
|
||||
static struct exclude_struct *exclude_the_rest;
|
||||
|
||||
int send_included_file_names(int f,struct file_list *flist)
|
||||
{
|
||||
struct exclude_struct *ex, **ex_list;
|
||||
int n;
|
||||
char *p;
|
||||
|
||||
if (!only_included_files || (exclude_the_rest == NULL) || delete_mode)
|
||||
return 0;
|
||||
|
||||
if (verbose > 1) {
|
||||
rprintf(FINFO,"(using include-only optimization) ");
|
||||
}
|
||||
|
||||
/* set exclude_list to NULL temporarily so check_exclude */
|
||||
/* will always return true */
|
||||
ex_list = exclude_list;
|
||||
exclude_list = NULL;
|
||||
for (n=0; (ex = ex_list[n]) != NULL; n++) {
|
||||
if (ex == exclude_the_rest)
|
||||
break;
|
||||
p = ex->pattern;
|
||||
while (*p == '/') {
|
||||
/* skip the allowed beginning slashes */
|
||||
p++;
|
||||
}
|
||||
/* silently skip files that don't exist to
|
||||
be more like non-optimized case */
|
||||
if (access(p,0) == 0)
|
||||
send_file_name(f,flist,p,0,0);
|
||||
}
|
||||
exclude_list = ex_list;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* build an exclude structure given a exclude pattern */
|
||||
static struct exclude_struct *make_exclude(char *pattern, int include)
|
||||
/** Build an exclude structure given a exclude pattern */
|
||||
static struct exclude_struct *make_exclude(const char *pattern, int include)
|
||||
{
|
||||
struct exclude_struct *ret;
|
||||
|
||||
@@ -95,15 +55,18 @@ static struct exclude_struct *make_exclude(char *pattern, int include)
|
||||
if (!ret->pattern) out_of_memory("make_exclude");
|
||||
|
||||
if (strpbrk(pattern, "*[?")) {
|
||||
if (!ret->include && (*pattern == '*') && (*(pattern+1) == '\0')) {
|
||||
exclude_the_rest = ret;
|
||||
} else {
|
||||
only_included_files = 0;
|
||||
}
|
||||
ret->regular_exp = 1;
|
||||
ret->fnmatch_flags = strstr(pattern, "**") ? 0 : FNM_PATHNAME;
|
||||
} else if (!ret->include) {
|
||||
only_included_files = 0;
|
||||
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] == '/') {
|
||||
@@ -125,8 +88,8 @@ static void free_exclude(struct exclude_struct *ex)
|
||||
free(ex);
|
||||
}
|
||||
|
||||
static int check_one_exclude(char *name,struct exclude_struct *ex,
|
||||
STRUCT_STAT *st)
|
||||
static int check_one_exclude(char *name, struct exclude_struct *ex,
|
||||
STRUCT_STAT *st)
|
||||
{
|
||||
char *p;
|
||||
int match_start=0;
|
||||
@@ -145,47 +108,79 @@ static int check_one_exclude(char *name,struct exclude_struct *ex,
|
||||
}
|
||||
|
||||
if (ex->regular_exp) {
|
||||
if (fnmatch(pattern, name, ex->fnmatch_flags) == 0)
|
||||
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)] == '/')))
|
||||
(l1==l2 || (!match_start && name[l1-(l2+1)] == '/'))) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int check_exclude(char *name,struct exclude_struct **local_exclude_list,
|
||||
static void report_exclude_result(char const *name,
|
||||
struct exclude_struct const *ent,
|
||||
STRUCT_STAT const *st)
|
||||
{
|
||||
/* If a trailing slash is present to match only directories,
|
||||
* then it is stripped out by make_exclude. So as a special
|
||||
* case we add it back in here. */
|
||||
|
||||
if (verbose >= 2)
|
||||
rprintf(FINFO, "%s %s %s because of pattern %s%s\n",
|
||||
ent->include ? "including" : "excluding",
|
||||
S_ISDIR(st->st_mode) ? "directory" : "file",
|
||||
name, ent->pattern,
|
||||
ent->directory ? "/" : "");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return true if file NAME is defined to be excluded by either
|
||||
* LOCAL_EXCLUDE_LIST or the globals EXCLUDE_LIST.
|
||||
*/
|
||||
int check_exclude(char *name, struct exclude_struct **local_exclude_list,
|
||||
STRUCT_STAT *st)
|
||||
{
|
||||
int n;
|
||||
struct exclude_struct *ent;
|
||||
|
||||
if (name && (name[0] == '.') && !name[1])
|
||||
/* never exclude '.', even if somebody does --exclude '*' */
|
||||
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;
|
||||
for (n=0; exclude_list[n]; n++) {
|
||||
ent = exclude_list[n];
|
||||
if (check_one_exclude(name, ent, st)) {
|
||||
report_exclude_result(name, ent, st);
|
||||
return !ent->include;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
for (n=0; local_exclude_list[n]; n++) {
|
||||
ent = local_exclude_list[n];
|
||||
if (check_one_exclude(name, ent, st)) {
|
||||
report_exclude_result(name, ent, st);
|
||||
return !ent->include;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void add_exclude_list(char *pattern,struct exclude_struct ***list, int include)
|
||||
void add_exclude_list(const char *pattern, struct exclude_struct ***list, int include)
|
||||
{
|
||||
int len=0;
|
||||
if (list && *list)
|
||||
@@ -199,8 +194,6 @@ void add_exclude_list(char *pattern,struct exclude_struct ***list, int include)
|
||||
}
|
||||
free((*list));
|
||||
*list = NULL;
|
||||
only_included_files = 1;
|
||||
exclude_the_rest = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -209,27 +202,38 @@ void add_exclude_list(char *pattern,struct exclude_struct ***list, int include)
|
||||
if (!*list || !((*list)[len] = make_exclude(pattern, include)))
|
||||
out_of_memory("add_exclude");
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"add_exclude(%s)\n",pattern);
|
||||
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO,"add_exclude(%s,%s)\n",pattern,
|
||||
include ? "include" : "exclude");
|
||||
}
|
||||
|
||||
(*list)[len+1] = NULL;
|
||||
}
|
||||
|
||||
void add_exclude(char *pattern, int include)
|
||||
void add_exclude(const char *pattern, int include)
|
||||
{
|
||||
add_exclude_list(pattern,&exclude_list, include);
|
||||
}
|
||||
|
||||
struct exclude_struct **make_exclude_list(char *fname,
|
||||
struct exclude_struct **make_exclude_list(const char *fname,
|
||||
struct exclude_struct **list1,
|
||||
int fatal, int include)
|
||||
{
|
||||
struct exclude_struct **list=list1;
|
||||
FILE *f = fopen(fname,"r");
|
||||
FILE *f;
|
||||
char line[MAXPATHLEN];
|
||||
|
||||
if (strcmp(fname, "-")) {
|
||||
f = fopen(fname,"r");
|
||||
} else {
|
||||
f = fdopen(0, "r");
|
||||
}
|
||||
if (!f) {
|
||||
if (fatal) {
|
||||
rprintf(FERROR,"%s : %s\n",fname,strerror(errno));
|
||||
rsyserr(FERROR, errno,
|
||||
"failed to open %s file %s",
|
||||
include ? "include" : "exclude",
|
||||
fname);
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
return list;
|
||||
@@ -237,7 +241,7 @@ struct exclude_struct **make_exclude_list(char *fname,
|
||||
|
||||
while (fgets(line,MAXPATHLEN,f)) {
|
||||
int l = strlen(line);
|
||||
if (l && line[l-1] == '\n') l--;
|
||||
while (l && (line[l-1] == '\n' || line[l-1] == '\r')) l--;
|
||||
line[l] = 0;
|
||||
if (line[0] && (line[0] != ';') && (line[0] != '#')) {
|
||||
/* Skip lines starting with semicolon or pound.
|
||||
@@ -251,7 +255,7 @@ struct exclude_struct **make_exclude_list(char *fname,
|
||||
}
|
||||
|
||||
|
||||
void add_exclude_file(char *fname,int fatal,int include)
|
||||
void add_exclude_file(const char *fname, int fatal, int include)
|
||||
{
|
||||
if (!fname || !*fname) return;
|
||||
|
||||
@@ -263,6 +267,15 @@ void send_exclude_list(int f)
|
||||
{
|
||||
int i;
|
||||
extern int remote_version;
|
||||
extern int list_only, recurse;
|
||||
|
||||
/* This is a complete hack - blame Rusty.
|
||||
*
|
||||
* FIXME: This pattern shows up in the output of
|
||||
* report_exclude_result(), which is not ideal. */
|
||||
if (list_only && !recurse) {
|
||||
add_exclude("/*/*", 0);
|
||||
}
|
||||
|
||||
if (!exclude_list) {
|
||||
write_int(f,0);
|
||||
@@ -270,8 +283,11 @@ void send_exclude_list(int f)
|
||||
}
|
||||
|
||||
for (i=0;exclude_list[i];i++) {
|
||||
char *pattern = exclude_list[i]->pattern;
|
||||
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;
|
||||
@@ -295,7 +311,8 @@ void send_exclude_list(int f)
|
||||
void recv_exclude_list(int f)
|
||||
{
|
||||
char line[MAXPATHLEN];
|
||||
int l;
|
||||
unsigned int l;
|
||||
|
||||
while ((l=read_int(f))) {
|
||||
if (l >= MAXPATHLEN) overflow("recv_exclude_list");
|
||||
read_sbuf(f,line,l);
|
||||
@@ -324,7 +341,7 @@ char *get_exclude_tok(char *p)
|
||||
return(NULL);
|
||||
|
||||
/* Skip over any initial spaces */
|
||||
while(isspace(*s))
|
||||
while (isspace(* (unsigned char *) s))
|
||||
s++;
|
||||
|
||||
/* Are we at the end of the string? */
|
||||
@@ -337,7 +354,7 @@ char *get_exclude_tok(char *p)
|
||||
s+=2;
|
||||
|
||||
/* Skip to the next space or the end of the string */
|
||||
while(!isspace(*s) && *s!='\0')
|
||||
while (!isspace(* (unsigned char *) s) && *s != '\0')
|
||||
s++;
|
||||
} else {
|
||||
t=NULL;
|
||||
@@ -376,12 +393,11 @@ void add_include_line(char *p)
|
||||
|
||||
|
||||
static char *cvs_ignore_list[] = {
|
||||
"RCS","SCCS","CVS","CVS.adm","RCSLOG","cvslog.*",
|
||||
"tags","TAGS",".make.state",".nse_depinfo",
|
||||
"*~", "#*", ".#*", ",*", "*.old", "*.bak", "*.BAK", "*.orig",
|
||||
"RCS/", "SCCS/", "CVS/", ".svn/", "CVS.adm", "RCSLOG", "cvslog.*",
|
||||
"tags", "TAGS", ".make.state", ".nse_depinfo",
|
||||
"*~", "#*", ".#*", ", *", "*.old", "*.bak", "*.BAK", "*.orig",
|
||||
"*.rej", ".del-*", "*.a", "*.o", "*.obj", "*.so", "*.Z", "*.elc", "*.ln",
|
||||
"core",NULL};
|
||||
|
||||
"core", NULL};
|
||||
|
||||
|
||||
void add_cvs_excludes(void)
|
||||
@@ -394,7 +410,7 @@ void add_cvs_excludes(void)
|
||||
add_exclude(cvs_ignore_list[i], 0);
|
||||
|
||||
if ((p=getenv("HOME")) && strlen(p) < (MAXPATHLEN-12)) {
|
||||
slprintf(fname,sizeof(fname), "%s/.cvsignore",p);
|
||||
snprintf(fname,sizeof(fname), "%s/.cvsignore",p);
|
||||
add_exclude_file(fname,0,0);
|
||||
}
|
||||
|
||||
|
||||
14
fileio.c
14
fileio.c
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright (C) Andrew Tridgell 1998
|
||||
Copyright (C) 2002 by Martin Pool
|
||||
|
||||
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
|
||||
@@ -36,9 +37,9 @@ int sparse_end(int f)
|
||||
}
|
||||
|
||||
|
||||
static int write_sparse(int f,char *buf,int len)
|
||||
static int write_sparse(int f,char *buf,size_t len)
|
||||
{
|
||||
int l1=0,l2=0;
|
||||
size_t l1=0, l2=0;
|
||||
int ret;
|
||||
|
||||
for (l1=0;l1<len && buf[l1]==0;l1++) ;
|
||||
@@ -56,10 +57,11 @@ static int write_sparse(int f,char *buf,int len)
|
||||
if (l1 == len)
|
||||
return len;
|
||||
|
||||
if ((ret=write(f,buf+l1,len-(l1+l2))) != len-(l1+l2)) {
|
||||
if (ret == -1 || ret == 0) return ret;
|
||||
ret = write(f, buf + l1, len - (l1+l2));
|
||||
if (ret == -1 || ret == 0)
|
||||
return ret;
|
||||
else if (ret != (int) (len - (l1+l2)))
|
||||
return (l1+ret);
|
||||
}
|
||||
|
||||
if (l2 > 0)
|
||||
do_lseek(f,l2,SEEK_CUR);
|
||||
@@ -69,7 +71,7 @@ static int write_sparse(int f,char *buf,int len)
|
||||
|
||||
|
||||
|
||||
int write_file(int f,char *buf,int len)
|
||||
int write_file(int f,char *buf,size_t len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
|
||||
306
generator.c
306
generator.c
@@ -1,6 +1,10 @@
|
||||
/*
|
||||
Copyright (C) Andrew Tridgell 1996
|
||||
/* -*- 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
|
||||
@@ -27,7 +31,7 @@ extern int am_root;
|
||||
extern int preserve_devices;
|
||||
extern int preserve_hard_links;
|
||||
extern int update_only;
|
||||
extern int whole_file;
|
||||
extern int opt_ignore_existing;
|
||||
extern int block_size;
|
||||
extern int csum_length;
|
||||
extern int ignore_times;
|
||||
@@ -35,6 +39,9 @@ extern int size_only;
|
||||
extern int io_timeout;
|
||||
extern int remote_version;
|
||||
extern int always_checksum;
|
||||
extern int modify_window;
|
||||
extern char *compare_dest;
|
||||
extern int link_dest;
|
||||
|
||||
|
||||
/* choose whether to skip a particular file */
|
||||
@@ -44,13 +51,35 @@ static int skip_file(char *fname,
|
||||
if (st->st_size != file->length) {
|
||||
return 0;
|
||||
}
|
||||
if (link_dest) {
|
||||
if((st->st_mode & ~_S_IFMT) != (file->mode & ~_S_IFMT)) {
|
||||
return 0;
|
||||
}
|
||||
if (st->st_uid != file->uid || st->st_gid != file->gid) {
|
||||
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);
|
||||
return (memcmp(sum,file->sum,csum_length) == 0);
|
||||
if (remote_version < 21) {
|
||||
return (memcmp(sum,file->sum,2) == 0);
|
||||
} else {
|
||||
return (memcmp(sum,file->sum,MD4_SUM_LENGTH) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (size_only) {
|
||||
@@ -61,7 +90,7 @@ static int skip_file(char *fname,
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (st->st_mtime == file->modtime);
|
||||
return (cmp_modtime(st->st_mtime,file->modtime) == 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -81,96 +110,119 @@ static int adapt_block_size(struct file_struct *file, int bsize)
|
||||
|
||||
|
||||
/*
|
||||
send a sums struct down a fd
|
||||
send a header that says "we have no checksums" down the f_out fd
|
||||
*/
|
||||
static void send_sums(struct sum_struct *s,int f_out)
|
||||
static void send_null_sums(int f_out)
|
||||
{
|
||||
int i;
|
||||
write_int(f_out, 0);
|
||||
write_int(f_out, block_size);
|
||||
write_int(f_out, 0);
|
||||
}
|
||||
|
||||
/* 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?s->count:0);
|
||||
write_int(f_out,s?s->n:block_size);
|
||||
write_int(f_out,s?s->remainder:0);
|
||||
if (s)
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Perhaps we want to just send an empty checksum set for this file,
|
||||
* which will force the whole thing to be literally transferred.
|
||||
*
|
||||
* When do we do this? If the user's explicitly said they
|
||||
* want the whole thing, or if { they haven't explicitly
|
||||
* requested a delta, and it's local but not batch mode.}
|
||||
*
|
||||
* Whew. */
|
||||
static BOOL disable_deltas_p(void)
|
||||
{
|
||||
extern int whole_file, no_whole_file;
|
||||
extern int local_server;
|
||||
extern int write_batch;
|
||||
|
||||
assert(whole_file == 0 || whole_file == 1);
|
||||
|
||||
/* whole_file and no_whole_file are never both on at the same time */
|
||||
|
||||
if (whole_file)
|
||||
return True;
|
||||
else if (no_whole_file)
|
||||
return False;
|
||||
else if (write_batch)
|
||||
return False;
|
||||
else
|
||||
return local_server;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
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)
|
||||
* Generate and send a stream of signatures/checksums that describe a buffer
|
||||
*
|
||||
* Generate approximately one checksum every block_len bytes.
|
||||
*/
|
||||
static void generate_and_send_sums(struct map_struct *buf, OFF_T len,
|
||||
int block_len, int f_out)
|
||||
{
|
||||
int i;
|
||||
struct sum_struct *s;
|
||||
int count;
|
||||
int block_len = n;
|
||||
int remainder = (len%block_len);
|
||||
size_t i;
|
||||
struct sum_struct sum;
|
||||
OFF_T offset = 0;
|
||||
|
||||
count = (len+(block_len-1))/block_len;
|
||||
sum.count = (len + (block_len - 1)) / block_len;
|
||||
sum.remainder = (len % block_len);
|
||||
sum.n = block_len;
|
||||
sum.flength = len;
|
||||
/* not needed here sum.sums = NULL; */
|
||||
|
||||
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 (sum.count && verbose > 3) {
|
||||
rprintf(FINFO, "count=%ld rem=%ld n=%ld flength=%.0f\n",
|
||||
(long) sum.count, (long) sum.remainder,
|
||||
(long) sum.n, (double) sum.flength);
|
||||
}
|
||||
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO,"count=%d rem=%d n=%d flength=%d\n",
|
||||
s->count,s->remainder,s->n,(int)s->flength);
|
||||
write_int(f_out, sum.count);
|
||||
write_int(f_out, sum.n);
|
||||
write_int(f_out, sum.remainder);
|
||||
|
||||
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);
|
||||
for (i = 0; i < sum.count; i++) {
|
||||
int n1 = MIN(len, block_len);
|
||||
char *map = map_ptr(buf, offset, n1);
|
||||
uint32 sum1 = get_checksum1(map, n1);
|
||||
char sum2[SUM_LENGTH];
|
||||
|
||||
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=%d len=%d sum1=%08x\n",
|
||||
i,(int)s->sums[i].offset,s->sums[i].len,s->sums[i].sum1);
|
||||
get_checksum2(map, n1, sum2);
|
||||
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO,
|
||||
"chunk[%d] offset=%.0f len=%d sum1=%08lx\n",
|
||||
i, (double) offset, n1, (unsigned long) sum1);
|
||||
}
|
||||
write_int(f_out, sum1);
|
||||
write_buf(f_out, sum2, csum_length);
|
||||
len -= n1;
|
||||
offset += n1;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
|
||||
|
||||
/**
|
||||
* Acts on file number @p i from @p flist, whose name is @p fname.
|
||||
*
|
||||
* First fixes up permissions, then generates checksums for the file.
|
||||
*
|
||||
* @note 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;
|
||||
extern int orig_umask;
|
||||
|
||||
if (list_only) return;
|
||||
|
||||
@@ -179,24 +231,49 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
|
||||
|
||||
statret = link_stat(fname,&st);
|
||||
|
||||
if (only_existing && statret == -1 && errno == ENOENT) {
|
||||
/* we only want to update existing files */
|
||||
if (verbose > 1) rprintf(FINFO, "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)) {
|
||||
if (dry_run) return;
|
||||
/* 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,"unlink %s : %s\n",fname,strerror(errno));
|
||||
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 &&
|
||||
create_directory_path(fname, orig_umask)==0 &&
|
||||
do_mkdir(fname,file->mode)==0)) {
|
||||
rprintf(FERROR,"mkdir %s : %s (2)\n",
|
||||
rprintf(FERROR, RSYNC_NAME ": recv_generator: mkdir \"%s\": %s (2)\n",
|
||||
fname,strerror(errno));
|
||||
}
|
||||
}
|
||||
if (set_perms(fname,file,NULL,0) && verbose)
|
||||
/* 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;
|
||||
}
|
||||
@@ -209,7 +286,7 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
|
||||
|
||||
if (safe_symlinks && unsafe_symlink(file->link, fname)) {
|
||||
if (verbose) {
|
||||
rprintf(FINFO,"ignoring unsafe symlink %s -> %s\n",
|
||||
rprintf(FINFO,"ignoring unsafe symlink \"%s\" -> \"%s\"\n",
|
||||
fname,file->link);
|
||||
}
|
||||
return;
|
||||
@@ -218,21 +295,26 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
|
||||
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);
|
||||
}
|
||||
delete_file(fname);
|
||||
if (do_symlink(file->link,fname) != 0) {
|
||||
rprintf(FERROR,"link %s -> %s : %s\n",
|
||||
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,"%s -> %s\n",
|
||||
fname,file->link);
|
||||
rprintf(FINFO,"%s -> %s\n", fname,file->link);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -264,12 +346,12 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
|
||||
|
||||
if (preserve_hard_links && check_hard_link(file)) {
|
||||
if (verbose > 1)
|
||||
rprintf(FINFO,"%s is a hard link\n",f_name(file));
|
||||
rprintf(FINFO, "recv_generator: \"%s\" is a hard link\n",f_name(file));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!S_ISREG(file->mode)) {
|
||||
rprintf(FINFO,"skipping non-regular file %s\n",fname);
|
||||
rprintf(FINFO, "skipping non-regular file \"%s\"\n",fname);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -278,12 +360,24 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
|
||||
if ((statret == -1) && (compare_dest != NULL)) {
|
||||
/* try the file at compare_dest instead */
|
||||
int saveerrno = errno;
|
||||
slprintf(fnamecmpbuf,MAXPATHLEN,"%s/%s",compare_dest,fname);
|
||||
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;
|
||||
#if HAVE_LINK
|
||||
else if (link_dest && !dry_run) {
|
||||
if (do_link(fnamecmpbuf, fname) != 0) {
|
||||
if (verbose > 0)
|
||||
rprintf(FINFO,"link %s => %s : %s\n",
|
||||
fnamecmpbuf,
|
||||
fname,
|
||||
strerror(errno));
|
||||
}
|
||||
fnamecmp = fnamecmpbuf;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
fnamecmp = fnamecmpbuf;
|
||||
}
|
||||
@@ -291,10 +385,12 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
|
||||
if (statret == -1) {
|
||||
if (errno == ENOENT) {
|
||||
write_int(f_out,i);
|
||||
if (!dry_run) send_sums(NULL,f_out);
|
||||
if (!dry_run) send_null_sums(f_out);
|
||||
} else {
|
||||
if (verbose > 1)
|
||||
rprintf(FERROR,"recv_generator failed to open %s\n",fname);
|
||||
rprintf(FERROR, RSYNC_NAME
|
||||
": recv_generator failed to open \"%s\": %s\n",
|
||||
fname, strerror(errno));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -306,11 +402,17 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
|
||||
|
||||
/* now pretend the file didn't exist */
|
||||
write_int(f_out,i);
|
||||
if (!dry_run) send_sums(NULL,f_out);
|
||||
if (!dry_run) send_null_sums(f_out);
|
||||
return;
|
||||
}
|
||||
|
||||
if (update_only && st.st_mtime > file->modtime && fnamecmp == fname) {
|
||||
if (opt_ignore_existing && fnamecmp == fname) {
|
||||
if (verbose > 1)
|
||||
rprintf(FINFO,"%s exists\n",fname);
|
||||
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;
|
||||
@@ -327,18 +429,20 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
|
||||
return;
|
||||
}
|
||||
|
||||
if (whole_file) {
|
||||
if (disable_deltas_p()) {
|
||||
write_int(f_out,i);
|
||||
send_sums(NULL,f_out);
|
||||
send_null_sums(f_out);
|
||||
return;
|
||||
}
|
||||
|
||||
/* open the file */
|
||||
fd = open(fnamecmp,O_RDONLY);
|
||||
fd = do_open(fnamecmp, O_RDONLY, 0);
|
||||
|
||||
if (fd == -1) {
|
||||
rprintf(FERROR,"failed to open %s : %s\n",fnamecmp,strerror(errno));
|
||||
rprintf(FERROR,"skipping %s\n",fname);
|
||||
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_null_sums(f_out);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -349,20 +453,17 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
|
||||
}
|
||||
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO,"gen mapped %s of size %d\n",fnamecmp,(int)st.st_size);
|
||||
|
||||
s = generate_sums(buf,st.st_size,adapt_block_size(file, block_size));
|
||||
rprintf(FINFO,"gen mapped %s of size %.0f\n",fnamecmp,(double)st.st_size);
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"sending sums for %d\n",i);
|
||||
rprintf(FINFO, "generating and sending sums for %d\n", i);
|
||||
|
||||
write_int(f_out,i);
|
||||
send_sums(s,f_out);
|
||||
generate_and_send_sums(buf, st.st_size,
|
||||
adapt_block_size(file, block_size), f_out);
|
||||
|
||||
close(fd);
|
||||
if (buf) unmap_file(buf);
|
||||
|
||||
free_sums(s);
|
||||
}
|
||||
|
||||
|
||||
@@ -376,6 +477,18 @@ void generate_files(int f,struct file_list *flist,char *local_name,int f_recv)
|
||||
rprintf(FINFO,"generator starting pid=%d count=%d\n",
|
||||
(int)getpid(),flist->count);
|
||||
|
||||
if (verbose >= 2) {
|
||||
rprintf(FINFO,
|
||||
disable_deltas_p()
|
||||
? "delta-transmission disabled for local transfer or --whole-file\n"
|
||||
: "delta transmission enabled\n");
|
||||
}
|
||||
|
||||
/* 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;
|
||||
@@ -386,6 +499,8 @@ void generate_files(int f,struct file_list *flist,char *local_name,int f_recv)
|
||||
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),
|
||||
@@ -403,11 +518,6 @@ void generate_files(int f,struct file_list *flist,char *local_name,int f_recv)
|
||||
|
||||
write_int(f,-1);
|
||||
|
||||
/* 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;
|
||||
|
||||
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 */
|
||||
|
||||
49
getgroups.c
Normal file
49
getgroups.c
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2002 by Martin Pool
|
||||
*
|
||||
* 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 getgroups.c
|
||||
*
|
||||
* Print out the gids of all groups for the current user. This is
|
||||
* like `id -G` on Linux, but it's too hard to find a portable
|
||||
* equivalent.
|
||||
**/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
#ifndef NGROUPS
|
||||
/* It ought to be defined, but just in case. */
|
||||
# define NGROUPS 32
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int n, i;
|
||||
gid_t list[NGROUPS];
|
||||
|
||||
if ((n = getgroups(NGROUPS, list)) == -1) {
|
||||
perror("getgroups");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
printf("%u ", list[i]);
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
158
hlink.c
158
hlink.c
@@ -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
|
||||
@@ -23,19 +24,22 @@ 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?1:-1);
|
||||
if (f1->dev != f2->dev)
|
||||
return (int) (f1->dev > f2->dev ? 1 : -1);
|
||||
|
||||
if (f1->inode != f2->inode)
|
||||
return (int)(f1->inode>f2->inode?1:-1);
|
||||
if (f1->inode != f2->inode)
|
||||
return (int) (f1->inode > f2->inode ? 1 : -1);
|
||||
|
||||
return file_compare(&f1,&f2);
|
||||
return file_compare(&f1, &f2);
|
||||
}
|
||||
|
||||
|
||||
@@ -47,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++)
|
||||
memcpy(&hlink_list[i], flist->files[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
|
||||
}
|
||||
|
||||
@@ -71,86 +78,109 @@ 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;
|
||||
/* XXX: To me this looks kind of dodgy -- why do we use [low]
|
||||
* here and [low-1] below? -- mbp */
|
||||
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) {
|
||||
if (verbose >= 2) {
|
||||
rprintf(FINFO, "check_hard_link: \"%s\" is a hard link to file %d, \"%s\"\n",
|
||||
f_name(file), low-1, f_name(&hlink_list[low-1]));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if SUPPORT_HARD_LINKS
|
||||
static void hard_link_one(int i)
|
||||
{
|
||||
STRUCT_STAT st1,st2;
|
||||
STRUCT_STAT st1, st2;
|
||||
|
||||
if (link_stat(f_name(&hlink_list[i-1]),&st1) != 0) return;
|
||||
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 (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",
|
||||
rprintf(FINFO, "link %s => %s : %s\n",
|
||||
f_name(&hlink_list[i]),
|
||||
f_name(&hlink_list[i-1]),strerror(errno));
|
||||
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 (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) {
|
||||
do_link(f_name(&hlink_list[i - 1]),
|
||||
f_name(&hlink_list[i])) != 0) {
|
||||
if (verbose > 0)
|
||||
rprintf(FINFO,"link %s => %s : %s\n",
|
||||
rprintf(FINFO, "link %s => %s : %s\n",
|
||||
f_name(&hlink_list[i]),
|
||||
f_name(&hlink_list[i-1]),strerror(errno));
|
||||
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]));
|
||||
rprintf(FINFO, "%s => %s\n",
|
||||
f_name(&hlink_list[i]),
|
||||
f_name(&hlink_list[i - 1]));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* create any hard links in the flist */
|
||||
void do_hard_links(struct file_list *flist)
|
||||
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
for (i=1;i<hlink_count;i++) {
|
||||
if (!hlink_list)
|
||||
return;
|
||||
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ else
|
||||
|
||||
# Make a temp file name in the proper directory.
|
||||
|
||||
dsttmp=$dstdir/#inst.$$#
|
||||
dsttmp=$dstdir/_inst.$$_
|
||||
|
||||
# Move or copy the file name to the temp name
|
||||
|
||||
|
||||
580
io.c
580
io.c
@@ -1,30 +1,42 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
/* -*- c-file-style: "linux" -*-
|
||||
*
|
||||
* Copyright (C) 1996-2001 by Andrew Tridgell
|
||||
* Copyright (C) Paul Mackerras 1996
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
Utilities used in rsync
|
||||
/**
|
||||
* @file io.c
|
||||
*
|
||||
* Socket and pipe IO utilities used in rsync.
|
||||
*
|
||||
* rsync provides its own multiplexing system, which is used to send
|
||||
* stderr and stdout over a single socket. We need this because
|
||||
* stdout normally carries the binary data stream, and stderr all our
|
||||
* error messages.
|
||||
*
|
||||
* For historical reasons this is off during the start of the
|
||||
* connection, but it's switched on quite early using
|
||||
* io_start_multiplex_out() and io_start_multiplex_in().
|
||||
**/
|
||||
|
||||
tridge, June 1996
|
||||
*/
|
||||
#include "rsync.h"
|
||||
|
||||
/* if no timeout is specified then use a 60 second select timeout */
|
||||
/** If no timeout is specified then use a 60 second select timeout */
|
||||
#define SELECT_TIMEOUT 60
|
||||
|
||||
static int io_multiplexing_out;
|
||||
@@ -32,21 +44,47 @@ 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;
|
||||
static int no_flush;
|
||||
|
||||
extern int bwlimit;
|
||||
extern int verbose;
|
||||
extern int io_timeout;
|
||||
extern struct stats stats;
|
||||
|
||||
static int buffer_f_in = -1;
|
||||
|
||||
void setup_readbuffer(int f_in)
|
||||
{
|
||||
buffer_f_in = f_in;
|
||||
}
|
||||
const char phase_unknown[] = "unknown";
|
||||
|
||||
/**
|
||||
* The connection might be dropped at some point; perhaps because the
|
||||
* remote instance crashed. Just giving the offset on the stream is
|
||||
* not very helpful. So instead we try to make io_phase_name point to
|
||||
* something useful.
|
||||
*
|
||||
* For buffered/multiplexed IO these names will be somewhat
|
||||
* approximate; perhaps for ease of support we would rather make the
|
||||
* buffer always flush when a single application-level IO finishes.
|
||||
*
|
||||
* @todo Perhaps we want some simple stack functionality, but there's
|
||||
* no need to overdo it.
|
||||
**/
|
||||
const char *io_write_phase = phase_unknown;
|
||||
const char *io_read_phase = phase_unknown;
|
||||
|
||||
/** Ignore EOF errors while reading a module listing if the remote
|
||||
version is 24 or less. */
|
||||
int kludge_around_eof = False;
|
||||
|
||||
|
||||
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;
|
||||
|
||||
err_list_push();
|
||||
|
||||
if (!io_timeout) return;
|
||||
|
||||
@@ -58,45 +96,143 @@ static void check_timeout(void)
|
||||
t = time(NULL);
|
||||
|
||||
if (last_io && io_timeout && (t-last_io) >= io_timeout) {
|
||||
rprintf(FERROR,"io timeout after %d second - exiting\n",
|
||||
(int)(t-last_io));
|
||||
if (!am_server && !am_daemon) {
|
||||
rprintf(FERROR,"io timeout after %d seconds - exiting\n",
|
||||
(int)(t-last_io));
|
||||
}
|
||||
exit_cleanup(RERR_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
/** Setup the fd used to propagate errors */
|
||||
void io_set_error_fd(int fd)
|
||||
{
|
||||
io_error_fd = fd;
|
||||
}
|
||||
|
||||
static char *read_buffer;
|
||||
static char *read_buffer_p;
|
||||
static int read_buffer_len;
|
||||
static int read_buffer_size;
|
||||
static int no_flush;
|
||||
static int no_flush_read;
|
||||
/** Read some data from the error fd and write it to the write log code */
|
||||
static void read_error_fd(void)
|
||||
{
|
||||
char buf[200];
|
||||
size_t n;
|
||||
int fd = io_error_fd;
|
||||
int tag, len;
|
||||
|
||||
/* 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, int len)
|
||||
/* io_error_fd is temporarily disabled -- is this meant to
|
||||
* prevent indefinite recursion? */
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* It's almost always an error to get an EOF when we're trying to read
|
||||
* from the network, because the protocol is self-terminating.
|
||||
*
|
||||
* However, there is one unfortunate cases where it is not, which is
|
||||
* rsync <2.4.6 sending a list of modules on a server, since the list
|
||||
* is terminated by closing the socket. So, for the section of the
|
||||
* program where that is a problem (start_socket_client),
|
||||
* kludge_around_eof is True and we just exit.
|
||||
*/
|
||||
static void whine_about_eof (void)
|
||||
{
|
||||
if (kludge_around_eof)
|
||||
exit_cleanup (0);
|
||||
else {
|
||||
rprintf (FERROR,
|
||||
"%s: connection unexpectedly closed "
|
||||
"(%.0f bytes read so far)\n",
|
||||
RSYNC_NAME, (double)stats.total_read);
|
||||
|
||||
exit_cleanup (RERR_STREAMIO);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void die_from_readerr (int err)
|
||||
{
|
||||
/* this prevents us trying to write errors on a dead socket */
|
||||
io_multiplexing_close();
|
||||
|
||||
rprintf(FERROR, "%s: read error: %s\n",
|
||||
RSYNC_NAME, strerror (err));
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* TODO: If the remote shell connection fails, then current versions
|
||||
* actually report an "unexpected EOF" error here. Since it's a
|
||||
* fairly common mistake to try to use rsh when ssh is required, we
|
||||
* should trap that: if we fail to read any data at all, we should
|
||||
* give a better explanation. We can tell whether the connection has
|
||||
* started by looking e.g. at whether the remote version is known yet.
|
||||
*/
|
||||
static int read_timeout (int fd, char *buf, size_t len)
|
||||
{
|
||||
int n, ret=0;
|
||||
|
||||
no_flush_read++;
|
||||
io_flush();
|
||||
no_flush_read--;
|
||||
|
||||
while (ret == 0) {
|
||||
/* until we manage to read *something* */
|
||||
fd_set fds;
|
||||
struct timeval tv;
|
||||
int fd_count = fd+1;
|
||||
int count;
|
||||
|
||||
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;
|
||||
|
||||
if (select(fd+1, &fds, NULL, NULL, &tv) != 1) {
|
||||
errno = 0;
|
||||
|
||||
count = select(fd_count, &fds, NULL, NULL, &tv);
|
||||
|
||||
if (count == 0) {
|
||||
check_timeout();
|
||||
}
|
||||
|
||||
if (count <= 0) {
|
||||
if (errno == EBADF) {
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
}
|
||||
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) {
|
||||
@@ -106,38 +242,29 @@ static int read_timeout(int fd, char *buf, int len)
|
||||
if (io_timeout)
|
||||
last_io = time(NULL);
|
||||
continue;
|
||||
} else if (n == 0) {
|
||||
whine_about_eof ();
|
||||
return -1; /* doesn't return */
|
||||
} else if (n == -1) {
|
||||
if (errno == EINTR || errno == EWOULDBLOCK ||
|
||||
errno == EAGAIN)
|
||||
continue;
|
||||
else
|
||||
die_from_readerr (errno);
|
||||
}
|
||||
|
||||
if (n == -1 && errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (n == -1 &&
|
||||
(errno == EAGAIN || errno == EWOULDBLOCK)) {
|
||||
/* this shouldn't happen, if it does then
|
||||
sleep for a short time to prevent us
|
||||
chewing too much CPU */
|
||||
u_sleep(100);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
if (eof_error) {
|
||||
rprintf(FERROR,"unexpected EOF in read_timeout\n");
|
||||
}
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
|
||||
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, int len)
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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);
|
||||
@@ -147,17 +274,20 @@ static void read_loop(int fd, char *buf, int len)
|
||||
}
|
||||
}
|
||||
|
||||
/* read from the file descriptor handling multiplexing -
|
||||
return number of bytes read
|
||||
never return <= 0 */
|
||||
static int read_unbuffered(int fd, char *buf, int len)
|
||||
|
||||
/**
|
||||
* Read from the file descriptor handling multiplexing - return number
|
||||
* of bytes read.
|
||||
*
|
||||
* Never returns <= 0.
|
||||
*/
|
||||
static int read_unbuffered(int fd, char *buf, size_t len)
|
||||
{
|
||||
static int remaining;
|
||||
char ibuf[4];
|
||||
int tag, ret=0;
|
||||
static size_t remaining;
|
||||
int tag, ret = 0;
|
||||
char line[1024];
|
||||
|
||||
if (!io_multiplexing_in || fd != multiplex_in_fd)
|
||||
if (!io_multiplexing_in || fd != multiplex_in_fd)
|
||||
return read_timeout(fd, buf, len);
|
||||
|
||||
while (ret == 0) {
|
||||
@@ -169,23 +299,24 @@ static int read_unbuffered(int fd, char *buf, int len)
|
||||
continue;
|
||||
}
|
||||
|
||||
read_loop(fd, ibuf, 4);
|
||||
tag = IVAL(ibuf, 0);
|
||||
read_loop(fd, line, 4);
|
||||
tag = IVAL(line, 0);
|
||||
|
||||
remaining = tag & 0xFFFFFF;
|
||||
tag = tag >> 24;
|
||||
|
||||
if (tag == MPLEX_BASE) continue;
|
||||
if (tag == MPLEX_BASE)
|
||||
continue;
|
||||
|
||||
tag -= MPLEX_BASE;
|
||||
|
||||
if (tag != FERROR && tag != FINFO) {
|
||||
rprintf(FERROR,"unexpected tag %d\n", tag);
|
||||
rprintf(FERROR, "unexpected tag %d\n", tag);
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
|
||||
if (remaining > sizeof(line)-1) {
|
||||
rprintf(FERROR,"multiplexing overflow %d\n\n",
|
||||
if (remaining > sizeof(line) - 1) {
|
||||
rprintf(FERROR, "multiplexing overflow %d\n\n",
|
||||
remaining);
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
@@ -193,7 +324,7 @@ static int read_unbuffered(int fd, char *buf, int len)
|
||||
read_loop(fd, line, remaining);
|
||||
line[remaining] = 0;
|
||||
|
||||
rprintf(tag,"%s", line);
|
||||
rprintf((enum logcode) tag, "%s", line);
|
||||
remaining = 0;
|
||||
}
|
||||
|
||||
@@ -202,65 +333,20 @@ static int read_unbuffered(int fd, char *buf, int len)
|
||||
|
||||
|
||||
|
||||
/* 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 = 8192;
|
||||
|
||||
if (f == -1) return;
|
||||
|
||||
if (read_buffer_len == 0) {
|
||||
read_buffer_p = read_buffer;
|
||||
}
|
||||
|
||||
if (n > MAX_READ_BUFFER/4)
|
||||
n = MAX_READ_BUFFER/4;
|
||||
|
||||
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;
|
||||
read_buffer = (char *)Realloc(read_buffer,read_buffer_size);
|
||||
if (!read_buffer) out_of_memory("read check");
|
||||
read_buffer_p = read_buffer;
|
||||
}
|
||||
|
||||
n = read_unbuffered(f,read_buffer+read_buffer_len,n);
|
||||
read_buffer_len += n;
|
||||
}
|
||||
|
||||
|
||||
/* 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,int N)
|
||||
/**
|
||||
* Do a buffered read from @p fd. Don't return until all @p n bytes
|
||||
* have been read. If all @p 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;
|
||||
|
||||
if ((read_buffer_len < N) && (N < 1024)) {
|
||||
read_check(buffer_f_in);
|
||||
}
|
||||
size_t total=0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
no_flush_read++;
|
||||
io_flush();
|
||||
no_flush_read--;
|
||||
|
||||
ret = read_unbuffered(fd,buffer + total,N-total);
|
||||
ret = read_unbuffered (fd, buffer + total, N-total);
|
||||
total += ret;
|
||||
}
|
||||
|
||||
@@ -303,37 +389,66 @@ 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)
|
||||
{
|
||||
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);
|
||||
read_buf (f,buf,len);
|
||||
buf[len] = 0;
|
||||
}
|
||||
|
||||
unsigned char read_byte(int f)
|
||||
{
|
||||
unsigned char c;
|
||||
read_buf(f,(char *)&c,1);
|
||||
read_buf (f, (char *)&c, 1);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* write len bytes to fd, possibly reading from buffer_f_in if set
|
||||
in order to unclog the pipe. don't return until all len
|
||||
bytes have been written */
|
||||
static void writefd_unbuffered(int fd,char *buf,int len)
|
||||
/**
|
||||
* Sleep after writing to limit I/O bandwidth usage.
|
||||
*
|
||||
* @todo Rather than sleeping after each write, it might be better to
|
||||
* use some kind of averaging. The current algorithm seems to always
|
||||
* use a bit less bandwidth than specified, because it doesn't make up
|
||||
* for slow periods. But arguably this is a feature. In addition, we
|
||||
* ought to take the time used to write the data into account.
|
||||
**/
|
||||
static void sleep_for_bwlimit(int bytes_written)
|
||||
{
|
||||
int total = 0;
|
||||
struct timeval tv;
|
||||
|
||||
if (!bwlimit)
|
||||
return;
|
||||
|
||||
assert(bytes_written > 0);
|
||||
assert(bwlimit > 0);
|
||||
|
||||
tv.tv_usec = bytes_written * 1000 / bwlimit;
|
||||
tv.tv_sec = tv.tv_usec / 1000000;
|
||||
tv.tv_usec = tv.tv_usec % 1000000;
|
||||
|
||||
select(0, NULL, NULL, NULL, &tv);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write len bytes to the file descriptor @p fd.
|
||||
*
|
||||
* This function underlies the multiplexing system. The body of the
|
||||
* application never calls this function directly.
|
||||
**/
|
||||
static void writefd_unbuffered(int fd,char *buf,size_t len)
|
||||
{
|
||||
size_t total = 0;
|
||||
fd_set w_fds, r_fds;
|
||||
int fd_count, count;
|
||||
struct timeval tv;
|
||||
int reading=0;
|
||||
int blocked=0;
|
||||
|
||||
err_list_push();
|
||||
|
||||
no_flush++;
|
||||
|
||||
@@ -341,55 +456,67 @@ static void writefd_unbuffered(int fd,char *buf,int len)
|
||||
FD_ZERO(&w_fds);
|
||||
FD_ZERO(&r_fds);
|
||||
FD_SET(fd,&w_fds);
|
||||
fd_count = fd+1;
|
||||
fd_count = fd;
|
||||
|
||||
if (!no_flush_read) {
|
||||
reading = (buffer_f_in != -1);
|
||||
}
|
||||
|
||||
if (reading) {
|
||||
FD_SET(buffer_f_in,&r_fds);
|
||||
if (buffer_f_in > fd)
|
||||
fd_count = buffer_f_in+1;
|
||||
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;
|
||||
|
||||
count = select(fd_count,
|
||||
reading?&r_fds:NULL,
|
||||
errno = 0;
|
||||
|
||||
count = select(fd_count+1,
|
||||
io_error_fd != -1?&r_fds:NULL,
|
||||
&w_fds,NULL,
|
||||
&tv);
|
||||
|
||||
if (count <= 0) {
|
||||
if (count == 0) {
|
||||
check_timeout();
|
||||
}
|
||||
|
||||
if (count <= 0) {
|
||||
if (errno == EBADF) {
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (reading && FD_ISSET(buffer_f_in, &r_fds)) {
|
||||
read_check(buffer_f_in);
|
||||
if (io_error_fd != -1 && FD_ISSET(io_error_fd, &r_fds)) {
|
||||
read_error_fd();
|
||||
}
|
||||
|
||||
if (FD_ISSET(fd, &w_fds)) {
|
||||
int n = (len-total)>>blocked;
|
||||
int ret = write(fd,buf+total,n?n:1);
|
||||
int ret;
|
||||
size_t n = len-total;
|
||||
ret = write(fd,buf+total,n);
|
||||
|
||||
if (ret == -1 && errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ret == -1 &&
|
||||
(errno == EAGAIN || errno == EWOULDBLOCK)) {
|
||||
blocked++;
|
||||
(errno == EWOULDBLOCK || errno == EAGAIN)) {
|
||||
msleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ret <= 0) {
|
||||
rprintf(FERROR,"erroring writing %d bytes - exiting\n", len);
|
||||
/* Don't try to write errors back
|
||||
* across the stream */
|
||||
io_multiplexing_close();
|
||||
rprintf(FERROR, RSYNC_NAME
|
||||
": writefd_unbuffered failed to write %ld bytes: phase \"%s\": %s\n",
|
||||
(long) len, io_write_phase,
|
||||
strerror(errno));
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
|
||||
blocked = 0;
|
||||
sleep_for_bwlimit(ret);
|
||||
|
||||
total += ret;
|
||||
|
||||
if (io_timeout)
|
||||
@@ -408,48 +535,77 @@ void io_start_buffering(int fd)
|
||||
{
|
||||
if (io_buffer) return;
|
||||
multiplex_out_fd = fd;
|
||||
io_buffer = (char *)malloc(IO_BUFFER_SIZE+4);
|
||||
io_buffer = (char *)malloc(IO_BUFFER_SIZE);
|
||||
if (!io_buffer) out_of_memory("writefd");
|
||||
io_buffer_count = 0;
|
||||
|
||||
/* leave room for the multiplex header in case it's needed */
|
||||
io_buffer += 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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];
|
||||
size_t n = len;
|
||||
|
||||
SIVAL(buffer, 0, ((MPLEX_BASE + (int)code)<<24) + len);
|
||||
|
||||
if (n > (sizeof(buffer)-4)) {
|
||||
n = sizeof(buffer)-4;
|
||||
}
|
||||
|
||||
memcpy(&buffer[4], buf, n);
|
||||
writefd_unbuffered(fd, buffer, n+4);
|
||||
|
||||
len -= n;
|
||||
buf += n;
|
||||
|
||||
if (len) {
|
||||
writefd_unbuffered(fd, buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void io_flush(void)
|
||||
{
|
||||
int fd = multiplex_out_fd;
|
||||
|
||||
err_list_push();
|
||||
|
||||
if (!io_buffer_count || no_flush) return;
|
||||
|
||||
if (io_multiplexing_out) {
|
||||
SIVAL(io_buffer-4, 0, (MPLEX_BASE<<24) + io_buffer_count);
|
||||
writefd_unbuffered(fd, io_buffer-4, io_buffer_count+4);
|
||||
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)
|
||||
|
||||
void io_end_buffering(void)
|
||||
{
|
||||
io_flush();
|
||||
if (!io_multiplexing_out) {
|
||||
free(io_buffer-4);
|
||||
free(io_buffer);
|
||||
io_buffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void writefd(int fd,char *buf,int len)
|
||||
static void writefd(int fd,char *buf,size_t len)
|
||||
{
|
||||
stats.total_written += len;
|
||||
|
||||
if (!io_buffer) {
|
||||
err_list_push();
|
||||
|
||||
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);
|
||||
int n = MIN((int) len, IO_BUFFER_SIZE-io_buffer_count);
|
||||
if (n > 0) {
|
||||
memcpy(io_buffer+io_buffer_count, buf, n);
|
||||
buf += n;
|
||||
@@ -469,6 +625,19 @@ void write_int(int f,int32 x)
|
||||
writefd(f,b,4);
|
||||
}
|
||||
|
||||
|
||||
void write_int_named(int f, int32 x, const char *phase)
|
||||
{
|
||||
io_write_phase = phase;
|
||||
write_int(f, x);
|
||||
io_write_phase = phase_unknown;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Note: int64 may actually be a 32-bit type if ./configure couldn't find any
|
||||
* 64-bit types on this platform.
|
||||
*/
|
||||
void write_longint(int f, int64 x)
|
||||
{
|
||||
extern int remote_version;
|
||||
@@ -486,12 +655,12 @@ void write_longint(int f, int64 x)
|
||||
writefd(f,b,8);
|
||||
}
|
||||
|
||||
void write_buf(int f,char *buf,int len)
|
||||
void write_buf(int f,char *buf,size_t len)
|
||||
{
|
||||
writefd(f,buf,len);
|
||||
}
|
||||
|
||||
/* write a string to the connection */
|
||||
/** Write a string to the connection */
|
||||
static void write_sbuf(int f,char *buf)
|
||||
{
|
||||
write_buf(f, buf, strlen(buf));
|
||||
@@ -503,14 +672,21 @@ void write_byte(int f,unsigned char c)
|
||||
write_buf(f,(char *)&c,1);
|
||||
}
|
||||
|
||||
int read_line(int f, char *buf, int maxlen)
|
||||
{
|
||||
eof_error = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Read a line of up to @p maxlen characters into @p buf. Does not
|
||||
* contain a trailing newline or carriage return.
|
||||
*
|
||||
* @return 1 for success; 0 for io error or truncation.
|
||||
**/
|
||||
int read_line(int f, char *buf, size_t maxlen)
|
||||
{
|
||||
while (maxlen) {
|
||||
buf[0] = 0;
|
||||
read_buf(f, buf, 1);
|
||||
if (buf[0] == 0) return 0;
|
||||
if (buf[0] == 0)
|
||||
return 0;
|
||||
if (buf[0] == '\n') {
|
||||
buf[0] = 0;
|
||||
break;
|
||||
@@ -525,8 +701,6 @@ int read_line(int f, char *buf, int maxlen)
|
||||
return 0;
|
||||
}
|
||||
|
||||
eof_error = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -538,7 +712,7 @@ void io_printf(int fd, const char *format, ...)
|
||||
int len;
|
||||
|
||||
va_start(ap, format);
|
||||
len = vslprintf(buf, sizeof(buf), format, ap);
|
||||
len = vsnprintf(buf, sizeof(buf), format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (len < 0) exit_cleanup(RERR_STREAMIO);
|
||||
@@ -547,7 +721,7 @@ void io_printf(int fd, const char *format, ...)
|
||||
}
|
||||
|
||||
|
||||
/* setup for multiplexing an error stream with the data stream */
|
||||
/** Setup for multiplexing an error stream with the data stream */
|
||||
void io_start_multiplex_out(int fd)
|
||||
{
|
||||
multiplex_out_fd = fd;
|
||||
@@ -556,36 +730,28 @@ void io_start_multiplex_out(int fd)
|
||||
io_multiplexing_out = 1;
|
||||
}
|
||||
|
||||
/* setup for multiplexing an error stream with the data stream */
|
||||
/** Setup for multiplexing an error stream with the data stream */
|
||||
void io_start_multiplex_in(int fd)
|
||||
{
|
||||
multiplex_in_fd = fd;
|
||||
io_flush();
|
||||
if (read_buffer_len) {
|
||||
fprintf(stderr,"ERROR: data in read buffer at mplx start\n");
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
|
||||
io_multiplexing_in = 1;
|
||||
}
|
||||
|
||||
/* write an message to the error stream */
|
||||
int io_multiplex_write(int f, char *buf, int len)
|
||||
/** 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();
|
||||
|
||||
SIVAL(io_buffer-4, 0, ((MPLEX_BASE + f)<<24) + len);
|
||||
memcpy(io_buffer, buf, len);
|
||||
|
||||
stats.total_written += (len+4);
|
||||
|
||||
writefd_unbuffered(multiplex_out_fd, io_buffer-4, len+4);
|
||||
mplex_write(multiplex_out_fd, code, buf, len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void io_close_input(int fd)
|
||||
/** Stop output multiplexing */
|
||||
void io_multiplexing_close(void)
|
||||
{
|
||||
buffer_f_in = -1;
|
||||
io_multiplexing_out = 0;
|
||||
}
|
||||
|
||||
|
||||
110
lib/compat.c
110
lib/compat.c
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright (C) Andrew Tridgell 1998
|
||||
Copyright (C) 2002 by Martin Pool
|
||||
|
||||
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
|
||||
@@ -16,11 +17,15 @@
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
compatibility functions - replacing functions for platforms that don't
|
||||
have them.
|
||||
/**
|
||||
* @file compat.c
|
||||
*
|
||||
* Reimplementations of standard functions for platforms that don't
|
||||
* have them.
|
||||
**/
|
||||
|
||||
|
||||
|
||||
*/
|
||||
#include "rsync.h"
|
||||
|
||||
|
||||
@@ -78,9 +83,11 @@
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRPBRK
|
||||
/* Find the first ocurrence in S of any character in ACCEPT.
|
||||
derived from glibc
|
||||
*/
|
||||
/**
|
||||
* Find the first ocurrence in @p s of any character in @p accept.
|
||||
*
|
||||
* Derived from glibc
|
||||
**/
|
||||
char *strpbrk(const char *s, const char *accept)
|
||||
{
|
||||
while (*s != '\0') {
|
||||
@@ -95,29 +102,21 @@
|
||||
}
|
||||
#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
|
||||
slprintf(buf, 18, "%d.%d.%d.%d",
|
||||
(int)p[0], (int)p[1], (int)p[2], (int)p[3]);
|
||||
#else
|
||||
slprintf(buf, 18, "%d.%d.%d.%d",
|
||||
(int)p[3], (int)p[2], (int)p[1], (int)p[0]);
|
||||
#endif
|
||||
return buf;
|
||||
}
|
||||
#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 */
|
||||
/**
|
||||
* Like strncpy but does not 0 fill the buffer and always null
|
||||
* terminates.
|
||||
*
|
||||
* @param bufsize is the size of the destination buffer.
|
||||
*
|
||||
* @return 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;
|
||||
@@ -126,9 +125,13 @@
|
||||
#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 */
|
||||
/**
|
||||
* Like strncat() but does not 0 fill the buffer and always null
|
||||
* terminates.
|
||||
*
|
||||
* @param bufsize 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);
|
||||
@@ -145,3 +148,56 @@
|
||||
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
|
||||
}
|
||||
|
||||
434
lib/fnmatch.c
434
lib/fnmatch.c
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
751
lib/getopt.c
751
lib/getopt.c
@@ -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
|
||||
129
lib/getopt.h
129
lib/getopt.h
@@ -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
184
lib/inet_ntop.c
Normal 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 */
|
||||
212
lib/inet_pton.c
Normal file
212
lib/inet_pton.c
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* 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);
|
||||
#ifdef INET6
|
||||
static int inet_pton6(const char *src, unsigned char *dst);
|
||||
#endif
|
||||
|
||||
/* int
|
||||
* inet_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
|
||||
38
lib/mdfour.c
38
lib/mdfour.c
@@ -28,30 +28,23 @@
|
||||
|
||||
static struct mdfour *m;
|
||||
|
||||
#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))
|
||||
#ifdef LARGE_INT32
|
||||
#define lshift(x,s) ((((x)<<(s))&0xFFFFFFFF) | (((x)>>(32-(s)))&0xFFFFFFFF))
|
||||
#else
|
||||
#define lshift(x,s) (((x)<<(s)) | ((x)>>(32-(s))))
|
||||
#endif
|
||||
#define MASK32 (0xffffffff)
|
||||
|
||||
#define ROUND1(a,b,c,d,k,s) a = lshift(a + F(b,c,d) + X[k], s)
|
||||
#define ROUND2(a,b,c,d,k,s) a = lshift(a + G(b,c,d) + X[k] + 0x5A827999,s)
|
||||
#define ROUND3(a,b,c,d,k,s) a = lshift(a + H(b,c,d) + X[k] + 0x6ED9EBA1,s)
|
||||
#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)
|
||||
{
|
||||
int j;
|
||||
uint32 AA, BB, CC, DD;
|
||||
uint32 X[16];
|
||||
uint32 A,B,C,D;
|
||||
|
||||
for (j=0;j<16;j++)
|
||||
X[j] = M[j];
|
||||
|
||||
A = m->A; B = m->B; C = m->C; D = m->D;
|
||||
AA = A; BB = B; CC = C; DD = D;
|
||||
|
||||
@@ -64,6 +57,7 @@ static void mdfour64(uint32 *M)
|
||||
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);
|
||||
@@ -82,15 +76,11 @@ static void mdfour64(uint32 *M)
|
||||
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 += AA; B += BB;
|
||||
C += CC; D += DD;
|
||||
|
||||
#ifdef LARGE_INT32
|
||||
A &= 0xFFFFFFFF; B &= 0xFFFFFFFF;
|
||||
C &= 0xFFFFFFFF; D &= 0xFFFFFFFF;
|
||||
#endif
|
||||
|
||||
for (j=0;j<16;j++)
|
||||
X[j] = 0;
|
||||
A &= MASK32; B &= MASK32;
|
||||
C &= MASK32; D &= MASK32;
|
||||
|
||||
m->A = A; m->B = B; m->C = C; m->D = D;
|
||||
}
|
||||
|
||||
63
lib/permstring.c
Normal file
63
lib/permstring.c
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
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';
|
||||
|
||||
#ifdef S_ISVTX
|
||||
if (mode & S_ISVTX)
|
||||
perms[9] = (mode & S_IXOTH) ? 't' : 'T';
|
||||
#endif
|
||||
|
||||
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
3
lib/permstring.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#define PERMSTRING_SIZE 11
|
||||
|
||||
void permstring(char *perms, int mode);
|
||||
1405
lib/snprintf.c
1405
lib/snprintf.c
File diff suppressed because it is too large
Load Diff
67
loadparm.c
67
loadparm.c
@@ -1,6 +1,11 @@
|
||||
/* This is based on loadparm.c from Samba, written by Andrew Tridgell
|
||||
and Karl Auer */
|
||||
|
||||
/* some fixes
|
||||
*
|
||||
* 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
|
||||
@@ -43,6 +48,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
/* TODO: Parameter to set debug level on server. */
|
||||
|
||||
#include "rsync.h"
|
||||
#define PTR_DIFF(p1,p2) ((ptrdiff_t)(((char *)(p1)) - (char *)(p2)))
|
||||
#define strequal(a,b) (strcasecmp(a,b)==0)
|
||||
@@ -77,8 +84,6 @@ struct parm_struct
|
||||
unsigned flags;
|
||||
};
|
||||
|
||||
static BOOL bLoaded = False;
|
||||
|
||||
#ifndef GLOBAL_NAME
|
||||
#define GLOBAL_NAME "global"
|
||||
#endif
|
||||
@@ -117,6 +122,7 @@ typedef struct
|
||||
BOOL list;
|
||||
BOOL use_chroot;
|
||||
BOOL transfer_logging;
|
||||
BOOL ignore_errors;
|
||||
char *uid;
|
||||
char *gid;
|
||||
char *hosts_allow;
|
||||
@@ -133,6 +139,7 @@ typedef struct
|
||||
char *dont_compress;
|
||||
int timeout;
|
||||
int max_connections;
|
||||
BOOL ignore_nonreadable;
|
||||
} service;
|
||||
|
||||
|
||||
@@ -147,8 +154,18 @@ static service sDefault =
|
||||
True, /* list */
|
||||
True, /* use chroot */
|
||||
False, /* transfer logging */
|
||||
False, /* ignore errors */
|
||||
"nobody",/* uid */
|
||||
|
||||
/* TODO: This causes problems on Debian, where it is called
|
||||
* "nogroup". Debian patch this in their version of the
|
||||
* package, but it would be nice to be consistent. Possibly
|
||||
* other systems are different again.
|
||||
*
|
||||
* What is the best behaviour? Perhaps always using (gid_t)
|
||||
* -2? */
|
||||
"nobody",/* gid */
|
||||
|
||||
NULL, /* hosts allow */
|
||||
NULL, /* hosts deny */
|
||||
NULL, /* auth users */
|
||||
@@ -160,9 +177,10 @@ static service sDefault =
|
||||
NULL, /* include from */
|
||||
"%o %h [%a] %m (%u) %f %l", /* log format */
|
||||
NULL, /* refuse options */
|
||||
"*.gz *.tgz *.zip *.z *.rpm *.deb", /* dont compress */
|
||||
"*.gz *.tgz *.zip *.z *.rpm *.deb *.iso *.bz2 *.tbz", /* dont compress */
|
||||
0, /* timeout */
|
||||
0 /* max connections */
|
||||
0, /* max connections */
|
||||
False /* ignore nonreadable */
|
||||
};
|
||||
|
||||
|
||||
@@ -260,6 +278,7 @@ static struct parm_struct parm_table[] =
|
||||
{"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},
|
||||
@@ -272,6 +291,7 @@ static struct parm_struct parm_table[] =
|
||||
{"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},
|
||||
@@ -336,6 +356,8 @@ 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)
|
||||
@@ -373,14 +395,28 @@ static void init_service(service *pservice)
|
||||
copy_service(pservice,&sDefault);
|
||||
}
|
||||
|
||||
static void string_set(char **s, char *v)
|
||||
|
||||
/**
|
||||
* 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);
|
||||
if (!*s)
|
||||
exit_cleanup(RERR_MALLOC);
|
||||
}
|
||||
|
||||
|
||||
@@ -443,11 +479,12 @@ static int strwicmp(char *psz1, char *psz2)
|
||||
/* sync the strings on first non-whitespace */
|
||||
while (1)
|
||||
{
|
||||
while (isspace(*psz1))
|
||||
while (isspace(* (unsigned char *) psz1))
|
||||
psz1++;
|
||||
while (isspace(*psz2))
|
||||
while (isspace(* (unsigned char *) psz2))
|
||||
psz2++;
|
||||
if (toupper(*psz1) != toupper(*psz2) || *psz1 == '\0' || *psz2 == '\0')
|
||||
if (toupper(* (unsigned char *) psz1) != toupper(* (unsigned char *) psz2)
|
||||
|| *psz1 == '\0' || *psz2 == '\0')
|
||||
break;
|
||||
psz1++;
|
||||
psz2++;
|
||||
@@ -711,6 +748,9 @@ False on failure.
|
||||
***************************************************************************/
|
||||
BOOL lp_load(char *pszFname, int globals_only)
|
||||
{
|
||||
extern int am_server;
|
||||
extern int am_daemon;
|
||||
extern int am_root;
|
||||
pstring n2;
|
||||
BOOL bRetval;
|
||||
|
||||
@@ -720,14 +760,17 @@ BOOL lp_load(char *pszFname, int globals_only)
|
||||
|
||||
init_globals();
|
||||
|
||||
pstrcpy(n2,pszFname);
|
||||
if (pszFname)
|
||||
pstrcpy(n2,pszFname);
|
||||
else if (am_server && am_daemon && !am_root)
|
||||
pstrcpy(n2,RSYNCD_USERCONF);
|
||||
else
|
||||
pstrcpy(n2,RSYNCD_SYSCONF);
|
||||
|
||||
/* 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);
|
||||
|
||||
bLoaded = True;
|
||||
|
||||
return (bRetval);
|
||||
}
|
||||
|
||||
|
||||
385
log.c
385
log.c
@@ -1,5 +1,7 @@
|
||||
/*
|
||||
Copyright (C) Andrew Tridgell 1998
|
||||
/* -*- c-file-style: "linux"; -*-
|
||||
|
||||
Copyright (C) 1998-2001 by Andrew Tridgell <tridge@samba.org>
|
||||
Copyright (C) 2000-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
|
||||
@@ -17,18 +19,124 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
logging and utility functions
|
||||
|
||||
Logging and utility functions.
|
||||
tridge, May 1998
|
||||
|
||||
Mapping to human-readable messages added by Martin Pool
|
||||
<mbp@samba.org>, Oct 2000.
|
||||
*/
|
||||
#include "rsync.h"
|
||||
|
||||
static int log_initialised;
|
||||
static char *logfname;
|
||||
static FILE *logfile;
|
||||
static int log_error_fd = -1;
|
||||
struct stats stats;
|
||||
|
||||
int log_got_error=0;
|
||||
|
||||
struct {
|
||||
int code;
|
||||
char const *name;
|
||||
} const rerr_names[] = {
|
||||
{ RERR_SYNTAX , "syntax or usage error" },
|
||||
{ RERR_PROTOCOL , "protocol incompatibility" },
|
||||
{ RERR_FILESELECT , "errors selecting input/output files, dirs" },
|
||||
{ RERR_UNSUPPORTED, "requested action not supported" },
|
||||
{ RERR_STARTCLIENT, "error starting client-server protocol" },
|
||||
{ RERR_SOCKETIO , "error in socket IO" },
|
||||
{ RERR_FILEIO , "error in file IO" },
|
||||
{ RERR_STREAMIO , "error in rsync protocol data stream" },
|
||||
{ RERR_MESSAGEIO , "errors with program diagnostics" },
|
||||
{ RERR_IPC , "error in IPC code" },
|
||||
{ RERR_SIGNAL , "received SIGUSR1 or SIGINT" },
|
||||
{ RERR_WAITCHILD , "some error returned by waitpid()" },
|
||||
{ RERR_MALLOC , "error allocating core memory buffers" },
|
||||
{ RERR_PARTIAL , "some files could not be transferred" },
|
||||
{ RERR_TIMEOUT , "timeout in data send/receive" },
|
||||
{ RERR_CMD_FAILED , "remote shell failed" },
|
||||
{ RERR_CMD_KILLED , "remote shell killed" },
|
||||
{ RERR_CMD_RUN, "remote command could not be run" },
|
||||
{ RERR_CMD_NOTFOUND, "remote command not found" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Map from rsync error code to name, or return NULL.
|
||||
*/
|
||||
static char const *rerr_name(int code)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; rerr_names[i].name; i++) {
|
||||
if (rerr_names[i].code == code)
|
||||
return rerr_names[i].name;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct err_list {
|
||||
struct err_list *next;
|
||||
char *buf;
|
||||
int len;
|
||||
int written; /* how many bytes we have written so far */
|
||||
};
|
||||
|
||||
static struct err_list *err_list_head;
|
||||
static struct err_list *err_list_tail;
|
||||
|
||||
/* add an error message to the pending error list */
|
||||
static void err_list_add(int code, char *buf, int len)
|
||||
{
|
||||
struct err_list *el;
|
||||
el = (struct err_list *)malloc(sizeof(*el));
|
||||
if (!el) exit_cleanup(RERR_MALLOC);
|
||||
el->next = NULL;
|
||||
el->buf = malloc(len+4);
|
||||
if (!el->buf) exit_cleanup(RERR_MALLOC);
|
||||
memcpy(el->buf+4, buf, len);
|
||||
SIVAL(el->buf, 0, ((code+MPLEX_BASE)<<24) | len);
|
||||
el->len = len+4;
|
||||
el->written = 0;
|
||||
if (err_list_tail) {
|
||||
err_list_tail->next = el;
|
||||
} else {
|
||||
err_list_head = el;
|
||||
}
|
||||
err_list_tail = el;
|
||||
}
|
||||
|
||||
|
||||
/* try to push errors off the error list onto the wire */
|
||||
void err_list_push(void)
|
||||
{
|
||||
if (log_error_fd == -1) return;
|
||||
|
||||
while (err_list_head) {
|
||||
struct err_list *el = err_list_head;
|
||||
int n = write(log_error_fd, el->buf+el->written, el->len - el->written);
|
||||
/* don't check for an error if the best way of handling the error is
|
||||
to ignore it */
|
||||
if (n == -1) break;
|
||||
if (n > 0) {
|
||||
el->written += n;
|
||||
}
|
||||
if (el->written == el->len) {
|
||||
free(el->buf);
|
||||
err_list_head = el->next;
|
||||
if (!err_list_head) err_list_tail = NULL;
|
||||
free(el);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void logit(int priority, char *buf)
|
||||
{
|
||||
if (logfile) {
|
||||
if (logfname) {
|
||||
if (!logfile)
|
||||
log_open();
|
||||
fprintf(logfile,"%s [%d] %s",
|
||||
timestring(time(NULL)), (int)getpid(), buf);
|
||||
fflush(logfile);
|
||||
@@ -37,15 +145,13 @@ static void logit(int priority, char *buf)
|
||||
}
|
||||
}
|
||||
|
||||
void log_open(void)
|
||||
void log_init(void)
|
||||
{
|
||||
static int initialised;
|
||||
int options = LOG_PID;
|
||||
time_t t;
|
||||
char *logf;
|
||||
|
||||
if (initialised) return;
|
||||
initialised = 1;
|
||||
if (log_initialised) return;
|
||||
log_initialised = 1;
|
||||
|
||||
/* this looks pointless, but it is needed in order for the
|
||||
C library on some systems to fetch the timezone info
|
||||
@@ -54,13 +160,13 @@ void log_open(void)
|
||||
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;
|
||||
logfname = lp_log_file();
|
||||
if (logfname) {
|
||||
if (*logfname) {
|
||||
log_open();
|
||||
return;
|
||||
}
|
||||
logfname = NULL;
|
||||
}
|
||||
|
||||
#ifdef LOG_NDELAY
|
||||
@@ -77,60 +183,96 @@ void log_open(void)
|
||||
logit(LOG_INFO,"rsyncd started\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* this is the rsync debugging function. Call it with FINFO, FERROR or FLOG */
|
||||
void rprintf(int fd, const char *format, ...)
|
||||
void log_open(void)
|
||||
{
|
||||
if (logfname && !logfile) {
|
||||
extern int orig_umask;
|
||||
int old_umask = umask(022 | orig_umask);
|
||||
logfile = fopen(logfname, "a");
|
||||
umask(old_umask);
|
||||
}
|
||||
}
|
||||
|
||||
void log_close(void)
|
||||
{
|
||||
if (logfile) {
|
||||
fclose(logfile);
|
||||
logfile = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
set_nonblocking(log_error_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)
|
||||
{
|
||||
va_list ap;
|
||||
char buf[1024];
|
||||
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 != 0 && fd == FINFO) return;
|
||||
|
||||
va_start(ap, format);
|
||||
len = vslprintf(buf, sizeof(buf), format, ap);
|
||||
va_end(ap);
|
||||
if (quiet && code == FINFO) return;
|
||||
|
||||
if (len < 0) exit_cleanup(RERR_MESSAGEIO);
|
||||
|
||||
if (len > sizeof(buf)-1) exit_cleanup(RERR_MESSAGEIO);
|
||||
|
||||
buf[len] = 0;
|
||||
|
||||
if (fd == FLOG) {
|
||||
if (code == FLOG) {
|
||||
if (am_daemon) logit(LOG_INFO, buf);
|
||||
return;
|
||||
}
|
||||
|
||||
if (am_daemon) {
|
||||
/* first try to pass it off to our sibling */
|
||||
if (am_server && log_error_fd != -1) {
|
||||
err_list_add(code, buf, len);
|
||||
err_list_push();
|
||||
return;
|
||||
}
|
||||
|
||||
/* next, if we are a server but not in daemon mode, and multiplexing
|
||||
* is enabled, pass it to the other side. */
|
||||
if (am_server && !am_daemon && io_multiplex_write(code, buf, len)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* otherwise, if in daemon mode and either we are not a server
|
||||
* (that is, we are not running --daemon over a remote shell) or
|
||||
* the log has already been initialised, log the message on this
|
||||
* side because we don't want the client to see most errors for
|
||||
* security reasons. We do want early messages when running daemon
|
||||
* mode over a remote shell to go to the remote side; those will
|
||||
* fall through to the next case. */
|
||||
if (am_daemon && (!am_server || log_initialised)) {
|
||||
static int depth;
|
||||
int priority = LOG_INFO;
|
||||
if (fd == FERROR) priority = LOG_WARNING;
|
||||
if (code == FERROR) priority = LOG_WARNING;
|
||||
|
||||
if (depth) return;
|
||||
|
||||
depth++;
|
||||
|
||||
log_open();
|
||||
if (!io_multiplex_write(fd, buf, strlen(buf))) {
|
||||
logit(priority, buf);
|
||||
}
|
||||
log_init();
|
||||
logit(priority, buf);
|
||||
|
||||
depth--;
|
||||
return;
|
||||
}
|
||||
|
||||
if (fd == FERROR) {
|
||||
if (code == FERROR) {
|
||||
log_got_error = 1;
|
||||
f = stderr;
|
||||
}
|
||||
|
||||
if (fd == FINFO) {
|
||||
extern int am_server;
|
||||
if (code == FINFO) {
|
||||
if (am_server)
|
||||
f = stderr;
|
||||
else
|
||||
@@ -143,8 +285,95 @@ void log_open(void)
|
||||
|
||||
if (buf[len-1] == '\r' || buf[len-1] == '\n') fflush(f);
|
||||
}
|
||||
|
||||
|
||||
void rflush(int fd)
|
||||
/* 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);
|
||||
/* Note: might return -1 */
|
||||
len = vsnprintf(buf, sizeof(buf), format, ap);
|
||||
va_end(ap);
|
||||
|
||||
/* Deal with buffer overruns. Instead of panicking, just
|
||||
* truncate the resulting string. Note that some vsnprintf()s
|
||||
* return -1 on truncation, e.g., glibc 2.0.6 and earlier. */
|
||||
if ((size_t) len > sizeof(buf)-1 || len < 0) {
|
||||
const char ellipsis[] = "[...]";
|
||||
|
||||
/* Reset length, and zero-terminate the end of our buffer */
|
||||
len = sizeof(buf)-1;
|
||||
buf[len] = '\0';
|
||||
|
||||
/* Copy the ellipsis to the end of the string, but give
|
||||
* us one extra character:
|
||||
*
|
||||
* v--- null byte at buf[sizeof(buf)-1]
|
||||
* abcdefghij0
|
||||
* -> abcd[...]00 <-- now two null bytes at end
|
||||
*
|
||||
* If the input format string has a trailing newline,
|
||||
* we copy it into that extra null; if it doesn't, well,
|
||||
* all we lose is one byte. */
|
||||
strncpy(buf+len-sizeof(ellipsis), ellipsis, sizeof(ellipsis));
|
||||
if (format[strlen(format)-1] == '\n') {
|
||||
buf[len-1] = '\n';
|
||||
}
|
||||
}
|
||||
|
||||
rwrite(code, buf, len);
|
||||
}
|
||||
|
||||
|
||||
/* This is like rprintf, but it also tries to print some
|
||||
* representation of the error code. Normally errcode = errno.
|
||||
*
|
||||
* Unlike rprintf, this always adds a newline and there should not be
|
||||
* one in the format string.
|
||||
*
|
||||
* Note that since strerror might involve dynamically loading a
|
||||
* message catalog we need to call it once before chroot-ing. */
|
||||
void rsyserr(enum logcode code, int errcode, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buf[1024];
|
||||
int len;
|
||||
size_t sys_len;
|
||||
char *sysmsg;
|
||||
|
||||
va_start(ap, format);
|
||||
/* Note: might return <0 */
|
||||
len = vsnprintf(buf, sizeof(buf), format, ap);
|
||||
va_end(ap);
|
||||
|
||||
/* TODO: Put in RSYNC_NAME at the start. */
|
||||
|
||||
if ((size_t) len > sizeof(buf)-1)
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
|
||||
sysmsg = strerror(errcode);
|
||||
sys_len = strlen(sysmsg);
|
||||
if ((size_t) len + 3 + sys_len > sizeof(buf) - 1)
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
|
||||
strcpy(buf + len, ": ");
|
||||
len += 2;
|
||||
strcpy(buf + len, sysmsg);
|
||||
len += sys_len;
|
||||
strcpy(buf + len, "\n");
|
||||
len++;
|
||||
|
||||
rwrite(code, buf, len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void rflush(enum logcode code)
|
||||
{
|
||||
FILE *f = NULL;
|
||||
extern int am_daemon;
|
||||
@@ -153,15 +382,15 @@ void rflush(int fd)
|
||||
return;
|
||||
}
|
||||
|
||||
if (fd == FLOG) {
|
||||
if (code == FLOG) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (fd == FERROR) {
|
||||
if (code == FERROR) {
|
||||
f = stderr;
|
||||
}
|
||||
|
||||
if (fd == FINFO) {
|
||||
if (code == FINFO) {
|
||||
extern int am_server;
|
||||
if (am_server)
|
||||
f = stderr;
|
||||
@@ -177,7 +406,7 @@ void rflush(int fd)
|
||||
|
||||
/* a generic logging routine for send/recv, with parameter
|
||||
substitiution */
|
||||
static void log_formatted(int fd,
|
||||
static void log_formatted(enum logcode code,
|
||||
char *format, char *op, struct file_struct *file,
|
||||
struct stats *initial_stats)
|
||||
{
|
||||
@@ -186,12 +415,18 @@ static void log_formatted(int fd,
|
||||
char buf[1024];
|
||||
char buf2[1024];
|
||||
char *p, *s, *n;
|
||||
int l;
|
||||
size_t l;
|
||||
extern struct stats stats;
|
||||
extern int am_sender;
|
||||
extern int am_daemon;
|
||||
int64 b;
|
||||
|
||||
/* We expand % codes one by one in place in buf. We don't
|
||||
* copy in the terminating nul of the inserted strings, but
|
||||
* rather keep going until we reach the nul of the format.
|
||||
* Just to make sure we don't clobber that nul and therefore
|
||||
* accidentally keep going, we zero the buffer now. */
|
||||
memset(buf, 0, sizeof buf);
|
||||
strlcpy(buf, format, sizeof(buf));
|
||||
|
||||
for (s=&buf[0];
|
||||
@@ -203,18 +438,18 @@ static void log_formatted(int fd,
|
||||
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",
|
||||
snprintf(buf2,sizeof(buf2),"%.0f",
|
||||
(double)file->length);
|
||||
n = buf2;
|
||||
break;
|
||||
case 'p':
|
||||
slprintf(buf2,sizeof(buf2),"%d",
|
||||
snprintf(buf2,sizeof(buf2),"%d",
|
||||
(int)getpid());
|
||||
n = buf2;
|
||||
break;
|
||||
case 'o': n = op; break;
|
||||
case 'f':
|
||||
slprintf(buf2, sizeof(buf2), "%s/%s",
|
||||
snprintf(buf2, sizeof(buf2), "%s/%s",
|
||||
file->basedir?file->basedir:"",
|
||||
f_name(file));
|
||||
clean_fname(buf2);
|
||||
@@ -233,7 +468,7 @@ static void log_formatted(int fd,
|
||||
b = stats.total_read -
|
||||
initial_stats->total_read;
|
||||
}
|
||||
slprintf(buf2,sizeof(buf2),"%.0f", (double)b);
|
||||
snprintf(buf2,sizeof(buf2),"%.0f", (double)b);
|
||||
n = buf2;
|
||||
break;
|
||||
case 'c':
|
||||
@@ -244,30 +479,39 @@ static void log_formatted(int fd,
|
||||
b = stats.total_read -
|
||||
initial_stats->total_read;
|
||||
}
|
||||
slprintf(buf2,sizeof(buf2),"%.0f", (double)b);
|
||||
snprintf(buf2,sizeof(buf2),"%.0f", (double)b);
|
||||
n = buf2;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!n) continue;
|
||||
/* n is the string to be inserted in place of this %
|
||||
* code; l is its length not including the trailing
|
||||
* NUL */
|
||||
if (!n)
|
||||
continue;
|
||||
|
||||
l = strlen(n);
|
||||
|
||||
if ((l-1) + ((int)(s - &buf[0])) > sizeof(buf)) {
|
||||
if (l + ((int)(s - &buf[0])) >= sizeof(buf)) {
|
||||
rprintf(FERROR,"buffer overflow expanding %%%c - exiting\n",
|
||||
p[0]);
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
}
|
||||
|
||||
/* Shuffle the rest of the string along to make space for n */
|
||||
if (l != 2) {
|
||||
memmove(s+(l-1), s+1, strlen(s+1)+1);
|
||||
}
|
||||
|
||||
/* Copy in n but NOT its nul, because the format sting
|
||||
* probably continues after this. */
|
||||
memcpy(p, n, l);
|
||||
|
||||
/* Skip over inserted string; continue looking */
|
||||
s = p+l;
|
||||
}
|
||||
|
||||
rprintf(fd,"%s\n", buf);
|
||||
rprintf(code,"%s\n", buf);
|
||||
}
|
||||
|
||||
/* log the outgoing transfer of a file */
|
||||
@@ -298,7 +542,15 @@ void log_recv(struct file_struct *file, struct stats *initial_stats)
|
||||
}
|
||||
}
|
||||
|
||||
/* called when the transfer is interrupted for some reason */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Called when the transfer is interrupted for some reason.
|
||||
*
|
||||
* Code is one of the RERR_* codes from errcode.h, or terminating
|
||||
* successfully.
|
||||
*/
|
||||
void log_exit(int code, const char *file, int line)
|
||||
{
|
||||
if (code == 0) {
|
||||
@@ -308,22 +560,27 @@ void log_exit(int code, const char *file, int line)
|
||||
(double)stats.total_read,
|
||||
(double)stats.total_size);
|
||||
} else {
|
||||
rprintf(FLOG,"transfer interrupted (code %d) at %s(%d)\n",
|
||||
code, file, line);
|
||||
const char *name;
|
||||
|
||||
name = rerr_name(code);
|
||||
if (!name)
|
||||
name = "unexplained error";
|
||||
|
||||
rprintf(FERROR,"rsync error: %s (code %d) at %s(%d)\n",
|
||||
name, 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
|
||||
*/
|
||||
/*
|
||||
* Log the incoming transfer of a file for interactive use,
|
||||
* this will be called at the end where the client was run.
|
||||
* 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);
|
||||
rprintf(FINFO, "%s\n", fname);
|
||||
}
|
||||
|
||||
|
||||
539
main.c
539
main.c
@@ -1,6 +1,8 @@
|
||||
/*
|
||||
Copyright (C) Andrew Tridgell 1996
|
||||
/* -*- c-file-style: "linux" -*-
|
||||
|
||||
Copyright (C) 1996-2001 by Andrew Tridgell <tridge@samba.org>
|
||||
Copyright (C) Paul Mackerras 1996
|
||||
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
|
||||
@@ -21,12 +23,55 @@
|
||||
|
||||
time_t starttime = 0;
|
||||
|
||||
struct stats stats;
|
||||
|
||||
extern int csum_length;
|
||||
|
||||
extern struct stats stats;
|
||||
extern int verbose;
|
||||
|
||||
/* there's probably never more than at most 2 outstanding child processes,
|
||||
* but set it higher just in case.
|
||||
*/
|
||||
#define MAXCHILDPROCS 5
|
||||
|
||||
struct pid_status {
|
||||
pid_t pid;
|
||||
int status;
|
||||
} pid_stat_table[MAXCHILDPROCS];
|
||||
|
||||
static void show_malloc_stats(void);
|
||||
|
||||
/****************************************************************************
|
||||
wait for a process to exit, calling io_flush while waiting
|
||||
****************************************************************************/
|
||||
void wait_process(pid_t pid, int *status)
|
||||
{
|
||||
pid_t waited_pid;
|
||||
int cnt;
|
||||
|
||||
while ((waited_pid = waitpid(pid, status, WNOHANG)) == 0) {
|
||||
msleep(20);
|
||||
io_flush();
|
||||
}
|
||||
|
||||
if ((waited_pid == -1) && (errno == ECHILD)) {
|
||||
/* status of requested child no longer available.
|
||||
* check to see if it was processed by the sigchld_handler.
|
||||
*/
|
||||
for (cnt = 0; cnt < MAXCHILDPROCS; cnt++) {
|
||||
if (pid == pid_stat_table[cnt].pid) {
|
||||
*status = pid_stat_table[cnt].status;
|
||||
pid_stat_table[cnt].pid = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: If the child exited on a signal, then log an
|
||||
* appropriate error message. Perhaps we should also accept a
|
||||
* message describing the purpose of the child. Also indicate
|
||||
* this to the caller so that thhey know something went
|
||||
* wrong. */
|
||||
*status = WEXITSTATUS(*status);
|
||||
}
|
||||
|
||||
static void report(int f)
|
||||
{
|
||||
time_t t = time(NULL);
|
||||
@@ -37,6 +82,12 @@ static void report(int f)
|
||||
extern int remote_version;
|
||||
int send_stats;
|
||||
|
||||
if (do_stats) {
|
||||
/* These come out from every process */
|
||||
show_malloc_stats();
|
||||
show_flist_stats();
|
||||
}
|
||||
|
||||
if (am_daemon) {
|
||||
log_exit(0, __FILE__, __LINE__);
|
||||
if (f == -1 || !am_sender) return;
|
||||
@@ -107,15 +158,53 @@ static void report(int f)
|
||||
}
|
||||
|
||||
|
||||
static int do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
|
||||
/**
|
||||
* If our C library can get malloc statistics, then show them to FINFO
|
||||
**/
|
||||
static void show_malloc_stats(void)
|
||||
{
|
||||
#ifdef HAVE_MALLINFO
|
||||
struct mallinfo mi;
|
||||
extern int am_server;
|
||||
extern int am_sender;
|
||||
extern int am_daemon;
|
||||
|
||||
mi = mallinfo();
|
||||
|
||||
rprintf(FINFO, RSYNC_NAME "[%d] (%s%s%s) heap statistics:\n",
|
||||
getpid(),
|
||||
am_server ? "server " : "",
|
||||
am_daemon ? "daemon " : "",
|
||||
am_sender ? "sender" : "receiver");
|
||||
rprintf(FINFO, " arena: %10d (bytes from sbrk)\n", mi.arena);
|
||||
rprintf(FINFO, " ordblks: %10d (chunks not in use)\n", mi.ordblks);
|
||||
rprintf(FINFO, " smblks: %10d\n", mi.smblks);
|
||||
rprintf(FINFO, " hblks: %10d (chunks from mmap)\n", mi.hblks);
|
||||
rprintf(FINFO, " hblkhd: %10d (bytes from mmap)\n", mi.hblkhd);
|
||||
rprintf(FINFO, " usmblks: %10d\n", mi.usmblks);
|
||||
rprintf(FINFO, " fsmblks: %10d\n", mi.fsmblks);
|
||||
rprintf(FINFO, " uordblks: %10d (bytes used)\n", mi.uordblks);
|
||||
rprintf(FINFO, " fordblks: %10d (bytes free)\n", mi.fordblks);
|
||||
rprintf(FINFO, " keepcost: %10d (bytes in releasable chunk)\n", mi.keepcost);
|
||||
#endif /* HAVE_MALLINFO */
|
||||
}
|
||||
|
||||
|
||||
/* Start the remote shell. cmd may be NULL to use the default. */
|
||||
static pid_t do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
|
||||
{
|
||||
char *args[100];
|
||||
int i,argc=0, ret;
|
||||
int i,argc=0;
|
||||
pid_t ret;
|
||||
char *tok,*dir=NULL;
|
||||
int dash_l_set = 0;
|
||||
extern int local_server;
|
||||
extern char *rsync_path;
|
||||
extern int blocking_io;
|
||||
extern int daemon_over_rsh;
|
||||
extern int read_batch;
|
||||
|
||||
if (!local_server) {
|
||||
if (!read_batch && !local_server) {
|
||||
if (!cmd)
|
||||
cmd = getenv(RSYNC_RSH_ENV);
|
||||
if (!cmd)
|
||||
@@ -128,15 +217,22 @@ static int do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f
|
||||
args[argc++] = tok;
|
||||
}
|
||||
|
||||
/* check to see if we've already been given '-l user' in
|
||||
the remote-shell command */
|
||||
for (i = 0; i < argc-1; i++) {
|
||||
if (!strcmp(args[i], "-l") && args[i+1][0] != '-')
|
||||
dash_l_set = 1;
|
||||
}
|
||||
|
||||
#if HAVE_REMSH
|
||||
/* remsh (on HPUX) takes the arguments the other way around */
|
||||
args[argc++] = machine;
|
||||
if (user) {
|
||||
if (user && !(daemon_over_rsh && dash_l_set)) {
|
||||
args[argc++] = "-l";
|
||||
args[argc++] = user;
|
||||
}
|
||||
#else
|
||||
if (user) {
|
||||
if (user && !(daemon_over_rsh && dash_l_set)) {
|
||||
args[argc++] = "-l";
|
||||
args[argc++] = user;
|
||||
}
|
||||
@@ -145,12 +241,16 @@ static int do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f
|
||||
|
||||
args[argc++] = rsync_path;
|
||||
|
||||
if ((blocking_io == -1) && (strcmp(cmd, RSYNC_RSH) == 0))
|
||||
blocking_io = 1;
|
||||
|
||||
server_options(args,&argc);
|
||||
|
||||
}
|
||||
|
||||
args[argc++] = ".";
|
||||
|
||||
if (path && *path)
|
||||
if (!daemon_over_rsh && path && *path)
|
||||
args[argc++] = path;
|
||||
|
||||
args[argc] = NULL;
|
||||
@@ -163,7 +263,9 @@ static int do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f
|
||||
}
|
||||
|
||||
if (local_server) {
|
||||
ret = local_child(argc, args, f_in, f_out);
|
||||
if (read_batch)
|
||||
create_flist_from_batch(); /* sets batch_flist */
|
||||
ret = local_child(argc, args, f_in, f_out, child_main);
|
||||
} else {
|
||||
ret = piped_child(args,f_in,f_out);
|
||||
}
|
||||
@@ -212,7 +314,8 @@ static char *get_local_name(struct file_list *flist,char *name)
|
||||
return name;
|
||||
|
||||
if (do_mkdir(name,0777 & ~orig_umask) != 0) {
|
||||
rprintf(FERROR,"mkdir %s : %s (1)\n",name,strerror(errno));
|
||||
rprintf(FERROR, RSYNC_NAME ": mkdir %s: %s\n",
|
||||
name, strerror(errno));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
} else {
|
||||
if (verbose > 0)
|
||||
@@ -220,8 +323,8 @@ static char *get_local_name(struct file_list *flist,char *name)
|
||||
}
|
||||
|
||||
if (!push_dir(name, 0)) {
|
||||
rprintf(FERROR,"push_dir %s : %s (2)\n",
|
||||
name,strerror(errno));
|
||||
rprintf(FERROR, RSYNC_NAME ": push_dir %s: %s\n",
|
||||
name, strerror(errno));
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
|
||||
@@ -238,6 +341,7 @@ static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
|
||||
char *dir = argv[0];
|
||||
extern int relative_paths;
|
||||
extern int recurse;
|
||||
extern int remote_version;
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
|
||||
@@ -263,17 +367,18 @@ static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
|
||||
argv[0] = ".";
|
||||
}
|
||||
|
||||
set_nonblocking(f_out);
|
||||
if (f_in != f_out)
|
||||
set_nonblocking(f_in);
|
||||
|
||||
flist = send_file_list(f_out,argc,argv);
|
||||
if (!flist || flist->count == 0) {
|
||||
exit_cleanup(0);
|
||||
}
|
||||
|
||||
send_files(flist,f_out,f_in);
|
||||
io_flush();
|
||||
report(f_out);
|
||||
if (remote_version >= 24) {
|
||||
/* final goodbye message */
|
||||
read_int(f_in);
|
||||
}
|
||||
io_flush();
|
||||
exit_cleanup(0);
|
||||
}
|
||||
@@ -284,45 +389,81 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
|
||||
int pid;
|
||||
int status=0;
|
||||
int recv_pipe[2];
|
||||
int error_pipe[2];
|
||||
extern int preserve_hard_links;
|
||||
extern int delete_after;
|
||||
extern int recurse;
|
||||
extern int delete_mode;
|
||||
extern int remote_version;
|
||||
|
||||
if (preserve_hard_links)
|
||||
init_hard_links(flist);
|
||||
|
||||
if (pipe(recv_pipe) < 0) {
|
||||
if (!delete_after) {
|
||||
/* I moved this here from recv_files() to prevent a race condition */
|
||||
if (recurse && delete_mode && !local_name && flist->count>0) {
|
||||
delete_files(flist);
|
||||
}
|
||||
}
|
||||
|
||||
if (fd_pair(recv_pipe) < 0) {
|
||||
rprintf(FERROR,"pipe failed in do_recv\n");
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
}
|
||||
|
||||
if (fd_pair(error_pipe) < 0) {
|
||||
rprintf(FERROR,"error pipe failed in do_recv\n");
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
}
|
||||
|
||||
io_flush();
|
||||
|
||||
if ((pid=do_fork()) == 0) {
|
||||
close(recv_pipe[0]);
|
||||
close(error_pipe[0]);
|
||||
if (f_in != f_out) close(f_out);
|
||||
|
||||
set_nonblocking(f_in);
|
||||
set_nonblocking(recv_pipe[1]);
|
||||
/* we can't let two processes write to the socket at one time */
|
||||
io_multiplexing_close();
|
||||
|
||||
/* set place to send errors */
|
||||
set_error_fd(error_pipe[1]);
|
||||
|
||||
recv_files(f_in,flist,local_name,recv_pipe[1]);
|
||||
io_flush();
|
||||
report(f_in);
|
||||
|
||||
write_int(recv_pipe[1],1);
|
||||
close(recv_pipe[1]);
|
||||
io_flush();
|
||||
_exit(0);
|
||||
/* finally we go to sleep until our parent kills us
|
||||
with a USR2 signal. We sleep for a short time as on
|
||||
some OSes a signal won't interrupt a sleep! */
|
||||
while (msleep(20))
|
||||
;
|
||||
}
|
||||
|
||||
close(recv_pipe[1]);
|
||||
io_close_input(f_in);
|
||||
close(error_pipe[1]);
|
||||
if (f_in != f_out) close(f_in);
|
||||
|
||||
set_nonblocking(f_out);
|
||||
set_nonblocking(recv_pipe[0]);
|
||||
|
||||
io_start_buffering(f_out);
|
||||
|
||||
io_set_error_fd(error_pipe[0]);
|
||||
|
||||
generate_files(f_out,flist,local_name,recv_pipe[0]);
|
||||
|
||||
read_int(recv_pipe[0]);
|
||||
close(recv_pipe[0]);
|
||||
if (remote_version >= 24) {
|
||||
/* send a final goodbye message */
|
||||
write_int(f_out, -1);
|
||||
}
|
||||
io_flush();
|
||||
waitpid(pid, &status, 0);
|
||||
|
||||
io_set_error_fd(-1);
|
||||
kill(pid, SIGUSR2);
|
||||
wait_process(pid, &status);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -336,9 +477,20 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
|
||||
extern int delete_mode;
|
||||
extern int delete_excluded;
|
||||
extern int am_daemon;
|
||||
extern int module_id;
|
||||
extern int am_sender;
|
||||
extern int read_batch;
|
||||
extern struct file_list *batch_flist;
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
|
||||
|
||||
if (am_daemon && lp_read_only(module_id) && !am_sender) {
|
||||
rprintf(FERROR,"ERROR: module is read only\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (argc > 0) {
|
||||
dir = argv[0];
|
||||
@@ -354,7 +506,10 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
|
||||
if (delete_mode && !delete_excluded)
|
||||
recv_exclude_list(f_in);
|
||||
|
||||
flist = recv_file_list(f_in);
|
||||
if (read_batch)
|
||||
flist = batch_flist;
|
||||
else
|
||||
flist = recv_file_list(f_in);
|
||||
if (!flist) {
|
||||
rprintf(FERROR,"server_recv: recv_file_list error\n");
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
@@ -373,21 +528,34 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
|
||||
}
|
||||
|
||||
|
||||
int child_main(int argc, char *argv[])
|
||||
{
|
||||
start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void start_server(int f_in, int f_out, int argc, char *argv[])
|
||||
{
|
||||
extern int cvs_exclude;
|
||||
extern int am_sender;
|
||||
extern int remote_version;
|
||||
extern int read_batch;
|
||||
|
||||
set_nonblocking(f_out);
|
||||
if (f_in != f_out)
|
||||
set_nonblocking(f_in);
|
||||
|
||||
setup_protocol(f_out, f_in);
|
||||
|
||||
set_nonblocking(f_in);
|
||||
set_nonblocking(f_out);
|
||||
|
||||
if (remote_version >= 23)
|
||||
io_start_multiplex_out(f_out);
|
||||
|
||||
if (am_sender) {
|
||||
recv_exclude_list(f_in);
|
||||
if (cvs_exclude)
|
||||
if (!read_batch) {
|
||||
recv_exclude_list(f_in);
|
||||
if (cvs_exclude)
|
||||
add_cvs_excludes();
|
||||
}
|
||||
do_server_sender(f_in, f_out, argc, argv);
|
||||
} else {
|
||||
do_server_recv(f_in, f_out, argc, argv);
|
||||
@@ -395,15 +563,34 @@ void start_server(int f_in, int f_out, int argc, char *argv[])
|
||||
exit_cleanup(0);
|
||||
}
|
||||
|
||||
int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
|
||||
|
||||
/*
|
||||
* This is called once the connection has been negotiated. It is used
|
||||
* for rsyncd, remote-shell, and local connections.
|
||||
*/
|
||||
int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
|
||||
{
|
||||
struct file_list *flist;
|
||||
struct file_list *flist = NULL;
|
||||
int status = 0, status2 = 0;
|
||||
char *local_name = NULL;
|
||||
extern int am_sender;
|
||||
extern int list_only;
|
||||
extern int remote_version;
|
||||
extern pid_t cleanup_child_pid;
|
||||
extern int write_batch;
|
||||
extern int read_batch;
|
||||
extern struct file_list *batch_flist;
|
||||
|
||||
cleanup_child_pid = pid;
|
||||
if (read_batch)
|
||||
flist = batch_flist;
|
||||
|
||||
set_nonblocking(f_in);
|
||||
set_nonblocking(f_out);
|
||||
|
||||
setup_protocol(f_out,f_in);
|
||||
|
||||
if (remote_version >= 23)
|
||||
io_start_multiplex_in(f_in);
|
||||
|
||||
if (am_sender) {
|
||||
extern int cvs_exclude;
|
||||
@@ -413,32 +600,39 @@ int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
|
||||
add_cvs_excludes();
|
||||
if (delete_mode && !delete_excluded)
|
||||
send_exclude_list(f_out);
|
||||
flist = send_file_list(f_out,argc,argv);
|
||||
if (!read_batch) /* dw -- don't write to pipe */
|
||||
flist = send_file_list(f_out,argc,argv);
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO,"file list sent\n");
|
||||
|
||||
set_nonblocking(f_out);
|
||||
if (f_in != f_out)
|
||||
set_nonblocking(f_in);
|
||||
|
||||
send_files(flist,f_out,f_in);
|
||||
if (remote_version >= 24) {
|
||||
/* final goodbye message */
|
||||
read_int(f_in);
|
||||
}
|
||||
if (pid != -1) {
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO,"client_run waiting on %d\n",pid);
|
||||
rprintf(FINFO,"client_run waiting on %d\n", (int) pid);
|
||||
io_flush();
|
||||
waitpid(pid, &status, 0);
|
||||
wait_process(pid, &status);
|
||||
}
|
||||
report(-1);
|
||||
exit_cleanup(status);
|
||||
}
|
||||
|
||||
if (argc == 0) list_only = 1;
|
||||
if (argc == 0) {
|
||||
extern int list_only;
|
||||
list_only = 1;
|
||||
}
|
||||
|
||||
send_exclude_list(f_out);
|
||||
if (!write_batch)
|
||||
send_exclude_list(f_out);
|
||||
|
||||
flist = recv_file_list(f_in);
|
||||
if (!flist || flist->count == 0) {
|
||||
rprintf(FINFO,"client: nothing to do\n");
|
||||
rprintf(FINFO, "client: nothing to do: "
|
||||
"perhaps you need to specify some filenames or "
|
||||
"the --recursive option?\n");
|
||||
exit_cleanup(0);
|
||||
}
|
||||
|
||||
@@ -448,12 +642,12 @@ int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
|
||||
|
||||
if (pid != -1) {
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO,"client_run2 waiting on %d\n",pid);
|
||||
rprintf(FINFO,"client_run2 waiting on %d\n", (int) pid);
|
||||
io_flush();
|
||||
waitpid(pid, &status, 0);
|
||||
wait_process(pid, &status);
|
||||
}
|
||||
|
||||
return status | status2;
|
||||
return MAX(status, status2);
|
||||
}
|
||||
|
||||
static char *find_colon(char *s)
|
||||
@@ -471,19 +665,54 @@ static char *find_colon(char *s)
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
static int copy_argv (char *argv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; argv[i]; i++) {
|
||||
if (!(argv[i] = strdup(argv[i]))) {
|
||||
rprintf (FERROR, "out of memory at %s(%d)\n",
|
||||
__FILE__, __LINE__);
|
||||
return RERR_MALLOC;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Start a client for either type of remote connection. Work out
|
||||
* whether the arguments request a remote shell or rsyncd connection,
|
||||
* and call the appropriate connection function, then run_client.
|
||||
*
|
||||
* Calls either start_socket_client (for sockets) or do_cmd and
|
||||
* client_run (for ssh).
|
||||
**/
|
||||
static int start_client(int argc, char *argv[])
|
||||
{
|
||||
char *p;
|
||||
char *shell_machine = NULL;
|
||||
char *shell_path = NULL;
|
||||
char *shell_user = NULL;
|
||||
int pid, ret;
|
||||
int ret;
|
||||
pid_t pid;
|
||||
int f_in,f_out;
|
||||
extern int local_server;
|
||||
extern int am_sender;
|
||||
extern char *shell_cmd;
|
||||
extern int rsync_port;
|
||||
extern int daemon_over_rsh;
|
||||
extern int read_batch;
|
||||
int rc;
|
||||
|
||||
/* Don't clobber argv[] so that ps(1) can still show the right
|
||||
command line. */
|
||||
if ((rc = copy_argv(argv)))
|
||||
return rc;
|
||||
|
||||
/* rsync:// always uses rsync server over direct socket connection */
|
||||
if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
|
||||
char *host, *path;
|
||||
|
||||
@@ -493,7 +722,7 @@ static int start_client(int argc, char *argv[])
|
||||
*p = 0;
|
||||
path = p+1;
|
||||
} else {
|
||||
path="";
|
||||
path = "";
|
||||
}
|
||||
p = strchr(host,':');
|
||||
if (p) {
|
||||
@@ -503,12 +732,18 @@ static int start_client(int argc, char *argv[])
|
||||
return start_socket_client(host, path, argc-1, argv+1);
|
||||
}
|
||||
|
||||
p = find_colon(argv[0]);
|
||||
if (!read_batch) {
|
||||
p = find_colon(argv[0]);
|
||||
|
||||
if (p) {
|
||||
if (p[1] == ':') {
|
||||
if (p[1] == ':') { /* double colon */
|
||||
*p = 0;
|
||||
return start_socket_client(argv[0], p+2, argc-1, argv+1);
|
||||
if (!shell_cmd) {
|
||||
return start_socket_client(argv[0], p+2,
|
||||
argc-1, argv+1);
|
||||
}
|
||||
p++;
|
||||
daemon_over_rsh = 1;
|
||||
}
|
||||
|
||||
if (argc < 1) {
|
||||
@@ -525,12 +760,37 @@ static int start_client(int argc, char *argv[])
|
||||
} else {
|
||||
am_sender = 1;
|
||||
|
||||
/* rsync:// destination uses rsync server over direct socket */
|
||||
if (strncasecmp(URL_PREFIX, argv[argc-1], strlen(URL_PREFIX)) == 0) {
|
||||
char *host, *path;
|
||||
|
||||
host = argv[argc-1] + strlen(URL_PREFIX);
|
||||
p = strchr(host,'/');
|
||||
if (p) {
|
||||
*p = 0;
|
||||
path = p+1;
|
||||
} else {
|
||||
path = "";
|
||||
}
|
||||
p = strchr(host,':');
|
||||
if (p) {
|
||||
rsync_port = atoi(p+1);
|
||||
*p = 0;
|
||||
}
|
||||
return start_socket_client(host, path, argc-1, argv);
|
||||
}
|
||||
|
||||
p = find_colon(argv[argc-1]);
|
||||
if (!p) {
|
||||
local_server = 1;
|
||||
} else if (p[1] == ':') {
|
||||
} else if (p[1] == ':') { /* double colon */
|
||||
*p = 0;
|
||||
return start_socket_client(argv[argc-1], p+2, argc-1, argv);
|
||||
if (!shell_cmd) {
|
||||
return start_socket_client(argv[argc-1], p+2,
|
||||
argc-1, argv);
|
||||
}
|
||||
p++;
|
||||
daemon_over_rsh = 1;
|
||||
}
|
||||
|
||||
if (argc < 2) {
|
||||
@@ -548,7 +808,12 @@ static int start_client(int argc, char *argv[])
|
||||
}
|
||||
argc--;
|
||||
}
|
||||
|
||||
} else {
|
||||
am_sender = 1;
|
||||
local_server = 1;
|
||||
shell_path = argv[argc-1];
|
||||
}
|
||||
|
||||
if (shell_machine) {
|
||||
p = strchr(shell_machine,'@');
|
||||
if (p) {
|
||||
@@ -570,9 +835,25 @@ static int start_client(int argc, char *argv[])
|
||||
usage(FERROR);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
if (argc == 0 && !am_sender) {
|
||||
extern int list_only;
|
||||
list_only = 1;
|
||||
}
|
||||
|
||||
pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
|
||||
|
||||
pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,
|
||||
&f_in,&f_out);
|
||||
|
||||
/* if we're running an rsync server on the remote host over a
|
||||
remote shell command, we need to do the RSYNCD protocol first */
|
||||
if (daemon_over_rsh) {
|
||||
int tmpret;
|
||||
tmpret = start_inband_exchange(shell_user, shell_path,
|
||||
f_in, f_out, argc);
|
||||
if (tmpret < 0)
|
||||
return tmpret;
|
||||
}
|
||||
|
||||
ret = client_run(f_in, f_out, pid, argc, argv);
|
||||
|
||||
fflush(stdout);
|
||||
@@ -582,10 +863,91 @@ static int start_client(int argc, char *argv[])
|
||||
}
|
||||
|
||||
|
||||
static RETSIGTYPE sigusr1_handler(int val) {
|
||||
static RETSIGTYPE sigusr1_handler(int UNUSED(val)) {
|
||||
exit_cleanup(RERR_SIGNAL);
|
||||
}
|
||||
|
||||
static RETSIGTYPE sigusr2_handler(int UNUSED(val)) {
|
||||
extern int log_got_error;
|
||||
if (log_got_error) _exit(RERR_PARTIAL);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
static RETSIGTYPE sigchld_handler(int UNUSED(val)) {
|
||||
#ifdef WNOHANG
|
||||
int cnt, status;
|
||||
pid_t pid;
|
||||
/* An empty waitpid() loop was put here by Tridge and we could never
|
||||
* get him to explain why he put it in, so rather than taking it
|
||||
* out we're instead saving the child exit statuses for later use.
|
||||
* The waitpid() loop presumably eliminates all possibility of leaving
|
||||
* zombie children, maybe that's why he did it.
|
||||
*/
|
||||
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
|
||||
/* save the child's exit status */
|
||||
for (cnt = 0; cnt < MAXCHILDPROCS; cnt++) {
|
||||
if (pid_stat_table[cnt].pid == 0) {
|
||||
pid_stat_table[cnt].pid = pid;
|
||||
pid_stat_table[cnt].status = status;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This routine catches signals and tries to send them to gdb.
|
||||
*
|
||||
* Because it's called from inside a signal handler it ought not to
|
||||
* use too many library routines.
|
||||
*
|
||||
* @todo Perhaps use "screen -X" instead/as well, to help people
|
||||
* debugging without easy access to X. Perhaps use an environment
|
||||
* variable, or just call a script?
|
||||
*
|
||||
* @todo The /proc/ magic probably only works on Linux (and
|
||||
* Solaris?) Can we be more portable?
|
||||
**/
|
||||
#ifdef MAINTAINER_MODE
|
||||
const char *get_panic_action(void)
|
||||
{
|
||||
const char *cmd_fmt = getenv("RSYNC_PANIC_ACTION");
|
||||
|
||||
if (cmd_fmt)
|
||||
return cmd_fmt;
|
||||
else
|
||||
return "xterm -display :0 -T Panic -n Panic "
|
||||
"-e gdb /proc/%d/exe %d";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle a fatal signal by launching a debugger, controlled by $RSYNC_PANIC_ACTION.
|
||||
*
|
||||
* This signal handler is only installed if we were configured with
|
||||
* --enable-maintainer-mode. Perhaps it should always be on and we
|
||||
* should just look at the environment variable, but I'm a bit leery
|
||||
* of a signal sending us into a busy loop.
|
||||
**/
|
||||
static RETSIGTYPE rsync_panic_handler(int UNUSED(whatsig))
|
||||
{
|
||||
char cmd_buf[300];
|
||||
int ret;
|
||||
|
||||
sprintf(cmd_buf, get_panic_action(),
|
||||
getpid(), getpid());
|
||||
|
||||
/* Unless we failed to execute gdb, we allow the process to
|
||||
* continue. I'm not sure if that's right. */
|
||||
ret = system(cmd_buf);
|
||||
if (ret)
|
||||
_exit(ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
extern int am_root;
|
||||
@@ -593,8 +955,23 @@ int main(int argc,char *argv[])
|
||||
extern int dry_run;
|
||||
extern int am_daemon;
|
||||
extern int am_server;
|
||||
int ret;
|
||||
extern int write_batch;
|
||||
int orig_argc;
|
||||
char **orig_argv;
|
||||
|
||||
orig_argc = argc;
|
||||
orig_argv = argv;
|
||||
|
||||
signal(SIGUSR1, sigusr1_handler);
|
||||
signal(SIGUSR2, sigusr2_handler);
|
||||
signal(SIGCHLD, sigchld_handler);
|
||||
#ifdef MAINTAINER_MODE
|
||||
signal(SIGSEGV, rsync_panic_handler);
|
||||
signal(SIGFPE, rsync_panic_handler);
|
||||
signal(SIGABRT, rsync_panic_handler);
|
||||
signal(SIGBUS, rsync_panic_handler);
|
||||
#endif /* def MAINTAINER_MODE */
|
||||
|
||||
starttime = time(NULL);
|
||||
am_root = (getuid() == 0);
|
||||
@@ -610,30 +987,34 @@ int main(int argc,char *argv[])
|
||||
carried across */
|
||||
orig_umask = (int)umask(0);
|
||||
|
||||
if (!parse_arguments(argc, argv, 1)) {
|
||||
if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
|
||||
/* FIXME: We ought to call the same error-handling
|
||||
* code here, rather than relying on getopt. */
|
||||
option_error();
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
optind = 0;
|
||||
|
||||
signal(SIGCHLD,SIG_IGN);
|
||||
signal(SIGINT,SIGNAL_CAST sig_int);
|
||||
signal(SIGPIPE,SIGNAL_CAST sig_int);
|
||||
signal(SIGHUP,SIGNAL_CAST sig_int);
|
||||
signal(SIGTERM,SIGNAL_CAST sig_int);
|
||||
|
||||
/* Ignore SIGPIPE; we consistently check error codes and will
|
||||
* see the EPIPE. */
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
/* Initialize push_dir here because on some old systems getcwd
|
||||
(implemented by forking "pwd" and reading its output) doesn't
|
||||
work when there are other child processes. Also, on all systems
|
||||
that implement getcwd that way "pwd" can't be found after chroot. */
|
||||
push_dir(NULL,0);
|
||||
|
||||
if (am_daemon) {
|
||||
return daemon_main();
|
||||
if (write_batch && !am_server) {
|
||||
write_batch_argvs_file(orig_argc, orig_argv);
|
||||
}
|
||||
|
||||
if (am_daemon && !am_server)
|
||||
return daemon_main();
|
||||
|
||||
if (argc < 1) {
|
||||
usage(FERROR);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
@@ -650,9 +1031,19 @@ int main(int argc,char *argv[])
|
||||
#endif
|
||||
|
||||
if (am_server) {
|
||||
set_nonblocking(STDIN_FILENO);
|
||||
set_nonblocking(STDOUT_FILENO);
|
||||
if (am_daemon)
|
||||
return start_daemon(STDIN_FILENO, STDOUT_FILENO);
|
||||
start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
|
||||
}
|
||||
|
||||
return start_client(argc, argv);
|
||||
}
|
||||
ret = start_client(argc, argv);
|
||||
if (ret == -1)
|
||||
exit_cleanup(RERR_STARTCLIENT);
|
||||
else
|
||||
exit_cleanup(ret);
|
||||
|
||||
exit(ret);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
69
match.c
69
match.c
@@ -71,7 +71,7 @@ static void build_hash_table(struct sum_struct *s)
|
||||
if (!tag_table || !targets)
|
||||
out_of_memory("build_hash_table");
|
||||
|
||||
for (i=0;i<s->count;i++) {
|
||||
for (i=0;i<(int) s->count;i++) {
|
||||
targets[i].i = i;
|
||||
targets[i].t = gettag(s->sums[i].sum1);
|
||||
}
|
||||
@@ -90,6 +90,18 @@ static void build_hash_table(struct sum_struct *s)
|
||||
static OFF_T last_match;
|
||||
|
||||
|
||||
/**
|
||||
* Transmit a literal and/or match token.
|
||||
*
|
||||
* This delightfully-named function is called either when we find a
|
||||
* match and need to transmit all the unmatched data leading up to it,
|
||||
* or when we get bored of accumulating literal data and just need to
|
||||
* transmit it. As a result of this second case, it is called even if
|
||||
* we have not matched at all!
|
||||
*
|
||||
* @param i If >0, the number of a matched token. If 0, indicates we
|
||||
* have only literal data.
|
||||
**/
|
||||
static void matched(int f,struct sum_struct *s,struct map_struct *buf,
|
||||
OFF_T offset,int i)
|
||||
{
|
||||
@@ -97,8 +109,8 @@ static void matched(int f,struct sum_struct *s,struct map_struct *buf,
|
||||
OFF_T j;
|
||||
|
||||
if (verbose > 2 && i >= 0)
|
||||
rprintf(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<0?0:s->sums[i].len);
|
||||
data_transfer += n;
|
||||
@@ -119,19 +131,19 @@ static void matched(int f,struct sum_struct *s,struct map_struct *buf,
|
||||
else
|
||||
last_match = offset;
|
||||
|
||||
if (buf)
|
||||
if (buf) {
|
||||
show_progress(last_match, buf->file_size);
|
||||
|
||||
if (i == -1) end_progress();
|
||||
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)
|
||||
{
|
||||
OFF_T offset;
|
||||
OFF_T offset, end;
|
||||
int j,k, last_i;
|
||||
int end;
|
||||
char sum2[SUM_LENGTH];
|
||||
uint32 s1, s2, sum;
|
||||
schar *map;
|
||||
@@ -141,9 +153,12 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
last_i = -1;
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"hash search b=%d len=%d\n",s->n,(int)len);
|
||||
rprintf(FINFO,"hash search b=%ld len=%.0f\n",
|
||||
(long) s->n, (double)len);
|
||||
|
||||
k = MIN(len, s->n);
|
||||
/* cast is to make s->n signed; it should always be reasonably
|
||||
* small */
|
||||
k = MIN(len, (OFF_T) s->n);
|
||||
|
||||
map = (schar *)map_ptr(buf,0,k);
|
||||
|
||||
@@ -158,8 +173,8 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
end = len + 1 - s->sums[s->count-1].len;
|
||||
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO,"hash search s->n=%d len=%d count=%d\n",
|
||||
s->n,(int)len,s->count);
|
||||
rprintf(FINFO, "hash search s->n=%ld len=%.0f count=%ld\n",
|
||||
(long) s->n, (double) len, (long) s->count);
|
||||
|
||||
do {
|
||||
tag t = gettag2(s1,s2);
|
||||
@@ -167,7 +182,7 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
|
||||
j = tag_table[t];
|
||||
if (verbose > 4)
|
||||
rprintf(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;
|
||||
@@ -175,7 +190,7 @@ 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++) {
|
||||
for (; j < (int) s->count && targets[j].t == t; j++) {
|
||||
int l, i = targets[j].i;
|
||||
|
||||
if (sum != s->sums[i].sum1) continue;
|
||||
@@ -185,8 +200,8 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
if (l != s->sums[i].len) continue;
|
||||
|
||||
if (verbose > 3)
|
||||
rprintf(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) {
|
||||
map = (schar *)map_ptr(buf,offset,l);
|
||||
@@ -201,7 +216,7 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
|
||||
/* 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++) {
|
||||
for (j++; j < (int) s->count && targets[j].t == t; j++) {
|
||||
int i2 = targets[j].i;
|
||||
if (i2 == last_i + 1) {
|
||||
if (sum != s->sums[i2].sum1) break;
|
||||
@@ -246,7 +261,8 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
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 &&
|
||||
if (offset > last_match &&
|
||||
offset-last_match >= CHUNK_SIZE+s->n &&
|
||||
(end-offset > CHUNK_SIZE)) {
|
||||
matched(f,s,buf,offset - s->n, -2);
|
||||
}
|
||||
@@ -257,9 +273,24 @@ 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)
|
||||
/**
|
||||
* Scan through a origin file, looking for sections that match
|
||||
* checksums from the generator, and transmit either literal or token
|
||||
* data.
|
||||
*
|
||||
* Also calculates the MD4 checksum of the whole file, using the md
|
||||
* accumulator. This is transmitted with the file as protection
|
||||
* against corruption on the wire.
|
||||
*
|
||||
* @param s Checksums received from the generator. If <tt>s->count ==
|
||||
* 0</tt>, then there are actually no checksums for this file.
|
||||
*
|
||||
* @param len Length of the file to send.
|
||||
**/
|
||||
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;
|
||||
@@ -295,6 +326,8 @@ void match_sums(int f,struct sum_struct *s,struct map_struct *buf,OFF_T len)
|
||||
if (verbose > 2)
|
||||
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) {
|
||||
|
||||
84
packaging/lsb/rsync.spec
Normal file
84
packaging/lsb/rsync.spec
Normal file
@@ -0,0 +1,84 @@
|
||||
Summary: Program for efficient remote updates of files.
|
||||
Name: rsync
|
||||
Version: 2.5.6
|
||||
Release: 1
|
||||
Copyright: GPL
|
||||
Group: Applications/Networking
|
||||
Source: ftp://samba.anu.edu.au/pub/rsync/rsync-2.5.6.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
|
||||
84
packaging/lsb/rsync.spec.tmpl
Normal file
84
packaging/lsb/rsync.spec.tmpl
Normal 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
|
||||
@@ -1,10 +1,10 @@
|
||||
Summary: Program for efficient remote updates of files.
|
||||
Name: rsync
|
||||
Version: 2.3.1
|
||||
Version: 2.5.6
|
||||
Release: 1
|
||||
Copyright: GPL
|
||||
Group: Applications/Networking
|
||||
Source: ftp://samba.anu.edu.au/pub/rsync/rsync-2.3.1.tar.gz
|
||||
Source: ftp://samba.anu.edu.au/pub/rsync/rsync-2.5.6.tar.gz
|
||||
URL: http://samba.anu.edu.au/rsync/
|
||||
Packager: Andrew Tridgell <tridge@samba.anu.edu.au>
|
||||
BuildRoot: /tmp/rsync
|
||||
|
||||
81
packaging/redhat/7.1/rsync.spec
Normal file
81
packaging/redhat/7.1/rsync.spec
Normal file
@@ -0,0 +1,81 @@
|
||||
Summary: Program for efficient remote updates of files.
|
||||
Name: rsync
|
||||
Version: 2.5.6
|
||||
Release: 1
|
||||
Copyright: GPL
|
||||
Group: Applications/Networking
|
||||
Source: ftp://samba.anu.edu.au/pub/rsync/rsync-2.5.6.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
|
||||
81
packaging/redhat/7.1/rsync.spec.tmpl
Normal file
81
packaging/redhat/7.1/rsync.spec.tmpl
Normal 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
|
||||
94
packaging/solaris/build_pkg.sh
Normal file
94
packaging/solaris/build_pkg.sh
Normal file
@@ -0,0 +1,94 @@
|
||||
#!/bin/sh
|
||||
# Shell script for building Solaris package of rsync
|
||||
# Author: Jens Apel <jens.apel@web.de>
|
||||
# License: GPL
|
||||
#
|
||||
# BASEDIR is /usr/local and should be the same as the
|
||||
# --prefix parameter of configure
|
||||
#
|
||||
# this script should be copied under
|
||||
# packaging/solaris/5.8/build_pkg.sh
|
||||
|
||||
# Definitions start here
|
||||
# you can edit this, if you like
|
||||
|
||||
# The Package name under which rsync will b installed
|
||||
PKGNAME=SMBrsync
|
||||
|
||||
# Extract common info requires for the 'info' part of the package.
|
||||
# This should be made generic and generated by the configure script
|
||||
# but for now it is hard coded
|
||||
BASEDIR=/usr/local
|
||||
VERSION="2.5.5"
|
||||
ARCH=`uname -p`
|
||||
NAME=rsync
|
||||
|
||||
# Definitions end here
|
||||
# Please do not edit below this line or you know what you do.
|
||||
|
||||
## Start by faking root install
|
||||
echo "Creating install directory (fake $BASEDIR)..."
|
||||
START=`pwd`
|
||||
FAKE_ROOT=$START/${PKGNAME}
|
||||
mkdir $FAKE_ROOT
|
||||
|
||||
# copy the binary and the man page to their places
|
||||
mkdir $FAKE_ROOT/bin
|
||||
mkdir -p $FAKE_ROOT/doc/rsync
|
||||
mkdir -p $FAKE_ROOT/man/man1
|
||||
mkdir -p $FAKE_ROOT/man/man5
|
||||
|
||||
cp ../../../rsync $FAKE_ROOT/bin/rsync
|
||||
cp ../../../rsync.1 $FAKE_ROOT/man/man1/rsync.1
|
||||
cp ../../../rsyncd.conf.5 $FAKE_ROOT/man/man5/rsyncd.conf.5
|
||||
cp ../../../README $FAKE_ROOT/doc/rsync/README
|
||||
cp ../../../COPYING $FAKE_ROOT/doc/rsync/COPYING
|
||||
cp ../../../tech_report.pdf $FAKE_ROOT/doc/rsync/tech_report.pdf
|
||||
cp ../../../COPYING $FAKE_ROOT/COPYING
|
||||
|
||||
## Build info file
|
||||
echo "Building pkginfo file..."
|
||||
cat > $FAKE_ROOT/pkginfo << EOF_INFO
|
||||
PKG=$PKGNAME
|
||||
NAME=$NAME
|
||||
DESC="Program for efficient remote updates of files."
|
||||
VENDOR="Samba Team URL: http://samba.anu.edu.au/rsync/"
|
||||
BASEDIR=$BASEDIR
|
||||
ARCH=$ARCH
|
||||
VERSION=$VERSION
|
||||
CATEGORY=application
|
||||
CLASSES=none
|
||||
EOF_INFO
|
||||
|
||||
## Build prototype file
|
||||
cat > $FAKE_ROOT/prototype << EOFPROTO
|
||||
i copyright=COPYING
|
||||
i pkginfo=pkginfo
|
||||
d none bin 0755 bin bin
|
||||
f none bin/rsync 0755 bin bin
|
||||
d none doc 0755 bin bin
|
||||
d none doc/$NAME 0755 bin bin
|
||||
f none doc/$NAME/README 0644 bin bin
|
||||
f none doc/$NAME/COPYING 0644 bin bin
|
||||
f none doc/$NAME/tech_report.pdf 0644 bin bin
|
||||
d none man 0755 bin bin
|
||||
d none man/man1 0755 bin bin
|
||||
f none man/man1/rsync.1 0644 bin bin
|
||||
d none man/man5 0755 bin bin
|
||||
f none man/man5/rsyncd.conf.5 0644 bin bin
|
||||
EOFPROTO
|
||||
|
||||
## And now build the package.
|
||||
OUTPUTFILE=$PKGNAME-$VERSION-sol8-$ARCH-local.pkg
|
||||
echo "Building package.."
|
||||
echo FAKE_ROOT = $FAKE_ROOT
|
||||
cd $FAKE_ROOT
|
||||
pkgmk -d . -r . -f ./prototype -o
|
||||
pkgtrans -os . $OUTPUTFILE $PKGNAME
|
||||
|
||||
mv $OUTPUTFILE ..
|
||||
cd ..
|
||||
|
||||
# Comment this out if you want to see, which file structure has been created
|
||||
rm -rf $FAKE_ROOT
|
||||
|
||||
8
params.c
8
params.c
@@ -164,7 +164,7 @@ static int Continuation( char *line, int pos )
|
||||
*/
|
||||
{
|
||||
pos--;
|
||||
while( (pos >= 0) && isspace(line[pos]) )
|
||||
while( (pos >= 0) && isspace(((unsigned char *)line)[pos]) )
|
||||
pos--;
|
||||
|
||||
return( ((pos >= 0) && ('\\' == line[pos])) ? pos : -1 );
|
||||
@@ -386,7 +386,7 @@ static BOOL Parameter( FILE *InFile, BOOL (*pfunc)(char *, char *), int c )
|
||||
c = 0;
|
||||
else
|
||||
{
|
||||
for( end = i; (end >= 0) && isspace(bufr[end]); end-- )
|
||||
for( end = i; (end >= 0) && isspace(((unsigned char *) bufr)[end]); end-- )
|
||||
;
|
||||
c = getc( InFile );
|
||||
}
|
||||
@@ -491,8 +491,8 @@ static FILE *OpenConfFile( char *FileName )
|
||||
OpenedFile = fopen( FileName, "r" );
|
||||
if( NULL == OpenedFile )
|
||||
{
|
||||
rprintf(FERROR,"%s Unable to open configuration file \"%s\":\n\t%s\n",
|
||||
func, FileName, strerror(errno));
|
||||
rprintf(FERROR,"rsync: unable to open configuration file \"%s\": %s\n",
|
||||
FileName, strerror(errno));
|
||||
}
|
||||
|
||||
return( OpenedFile );
|
||||
|
||||
148
pipe.c
Normal file
148
pipe.c
Normal file
@@ -0,0 +1,148 @@
|
||||
/* -*- c-file-style: "linux" -*-
|
||||
*
|
||||
* Copyright (C) 1996-2000 by Andrew Tridgell
|
||||
* Copyright (C) Paul Mackerras 1996
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
/**
|
||||
* Create a child connected to use on stdin/stdout.
|
||||
*
|
||||
* This is derived from CVS code
|
||||
*
|
||||
* Note that in the child STDIN is set to blocking and STDOUT
|
||||
* is set to non-blocking. This is necessary as rsh relies on stdin being blocking
|
||||
* and ssh relies on stdout being non-blocking
|
||||
*
|
||||
* If blocking_io is set then use blocking io on both fds. That can be
|
||||
* used to cope with badly broken rsh implementations like the one on
|
||||
* Solaris.
|
||||
**/
|
||||
pid_t piped_child(char **command, int *f_in, int *f_out)
|
||||
{
|
||||
pid_t pid;
|
||||
int to_child_pipe[2];
|
||||
int from_child_pipe[2];
|
||||
extern int blocking_io;
|
||||
|
||||
if (verbose >= 2) {
|
||||
print_child_argv(command);
|
||||
}
|
||||
|
||||
if (fd_pair(to_child_pipe) < 0 || fd_pair(from_child_pipe) < 0) {
|
||||
rprintf(FERROR, "pipe: %s\n", strerror(errno));
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
|
||||
pid = do_fork();
|
||||
if (pid == -1) {
|
||||
rprintf(FERROR, "fork: %s\n", strerror(errno));
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
extern int orig_umask;
|
||||
if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
|
||||
close(to_child_pipe[1]) < 0 ||
|
||||
close(from_child_pipe[0]) < 0 ||
|
||||
dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
|
||||
rprintf(FERROR, "Failed to dup/close : %s\n",
|
||||
strerror(errno));
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
if (to_child_pipe[0] != STDIN_FILENO)
|
||||
close(to_child_pipe[0]);
|
||||
if (from_child_pipe[1] != STDOUT_FILENO)
|
||||
close(from_child_pipe[1]);
|
||||
umask(orig_umask);
|
||||
set_blocking(STDIN_FILENO);
|
||||
if (blocking_io) {
|
||||
set_blocking(STDOUT_FILENO);
|
||||
}
|
||||
execvp(command[0], command);
|
||||
rprintf(FERROR, "Failed to exec %s : %s\n",
|
||||
command[0], strerror(errno));
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
if (close(from_child_pipe[1]) < 0 || close(to_child_pipe[0]) < 0) {
|
||||
rprintf(FERROR, "Failed to close : %s\n", strerror(errno));
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
*f_in = from_child_pipe[0];
|
||||
*f_out = to_child_pipe[1];
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
pid_t local_child(int argc, char **argv,int *f_in,int *f_out,
|
||||
int (*child_main)(int, char*[]))
|
||||
{
|
||||
pid_t pid;
|
||||
int to_child_pipe[2];
|
||||
int from_child_pipe[2];
|
||||
extern int read_batch; /* dw */
|
||||
|
||||
if (fd_pair(to_child_pipe) < 0 ||
|
||||
fd_pair(from_child_pipe) < 0) {
|
||||
rprintf(FERROR,"pipe: %s\n",strerror(errno));
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
|
||||
pid = do_fork();
|
||||
if (pid == -1) {
|
||||
rprintf(FERROR,"fork: %s\n",strerror(errno));
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
extern int am_sender;
|
||||
extern int am_server;
|
||||
|
||||
am_sender = read_batch ? 0 : !am_sender;
|
||||
am_server = 1;
|
||||
|
||||
if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
|
||||
close(to_child_pipe[1]) < 0 ||
|
||||
close(from_child_pipe[0]) < 0 ||
|
||||
dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
|
||||
rprintf(FERROR,"Failed to dup/close : %s\n",strerror(errno));
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
if (to_child_pipe[0] != STDIN_FILENO) close(to_child_pipe[0]);
|
||||
if (from_child_pipe[1] != STDOUT_FILENO) close(from_child_pipe[1]);
|
||||
child_main(argc, argv);
|
||||
}
|
||||
|
||||
if (close(from_child_pipe[1]) < 0 ||
|
||||
close(to_child_pipe[0]) < 0) {
|
||||
rprintf(FERROR,"Failed to close : %s\n",strerror(errno));
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
*f_in = from_child_pipe[0];
|
||||
*f_out = to_child_pipe[1];
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
|
||||
9
popt/.cvsignore
Normal file
9
popt/.cvsignore
Normal file
@@ -0,0 +1,9 @@
|
||||
ID
|
||||
Makefile
|
||||
config.cache
|
||||
config.h
|
||||
config.log
|
||||
config.status
|
||||
dummy
|
||||
rsync
|
||||
zlib/dummy
|
||||
46
popt/CHANGES
Normal file
46
popt/CHANGES
Normal file
@@ -0,0 +1,46 @@
|
||||
1.5 -> 1.6
|
||||
- add ability to perform callbacks for every, not just first, match.
|
||||
|
||||
1.3 -> 1.5
|
||||
- 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
22
popt/COPYING
Normal 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
18
popt/README
Normal 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 parsing 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.
|
||||
4
popt/README.rsync
Normal file
4
popt/README.rsync
Normal file
@@ -0,0 +1,4 @@
|
||||
This is a perfectly ordinary copy of libpopt. It is only used on platforms
|
||||
that do not have a sufficiently up-to-date copy of their own. If you build
|
||||
rsync on a platform which has popt, this directory should not be used. (You
|
||||
can control that using the --with-included-popt configure flag.)
|
||||
104
popt/config.log
Normal file
104
popt/config.log
Normal 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
0
popt/dummy.in
Normal file
50
popt/findme.c
Normal file
50
popt/findme.c
Normal file
@@ -0,0 +1,50 @@
|
||||
/** \ingroup popt
|
||||
* \file popt/findme.c
|
||||
*/
|
||||
|
||||
/* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING
|
||||
file accompanying popt source distributions, available from
|
||||
ftp://ftp.rpm.org/pub/rpm/dist. */
|
||||
|
||||
#include "system.h"
|
||||
#include "findme.h"
|
||||
|
||||
const char * findProgramPath(const char * argv0) {
|
||||
char * path = getenv("PATH");
|
||||
char * pathbuf;
|
||||
char * start, * chptr;
|
||||
char * buf;
|
||||
|
||||
if (argv0 == NULL) return NULL; /* XXX can't happen */
|
||||
/* If there is a / in the argv[0], it has to be an absolute path */
|
||||
if (strchr(argv0, '/'))
|
||||
return xstrdup(argv0);
|
||||
|
||||
if (path == NULL) return NULL;
|
||||
|
||||
start = pathbuf = alloca(strlen(path) + 1);
|
||||
buf = malloc(strlen(path) + strlen(argv0) + sizeof("/"));
|
||||
if (buf == NULL) return NULL; /* XXX can't happen */
|
||||
strcpy(pathbuf, path);
|
||||
|
||||
chptr = NULL;
|
||||
/*@-branchstate@*/
|
||||
do {
|
||||
if ((chptr = strchr(start, ':')))
|
||||
*chptr = '\0';
|
||||
sprintf(buf, "%s/%s", start, argv0);
|
||||
|
||||
if (!access(buf, X_OK))
|
||||
return buf;
|
||||
|
||||
if (chptr)
|
||||
start = chptr + 1;
|
||||
else
|
||||
start = NULL;
|
||||
} while (start && *start);
|
||||
/*@=branchstate@*/
|
||||
|
||||
free(buf);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
20
popt/findme.h
Normal file
20
popt/findme.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/** \ingroup popt
|
||||
* \file popt/findme.h
|
||||
*/
|
||||
|
||||
/* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING
|
||||
file accompanying popt source distributions, available from
|
||||
ftp://ftp.rpm.org/pub/rpm/dist. */
|
||||
|
||||
#ifndef H_FINDME
|
||||
#define H_FINDME
|
||||
|
||||
/**
|
||||
* Return absolute path to executable by searching PATH.
|
||||
* @param argv0 name of executable
|
||||
* @return (malloc'd) absolute path to executable (or NULL)
|
||||
*/
|
||||
/*@null@*/ const char * findProgramPath(/*@null@*/ const char * argv0)
|
||||
/*@*/;
|
||||
|
||||
#endif
|
||||
1209
popt/popt.c
Normal file
1209
popt/popt.c
Normal file
File diff suppressed because it is too large
Load Diff
446
popt/popt.h
Normal file
446
popt/popt.h
Normal file
@@ -0,0 +1,446 @@
|
||||
/** \file popt/popt.h
|
||||
* \ingroup popt
|
||||
*/
|
||||
|
||||
/* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING
|
||||
file accompanying popt source distributions, available from
|
||||
ftp://ftp.rpm.org/pub/rpm/dist. */
|
||||
|
||||
#ifndef H_POPT
|
||||
#define H_POPT
|
||||
|
||||
#include <stdio.h> /* for FILE * */
|
||||
|
||||
#define POPT_OPTION_DEPTH 10
|
||||
|
||||
/** \ingroup popt
|
||||
* \name Arg type identifiers
|
||||
*/
|
||||
/*@{*/
|
||||
#define POPT_ARG_NONE 0 /*!< no arg */
|
||||
#define POPT_ARG_STRING 1 /*!< arg will be saved as string */
|
||||
#define POPT_ARG_INT 2 /*!< arg will be converted to int */
|
||||
#define POPT_ARG_LONG 3 /*!< arg will be converted to long */
|
||||
#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_FLOAT 8 /*!< arg will be converted to float */
|
||||
#define POPT_ARG_DOUBLE 9 /*!< arg will be converted to double */
|
||||
|
||||
#define POPT_ARG_MASK 0x0000FFFF
|
||||
/*@}*/
|
||||
|
||||
/** \ingroup popt
|
||||
* \name Arg modifiers
|
||||
*/
|
||||
/*@{*/
|
||||
#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_ARGFLAG_OPTIONAL 0x10000000 /*!< arg may be missing */
|
||||
|
||||
#define POPT_ARGFLAG_OR 0x08000000 /*!< arg will be or'ed */
|
||||
#define POPT_ARGFLAG_NOR 0x09000000 /*!< arg will be nor'ed */
|
||||
#define POPT_ARGFLAG_AND 0x04000000 /*!< arg will be and'ed */
|
||||
#define POPT_ARGFLAG_NAND 0x05000000 /*!< arg will be nand'ed */
|
||||
#define POPT_ARGFLAG_XOR 0x02000000 /*!< arg will be xor'ed */
|
||||
#define POPT_ARGFLAG_NOT 0x01000000 /*!< arg will be negated */
|
||||
#define POPT_ARGFLAG_LOGICALOPS \
|
||||
(POPT_ARGFLAG_OR|POPT_ARGFLAG_AND|POPT_ARGFLAG_XOR)
|
||||
|
||||
#define POPT_BIT_SET (POPT_ARG_VAL|POPT_ARGFLAG_OR)
|
||||
/*!< set arg bit(s) */
|
||||
#define POPT_BIT_CLR (POPT_ARG_VAL|POPT_ARGFLAG_NAND)
|
||||
/*!< clear arg bit(s) */
|
||||
|
||||
#define POPT_ARGFLAG_SHOW_DEFAULT 0x00800000 /*!< show default value in --help */
|
||||
|
||||
/*@}*/
|
||||
|
||||
/** \ingroup popt
|
||||
* \name Callback modifiers
|
||||
*/
|
||||
/*@{*/
|
||||
#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_CBFLAG_SKIPOPTION 0x10000000 /*!< don't callback with option */
|
||||
#define POPT_CBFLAG_CONTINUE 0x08000000 /*!< continue callbacks with option */
|
||||
/*@}*/
|
||||
|
||||
/** \ingroup popt
|
||||
* \name Error return values
|
||||
*/
|
||||
/*@{*/
|
||||
#define POPT_ERROR_NOARG -10 /*!< missing argument */
|
||||
#define POPT_ERROR_BADOPT -11 /*!< unknown option */
|
||||
#define POPT_ERROR_OPTSTOODEEP -13 /*!< aliases nested too deeply */
|
||||
#define POPT_ERROR_BADQUOTE -15 /*!< error in paramter quoting */
|
||||
#define POPT_ERROR_ERRNO -16 /*!< errno set, use strerror(errno) */
|
||||
#define POPT_ERROR_BADNUMBER -17 /*!< invalid numeric value */
|
||||
#define POPT_ERROR_OVERFLOW -18 /*!< number too large or too small */
|
||||
#define POPT_ERROR_BADOPERATION -19 /*!< mutually exclusive logical operations requested */
|
||||
#define POPT_ERROR_NULLARG -20 /*!< opt->arg should not be NULL */
|
||||
#define POPT_ERROR_MALLOC -21 /*!< memory allocation failed */
|
||||
/*@}*/
|
||||
|
||||
/** \ingroup popt
|
||||
* \name poptBadOption() flags
|
||||
*/
|
||||
/*@{*/
|
||||
#define POPT_BADOPTION_NOALIAS (1 << 0) /*!< don't go into an alias */
|
||||
/*@}*/
|
||||
|
||||
/** \ingroup popt
|
||||
* \name 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 */
|
||||
#define POPT_CONTEXT_ARG_OPTS (1 << 4) /*!< return args as options with value 0 */
|
||||
/*@}*/
|
||||
|
||||
/** \ingroup popt
|
||||
*/
|
||||
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 */
|
||||
/*@observer@*/ /*@null@*/ const char * descrip; /*!< description for autohelp -- may be NULL */
|
||||
/*@observer@*/ /*@null@*/ const char * argDescrip; /*!< argument description for autohelp */
|
||||
};
|
||||
|
||||
/** \ingroup popt
|
||||
* A popt alias argument for poptAddAlias().
|
||||
*/
|
||||
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 */
|
||||
};
|
||||
|
||||
/** \ingroup popt
|
||||
* A popt alias or exec argument for poptAddItem().
|
||||
*/
|
||||
typedef struct poptItem_s {
|
||||
struct poptOption option; /*!< alias/exec name(s) and description. */
|
||||
int argc; /*!< (alias) no. of args. */
|
||||
/*@owned@*/ const char ** argv; /*!< (alias) args, must be free()able. */
|
||||
} * poptItem;
|
||||
|
||||
/** \ingroup popt
|
||||
* \name Auto-generated help/usage
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* Empty table marker to enable displaying popt alias/exec options.
|
||||
*/
|
||||
/*@observer@*/ /*@checked@*/
|
||||
extern struct poptOption poptAliasOptions[];
|
||||
#define POPT_AUTOALIAS { NULL, '\0', POPT_ARG_INCLUDE_TABLE, poptAliasOptions, \
|
||||
0, "Options implemented via popt alias/exec:", NULL },
|
||||
|
||||
/**
|
||||
* Auto help table options.
|
||||
*/
|
||||
/*@observer@*/ /*@checked@*/
|
||||
extern struct poptOption poptHelpOptions[];
|
||||
#define POPT_AUTOHELP { NULL, '\0', POPT_ARG_INCLUDE_TABLE, poptHelpOptions, \
|
||||
0, "Help options:", NULL },
|
||||
|
||||
#define POPT_TABLEEND { NULL, '\0', 0, 0, 0, NULL, NULL }
|
||||
/*@}*/
|
||||
|
||||
/** \ingroup popt
|
||||
*/
|
||||
typedef /*@abstract@*/ struct poptContext_s * poptContext;
|
||||
|
||||
/** \ingroup popt
|
||||
*/
|
||||
#ifndef __cplusplus
|
||||
/*@-typeuse@*/
|
||||
typedef struct poptOption * poptOption;
|
||||
/*@=typeuse@*/
|
||||
#endif
|
||||
|
||||
enum poptCallbackReason { POPT_CALLBACK_REASON_PRE,
|
||||
POPT_CALLBACK_REASON_POST,
|
||||
POPT_CALLBACK_REASON_OPTION };
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*@-type@*/
|
||||
|
||||
/** \ingroup popt
|
||||
* Table callback prototype.
|
||||
* @param con context
|
||||
* @param reason reason for callback
|
||||
* @param opt option that triggered callback
|
||||
* @param arg @todo Document.
|
||||
* @param data @todo Document.
|
||||
*/
|
||||
typedef void (*poptCallbackType) (poptContext con,
|
||||
enum poptCallbackReason reason,
|
||||
/*@null@*/ const struct poptOption * opt,
|
||||
/*@null@*/ const char * arg,
|
||||
/*@null@*/ const void * data)
|
||||
/*@*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Initialize popt context.
|
||||
* @param name
|
||||
* @param argc no. of arguments
|
||||
* @param argv argument array
|
||||
* @param options address of popt option table
|
||||
* @param flags or'd POPT_CONTEXT_* bits
|
||||
* @return initialized popt context
|
||||
*/
|
||||
/*@only@*/ /*@null@*/ poptContext poptGetContext(
|
||||
/*@dependent@*/ /*@keep@*/ const char * name,
|
||||
int argc, /*@dependent@*/ /*@keep@*/ const char ** argv,
|
||||
/*@dependent@*/ /*@keep@*/ const struct poptOption * options,
|
||||
int flags)
|
||||
/*@*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Reinitialize popt context.
|
||||
* @param con context
|
||||
*/
|
||||
void poptResetContext(/*@null@*/poptContext con)
|
||||
/*@modifies con @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Return value of next option found.
|
||||
* @param con context
|
||||
* @return next option val, -1 on last item, POPT_ERROR_* on error
|
||||
*/
|
||||
int poptGetNextOpt(/*@null@*/poptContext con)
|
||||
/*@globals fileSystem@*/
|
||||
/*@modifies con, fileSystem @*/;
|
||||
|
||||
/*@-redecl@*/
|
||||
/** \ingroup popt
|
||||
* Return next option argument (if any).
|
||||
* @param con context
|
||||
* @return option argument, NULL if no more options are available
|
||||
*/
|
||||
/*@observer@*/ /*@null@*/ const char * poptGetOptArg(/*@null@*/poptContext con)
|
||||
/*@modifies con @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Return current option's argument.
|
||||
* @param con context
|
||||
* @return option argument, NULL if no more options are available
|
||||
*/
|
||||
/*@observer@*/ /*@null@*/ const char * poptGetArg(/*@null@*/poptContext con)
|
||||
/*@modifies con @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Peek at current option's argument.
|
||||
* @param con context
|
||||
* @return option argument
|
||||
*/
|
||||
/*@observer@*/ /*@null@*/ const char * poptPeekArg(/*@null@*/poptContext con)
|
||||
/*@*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Return remaining arguments.
|
||||
* @param con context
|
||||
* @return argument array, terminated with NULL
|
||||
*/
|
||||
/*@observer@*/ /*@null@*/ const char ** poptGetArgs(/*@null@*/poptContext con)
|
||||
/*@modifies con @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Return the option which caused the most recent error.
|
||||
* @param con context
|
||||
* @return offending option
|
||||
*/
|
||||
/*@observer@*/ const char * poptBadOption(/*@null@*/poptContext con, int flags)
|
||||
/*@*/;
|
||||
/*@=redecl@*/
|
||||
|
||||
/** \ingroup popt
|
||||
* Destroy context.
|
||||
* @param con context
|
||||
* @return NULL always
|
||||
*/
|
||||
/*@null@*/ poptContext poptFreeContext( /*@only@*/ /*@null@*/ poptContext con)
|
||||
/*@modifies con @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Add arguments to context.
|
||||
* @param con context
|
||||
* @param argv argument array, NULL terminated
|
||||
* @return 0 on success, POPT_ERROR_OPTSTOODEEP on failure
|
||||
*/
|
||||
int poptStuffArgs(poptContext con, /*@keep@*/ const char ** argv)
|
||||
/*@modifies con @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Add alias to context.
|
||||
* @todo Pass alias by reference, not value.
|
||||
* @deprecated Use poptAddItem instead.
|
||||
* @param con context
|
||||
* @param alias alias to add
|
||||
* @param flags (unused)
|
||||
* @return 0 on success
|
||||
*/
|
||||
/*@unused@*/
|
||||
int poptAddAlias(poptContext con, struct poptAlias alias, int flags)
|
||||
/*@modifies con @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Add alias/exec item to context.
|
||||
* @param con context
|
||||
* @param item alias/exec item to add
|
||||
* @param flags 0 for alias, 1 for exec
|
||||
* @return 0 on success
|
||||
*/
|
||||
int poptAddItem(poptContext con, poptItem newItem, int flags)
|
||||
/*@modifies con @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Read configuration file.
|
||||
* @param con context
|
||||
* @param fn file name to read
|
||||
* @return 0 on success, POPT_ERROR_ERRNO on failure
|
||||
*/
|
||||
int poptReadConfigFile(poptContext con, const char * fn)
|
||||
/*@globals fileSystem@*/
|
||||
/*@modifies fileSystem,
|
||||
con->execs, con->numExecs @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Read default configuration from /etc/popt and $HOME/.popt.
|
||||
* @param con context
|
||||
* @param useEnv (unused)
|
||||
* @return 0 on success, POPT_ERROR_ERRNO on failure
|
||||
*/
|
||||
int poptReadDefaultConfig(poptContext con, /*@unused@*/ int useEnv)
|
||||
/*@globals fileSystem@*/
|
||||
/*@modifies fileSystem,
|
||||
con->execs, con->numExecs @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Duplicate an argument array.
|
||||
* @note: The argument array is malloc'd as a single area, so only argv must
|
||||
* be free'd.
|
||||
*
|
||||
* @param argc no. of arguments
|
||||
* @param argv argument array
|
||||
* @retval argcPtr address of returned no. of arguments
|
||||
* @retval argvPtr address of returned argument array
|
||||
* @return 0 on success, POPT_ERROR_NOARG on failure
|
||||
*/
|
||||
int poptDupArgv(int argc, /*@null@*/ const char **argv,
|
||||
/*@null@*/ /*@out@*/ int * argcPtr,
|
||||
/*@null@*/ /*@out@*/ const char *** argvPtr)
|
||||
/*@modifies *argcPtr, *argvPtr @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Parse a string into an argument array.
|
||||
* The parse allows ', ", and \ quoting, but ' is treated the same as " and
|
||||
* both may include \ quotes.
|
||||
* @note: The argument array is malloc'd as a single area, so only argv must
|
||||
* be free'd.
|
||||
*
|
||||
* @param s string to parse
|
||||
* @retval argcPtr address of returned no. of arguments
|
||||
* @retval argvPtr address of returned argument array
|
||||
*/
|
||||
int poptParseArgvString(const char * s,
|
||||
/*@out@*/ int * argcPtr, /*@out@*/ const char *** argvPtr)
|
||||
/*@modifies *argcPtr, *argvPtr @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Return formatted error string for popt failure.
|
||||
* @param error popt error
|
||||
* @return error string
|
||||
*/
|
||||
/*@-redecl@*/
|
||||
/*@observer@*/ const char *const poptStrerror(const int error)
|
||||
/*@*/;
|
||||
/*@=redecl@*/
|
||||
|
||||
/** \ingroup popt
|
||||
* Limit search for executables.
|
||||
* @param con context
|
||||
* @param path single path to search for executables
|
||||
* @param allowAbsolute absolute paths only?
|
||||
*/
|
||||
void poptSetExecPath(poptContext con, const char * path, int allowAbsolute)
|
||||
/*@modifies con @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Print detailed description of options.
|
||||
* @param con context
|
||||
* @param fp ouput file handle
|
||||
* @param flags (unused)
|
||||
*/
|
||||
void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ int flags)
|
||||
/*@globals fileSystem @*/
|
||||
/*@modifies *fp, fileSystem @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Print terse description of options.
|
||||
* @param con context
|
||||
* @param fp ouput file handle
|
||||
* @param flags (unused)
|
||||
*/
|
||||
void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ int flags)
|
||||
/*@globals fileSystem @*/
|
||||
/*@modifies *fp, fileSystem @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Provide text to replace default "[OPTION...]" in help/usage output.
|
||||
* @param con context
|
||||
* @param text replacement text
|
||||
*/
|
||||
/*@-fcnuse@*/
|
||||
void poptSetOtherOptionHelp(poptContext con, const char * text)
|
||||
/*@modifies con @*/;
|
||||
/*@=fcnuse@*/
|
||||
|
||||
/** \ingroup popt
|
||||
* Return argv[0] from context.
|
||||
* @param con context
|
||||
* @return argv[0]
|
||||
*/
|
||||
/*@-redecl -fcnuse@*/
|
||||
/*@observer@*/ const char * poptGetInvocationName(poptContext con)
|
||||
/*@*/;
|
||||
/*@=redecl =fcnuse@*/
|
||||
|
||||
/** \ingroup popt
|
||||
* Shuffle argv pointers to remove stripped args, returns new argc.
|
||||
* @param con context
|
||||
* @param argc no. of args
|
||||
* @param argv arg vector
|
||||
* @return new argc
|
||||
*/
|
||||
/*@-fcnuse@*/
|
||||
int poptStrippedArgv(poptContext con, int argc, char ** argv)
|
||||
/*@modifies *argv @*/;
|
||||
/*@=fcnuse@*/
|
||||
|
||||
/*@=type@*/
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
183
popt/poptconfig.c
Normal file
183
popt/poptconfig.c
Normal file
@@ -0,0 +1,183 @@
|
||||
/** \ingroup popt
|
||||
* \file popt/poptconfig.c
|
||||
*/
|
||||
|
||||
/* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING
|
||||
file accompanying popt source distributions, available from
|
||||
ftp://ftp.rpm.org/pub/rpm/dist. */
|
||||
|
||||
#include "system.h"
|
||||
#include "poptint.h"
|
||||
|
||||
/*@-compmempass@*/ /* FIX: item->option.longName kept, not dependent. */
|
||||
static void configLine(poptContext con, char * line)
|
||||
/*@modifies con @*/
|
||||
{
|
||||
/*@-type@*/
|
||||
int nameLength = strlen(con->appName);
|
||||
/*@=type@*/
|
||||
const char * entryType;
|
||||
const char * opt;
|
||||
poptItem item = (poptItem) alloca(sizeof(*item));
|
||||
int i, j;
|
||||
|
||||
memset(item, 0, sizeof(*item));
|
||||
|
||||
/*@-type@*/
|
||||
if (strncmp(line, con->appName, nameLength)) return;
|
||||
/*@=type@*/
|
||||
|
||||
line += nameLength;
|
||||
if (*line == '\0' || !isspace(*line)) return;
|
||||
|
||||
while (*line != '\0' && isspace(*line)) line++;
|
||||
entryType = line;
|
||||
while (*line == '\0' || !isspace(*line)) line++;
|
||||
*line++ = '\0';
|
||||
|
||||
while (*line != '\0' && isspace(*line)) line++;
|
||||
if (*line == '\0') return;
|
||||
opt = line;
|
||||
while (*line == '\0' || !isspace(*line)) line++;
|
||||
*line++ = '\0';
|
||||
|
||||
while (*line != '\0' && isspace(*line)) line++;
|
||||
if (*line == '\0') return;
|
||||
|
||||
/*@-temptrans@*/ /* FIX: line alias is saved */
|
||||
if (opt[0] == '-' && opt[1] == '-')
|
||||
item->option.longName = opt + 2;
|
||||
else if (opt[0] == '-' && opt[2] == '\0')
|
||||
item->option.shortName = opt[1];
|
||||
/*@=temptrans@*/
|
||||
|
||||
if (poptParseArgvString(line, &item->argc, &item->argv)) return;
|
||||
|
||||
/*@-modobserver@*/
|
||||
item->option.argInfo = POPT_ARGFLAG_DOC_HIDDEN;
|
||||
for (i = 0, j = 0; i < item->argc; i++, j++) {
|
||||
const char * f;
|
||||
if (!strncmp(item->argv[i], "--POPTdesc=", sizeof("--POPTdesc=")-1)) {
|
||||
f = item->argv[i] + sizeof("--POPTdesc=");
|
||||
if (f[0] == '$' && f[1] == '"') f++;
|
||||
item->option.descrip = f;
|
||||
item->option.argInfo &= ~POPT_ARGFLAG_DOC_HIDDEN;
|
||||
j--;
|
||||
} else
|
||||
if (!strncmp(item->argv[i], "--POPTargs=", sizeof("--POPTargs=")-1)) {
|
||||
f = item->argv[i] + sizeof("--POPTargs=");
|
||||
if (f[0] == '$' && f[1] == '"') f++;
|
||||
item->option.argDescrip = f;
|
||||
item->option.argInfo &= ~POPT_ARGFLAG_DOC_HIDDEN;
|
||||
item->option.argInfo |= POPT_ARG_STRING;
|
||||
j--;
|
||||
} else
|
||||
if (j != i)
|
||||
item->argv[j] = item->argv[i];
|
||||
}
|
||||
if (j != i) {
|
||||
item->argv[j] = NULL;
|
||||
item->argc = j;
|
||||
}
|
||||
/*@=modobserver@*/
|
||||
|
||||
/*@-nullstate@*/ /* FIX: item->argv[] may be NULL */
|
||||
if (!strcmp(entryType, "alias"))
|
||||
(void) poptAddItem(con, item, 0);
|
||||
else if (!strcmp(entryType, "exec"))
|
||||
(void) poptAddItem(con, item, 1);
|
||||
/*@=nullstate@*/
|
||||
}
|
||||
/*@=compmempass@*/
|
||||
|
||||
int poptReadConfigFile(poptContext con, const char * fn)
|
||||
{
|
||||
const char * file, * chptr, * end;
|
||||
char * buf;
|
||||
/*@dependent@*/ char * dst;
|
||||
int fd, rc;
|
||||
off_t fileLength;
|
||||
|
||||
fd = open(fn, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return (errno == ENOENT ? 0 : POPT_ERROR_ERRNO);
|
||||
|
||||
fileLength = lseek(fd, 0, SEEK_END);
|
||||
if (fileLength == -1 || lseek(fd, 0, 0) == -1) {
|
||||
rc = errno;
|
||||
(void) close(fd);
|
||||
/*@-mods@*/
|
||||
errno = rc;
|
||||
/*@=mods@*/
|
||||
return POPT_ERROR_ERRNO;
|
||||
}
|
||||
|
||||
file = alloca(fileLength + 1);
|
||||
if (read(fd, (char *)file, fileLength) != fileLength) {
|
||||
rc = errno;
|
||||
(void) close(fd);
|
||||
/*@-mods@*/
|
||||
errno = rc;
|
||||
/*@=mods@*/
|
||||
return POPT_ERROR_ERRNO;
|
||||
}
|
||||
if (close(fd) == -1)
|
||||
return POPT_ERROR_ERRNO;
|
||||
|
||||
dst = buf = alloca(fileLength + 1);
|
||||
|
||||
chptr = file;
|
||||
end = (file + fileLength);
|
||||
/*@-infloops@*/ /* LCL: can't detect chptr++ */
|
||||
while (chptr < end) {
|
||||
switch (*chptr) {
|
||||
case '\n':
|
||||
*dst = '\0';
|
||||
dst = buf;
|
||||
while (*dst && isspace(*dst)) dst++;
|
||||
if (*dst && *dst != '#')
|
||||
configLine(con, dst);
|
||||
chptr++;
|
||||
/*@switchbreak@*/ 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++;
|
||||
}
|
||||
/*@switchbreak@*/ break;
|
||||
default:
|
||||
*dst++ = *chptr++;
|
||||
/*@switchbreak@*/ break;
|
||||
}
|
||||
}
|
||||
/*@=infloops@*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int poptReadDefaultConfig(poptContext con, /*@unused@*/ int useEnv) {
|
||||
char * fn, * home;
|
||||
int rc;
|
||||
|
||||
/*@-type@*/
|
||||
if (!con->appName) return 0;
|
||||
/*@=type@*/
|
||||
|
||||
rc = poptReadConfigFile(con, "/etc/popt");
|
||||
if (rc) return rc;
|
||||
if (getuid() != geteuid()) return 0;
|
||||
|
||||
if ((home = getenv("HOME"))) {
|
||||
fn = alloca(strlen(home) + 20);
|
||||
strcpy(fn, home);
|
||||
strcat(fn, "/.popt");
|
||||
rc = poptReadConfigFile(con, fn);
|
||||
if (rc) return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
661
popt/popthelp.c
Normal file
661
popt/popthelp.c
Normal file
@@ -0,0 +1,661 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
||||
|
||||
/*@-type@*/
|
||||
/** \ingroup popt
|
||||
* \file popt/popthelp.c
|
||||
*/
|
||||
|
||||
/* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING
|
||||
file accompanying popt source distributions, available from
|
||||
ftp://ftp.rpm.org/pub/rpm/dist. */
|
||||
|
||||
#include "system.h"
|
||||
#include "poptint.h"
|
||||
|
||||
/**
|
||||
* @param con context
|
||||
* @param key option(s)
|
||||
*/
|
||||
static void displayArgs(poptContext con,
|
||||
/*@unused@*/ enum poptCallbackReason foo,
|
||||
struct poptOption * key,
|
||||
/*@unused@*/ const char * arg, /*@unused@*/ void * data)
|
||||
/*@globals fileSystem@*/
|
||||
/*@modifies fileSystem@*/
|
||||
{
|
||||
if (key->shortName == '?')
|
||||
poptPrintHelp(con, stdout, 0);
|
||||
else
|
||||
poptPrintUsage(con, stdout, 0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#ifdef NOTYET
|
||||
/*@unchecked@*/
|
||||
static int show_option_defaults = 0;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Empty table marker to enable displaying popt alias/exec options.
|
||||
*/
|
||||
/*@observer@*/ /*@unchecked@*/
|
||||
struct poptOption poptAliasOptions[] = {
|
||||
POPT_TABLEEND
|
||||
};
|
||||
|
||||
/**
|
||||
* Auto help table options.
|
||||
*/
|
||||
/*@-castfcnptr@*/
|
||||
/*@observer@*/ /*@unchecked@*/
|
||||
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 },
|
||||
#ifdef NOTYET
|
||||
{ "defaults", '\0', POPT_ARG_NONE, &show_option_defaults, 0,
|
||||
N_("Display option defaults in message"), NULL },
|
||||
#endif
|
||||
POPT_TABLEEND
|
||||
} ;
|
||||
/*@=castfcnptr@*/
|
||||
|
||||
/**
|
||||
* @param table option(s)
|
||||
*/
|
||||
/*@observer@*/ /*@null@*/ static const char *const
|
||||
getTableTranslationDomain(/*@null@*/ const struct poptOption *table)
|
||||
/*@*/
|
||||
{
|
||||
const struct poptOption *opt;
|
||||
|
||||
if (table != NULL)
|
||||
for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) {
|
||||
if (opt->argInfo == POPT_ARG_INTL_DOMAIN)
|
||||
return opt->arg;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param opt option(s)
|
||||
* @param translation_domain translation domain
|
||||
*/
|
||||
/*@observer@*/ /*@null@*/ static const char *const
|
||||
getArgDescrip(const struct poptOption * opt,
|
||||
/*@-paramuse@*/ /* FIX: wazzup? */
|
||||
/*@null@*/ const char * translation_domain)
|
||||
/*@=paramuse@*/
|
||||
/*@*/
|
||||
{
|
||||
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);
|
||||
|
||||
switch (opt->argInfo & POPT_ARG_MASK) {
|
||||
case POPT_ARG_NONE: return POPT_("NONE");
|
||||
case POPT_ARG_VAL: return POPT_("VAL");
|
||||
case POPT_ARG_INT: return POPT_("INT");
|
||||
case POPT_ARG_LONG: return POPT_("LONG");
|
||||
case POPT_ARG_STRING: return POPT_("STRING");
|
||||
case POPT_ARG_FLOAT: return POPT_("FLOAT");
|
||||
case POPT_ARG_DOUBLE: return POPT_("DOUBLE");
|
||||
default: return POPT_("ARG");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param opt option(s)
|
||||
* @param translation_domain translation domain
|
||||
*/
|
||||
static /*@only@*/ /*@null@*/ char *
|
||||
singleOptionDefaultValue(int lineLength,
|
||||
const struct poptOption * opt,
|
||||
/*@-paramuse@*/ /* FIX: i18n macros disable with lclint */
|
||||
/*@null@*/ const char * translation_domain)
|
||||
/*@=paramuse@*/
|
||||
/*@*/
|
||||
{
|
||||
const char * defstr = D_(translation_domain, "default");
|
||||
char * le = malloc(4*lineLength + 1);
|
||||
char * l = le;
|
||||
|
||||
if (le == NULL) return NULL; /* XXX can't happen */
|
||||
*le = '\0';
|
||||
*le++ = '(';
|
||||
strcpy(le, defstr); le += strlen(le);
|
||||
*le++ = ':';
|
||||
*le++ = ' ';
|
||||
if (opt->arg) /* XXX programmer error */
|
||||
switch (opt->argInfo & POPT_ARG_MASK) {
|
||||
case POPT_ARG_VAL:
|
||||
case POPT_ARG_INT:
|
||||
{ long aLong = *((int *)opt->arg);
|
||||
sprintf(le, "%ld", aLong);
|
||||
le += strlen(le);
|
||||
} break;
|
||||
case POPT_ARG_LONG:
|
||||
{ long aLong = *((long *)opt->arg);
|
||||
sprintf(le, "%ld", aLong);
|
||||
le += strlen(le);
|
||||
} break;
|
||||
case POPT_ARG_FLOAT:
|
||||
{ double aDouble = *((float *)opt->arg);
|
||||
sprintf(le, "%g", aDouble);
|
||||
le += strlen(le);
|
||||
} break;
|
||||
case POPT_ARG_DOUBLE:
|
||||
{ double aDouble = *((double *)opt->arg);
|
||||
sprintf(le, "%g", aDouble);
|
||||
le += strlen(le);
|
||||
} break;
|
||||
case POPT_ARG_STRING:
|
||||
{ const char * s = *(const char **)opt->arg;
|
||||
if (s == NULL) {
|
||||
strcpy(le, "null"); le += strlen(le);
|
||||
} else {
|
||||
size_t slen = 4*lineLength - (le - l) - sizeof("\"...\")");
|
||||
*le++ = '"';
|
||||
strncpy(le, s, slen); le[slen] = '\0'; le += strlen(le);
|
||||
if (slen < strlen(s)) {
|
||||
strcpy(le, "..."); le += strlen(le);
|
||||
}
|
||||
*le++ = '"';
|
||||
}
|
||||
} break;
|
||||
case POPT_ARG_NONE:
|
||||
default:
|
||||
l = _free(l);
|
||||
return NULL;
|
||||
/*@notreached@*/ break;
|
||||
}
|
||||
*le++ = ')';
|
||||
*le = '\0';
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fp output file handle
|
||||
* @param opt option(s)
|
||||
* @param translation_domain translation domain
|
||||
*/
|
||||
static void singleOptionHelp(FILE * fp, int maxLeftCol,
|
||||
const struct poptOption * opt,
|
||||
/*@null@*/ const char * translation_domain)
|
||||
/*@globals fileSystem @*/
|
||||
/*@modifies *fp, fileSystem @*/
|
||||
{
|
||||
int indentLength = maxLeftCol + 5;
|
||||
int lineLength = 79 - indentLength;
|
||||
const char * help = D_(translation_domain, opt->descrip);
|
||||
const char * argDescrip = getArgDescrip(opt, translation_domain);
|
||||
int helpLength;
|
||||
char * defs = NULL;
|
||||
char * left;
|
||||
int nb = maxLeftCol + 1;
|
||||
|
||||
/* Make sure there's more than enough room in target buffer. */
|
||||
if (opt->longName) nb += strlen(opt->longName);
|
||||
if (argDescrip) nb += strlen(argDescrip);
|
||||
|
||||
left = malloc(nb);
|
||||
if (left == NULL) return; /* XXX can't happen */
|
||||
left[0] = '\0';
|
||||
left[maxLeftCol] = '\0';
|
||||
|
||||
if (opt->longName && opt->shortName)
|
||||
sprintf(left, "-%c, %s%s", opt->shortName,
|
||||
((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
|
||||
opt->longName);
|
||||
else if (opt->shortName != '\0')
|
||||
sprintf(left, "-%c", opt->shortName);
|
||||
else if (opt->longName)
|
||||
sprintf(left, "%s%s",
|
||||
((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
|
||||
opt->longName);
|
||||
if (!*left) goto out;
|
||||
if (argDescrip) {
|
||||
char * le = left + strlen(left);
|
||||
|
||||
if (opt->argInfo & POPT_ARGFLAG_OPTIONAL)
|
||||
*le++ = '[';
|
||||
|
||||
/* Choose type of output */
|
||||
/*@-branchstate@*/
|
||||
if (opt->argInfo & POPT_ARGFLAG_SHOW_DEFAULT) {
|
||||
defs = singleOptionDefaultValue(lineLength, opt, translation_domain);
|
||||
if (defs) {
|
||||
char * t = malloc((help ? strlen(help) : 0) +
|
||||
strlen(defs) + sizeof(" "));
|
||||
if (t) {
|
||||
char * te = t;
|
||||
*te = '\0';
|
||||
if (help) {
|
||||
strcpy(te, help); te += strlen(te);
|
||||
}
|
||||
*te++ = ' ';
|
||||
strcpy(te, defs);
|
||||
defs = _free(defs);
|
||||
}
|
||||
defs = t;
|
||||
}
|
||||
}
|
||||
/*@=branchstate@*/
|
||||
|
||||
if (opt->argDescrip == NULL) {
|
||||
switch (opt->argInfo & POPT_ARG_MASK) {
|
||||
case POPT_ARG_NONE:
|
||||
break;
|
||||
case POPT_ARG_VAL:
|
||||
{ long aLong = opt->val;
|
||||
int ops = (opt->argInfo & POPT_ARGFLAG_LOGICALOPS);
|
||||
int negate = (opt->argInfo & POPT_ARGFLAG_NOT);
|
||||
|
||||
/* Don't bother displaying typical values */
|
||||
if (!ops && (aLong == 0L || aLong == 1L || aLong == -1L))
|
||||
break;
|
||||
*le++ = '[';
|
||||
switch (ops) {
|
||||
case POPT_ARGFLAG_OR:
|
||||
*le++ = '|';
|
||||
/*@innerbreak@*/ break;
|
||||
case POPT_ARGFLAG_AND:
|
||||
*le++ = '&';
|
||||
/*@innerbreak@*/ break;
|
||||
case POPT_ARGFLAG_XOR:
|
||||
*le++ = '^';
|
||||
/*@innerbreak@*/ break;
|
||||
default:
|
||||
/*@innerbreak@*/ break;
|
||||
}
|
||||
*le++ = '=';
|
||||
if (negate) *le++ = '~';
|
||||
/*@-formatconst@*/
|
||||
sprintf(le, (ops ? "0x%lx" : "%ld"), aLong);
|
||||
le += strlen(le);
|
||||
/*@=formatconst@*/
|
||||
*le++ = ']';
|
||||
} break;
|
||||
case POPT_ARG_INT:
|
||||
case POPT_ARG_LONG:
|
||||
case POPT_ARG_FLOAT:
|
||||
case POPT_ARG_DOUBLE:
|
||||
case POPT_ARG_STRING:
|
||||
*le++ = '=';
|
||||
strcpy(le, argDescrip); le += strlen(le);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
*le++ = '=';
|
||||
strcpy(le, argDescrip); le += strlen(le);
|
||||
}
|
||||
if (opt->argInfo & POPT_ARGFLAG_OPTIONAL)
|
||||
*le++ = ']';
|
||||
*le = '\0';
|
||||
}
|
||||
|
||||
if (help)
|
||||
fprintf(fp," %-*s ", maxLeftCol, left);
|
||||
else {
|
||||
fprintf(fp," %s\n", left);
|
||||
goto out;
|
||||
}
|
||||
|
||||
left = _free(left);
|
||||
if (defs) {
|
||||
help = defs; defs = NULL;
|
||||
}
|
||||
|
||||
helpLength = strlen(help);
|
||||
while (helpLength > lineLength) {
|
||||
const char * ch;
|
||||
char format[10];
|
||||
|
||||
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);
|
||||
/*@-formatconst@*/
|
||||
fprintf(fp, format, help, " ");
|
||||
/*@=formatconst@*/
|
||||
help = ch;
|
||||
while (isspace(*help) && *help) help++;
|
||||
helpLength = strlen(help);
|
||||
}
|
||||
|
||||
if (helpLength) fprintf(fp, "%s\n", help);
|
||||
|
||||
out:
|
||||
/*@-dependenttrans@*/
|
||||
defs = _free(defs);
|
||||
/*@=dependenttrans@*/
|
||||
left = _free(left);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param opt option(s)
|
||||
* @param translation_domain translation domain
|
||||
*/
|
||||
static int maxArgWidth(const struct poptOption * opt,
|
||||
/*@null@*/ const char * translation_domain)
|
||||
/*@*/
|
||||
{
|
||||
int max = 0;
|
||||
int len = 0;
|
||||
const char * s;
|
||||
|
||||
if (opt != NULL)
|
||||
while (opt->longName || opt->shortName || opt->arg) {
|
||||
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
|
||||
if (opt->arg) /* XXX program error */
|
||||
len = maxArgWidth(opt->arg, translation_domain);
|
||||
if (len > max) max = len;
|
||||
} else if (!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
|
||||
len = sizeof(" ")-1;
|
||||
if (opt->shortName != '\0') len += sizeof("-X")-1;
|
||||
if (opt->shortName != '\0' && opt->longName) len += sizeof(", ")-1;
|
||||
if (opt->longName) {
|
||||
len += ((opt->argInfo & POPT_ARGFLAG_ONEDASH)
|
||||
? sizeof("-")-1 : sizeof("--")-1);
|
||||
len += strlen(opt->longName);
|
||||
}
|
||||
|
||||
s = getArgDescrip(opt, translation_domain);
|
||||
if (s)
|
||||
len += sizeof("=")-1 + strlen(s);
|
||||
if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) len += sizeof("[]")-1;
|
||||
if (len > max) max = len;
|
||||
}
|
||||
|
||||
opt++;
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display popt alias and exec help.
|
||||
* @param fp output file handle
|
||||
* @param items alias/exec array
|
||||
* @param nitems no. of alias/exec entries
|
||||
* @param translation_domain translation domain
|
||||
*/
|
||||
static void itemHelp(FILE * fp,
|
||||
/*@null@*/ poptItem items, int nitems, int left,
|
||||
/*@null@*/ const char * translation_domain)
|
||||
/*@globals fileSystem @*/
|
||||
/*@modifies *fp, fileSystem @*/
|
||||
{
|
||||
poptItem item;
|
||||
int i;
|
||||
|
||||
if (items != NULL)
|
||||
for (i = 0, item = items; i < nitems; i++, item++) {
|
||||
const struct poptOption * opt;
|
||||
opt = &item->option;
|
||||
if ((opt->longName || opt->shortName) &&
|
||||
!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
|
||||
singleOptionHelp(fp, left, opt, translation_domain);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fp output file handle
|
||||
* @param table option(s)
|
||||
* @param translation_domain translation domain
|
||||
*/
|
||||
static void singleTableHelp(poptContext con, FILE * fp,
|
||||
/*@null@*/ const struct poptOption * table, int left,
|
||||
/*@null@*/ const char * translation_domain)
|
||||
/*@globals fileSystem @*/
|
||||
/*@modifies *fp, fileSystem @*/
|
||||
{
|
||||
const struct poptOption * opt;
|
||||
const char *sub_transdom;
|
||||
|
||||
if (table == poptAliasOptions) {
|
||||
itemHelp(fp, con->aliases, con->numAliases, left, NULL);
|
||||
itemHelp(fp, con->execs, con->numExecs, left, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (table != NULL)
|
||||
for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) {
|
||||
if ((opt->longName || opt->shortName) &&
|
||||
!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
|
||||
singleOptionHelp(fp, left, opt, translation_domain);
|
||||
}
|
||||
|
||||
if (table != NULL)
|
||||
for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) {
|
||||
if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_INCLUDE_TABLE)
|
||||
continue;
|
||||
sub_transdom = getTableTranslationDomain(opt->arg);
|
||||
if (sub_transdom == NULL)
|
||||
sub_transdom = translation_domain;
|
||||
|
||||
if (opt->descrip)
|
||||
fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip));
|
||||
|
||||
singleTableHelp(con, fp, opt->arg, left, sub_transdom);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param con context
|
||||
* @param fp output file handle
|
||||
*/
|
||||
static int showHelpIntro(poptContext con, FILE * fp)
|
||||
/*@globals fileSystem @*/
|
||||
/*@modifies *fp, fileSystem @*/
|
||||
{
|
||||
int len = 6;
|
||||
const char * fn;
|
||||
|
||||
fprintf(fp, POPT_("Usage:"));
|
||||
if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) {
|
||||
/*@-nullderef@*/ /* LCL: wazzup? */
|
||||
fn = con->optionStack->argv[0];
|
||||
/*@=nullderef@*/
|
||||
if (fn == NULL) return len;
|
||||
if (strchr(fn, '/')) fn = strrchr(fn, '/') + 1;
|
||||
fprintf(fp, " %s", fn);
|
||||
len += strlen(fn) + 1;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ int flags)
|
||||
{
|
||||
int leftColWidth;
|
||||
|
||||
(void) showHelpIntro(con, fp);
|
||||
if (con->otherHelp)
|
||||
fprintf(fp, " %s\n", con->otherHelp);
|
||||
else
|
||||
fprintf(fp, " %s\n", POPT_("[OPTION...]"));
|
||||
|
||||
leftColWidth = maxArgWidth(con->options, NULL);
|
||||
singleTableHelp(con, fp, con->options, leftColWidth, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fp output file handle
|
||||
* @param opt option(s)
|
||||
* @param translation_domain translation domain
|
||||
*/
|
||||
static int singleOptionUsage(FILE * fp, int cursor,
|
||||
const struct poptOption * opt,
|
||||
/*@null@*/ const char *translation_domain)
|
||||
/*@globals fileSystem @*/
|
||||
/*@modifies *fp, fileSystem @*/
|
||||
{
|
||||
int len = 3;
|
||||
char shortStr[2] = { '\0', '\0' };
|
||||
const char * item = shortStr;
|
||||
const char * argDescrip = getArgDescrip(opt, translation_domain);
|
||||
|
||||
if (opt->shortName!= '\0' ) {
|
||||
if (!(opt->argInfo & POPT_ARG_MASK))
|
||||
return cursor; /* we did these already */
|
||||
len++;
|
||||
shortStr[0] = 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(fp, "\n ");
|
||||
cursor = 7;
|
||||
}
|
||||
|
||||
fprintf(fp, " [-%s%s%s%s]",
|
||||
((opt->shortName || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) ? "" : "-"),
|
||||
item,
|
||||
(argDescrip ? (opt->shortName != '\0' ? " " : "=") : ""),
|
||||
(argDescrip ? argDescrip : ""));
|
||||
|
||||
return cursor + len + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display popt alias and exec usage.
|
||||
* @param fp output file handle
|
||||
* @param item alias/exec array
|
||||
* @param nitems no. of ara/exec entries
|
||||
* @param translation_domain translation domain
|
||||
*/
|
||||
static int itemUsage(FILE * fp, int cursor, poptItem item, int nitems,
|
||||
/*@null@*/ const char * translation_domain)
|
||||
/*@globals fileSystem @*/
|
||||
/*@modifies *fp, fileSystem @*/
|
||||
{
|
||||
int i;
|
||||
|
||||
/*@-branchstate@*/ /* FIX: W2DO? */
|
||||
if (item != NULL)
|
||||
for (i = 0; i < nitems; i++, item++) {
|
||||
const struct poptOption * opt;
|
||||
opt = &item->option;
|
||||
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) {
|
||||
translation_domain = (const char *)opt->arg;
|
||||
} else if ((opt->longName || opt->shortName) &&
|
||||
!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
|
||||
cursor = singleOptionUsage(fp, cursor, opt, translation_domain);
|
||||
}
|
||||
}
|
||||
/*@=branchstate@*/
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fp output file handle
|
||||
* @param opt option(s)
|
||||
* @param translation_domain translation domain
|
||||
*/
|
||||
static int singleTableUsage(poptContext con, FILE * fp,
|
||||
int cursor, const struct poptOption * opt,
|
||||
/*@null@*/ const char * translation_domain)
|
||||
/*@globals fileSystem @*/
|
||||
/*@modifies *fp, fileSystem @*/
|
||||
{
|
||||
/*@-branchstate@*/ /* FIX: W2DO? */
|
||||
if (opt != NULL)
|
||||
for (; (opt->longName || opt->shortName || opt->arg) ; opt++) {
|
||||
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) {
|
||||
if (opt->arg) /* XXX program error */
|
||||
cursor = singleTableUsage(con, fp, cursor, opt->arg,
|
||||
translation_domain);
|
||||
} else if ((opt->longName || opt->shortName) &&
|
||||
!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
|
||||
cursor = singleOptionUsage(fp, cursor, opt, translation_domain);
|
||||
}
|
||||
}
|
||||
/*@=branchstate@*/
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return concatenated short options for display.
|
||||
* @param opt option(s)
|
||||
* @param fp output file handle
|
||||
* @retval str concatenation of short options
|
||||
* @return length of display string
|
||||
*/
|
||||
static int showShortOptions(const struct poptOption * opt, FILE * fp,
|
||||
/*@null@*/ char * str)
|
||||
/*@globals fileSystem @*/
|
||||
/*@modifies *str, *fp, fileSystem @*/
|
||||
{
|
||||
char * s = alloca(300); /* larger then the ascii set */
|
||||
|
||||
s[0] = '\0';
|
||||
/*@-branchstate@*/ /* FIX: W2DO? */
|
||||
if (str == NULL) {
|
||||
memset(s, 0, sizeof(s));
|
||||
str = s;
|
||||
}
|
||||
/*@=branchstate@*/
|
||||
|
||||
if (opt != NULL)
|
||||
for (; (opt->longName || opt->shortName || opt->arg); opt++) {
|
||||
if (opt->shortName && !(opt->argInfo & POPT_ARG_MASK))
|
||||
str[strlen(str)] = opt->shortName;
|
||||
else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE)
|
||||
if (opt->arg) /* XXX program error */
|
||||
(void) showShortOptions(opt->arg, fp, str);
|
||||
}
|
||||
|
||||
if (s != str || *s != '\0')
|
||||
return 0;
|
||||
|
||||
fprintf(fp, " [-%s]", s);
|
||||
return strlen(s) + 4;
|
||||
}
|
||||
|
||||
void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ int flags)
|
||||
{
|
||||
int cursor;
|
||||
|
||||
cursor = showHelpIntro(con, fp);
|
||||
cursor += showShortOptions(con->options, fp, NULL);
|
||||
(void) singleTableUsage(con, fp, cursor, con->options, NULL);
|
||||
(void) itemUsage(fp, cursor, con->aliases, con->numAliases, NULL);
|
||||
(void) itemUsage(fp, cursor, con->execs, con->numExecs, NULL);
|
||||
|
||||
if (con->otherHelp) {
|
||||
cursor += strlen(con->otherHelp) + 1;
|
||||
if (cursor > 79) fprintf(fp, "\n ");
|
||||
fprintf(fp, " %s", con->otherHelp);
|
||||
}
|
||||
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
|
||||
void poptSetOtherOptionHelp(poptContext con, const char * text)
|
||||
{
|
||||
con->otherHelp = _free(con->otherHelp);
|
||||
con->otherHelp = xstrdup(text);
|
||||
}
|
||||
/*@=type@*/
|
||||
96
popt/poptint.h
Normal file
96
popt/poptint.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/** \ingroup popt
|
||||
* \file popt/poptint.h
|
||||
*/
|
||||
|
||||
/* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING
|
||||
file accompanying popt source distributions, available from
|
||||
ftp://ftp.rpm.org/pub/rpm/dist. */
|
||||
|
||||
#ifndef H_POPTINT
|
||||
#define H_POPTINT
|
||||
|
||||
/**
|
||||
* Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
|
||||
* @param p memory to free
|
||||
* @retval NULL always
|
||||
*/
|
||||
/*@unused@*/ static inline /*@null@*/ void *
|
||||
_free(/*@only@*/ /*@null@*/ const void * p)
|
||||
/*@modifies p @*/
|
||||
{
|
||||
if (p != NULL) free((void *)p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 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 << (((unsigned)(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@*/ /*@null@*/ const char ** argv;
|
||||
/*@only@*/ /*@null@*/ pbm_set * argb;
|
||||
int next;
|
||||
/*@only@*/ /*@null@*/ const char * nextArg;
|
||||
/*@keep@*/ /*@null@*/ const char * nextCharArg;
|
||||
/*@dependent@*/ /*@null@*/ poptItem currAlias;
|
||||
int stuffed;
|
||||
};
|
||||
|
||||
struct poptContext_s {
|
||||
struct optionStackEntry optionStack[POPT_OPTION_DEPTH];
|
||||
/*@dependent@*/ struct optionStackEntry * os;
|
||||
/*@owned@*/ /*@null@*/ const char ** leftovers;
|
||||
int numLeftovers;
|
||||
int nextLeftover;
|
||||
/*@keep@*/ const struct poptOption * options;
|
||||
int restLeftover;
|
||||
/*@only@*/ /*@null@*/ const char * appName;
|
||||
/*@only@*/ /*@null@*/ poptItem aliases;
|
||||
int numAliases;
|
||||
int flags;
|
||||
/*@owned@*/ /*@null@*/ poptItem execs;
|
||||
int numExecs;
|
||||
/*@only@*/ /*@null@*/ const char ** finalArgv;
|
||||
int finalArgvCount;
|
||||
int finalArgvAlloced;
|
||||
/*@dependent@*/ /*@null@*/ poptItem doExec;
|
||||
/*@only@*/ const char * execPath;
|
||||
int execAbsolute;
|
||||
/*@only@*/ const char * otherHelp;
|
||||
/*@null@*/ pbm_set * arg_strip;
|
||||
};
|
||||
|
||||
#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 D_(dom, str) str
|
||||
#define POPT_(foo) foo
|
||||
#endif
|
||||
|
||||
#define N_(foo) foo
|
||||
|
||||
#endif
|
||||
118
popt/poptparse.c
Normal file
118
popt/poptparse.c
Normal file
@@ -0,0 +1,118 @@
|
||||
/** \ingroup popt
|
||||
* \file popt/poptparse.c
|
||||
*/
|
||||
|
||||
/* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING
|
||||
file accompanying popt source distributions, available from
|
||||
ftp://ftp.rpm.org/pub/rpm/dist. */
|
||||
|
||||
#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;
|
||||
|
||||
if (argc <= 0 || argv == NULL) /* XXX can't happen */
|
||||
return POPT_ERROR_NOARG;
|
||||
for (i = 0; i < argc; i++) {
|
||||
if (argv[i] == NULL)
|
||||
return POPT_ERROR_NOARG;
|
||||
nb += strlen(argv[i]) + 1;
|
||||
}
|
||||
|
||||
dst = malloc(nb);
|
||||
if (dst == NULL) /* XXX can't happen */
|
||||
return POPT_ERROR_MALLOC;
|
||||
argv2 = (void *) dst;
|
||||
dst += (argc + 1) * sizeof(*argv);
|
||||
|
||||
/*@-branchstate@*/
|
||||
for (i = 0; i < argc; i++) {
|
||||
argv2[i] = dst;
|
||||
dst += strlen(strcpy(dst, argv[i])) + 1;
|
||||
}
|
||||
/*@=branchstate@*/
|
||||
argv2[argc] = NULL;
|
||||
|
||||
if (argvPtr) {
|
||||
*argvPtr = argv2;
|
||||
} else {
|
||||
free(argv2);
|
||||
argv2 = NULL;
|
||||
}
|
||||
if (argcPtr)
|
||||
*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 * buf = memset(alloca(buflen), 0, buflen);
|
||||
int rc = POPT_ERROR_MALLOC;
|
||||
|
||||
if (argv == NULL) return rc;
|
||||
argv[argc] = buf;
|
||||
|
||||
for (src = s; *src != '\0'; src++) {
|
||||
if (quote == *src) {
|
||||
quote = '\0';
|
||||
} else if (quote != '\0') {
|
||||
if (*src == '\\') {
|
||||
src++;
|
||||
if (!*src) {
|
||||
rc = POPT_ERROR_BADQUOTE;
|
||||
goto exit;
|
||||
}
|
||||
if (*src != quote) *buf++ = '\\';
|
||||
}
|
||||
*buf++ = *src;
|
||||
} else if (isspace(*src)) {
|
||||
if (*argv[argc] != '\0') {
|
||||
buf++, argc++;
|
||||
if (argc == argvAlloced) {
|
||||
argvAlloced += POPT_ARGV_ARRAY_GROW_DELTA;
|
||||
argv = realloc(argv, sizeof(*argv) * argvAlloced);
|
||||
if (argv == NULL) goto exit;
|
||||
}
|
||||
argv[argc] = buf;
|
||||
}
|
||||
} else switch (*src) {
|
||||
case '"':
|
||||
case '\'':
|
||||
quote = *src;
|
||||
/*@switchbreak@*/ break;
|
||||
case '\\':
|
||||
src++;
|
||||
if (!*src) {
|
||||
rc = POPT_ERROR_BADQUOTE;
|
||||
goto exit;
|
||||
}
|
||||
/*@fallthrough@*/
|
||||
default:
|
||||
*buf++ = *src;
|
||||
/*@switchbreak@*/ break;
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen(argv[argc])) {
|
||||
argc++, buf++;
|
||||
}
|
||||
|
||||
rc = poptDupArgv(argc, argv, argcPtr, argvPtr);
|
||||
|
||||
exit:
|
||||
if (argv) free(argv);
|
||||
return rc;
|
||||
}
|
||||
73
popt/system.h
Normal file
73
popt/system.h
Normal file
@@ -0,0 +1,73 @@
|
||||
#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
|
||||
|
||||
#if defined(__LCLINT__)
|
||||
/*@-declundef -incondefs -redecl@*/ /* LCL: missing annotation */
|
||||
/*@only@*/ void * alloca (size_t __size)
|
||||
/*@ensures MaxSet(result) == (__size - 1) @*/
|
||||
/*@*/;
|
||||
/*@=declundef =incondefs =redecl@*/
|
||||
#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
|
||||
# if HAVE_ALLOCA
|
||||
# ifndef alloca /* predefined by HP cc +Olibcalls */
|
||||
char *alloca ();
|
||||
# endif
|
||||
# else
|
||||
# ifdef alloca
|
||||
# undef alloca
|
||||
# endif
|
||||
# define alloca(sz) malloc(sz) /* Kludge this for now */
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
#elif defined(__GNUC__) && defined(__STRICT_ANSI__)
|
||||
#define alloca __builtin_alloca
|
||||
#endif
|
||||
|
||||
/*@-redecl -redef@*/
|
||||
/*@mayexit@*/ /*@only@*/ char * xstrdup (const char *str)
|
||||
/*@*/;
|
||||
/*@=redecl =redef@*/
|
||||
|
||||
#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"
|
||||
117
progress.c
Normal file
117
progress.c
Normal file
@@ -0,0 +1,117 @@
|
||||
/* -*- c-file-style: "linux" -*-
|
||||
*
|
||||
* Copyright (C) 1996-2000 by Andrew Tridgell
|
||||
* Copyright (C) Paul Mackerras 1996
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
static OFF_T last_ofs;
|
||||
static struct timeval print_time;
|
||||
static struct timeval start_time;
|
||||
static OFF_T start_ofs;
|
||||
|
||||
static unsigned long msdiff(struct timeval *t1, struct timeval *t2)
|
||||
{
|
||||
return (t2->tv_sec - t1->tv_sec) * 1000
|
||||
+ (t2->tv_usec - t1->tv_usec) / 1000;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ofs Current position in file
|
||||
* @param size Total size of file
|
||||
* @param is_last True if this is the last time progress will be
|
||||
* printed for this file, so we should output a newline. (Not
|
||||
* necessarily the same as all bytes being received.)
|
||||
**/
|
||||
static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
|
||||
int is_last)
|
||||
{
|
||||
int pct = (ofs == size) ? 100 : (int)((100.0*ofs)/size);
|
||||
unsigned long diff = msdiff(&start_time, now);
|
||||
double rate = diff ? (double) (ofs-start_ofs) * 1000.0 / diff / 1024.0 : 0;
|
||||
const char *units;
|
||||
/* If we've finished transferring this file, show the time taken;
|
||||
* otherwise show expected time to complete. That's kind of
|
||||
* inconsistent, but people can probably cope. Hopefully we'll
|
||||
* get more consistent and complete progress reporting soon. --
|
||||
* mbp */
|
||||
double remain = is_last
|
||||
? (double) diff / 1000.0
|
||||
: rate ? (double) (size-ofs) / rate / 1000.0 : 0.0;
|
||||
int remain_h, remain_m, remain_s;
|
||||
|
||||
if (rate > 1024*1024) {
|
||||
rate /= 1024.0 * 1024.0;
|
||||
units = "GB/s";
|
||||
} else if (rate > 1024) {
|
||||
rate /= 1024.0;
|
||||
units = "MB/s";
|
||||
} else {
|
||||
units = "kB/s";
|
||||
}
|
||||
|
||||
remain_s = (int) remain % 60;
|
||||
remain_m = (int) (remain / 60.0) % 60;
|
||||
remain_h = (int) (remain / 3600.0);
|
||||
|
||||
rprintf(FINFO, "%12.0f %3d%% %7.2f%s %4d:%02d:%02d%s",
|
||||
(double) ofs, pct, rate, units,
|
||||
remain_h, remain_m, remain_s,
|
||||
is_last ? "\n" : "\r");
|
||||
}
|
||||
|
||||
void end_progress(OFF_T size)
|
||||
{
|
||||
extern int do_progress, am_server;
|
||||
|
||||
if (do_progress && !am_server) {
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
rprint_progress(size, size, &now, True);
|
||||
}
|
||||
last_ofs = 0;
|
||||
start_ofs = 0;
|
||||
print_time.tv_sec = print_time.tv_usec = 0;
|
||||
start_time.tv_sec = start_time.tv_usec = 0;
|
||||
}
|
||||
|
||||
void show_progress(OFF_T ofs, OFF_T size)
|
||||
{
|
||||
extern int do_progress, am_server;
|
||||
struct timeval now;
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
|
||||
if (!start_time.tv_sec && !start_time.tv_usec) {
|
||||
start_time.tv_sec = now.tv_sec;
|
||||
start_time.tv_usec = now.tv_usec;
|
||||
start_ofs = ofs;
|
||||
}
|
||||
|
||||
if (do_progress
|
||||
&& !am_server
|
||||
&& ofs > last_ofs + 1000
|
||||
&& msdiff(&print_time, &now) > 250) {
|
||||
rprint_progress(ofs, size, &now, False);
|
||||
last_ofs = ofs;
|
||||
print_time.tv_sec = now.tv_sec;
|
||||
print_time.tv_usec = now.tv_usec;
|
||||
}
|
||||
}
|
||||
121
receiver.c
121
receiver.c
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright (C) Andrew Tridgell 1996
|
||||
/* -*- 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
|
||||
@@ -36,14 +37,12 @@ extern char *compare_dest;
|
||||
extern int make_backups;
|
||||
extern char *backup_suffix;
|
||||
|
||||
|
||||
static struct delete_list {
|
||||
dev_t dev;
|
||||
INO_T inode;
|
||||
DEV64_T dev;
|
||||
INO64_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.
|
||||
@@ -84,14 +83,15 @@ 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));
|
||||
rprintf(FERROR,"delete_one: 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));
|
||||
rprintf(FERROR,"delete_one: rmdir %s: %s\n",
|
||||
f_name(f), strerror(errno));
|
||||
} else if (verbose) {
|
||||
rprintf(FINFO,"deleting directory %s\n",f_name(f));
|
||||
}
|
||||
@@ -104,16 +104,20 @@ static void delete_one(struct file_struct *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 */
|
||||
static void delete_files(struct file_list *flist)
|
||||
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) {
|
||||
if (io_error && !(lp_ignore_errors(module_id) || ignore_errors)) {
|
||||
rprintf(FINFO,"IO error encountered - skipping file deletion\n");
|
||||
return;
|
||||
}
|
||||
@@ -136,6 +140,7 @@ static void delete_files(struct file_list *flist)
|
||||
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))
|
||||
@@ -143,10 +148,12 @@ static void delete_files(struct file_list *flist)
|
||||
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]);
|
||||
}
|
||||
}
|
||||
@@ -172,7 +179,7 @@ static int get_tmpname(char *fnametmp, char *fname)
|
||||
rprintf(FERROR,"filename too long\n");
|
||||
return 0;
|
||||
}
|
||||
slprintf(fnametmp,MAXPATHLEN, "%s/.%s.XXXXXX",tmpdir,f);
|
||||
snprintf(fnametmp,MAXPATHLEN, "%s/.%s.XXXXXX",tmpdir,f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -185,11 +192,11 @@ static int get_tmpname(char *fnametmp, char *fname)
|
||||
|
||||
if (f) {
|
||||
*f = 0;
|
||||
slprintf(fnametmp,MAXPATHLEN,"%s/.%s.XXXXXX",
|
||||
snprintf(fnametmp,MAXPATHLEN,"%s/.%s.XXXXXX",
|
||||
fname,f+1);
|
||||
*f = '/';
|
||||
} else {
|
||||
slprintf(fnametmp,MAXPATHLEN,".%s.XXXXXX",fname);
|
||||
snprintf(fnametmp,MAXPATHLEN,".%s.XXXXXX",fname);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -199,7 +206,8 @@ static int get_tmpname(char *fnametmp, char *fname)
|
||||
static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname,
|
||||
OFF_T total_size)
|
||||
{
|
||||
int i,n,remainder,len,count;
|
||||
int i;
|
||||
unsigned int n,remainder,len,count;
|
||||
OFF_T offset = 0;
|
||||
OFF_T offset2;
|
||||
char *data;
|
||||
@@ -221,8 +229,8 @@ static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname,
|
||||
extern int cleanup_got_literal;
|
||||
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO,"data recv %d at %d\n",
|
||||
i,(int)offset);
|
||||
rprintf(FINFO,"data recv %d at %.0f\n",
|
||||
i,(double)offset);
|
||||
}
|
||||
|
||||
stats.literal_data += i;
|
||||
@@ -239,23 +247,25 @@ static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname,
|
||||
}
|
||||
|
||||
i = -(i+1);
|
||||
offset2 = i*n;
|
||||
offset2 = i*(OFF_T)n;
|
||||
len = n;
|
||||
if (i == count-1 && remainder != 0)
|
||||
if (i == (int) count-1 && remainder != 0)
|
||||
len = remainder;
|
||||
|
||||
stats.matched_data += len;
|
||||
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO,"chunk[%d] of size %d at %d offset=%d\n",
|
||||
i,len,(int)offset2,(int)offset);
|
||||
rprintf(FINFO,"chunk[%d] of size %d at %.0f offset=%.0f\n",
|
||||
i,len,(double)offset2,(double)offset);
|
||||
|
||||
map = map_ptr(buf,offset2,len);
|
||||
if (buf) {
|
||||
map = map_ptr(buf,offset2,len);
|
||||
|
||||
see_token(map, len);
|
||||
sum_update(map,len);
|
||||
see_token(map, len);
|
||||
sum_update(map,len);
|
||||
}
|
||||
|
||||
if (fd != -1 && write_file(fd,map,len) != len) {
|
||||
if (fd != -1 && write_file(fd,map,len) != (int) len) {
|
||||
rprintf(FERROR,"write failed on %s : %s\n",
|
||||
fname,strerror(errno));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
@@ -263,7 +273,7 @@ static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname,
|
||||
offset += len;
|
||||
}
|
||||
|
||||
end_progress();
|
||||
end_progress(total_size);
|
||||
|
||||
if (fd != -1 && offset > 0 && sparse_end(fd) != 0) {
|
||||
rprintf(FERROR,"write failed on %s : %s\n",
|
||||
@@ -287,12 +297,16 @@ static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname,
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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 template[MAXPATHLEN];
|
||||
char fnametmp[MAXPATHLEN];
|
||||
char *fnamecmp;
|
||||
char fnamecmpbuf[MAXPATHLEN];
|
||||
@@ -302,16 +316,15 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
|
||||
int phase=0;
|
||||
int recv_ok;
|
||||
extern struct stats stats;
|
||||
extern int preserve_perms;
|
||||
extern int delete_after;
|
||||
extern int orig_umask;
|
||||
struct stats initial_stats;
|
||||
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO,"recv_files(%d) starting\n",flist->count);
|
||||
}
|
||||
|
||||
if (recurse && delete_mode && !local_name && flist->count>0) {
|
||||
delete_files(flist);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
cleanup_disable();
|
||||
|
||||
@@ -358,14 +371,14 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
|
||||
fnamecmp = fname;
|
||||
|
||||
/* open the file */
|
||||
fd1 = open(fnamecmp,O_RDONLY);
|
||||
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",
|
||||
snprintf(fnamecmpbuf,MAXPATHLEN,"%s/%s",
|
||||
compare_dest,fname);
|
||||
fnamecmp = fnamecmpbuf;
|
||||
fd1 = open(fnamecmp,O_RDONLY);
|
||||
fd1 = do_open(fnamecmp, O_RDONLY, 0);
|
||||
}
|
||||
|
||||
if (fd1 != -1 && do_fstat(fd1,&st) != 0) {
|
||||
@@ -382,10 +395,17 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
|
||||
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 %d\n",fnamecmp,(int)st.st_size);
|
||||
rprintf(FINFO,"recv mapped %s of size %.0f\n",fnamecmp,(double)st.st_size);
|
||||
} else {
|
||||
buf = NULL;
|
||||
}
|
||||
@@ -396,17 +416,7 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
|
||||
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;
|
||||
}
|
||||
strlcpy(template, fnametmp, sizeof(template));
|
||||
|
||||
/* we initially set the perms without the
|
||||
setuid/setgid bits to ensure that there is no race
|
||||
@@ -414,19 +424,18 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
|
||||
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);
|
||||
fd2 = do_mkstemp(fnametmp, 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);
|
||||
create_directory_path(fnametmp, orig_umask) == 0) {
|
||||
strlcpy(fnametmp, template, sizeof(fnametmp));
|
||||
fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
|
||||
}
|
||||
if (fd2 == -1) {
|
||||
rprintf(FERROR,"cannot create %s : %s\n",fnametmp,strerror(errno));
|
||||
rprintf(FERROR,"mkstemp %s failed: %s\n",fnametmp,strerror(errno));
|
||||
receive_data(f_in,buf,-1,NULL,file->length);
|
||||
if (buf) unmap_file(buf);
|
||||
if (fd1 != -1) close(fd1);
|
||||
@@ -456,7 +465,7 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
|
||||
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",
|
||||
@@ -469,8 +478,14 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
|
||||
}
|
||||
}
|
||||
|
||||
if (delete_after) {
|
||||
if (recurse && delete_mode && !local_name && flist->count>0) {
|
||||
delete_files(flist);
|
||||
}
|
||||
}
|
||||
|
||||
if (preserve_hard_links)
|
||||
do_hard_links(flist);
|
||||
do_hard_links();
|
||||
|
||||
/* now we need to fix any directory permissions that were
|
||||
modified during the transfer */
|
||||
|
||||
59
rsync.c
59
rsync.c
@@ -30,7 +30,6 @@ extern int preserve_uid;
|
||||
extern int preserve_gid;
|
||||
extern int preserve_perms;
|
||||
extern int make_backups;
|
||||
extern char *backup_suffix;
|
||||
|
||||
|
||||
/*
|
||||
@@ -44,7 +43,7 @@ void free_sums(struct sum_struct *s)
|
||||
|
||||
|
||||
/*
|
||||
* delete a file or directory. If force_delet is set then delete
|
||||
* delete a file or directory. If force_delete is set then delete
|
||||
* recursively
|
||||
*/
|
||||
int delete_file(char *fname)
|
||||
@@ -57,34 +56,32 @@ int delete_file(char *fname)
|
||||
int ret;
|
||||
extern int recurse;
|
||||
|
||||
if (robust_unlink(fname) == 0 || errno == ENOENT) return 0;
|
||||
|
||||
#if SUPPORT_LINKS
|
||||
ret = do_lstat(fname, &st);
|
||||
#else
|
||||
ret = do_stat(fname, &st);
|
||||
#endif
|
||||
if (ret) {
|
||||
rprintf(FERROR,"stat(%s) : %s\n", fname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!S_ISDIR(st.st_mode)) {
|
||||
rprintf(FERROR,"unlink(%s) : %s\n", fname, strerror(errno));
|
||||
if (robust_unlink(fname) == 0 || errno == ENOENT) return 0;
|
||||
rprintf(FERROR,"delete_file: unlink(%s) : %s\n", fname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (do_rmdir(fname) == 0 || errno == ENOENT) return 0;
|
||||
if (!force_delete || !recurse ||
|
||||
(errno != ENOTEMPTY && errno != EEXIST)) {
|
||||
rprintf(FERROR,"rmdir(%s) : %s\n", fname, strerror(errno));
|
||||
rprintf(FERROR,"delete_file: rmdir(%s) : %s\n", fname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* now we do a recsursive delete on the directory ... */
|
||||
d = opendir(fname);
|
||||
if (!d) {
|
||||
rprintf(FERROR,"opendir(%s): %s\n",
|
||||
rprintf(FERROR,"delete_file: opendir(%s): %s\n",
|
||||
fname,strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
@@ -94,7 +91,7 @@ int delete_file(char *fname)
|
||||
if (strcmp(dname,".")==0 ||
|
||||
strcmp(dname,"..")==0)
|
||||
continue;
|
||||
slprintf(buf, sizeof(buf), "%s/%s", fname, dname);
|
||||
snprintf(buf, sizeof(buf), "%s/%s", fname, dname);
|
||||
if (verbose > 0)
|
||||
rprintf(FINFO,"deleting %s\n", buf);
|
||||
if (delete_file(buf) != 0) {
|
||||
@@ -106,7 +103,7 @@ int delete_file(char *fname)
|
||||
closedir(d);
|
||||
|
||||
if (do_rmdir(fname) != 0) {
|
||||
rprintf(FERROR,"rmdir(%s) : %s\n", fname, strerror(errno));
|
||||
rprintf(FERROR,"delete_file: rmdir(%s) : %s\n", fname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -153,7 +150,6 @@ int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
|
||||
int updated = 0;
|
||||
STRUCT_STAT st2;
|
||||
int change_uid, change_gid;
|
||||
extern int am_daemon;
|
||||
|
||||
if (dry_run) return 0;
|
||||
|
||||
@@ -166,7 +162,7 @@ int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
|
||||
}
|
||||
|
||||
if (preserve_times && !S_ISLNK(st->st_mode) &&
|
||||
st->st_mtime != file->modtime) {
|
||||
cmp_modtime(st->st_mtime, file->modtime) != 0) {
|
||||
/* don't complain about not setting times on directories
|
||||
because some filesystems can't do it */
|
||||
if (set_modtime(fname,file->modtime) != 0 &&
|
||||
@@ -180,7 +176,7 @@ int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
|
||||
}
|
||||
|
||||
change_uid = am_root && preserve_uid && st->st_uid != file->uid;
|
||||
change_gid = !am_daemon && preserve_gid && file->gid != (gid_t) -1 && \
|
||||
change_gid = preserve_gid && file->gid != (gid_t) -1 && \
|
||||
st->st_gid != file->gid;
|
||||
if (change_gid && !am_root) {
|
||||
/* enforce bsd-style group semantics: non-root can only
|
||||
@@ -196,19 +192,20 @@ int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
|
||||
rprintf(FERROR,"chown %s : %s\n", fname,strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
/* a lchown had been done - we have to re-stat if the
|
||||
destination had the setuid or setgid bits set due
|
||||
to the side effect of the chown call */
|
||||
if (st->st_mode & (S_ISUID | S_ISGID)) {
|
||||
link_stat(fname, st);
|
||||
}
|
||||
updated = 1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_CHMOD
|
||||
if (!S_ISLNK(st->st_mode)) {
|
||||
int file_mode;
|
||||
if (preserve_perms)
|
||||
file_mode = file->mode;
|
||||
else
|
||||
file_mode = file->mode & ACCESSPERMS;
|
||||
if (st->st_mode != file->mode) {
|
||||
updated = 1;
|
||||
if (do_chmod(fname,file_mode) != 0) {
|
||||
if (do_chmod(fname,file->mode) != 0) {
|
||||
rprintf(FERROR,"failed to set permissions on %s : %s\n",
|
||||
fname,strerror(errno));
|
||||
return 0;
|
||||
@@ -232,27 +229,6 @@ void sig_int(void)
|
||||
exit_cleanup(RERR_SIGNAL);
|
||||
}
|
||||
|
||||
int make_backup(char *fname)
|
||||
{
|
||||
char fnamebak[MAXPATHLEN];
|
||||
if (strlen(fname) + strlen(backup_suffix) > (MAXPATHLEN-1)) {
|
||||
rprintf(FERROR,"backup filename too long\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
slprintf(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) {
|
||||
rprintf(FERROR,"rename %s %s : %s\n",fname,fnamebak,strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
} else if (verbose > 1) {
|
||||
rprintf(FINFO,"backed up %s to %s\n",fname,fnamebak);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* finish off a file transfer, renaming the file and setting the permissions
|
||||
and ownership */
|
||||
@@ -281,6 +257,3 @@ void finish_transfer(char *fname, char *fnametmp, struct file_struct *file)
|
||||
set_perms(fname,file,NULL,0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
223
rsync.h
223
rsync.h
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
Copyright (C) Andrew Tridgell 1996
|
||||
Copyright (C) by Andrew Tridgell 1996, 2000
|
||||
Copyright (C) Paul Mackerras 1996
|
||||
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
|
||||
@@ -17,6 +18,7 @@
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
|
||||
#define False 0
|
||||
#define True 1
|
||||
|
||||
@@ -24,7 +26,8 @@
|
||||
#define RSYNC_RSH_ENV "RSYNC_RSH"
|
||||
|
||||
#define RSYNC_NAME "rsync"
|
||||
#define RSYNCD_CONF "/etc/rsyncd.conf"
|
||||
#define RSYNCD_SYSCONF "/etc/rsyncd.conf"
|
||||
#define RSYNCD_USERCONF "rsyncd.conf"
|
||||
|
||||
#define DEFAULT_LOCK_FILE "/var/run/rsyncd.lock"
|
||||
#define URL_PREFIX "rsync://"
|
||||
@@ -47,8 +50,19 @@
|
||||
#define SAME_TIME (1<<7)
|
||||
|
||||
/* update this if you make incompatible changes */
|
||||
#define PROTOCOL_VERSION 20
|
||||
#define MIN_PROTOCOL_VERSION 11
|
||||
#define PROTOCOL_VERSION 26
|
||||
|
||||
/* We refuse to interoperate with versions that are not in this range.
|
||||
* Note that we assume we'll work with later versions: the onus is on
|
||||
* people writing them to make sure that they don't send us anything
|
||||
* we won't understand.
|
||||
*
|
||||
* There are two possible explanations for the limit at thirty: either
|
||||
* to allow new major-rev versions that do not interoperate with us,
|
||||
* and (more likely) so that we can detect an attempt to connect rsync
|
||||
* to a non-rsync server, which is unlikely to begin by sending a byte
|
||||
* between 15 and 30. */
|
||||
#define MIN_PROTOCOL_VERSION 15
|
||||
#define MAX_PROTOCOL_VERSION 30
|
||||
|
||||
#define RSYNC_PORT 873
|
||||
@@ -58,33 +72,26 @@
|
||||
#define CHUNK_SIZE (32*1024)
|
||||
#define MAX_MAP_SIZE (256*1024)
|
||||
#define IO_BUFFER_SIZE (4092)
|
||||
#define MAX_READ_BUFFER (1024*1024)
|
||||
|
||||
#define MAX_ARGS 1000
|
||||
|
||||
#define MPLEX_BASE 7
|
||||
#define FERROR 1
|
||||
#define FINFO 2
|
||||
#define FLOG 3
|
||||
|
||||
/* Log values. I *think* what these mean is: FLOG goes to the server
|
||||
* logfile; FERROR and FINFO try to end up on the client, with
|
||||
* different levels of filtering. */
|
||||
enum logcode {FNONE=0, FERROR=1, FINFO=2, FLOG=3 };
|
||||
|
||||
#include "errcode.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if HAVE_REMSH
|
||||
#define RSYNC_RSH "remsh"
|
||||
#else
|
||||
#define RSYNC_RSH "rsh"
|
||||
#endif
|
||||
/* The default RSYNC_RSH is always set in config.h, either to "remsh",
|
||||
* "rsh", or otherwise something specified by the user. HAVE_REMSH
|
||||
* controls parameter munging for HP/UX, etc. */
|
||||
|
||||
#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
|
||||
@@ -177,6 +184,10 @@
|
||||
#include <glob.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MALLOC_H
|
||||
# include <malloc.h>
|
||||
#endif
|
||||
|
||||
/* these are needed for the uid/gid mapping code */
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
@@ -207,6 +218,8 @@
|
||||
#include <compat.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
#define BOOL int
|
||||
|
||||
@@ -255,15 +268,44 @@
|
||||
#elif HAVE_LONGLONG
|
||||
#define int64 long long
|
||||
#else
|
||||
/* As long as it gets... */
|
||||
#define int64 off_t
|
||||
#define NO_INT64
|
||||
#endif
|
||||
|
||||
#if HAVE_SHORT_INO_T
|
||||
#define INO_T uint32
|
||||
#else
|
||||
#define INO_T ino_t
|
||||
#endif
|
||||
/* Starting from protocol version 26, we always use 64-bit
|
||||
* ino_t and dev_t internally, even if this platform does not
|
||||
* allow files to have 64-bit inums. That's because the
|
||||
* receiver needs to find duplicate (dev,ino) tuples to detect
|
||||
* hardlinks, and it might have files coming from a platform
|
||||
* that has 64-bit inums.
|
||||
*
|
||||
* The only exception is if we're on a platform with no 64-bit type at
|
||||
* all.
|
||||
*
|
||||
* Because we use read_longint() to get these off the wire, if you
|
||||
* transfer devices or hardlinks with dev or inum > 2**32 to a machine
|
||||
* with no 64-bit types then you will get an overflow error. Probably
|
||||
* not many people have that combination of machines, and you can
|
||||
* avoid it by not preserving hardlinks or not transferring device
|
||||
* nodes. It's not clear that any other behaviour is better.
|
||||
*
|
||||
* Note that if you transfer devices from a 64-bit-devt machine (say,
|
||||
* Solaris) to a 32-bit-devt machine (say, Linux-2.2/x86) then the
|
||||
* device numbers will be truncated. But it's a kind of silly thing
|
||||
* to do anyhow.
|
||||
*
|
||||
* FIXME: In future, we should probable split the device number into
|
||||
* major/minor, and transfer the two parts as 32-bit ints. That gives
|
||||
* you somewhat more of a chance that they'll come from a big machine
|
||||
* to a little one in a useful way.
|
||||
*
|
||||
* FIXME: Really we need an unsigned type, and we perhaps ought to
|
||||
* cope with platforms on which this is an unsigned int or even a
|
||||
* struct. Later.
|
||||
*/
|
||||
#define INO64_T int64
|
||||
#define DEV64_T int64
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||
@@ -289,14 +331,22 @@
|
||||
#define INADDR_NONE 0xffffffff
|
||||
#endif
|
||||
|
||||
#ifndef IN_LOOPBACKNET
|
||||
#define IN_LOOPBACKNET 127
|
||||
#endif
|
||||
|
||||
struct file_struct {
|
||||
unsigned flags;
|
||||
time_t modtime;
|
||||
OFF_T length;
|
||||
mode_t mode;
|
||||
INO_T inode;
|
||||
dev_t dev;
|
||||
dev_t rdev;
|
||||
|
||||
INO64_T inode;
|
||||
/** Device this file lives upon */
|
||||
DEV64_T dev;
|
||||
|
||||
/** If this is a device node, the device number. */
|
||||
DEV64_T rdev;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
char *basename;
|
||||
@@ -307,26 +357,36 @@ struct file_struct {
|
||||
};
|
||||
|
||||
|
||||
#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 */
|
||||
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 */
|
||||
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 {
|
||||
@@ -336,7 +396,6 @@ struct map_struct {
|
||||
};
|
||||
|
||||
struct exclude_struct {
|
||||
char *orig;
|
||||
char *pattern;
|
||||
int regular_exp;
|
||||
int fnmatch_flags;
|
||||
@@ -368,9 +427,29 @@ static inline int flist_up(struct file_list *flist, int i)
|
||||
}
|
||||
|
||||
#include "byteorder.h"
|
||||
#include "version.h"
|
||||
#include "proto.h"
|
||||
#include "lib/mdfour.h"
|
||||
#include "lib/permstring.h"
|
||||
#include "lib/addrinfo.h"
|
||||
|
||||
#include "proto.h"
|
||||
|
||||
/* We have replacement versions of these if they're missing. */
|
||||
#ifndef HAVE_ASPRINTF
|
||||
int asprintf(char **ptr, const char *format, ...);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_VASPRINTF
|
||||
int vasprintf(char **ptr, const char *format, va_list ap);
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_VSNPRINTF) && !defined(HAVE_C99_VSNPRINTF)
|
||||
int vsnprintf (char *str, size_t count, const char *fmt, va_list args);
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_SNPRINTF) && !defined(HAVE_C99_VSNPRINTF)
|
||||
int snprintf(char *str,size_t count,const char *fmt,...);
|
||||
#endif
|
||||
|
||||
|
||||
#if !HAVE_STRERROR
|
||||
extern char *sys_errlist[];
|
||||
@@ -389,6 +468,9 @@ extern int errno;
|
||||
#define SUPPORT_LINKS HAVE_READLINK
|
||||
#define SUPPORT_HARD_LINKS HAVE_LINK
|
||||
|
||||
/* This could be bad on systems which have no lchown and where chown
|
||||
* follows symbollic links. On such systems it might be better not to
|
||||
* try to chown symlinks at all. */
|
||||
#ifndef HAVE_LCHOWN
|
||||
#define lchown chown
|
||||
#endif
|
||||
@@ -459,6 +541,22 @@ extern int errno;
|
||||
#define S_ISREG(mode) (((mode) & (_S_IFMT)) == (_S_IFREG))
|
||||
#endif
|
||||
|
||||
/* 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
|
||||
|
||||
#ifndef INADDR_LOOPBACK
|
||||
#define INADDR_LOOPBACK 0x7f000001
|
||||
#endif
|
||||
|
||||
#ifndef INADDR_NONE
|
||||
#define INADDR_NONE 0xffffffff
|
||||
#endif
|
||||
|
||||
#define IS_DEVICE(mode) (S_ISCHR(mode) || S_ISBLK(mode) || S_ISSOCK(mode) || S_ISFIFO(mode))
|
||||
|
||||
@@ -473,13 +571,26 @@ extern int errno;
|
||||
/* handler for null strings in printf format */
|
||||
#define NS(s) ((s)?(s):"<NULL>")
|
||||
|
||||
/* use magic gcc attributes to catch format errors */
|
||||
void rprintf(int , const char *, ...)
|
||||
#ifdef __GNUC__
|
||||
__attribute__ ((format (printf, 2, 3)))
|
||||
#if !defined(__GNUC__) || defined(APPLE)
|
||||
/* Apparently the OS X port of gcc gags on __attribute__.
|
||||
*
|
||||
* <http://www.opensource.apple.com/bugs/X/gcc/2512150.html> */
|
||||
#define __attribute__(x)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* use magic gcc attributes to catch format errors */
|
||||
void rprintf(enum logcode , const char *, ...)
|
||||
__attribute__((format (printf, 2, 3)))
|
||||
;
|
||||
|
||||
/* This is just like rprintf, but it also tries to print some
|
||||
* representation of the error code. Normally errcode = errno. */
|
||||
void rsyserr(enum logcode, int, const char *, ...)
|
||||
__attribute__((format (printf, 3, 4)))
|
||||
;
|
||||
|
||||
#ifdef REPLACE_INET_NTOA
|
||||
#define inet_ntoa rep_inet_ntoa
|
||||
#endif
|
||||
@@ -493,4 +604,28 @@ size_t strlcpy(char *d, const char *s, size_t bufsize);
|
||||
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__)
|
||||
|
||||
|
||||
extern int verbose;
|
||||
|
||||
#ifndef HAVE_INET_NTOP
|
||||
const char *
|
||||
inet_ntop(int af, const void *src, char *dst, size_t size);
|
||||
#endif /* !HAVE_INET_NTOP */
|
||||
|
||||
#ifndef HAVE_INET_PTON
|
||||
int inet_pton(int af, const char *src, void *dst);
|
||||
#endif
|
||||
|
||||
#ifdef MAINTAINER_MODE
|
||||
const char *get_panic_action(void);
|
||||
#endif
|
||||
|
||||
#define UNUSED(x) x __attribute__((__unused__))
|
||||
|
||||
extern const char *io_write_phase, *io_read_phase;
|
||||
|
||||
640
rsync.yo
640
rsync.yo
@@ -1,5 +1,5 @@
|
||||
mailto(rsync-bugs@samba.org)
|
||||
manpage(rsync)(1)(1 Mar 1999)()()
|
||||
manpage(rsync)(1)(26 Jan 2003)()()
|
||||
manpagename(rsync)(faster, flexible replacement for rcp)
|
||||
manpagesynopsis()
|
||||
|
||||
@@ -15,11 +15,13 @@ rsync [OPTION]... SRC [SRC]... [USER@]HOST::DEST
|
||||
|
||||
rsync [OPTION]... rsync://[USER@]HOST[:PORT]/SRC [DEST]
|
||||
|
||||
rsync [OPTION]... SRC [SRC]... rsync://[USER@]HOST[:PORT]/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 speedup file transfers when the destination file already
|
||||
greatly speed up file transfers when the destination file already
|
||||
exists.
|
||||
|
||||
The rsync remote-update protocol allows rsync to transfer just the
|
||||
@@ -42,7 +44,7 @@ itemize(
|
||||
|
||||
manpagesection(GENERAL)
|
||||
|
||||
There are six different ways of using rsync. They are:
|
||||
There are eight different ways of using rsync. They are:
|
||||
|
||||
itemize(
|
||||
it() for copying local files. This is invoked when neither
|
||||
@@ -63,7 +65,19 @@ itemize(
|
||||
|
||||
it() for copying from the local machine to a remote rsync
|
||||
server. This is invoked when the destination path contains a ::
|
||||
separator.
|
||||
separator or a rsync:// URL.
|
||||
|
||||
it() for copying from a remote machine using a remote shell
|
||||
program as the transport, using rsync server on the remote
|
||||
machine. This is invoked when the source path contains a ::
|
||||
separator and the --rsh=COMMAND (aka "-e COMMAND") option is
|
||||
also provided.
|
||||
|
||||
it() for copying from the local machine to a remote machine
|
||||
using a remote shell program as the transport, using rsync
|
||||
server on the remote machine. This is invoked when the
|
||||
destination path contains a :: separator and the
|
||||
--rsh=COMMMAND option is also provided.
|
||||
|
||||
it() for listing files on a remote machine. This is done the
|
||||
same way as rsync transfers except that you leave off the
|
||||
@@ -77,11 +91,13 @@ 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.
|
||||
Once installed, you can use rsync to any machine that you can access via
|
||||
a remote shell (as well as some that you can access using the rsync
|
||||
daemon-mode protocol). For remote transfers, rsync typically uses rsh
|
||||
for its communications, but it may have been configured to use a
|
||||
different remote shell by default, such as ssh.
|
||||
|
||||
You can also specify an alternative to rsh, by either using the -e
|
||||
You can also specify any remote shell you like, 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
|
||||
@@ -135,16 +151,21 @@ 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
|
||||
It is also possible to use rsync without a remote shell as the
|
||||
transport. In this case you will connect to a remote rsync server
|
||||
running on TCP port 873.
|
||||
|
||||
Using rsync in this way is the same as using it with rsh or ssh except
|
||||
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 a remote shell except
|
||||
that:
|
||||
|
||||
itemize(
|
||||
it() you use a double colon :: instead of a single colon to
|
||||
separate the hostname from the path.
|
||||
separate the hostname from the path or a rsync:// URL.
|
||||
|
||||
it() the remote server may print a message of the day when you
|
||||
connect.
|
||||
@@ -165,11 +186,61 @@ 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(CONNECTING TO AN RSYNC SERVER OVER A REMOTE SHELL PROGRAM)
|
||||
|
||||
It is sometimes useful to be able to set up file transfers using rsync
|
||||
server capabilities on the remote machine, while still using rsh or
|
||||
ssh for transport. This is especially useful when you want to connect
|
||||
to a remote machine via ssh (for encryption or to get through a
|
||||
firewall), but you still want to have access to the rsync server
|
||||
features (see RUNNING AN RSYNC SERVER OVER A REMOTE SHELL PROGRAM,
|
||||
below).
|
||||
|
||||
From the user's perspective, using rsync in this way is the same as
|
||||
using it to connect to an rsync server, except that you must
|
||||
explicitly set the remote shell program on the command line with
|
||||
--rsh=COMMAND. (Setting RSYNC_RSH in the environment will not turn on
|
||||
this functionality.)
|
||||
|
||||
In order to distinguish between the remote-shell user and the rsync
|
||||
server user, you can use '-l user' on your remote-shell command:
|
||||
|
||||
quote(rsync -av --rsh="ssh -l ssh-user" rsync-user@host::module[/path] local-path)
|
||||
|
||||
The "ssh-user" will be used at the ssh level; the "rsync-user" will be
|
||||
used to check against the rsyncd.conf on the remote host.
|
||||
|
||||
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.
|
||||
An rsync server is configured using a config file. Please see the
|
||||
rsyncd.conf(5) man page for more information. By default the configuration
|
||||
file is called /etc/rsyncd.conf, unless rsync is running over a remote
|
||||
shell program and is not running as root; in that case, the default name
|
||||
is rsyncd.conf in the current directory on the remote computer
|
||||
(typically $HOME).
|
||||
|
||||
manpagesection(RUNNING AN RSYNC SERVER OVER A REMOTE SHELL PROGRAM)
|
||||
|
||||
See the rsyncd.conf(5) man page for full information on the rsync
|
||||
server configuration file.
|
||||
|
||||
Several configuration options will not be available unless the remote
|
||||
user is root (e.g. chroot, setuid/setgid, etc.). There is no need to
|
||||
configure inetd or the services map to include the rsync server port
|
||||
if you run an rsync server only via a remote shell program.
|
||||
|
||||
To run an rsync server out of a single-use ssh key, use the
|
||||
"command=em(COMMAND)" syntax in the remote user's
|
||||
authorized_keys entry, where command would be
|
||||
|
||||
quote(rsync --server --daemon .)
|
||||
|
||||
NOTE: rsync's argument parsing expects the trailing ".", so make sure
|
||||
that it's there. If you want to use a rsyncd.conf(5)-style
|
||||
configuration file other than the default, you can added a
|
||||
--config option to the em(command):
|
||||
|
||||
quote(rsync --server --daemon --config=em(file) .)
|
||||
|
||||
manpagesection(EXAMPLES)
|
||||
|
||||
@@ -211,28 +282,18 @@ Here is a short summary of the options available in rsync. Please refer
|
||||
to the detailed description below for a complete description.
|
||||
|
||||
verb(
|
||||
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
|
||||
-a, --archive archive mode, equivalent to -rlptgoD
|
||||
-r, --recursive recurse into directories
|
||||
-R, --relative use relative path names
|
||||
-b, --backup make backups (default ~ suffix)
|
||||
--suffix=SUFFIX override backup suffix
|
||||
--backup-dir make backups into this directory
|
||||
--suffix=SUFFIX define 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
|
||||
-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
|
||||
@@ -244,21 +305,30 @@ Options
|
||||
-S, --sparse handle sparse files efficiently
|
||||
-n, --dry-run show what would have been transferred
|
||||
-W, --whole-file copy whole files, no incremental checks
|
||||
--no-whole-file turn off --whole-file
|
||||
-x, --one-file-system don't cross filesystem boundaries
|
||||
-B, --block-size=SIZE checksum blocking size (default 700)
|
||||
-e, --rsh=COMMAND specify rsh replacement
|
||||
-e, --rsh=COMMAND specify the remote shell to use
|
||||
--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
|
||||
--ignore-existing ignore files that already exist on the receiving side
|
||||
--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
|
||||
--link-dest=DIR create hardlinks to DIR for unchanged files
|
||||
-P equivalent to --partial --progress
|
||||
-z, --compress compress file data
|
||||
--exclude=PATTERN exclude files matching PATTERN
|
||||
--exclude-from=FILE exclude patterns listed in FILE
|
||||
@@ -266,13 +336,22 @@ Options
|
||||
--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
|
||||
--no-blocking-io turn off --blocking-io
|
||||
--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=PREFIX read batch fileset starting with PREFIX
|
||||
--write-batch=PREFIX write batch fileset starting with PREFIX
|
||||
-h, --help show this help screen
|
||||
|
||||
|
||||
)
|
||||
|
||||
manpageoptions()
|
||||
@@ -306,24 +385,33 @@ 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(-I, --size-only)) Normally rsync will skip any files that are
|
||||
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 Windows FAT filesystems which cannot represent times
|
||||
with a 1 second resolution --modify-window=1 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 -rlptg. It is a quick way
|
||||
of saying you want recursion and want to preserve everything.
|
||||
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: if the user launching rsync is root then the -o (preserve
|
||||
uid) and -D (preserve devices) options are also implied.
|
||||
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
|
||||
@@ -349,24 +437,32 @@ 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. You can additionally
|
||||
specify a backup suffix using the --suffix option
|
||||
(otherwise the files backed up in the specified directory
|
||||
will keep their original filenames).
|
||||
|
||||
dit(bf(--suffix=SUFFIX)) This option allows you to override the default
|
||||
backup suffix used with the -b option. The default is a ~.
|
||||
If --backup-dir and --suffix are both specified,
|
||||
the SUFFIX is appended to the filename even in the backup directory.
|
||||
|
||||
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)) This tells rsync to recreate symbolic links on the
|
||||
remote system to be the same as the local system. Without this
|
||||
option, all symbolic links are skipped.
|
||||
dit(bf(-l, --links)) When symlinks are encountered, recreate the
|
||||
symlink on the destination.
|
||||
|
||||
dit(bf(-L, --copy-links)) This tells rsync to treat symbolic links just
|
||||
like ordinary files.
|
||||
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 treat symbolic links that
|
||||
point outside the source tree like ordinary files. Absolute symlinks are
|
||||
also treated like ordinary files, and so are any symlinks in the source
|
||||
path itself when --relative is used.
|
||||
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
|
||||
@@ -383,28 +479,29 @@ 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. This may be
|
||||
useful when using rsync with a local machine.
|
||||
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(--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(--no-whole-file)) Turn off --whole-file, for use when it is the
|
||||
default.
|
||||
|
||||
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 update the remote owner
|
||||
of the file to be the same as the local owner. This is only available
|
||||
to the super-user. Note that if the source system is a daemon using chroot,
|
||||
the --numeric-ids option is implied because the source system cannot get
|
||||
access to the usernames.
|
||||
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. Note that if the remote system
|
||||
is a daemon using chroot, the --numeric-ids option is implied because the
|
||||
remote system cannot get access to the usernames from /etc/passwd.
|
||||
|
||||
dit(bf(-g, --group)) This option causes rsync to update the remote group
|
||||
of the file to be the same as the local group. If the receving system 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(-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
|
||||
@@ -432,6 +529,17 @@ 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(--ignore-existing))
|
||||
This tells rsync not to 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.
|
||||
@@ -442,46 +550,62 @@ 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.
|
||||
|
||||
rsync 1.6.4 changed the behavior of --delete to make it less
|
||||
dangerous. rsync now only scans directories on the receiving side
|
||||
that are explicitly transferred from the sending side. Only files in
|
||||
these directories are deleted.
|
||||
|
||||
Still, it is probably easy to get burnt with this option. The moral
|
||||
of the story is to use the -n option until you get used to the
|
||||
behavior of --delete.
|
||||
|
||||
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.
|
||||
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).
|
||||
Implies --delete.
|
||||
|
||||
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. Implies --delete.
|
||||
|
||||
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.
|
||||
they are not empty when they are to be replaced by non-directories. This
|
||||
is only relevant without --delete because deletions are now done depth-first.
|
||||
Requires the --recursive option (which is implied by -a) to have any effect.
|
||||
|
||||
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
|
||||
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.
|
||||
remote copies of rsync. Typically, rsync is configured to use rsh by
|
||||
default, but you may prefer to use ssh because of its high security.
|
||||
|
||||
If this option is used with bf([user@]host::module/path), then the
|
||||
remote shell em(COMMMAND) will be used to run an rsync server on the
|
||||
remote host, and all data will be transmitted through that remote
|
||||
shell connection, rather than through a direct socket connection to a
|
||||
running rsync server on the remote host. See the section "CONNECTING
|
||||
TO AN RSYNC SERVER OVER A REMOTE SHELL PROGRAM" above.
|
||||
|
||||
Command-line arguments are permitted in COMMAND provided that COMMAND is
|
||||
presented to rsync as a single argument. For example:
|
||||
|
||||
quote(-e "ssh -p 2234")
|
||||
|
||||
(Note that ssh users can alternately customize site-specific connect
|
||||
options in their .ssh/config file.)
|
||||
|
||||
You can also choose the remote shell program using the RSYNC_RSH
|
||||
environment variable.
|
||||
environment variable, which accepts the same range of values as -e.
|
||||
|
||||
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.
|
||||
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
|
||||
@@ -494,9 +618,11 @@ 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 filenames listed in the file FILE to
|
||||
the exclude list. Blank lines in FILE and lines starting with ';' or '#'
|
||||
are ignored.
|
||||
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.
|
||||
If em(FILE) is bf(-) the list will be read from standard input.
|
||||
|
||||
|
||||
dit(bf(--include=PATTERN)) This option tells rsync to not exclude the
|
||||
specified pattern of filenames. This is useful as it allows you to
|
||||
@@ -507,6 +633,8 @@ this option.
|
||||
|
||||
dit(bf(--include-from=FILE)) This specifies a list of include patterns
|
||||
from a file.
|
||||
If em(FILE) is bf(-) the list will be read from standard input.
|
||||
|
||||
|
||||
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
|
||||
@@ -515,15 +643,16 @@ a file should be ignored.
|
||||
|
||||
The exclude list is initialized to:
|
||||
|
||||
quote(RCS SCCS CVS CVS.adm RCSLOG cvslog.* tags TAGS .make.state
|
||||
quote(RCS/ SCCS/ CVS/ .svn/ 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 in each directory any files listed in the .cvsignore file in
|
||||
that directory are added to the list.
|
||||
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
|
||||
@@ -549,20 +678,26 @@ 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 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(--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 if the files are missing in the
|
||||
destination directory. 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 skips files that haven't changed; see also --link-dest).
|
||||
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(--link-dest=DIR)) This option behaves like bf(--compare-dest) but
|
||||
also will create hard links from em(DIR) to the destination directory for
|
||||
unchanged files. Files with changed ownership or permissions will not be
|
||||
linked.
|
||||
|
||||
dit(bf(-z, --compress)) With this option, rsync compresses any data from
|
||||
the source file(s) which it sends to the destination machine. This
|
||||
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.
|
||||
|
||||
@@ -580,29 +715,59 @@ 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.
|
||||
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 rsync
|
||||
daemon. 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(--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
|
||||
(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.
|
||||
the default. This is only relevant when --daemon is specified.
|
||||
The default is /etc/rsyncd.conf unless the daemon is running over
|
||||
a remote shell program and the remote user is not root; in that case
|
||||
the default is rsyncd.conf in the current directory (typically $HOME).
|
||||
|
||||
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. (Note that ssh prefers
|
||||
non-blocking IO.)
|
||||
|
||||
dit(bf(--no-blocking-io)) Turn off --blocking-io, for use when it is the
|
||||
default.
|
||||
|
||||
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
|
||||
@@ -612,15 +777,45 @@ 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.
|
||||
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(--write-batch=PREFIX)) Generate a set of files that can be
|
||||
transferred as a batch update. Each filename in the set starts with
|
||||
PREFIX. See the "BATCH MODE" section for details.
|
||||
|
||||
dit(bf(--read-batch=PREFIX)) Apply a previously generated change batch,
|
||||
using the fileset whose filenames start with PREFIX. See the "BATCH
|
||||
MODE" section for details.
|
||||
|
||||
enddit()
|
||||
|
||||
@@ -629,22 +824,32 @@ 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 a ordered list of include/exclude options as specified on
|
||||
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 than that file is
|
||||
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 whereas foo would match any file
|
||||
called foo anywhere in the tree.
|
||||
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.
|
||||
@@ -653,12 +858,15 @@ itemize(
|
||||
*?[ 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. Furthermore, if
|
||||
the pattern includes a double asterisk "**" then all wildcards in
|
||||
the pattern will match slashes, otherwise they will stop at slashes.
|
||||
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
|
||||
@@ -669,13 +877,20 @@ itemize(
|
||||
part of an include option. The "- " part is discarded before matching.
|
||||
|
||||
it() if the pattern is a single exclamation mark ! then the current
|
||||
exclude list is reset, removing all previous exclude patterns.
|
||||
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.
|
||||
|
||||
Here are some examples:
|
||||
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
|
||||
@@ -692,6 +907,116 @@ itemize(
|
||||
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.
|
||||
|
||||
Batch mode can be used to apply the same set of updates to many
|
||||
identical systems. Suppose one has a tree which is replicated on a
|
||||
number of hosts. Now suppose some changes have been made to this
|
||||
source tree and those changes need to be propagated to the other
|
||||
hosts. In order to do this using batch mode, rsync is run with the
|
||||
write-batch option to apply the changes made to the source tree to one
|
||||
of the destination trees. The write-batch option causes the rsync
|
||||
client to store the information needed to repeat this operation against
|
||||
other destination trees in a batch update fileset (see below). The
|
||||
filename of each file in the fileset starts with a prefix specified by
|
||||
the user as an argument to the write-batch option. This fileset is
|
||||
then copied to each remote host, where rsync is run with the read-batch
|
||||
option, again specifying the same prefix, and the destination tree.
|
||||
Rsync updates the destination tree using the information stored in the
|
||||
batch update fileset.
|
||||
|
||||
The fileset consists of 4 files:
|
||||
|
||||
itemize(
|
||||
it() bf(<prefix>.rsync_argvs) command-line arguments
|
||||
it() bf(<prefix>.rsync_flist) rsync internal file metadata
|
||||
it() bf(<prefix>.rsync_csums) rsync checksums
|
||||
it() bf(<prefix>.rsync_delta) data blocks for file update & change
|
||||
)
|
||||
|
||||
The .rsync_argvs file contains a command-line suitable for updating a
|
||||
destination tree using that batch update fileset. It can be executed
|
||||
using a Bourne(-like) shell, optionally passing in an alternate
|
||||
destination tree pathname which is then used instead of the original
|
||||
path. This is useful when the destination tree path differs from the
|
||||
original destination tree path.
|
||||
|
||||
Generating the batch update fileset once saves having to perform the
|
||||
file status, checksum and data block generation more than once when
|
||||
updating multiple destination trees. Multicast transport protocols can
|
||||
be used to transfer the batch update files in parallel to many hosts at
|
||||
once, instead of sending the same data to every host individually.
|
||||
|
||||
Example:
|
||||
|
||||
verb(
|
||||
$ rsync --write_batch=pfx -a /source/dir/ /adest/dir/
|
||||
$ rcp pfx.rsync_* remote:
|
||||
$ rsh remote rsync --read_batch=pfx -a /bdest/dir/
|
||||
# or alternatively
|
||||
$ rsh remote ./pfx.rsync_argvs /bdest/dir/
|
||||
)
|
||||
|
||||
In this example, rsync is used to update /adest/dir/ with /source/dir/
|
||||
and the information to repeat this operation is stored in the files
|
||||
pfx.rsync_*. These files are then copied to the machine named "remote".
|
||||
Rsync is then invoked on "remote" to update /bdest/dir/ the same way as
|
||||
/adest/dir/. The last line shows the rsync_argvs file being used to
|
||||
invoke rsync.
|
||||
|
||||
Caveats:
|
||||
|
||||
The read-batch option expects the destination tree it is meant to update
|
||||
to be identical to the destination tree that was used to create the
|
||||
batch update fileset. When a difference between the destination trees
|
||||
is encountered the update will fail at that point, leaving the
|
||||
destination tree in a partially updated state. In that case, rsync can
|
||||
be used in its regular (non-batch) mode of operation to fix up the
|
||||
destination tree.
|
||||
|
||||
The rsync version used on all destinations should be identical to the
|
||||
one used on the original destination.
|
||||
|
||||
The -z/--compress option does not work in batch mode and yields a usage
|
||||
error. A separate compression tool can be used instead to reduce the
|
||||
size of the batch update files for transport to the destination.
|
||||
|
||||
The -n/--dryrun option does not work in batch mode and yields a runtime
|
||||
error.
|
||||
|
||||
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.
|
||||
|
||||
Symbolic links are considered unsafe if they are absolute symlinks
|
||||
(start with bf(/)), empty, or if they contain enough bf("..")
|
||||
components to ascend from the directory being copied.
|
||||
|
||||
manpagesection(DIAGNOSTICS)
|
||||
|
||||
rsync occasionally produces error messages that may seem a little
|
||||
@@ -715,6 +1040,33 @@ 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()
|
||||
@@ -724,8 +1076,12 @@ 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.
|
||||
override the default shell used as the transport for rsync. Command line
|
||||
options are permitted after the command name, just as in 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
|
||||
@@ -742,7 +1098,7 @@ enddit()
|
||||
|
||||
manpagefiles()
|
||||
|
||||
/etc/rsyncd.conf
|
||||
/etc/rsyncd.conf or rsyncd.conf
|
||||
|
||||
manpageseealso()
|
||||
|
||||
@@ -754,16 +1110,17 @@ manpagebugs()
|
||||
|
||||
times are transferred as unix time_t values
|
||||
|
||||
When transferring to FAT filesystmes rsync may resync
|
||||
unmodified files.
|
||||
See the comments on the --modify-window option.
|
||||
|
||||
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
|
||||
Please report bugs! See the website at
|
||||
url(http://rsync.samba.org/)(http://rsync.samba.org/)
|
||||
|
||||
manpagesection(CREDITS)
|
||||
|
||||
@@ -771,7 +1128,9 @@ 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/)
|
||||
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).
|
||||
@@ -784,13 +1143,22 @@ Jean-loup Gailly and Mark Adler.
|
||||
manpagesection(THANKS)
|
||||
|
||||
Thanks to Richard Brent, Brendan Mackay, Bill Waite, Stephen Rothwell
|
||||
and David Bell for helpful suggestions and testing of rsync. I've
|
||||
probably missed some people, my apologies if I have.
|
||||
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 and Paul Mackerras. They may be
|
||||
contacted via email at tridge@samba.org and
|
||||
Paul.Mackerras@cs.anu.edu.au
|
||||
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
469
rsync3.txt
Normal 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§ion=projects
|
||||
|
||||
- BitTorrent -- p2p mirroring
|
||||
http://bitconjurer.org/BitTorrent/
|
||||
158
rsyncd.conf.yo
158
rsyncd.conf.yo
@@ -1,5 +1,5 @@
|
||||
mailto(rsync-bugs@samba.org)
|
||||
manpage(rsyncd.conf)(5)(12 Feb 1999)()()
|
||||
manpage(rsyncd.conf)(5)(26 Jan 2003)()()
|
||||
manpagename(rsyncd.conf)(configuration file for rsync server)
|
||||
manpagesynopsis()
|
||||
|
||||
@@ -8,9 +8,7 @@ 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.
|
||||
run as an rsync server.
|
||||
|
||||
The rsyncd.conf file controls authentication, access, logging and
|
||||
available modules.
|
||||
@@ -44,11 +42,19 @@ 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.
|
||||
rsync.
|
||||
|
||||
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.
|
||||
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, as a stand-alone daemon, or from
|
||||
an rsync client via a remote shell. If run as a stand-alone daemon then
|
||||
just run the command "rsync --daemon" from a suitable startup script.
|
||||
If run from an rsync client via a remote shell (by specifying both the
|
||||
"-e/--rsh" option and server mode with "::" or "rsync://"), the --daemon
|
||||
option is automatically passed to the remote side.
|
||||
|
||||
When run via inetd you should add a line like this to /etc/services:
|
||||
|
||||
@@ -58,11 +64,12 @@ and a single line something like this to /etc/inetd.conf:
|
||||
|
||||
quote(rsync stream tcp nowait root /usr/bin/rsync rsyncd --daemon)
|
||||
|
||||
You will then need to send inetd a HUP signal to tell it to reread its
|
||||
config file.
|
||||
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
|
||||
it to reread the tt(rsyncd.conf) file. The file is re-read on each client
|
||||
connection.
|
||||
|
||||
manpagesection(GLOBAL OPTIONS)
|
||||
@@ -121,25 +128,30 @@ 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).
|
||||
for each module in tt(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.
|
||||
The default is to use chroot.
|
||||
holes, but it has the disadvantages of requiring super-user privileges,
|
||||
of not being able to follow symbolic links outside of the new root path
|
||||
when reading, and of implying the --numeric-ids option because /etc/passwd
|
||||
becomes inaccessible. 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.
|
||||
specify the maximum number of simultaneous connections you will allow.
|
||||
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.
|
||||
See also the "lock file" option.
|
||||
|
||||
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).
|
||||
exceeded for the modules sharing the lock file.
|
||||
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
|
||||
@@ -155,20 +167,24 @@ 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 the user "nobody".
|
||||
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 the
|
||||
group "nobody".
|
||||
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.
|
||||
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 applies on
|
||||
the server: that is, it excludes files received by a client when receiving
|
||||
from a server and files deleted on a server when sending to a server, but
|
||||
it doesn't exclude files sent from a client when sending to a server or
|
||||
files deleted on a client when receiving from a 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
|
||||
@@ -179,35 +195,39 @@ 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.
|
||||
equivalent file except that it applies only on the server. See also
|
||||
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.
|
||||
option except that it applies only on the server. 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 also the "exclude" option above.
|
||||
|
||||
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.
|
||||
equivalent file except that it applies only on the server. See also
|
||||
the "exclude" option above.
|
||||
|
||||
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. 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
|
||||
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").
|
||||
|
||||
See also the bf(CONNECTING TO AN RSYNC SERVER OVER A REMOTE SHELL
|
||||
PROGRAM) section in rsync(1) for information on how handle an
|
||||
rsyncd.conf-level username that differs from the remote-shell-level
|
||||
username when using a remote shell to connect to a rsync server.
|
||||
|
||||
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
|
||||
@@ -219,7 +239,8 @@ 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)).
|
||||
(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
|
||||
@@ -236,16 +257,18 @@ 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 dotted decimal IPv4 address of the form a.b.c.d, or an IPv6 address
|
||||
of the form a:b:c::d:e:f. In this case the incoming machine's 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() an address/mask in the form ipaddr/n where ipaddr is the IP address
|
||||
and n is the number of one bits 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() an address/mask in the form ipaddr/maskaddr where ipaddr is the
|
||||
IP address and maskaddr is the netmask in dotted decimal notation for IPv4,
|
||||
or similar for IPv6, e.g. ffff:ffff:ffff:ffff:: instead of /64. 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
|
||||
@@ -256,6 +279,12 @@ itemize(
|
||||
then the client is allowed in.
|
||||
)
|
||||
|
||||
Note IPv6 link-local addresses can have a scope in the address specification:
|
||||
|
||||
quote(fe80::1%link1)
|
||||
quote(fe80::%link1/64)
|
||||
quote(fe80::%link1/ffff:ffff:ffff:ffff::)
|
||||
|
||||
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
|
||||
@@ -273,6 +302,19 @@ 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
|
||||
@@ -333,7 +375,7 @@ 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)
|
||||
The default setting is verb(*.gz *.tgz *.zip *.z *.rpm *.deb *.iso *.bz2 *.tbz)
|
||||
|
||||
enddit()
|
||||
|
||||
@@ -373,7 +415,7 @@ gid = nobody nl()
|
||||
use chroot = no nl()
|
||||
max connections = 4 nl()
|
||||
syslog facility = local5 nl()
|
||||
pid file = /etc/rsyncd.pid
|
||||
pid file = /var/run/rsyncd.pid
|
||||
|
||||
verb([ftp]
|
||||
path = /var/ftp/pub
|
||||
@@ -405,7 +447,7 @@ susan:herpass
|
||||
|
||||
manpagefiles()
|
||||
|
||||
/etc/rsyncd.conf
|
||||
/etc/rsyncd.conf or rsyncd.conf
|
||||
|
||||
manpageseealso()
|
||||
|
||||
|
||||
26
rsyncsh.txt
Normal file
26
rsyncsh.txt
Normal 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.
|
||||
270
runtests.sh
Executable file
270
runtests.sh
Executable file
@@ -0,0 +1,270 @@
|
||||
#! /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'
|
||||
|
||||
# for Solaris
|
||||
PATH="/usr/xpg4/bin/:$PATH"
|
||||
|
||||
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"
|
||||
|
||||
testuser=`whoami || echo UNKNOWN`
|
||||
|
||||
echo " testuser=$testuser"
|
||||
echo " os=`uname -a`"
|
||||
|
||||
# It must be "yes", not just nonnull
|
||||
if test "x$preserve_scratch" = xyes
|
||||
then
|
||||
echo " preserve_scratch=yes"
|
||||
else
|
||||
echo " preserve_scratch=no"
|
||||
fi
|
||||
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
maybe_discard_scratch() {
|
||||
[ x"$preserve_scratch" != xyes ] && [ -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
|
||||
|
||||
if [ "x$always_log" = xyes -o \( $result != 0 -a $result != 77 -a $result != 78 \) ]
|
||||
then
|
||||
echo "----- $testbase log follows"
|
||||
cat "$scratchdir/test.log"
|
||||
echo "----- $testbase log ends"
|
||||
fi
|
||||
|
||||
case $result in
|
||||
0)
|
||||
echo "PASS $testbase"
|
||||
passed=`expr $passed + 1`
|
||||
maybe_discard_scratch
|
||||
;;
|
||||
77)
|
||||
# backticks will fill the whole file onto one line, which is a feature
|
||||
whyskipped=`cat "$scratchdir/whyskipped"`
|
||||
echo "SKIP $testbase ($whyskipped)"
|
||||
skipped=`expr $skipped + 1`
|
||||
maybe_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"
|
||||
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
|
||||
176
sender.c
176
sender.c
@@ -28,9 +28,18 @@ extern int dry_run;
|
||||
extern int am_server;
|
||||
|
||||
|
||||
/*
|
||||
receive the checksums for a buffer
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* The sender gets checksums from the generator, calculates deltas,
|
||||
* and transmits them to the receiver. The sender process runs on the
|
||||
* machine holding the source files.
|
||||
**/
|
||||
|
||||
|
||||
/**
|
||||
* Receive the checksums for a buffer
|
||||
**/
|
||||
static struct sum_struct *receive_sums(int f)
|
||||
{
|
||||
struct sum_struct *s;
|
||||
@@ -46,8 +55,8 @@ static struct sum_struct *receive_sums(int f)
|
||||
s->sums = NULL;
|
||||
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO,"count=%d n=%d rem=%d\n",
|
||||
s->count,s->n,s->remainder);
|
||||
rprintf(FINFO,"count=%ld n=%ld rem=%ld\n",
|
||||
(long) s->count, (long) s->n, (long) s->remainder);
|
||||
|
||||
if (s->count == 0)
|
||||
return(s);
|
||||
@@ -55,14 +64,14 @@ static struct sum_struct *receive_sums(int f)
|
||||
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++) {
|
||||
for (i=0; i < (int) 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) {
|
||||
if (i == (int) s->count-1 && s->remainder != 0) {
|
||||
s->sums[i].len = s->remainder;
|
||||
} else {
|
||||
s->sums[i].len = s->n;
|
||||
@@ -70,8 +79,8 @@ static struct sum_struct *receive_sums(int f)
|
||||
offset += s->sums[i].len;
|
||||
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO,"chunk[%d] len=%d offset=%d sum1=%08x\n",
|
||||
i,s->sums[i].len,(int)s->sums[i].offset,s->sums[i].sum1);
|
||||
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;
|
||||
@@ -83,9 +92,9 @@ static struct sum_struct *receive_sums(int f)
|
||||
|
||||
void send_files(struct file_list *flist,int f_out,int f_in)
|
||||
{
|
||||
int fd;
|
||||
int fd = -1;
|
||||
struct sum_struct *s;
|
||||
struct map_struct *buf;
|
||||
struct map_struct *buf = NULL;
|
||||
STRUCT_STAT st;
|
||||
char fname[MAXPATHLEN];
|
||||
int i;
|
||||
@@ -93,12 +102,17 @@ void send_files(struct file_list *flist,int f_out,int f_in)
|
||||
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");
|
||||
|
||||
setup_readbuffer(f_in);
|
||||
|
||||
while (1) {
|
||||
int offset=0;
|
||||
|
||||
@@ -159,56 +173,109 @@ void send_files(struct file_list *flist,int f_out,int f_in)
|
||||
rprintf(FERROR,"receive_sums failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fd = open(fname,O_RDONLY);
|
||||
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 %d\n",
|
||||
fname,(int)st.st_size);
|
||||
|
||||
write_int(f_out,i);
|
||||
if (write_batch)
|
||||
write_batch_csum_info(&i,flist->count,s);
|
||||
|
||||
write_int(f_out,s->count);
|
||||
write_int(f_out,s->n);
|
||||
write_int(f_out,s->remainder);
|
||||
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)
|
||||
rprintf(FINFO,"calling match_sums %s\n",fname);
|
||||
if (!read_batch)
|
||||
rprintf(FINFO,"calling match_sums %s\n",fname);
|
||||
|
||||
if (!am_server) {
|
||||
log_transfer(file, fname+offset);
|
||||
}
|
||||
|
||||
set_compression(fname);
|
||||
|
||||
match_sums(f_out,s,buf,st.st_size);
|
||||
|
||||
log_send(file, &initial_stats);
|
||||
|
||||
if (buf) unmap_file(buf);
|
||||
close(fd);
|
||||
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);
|
||||
|
||||
@@ -222,6 +289,11 @@ void send_files(struct file_list *flist,int f_out,int f_in)
|
||||
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
12
shconfig.in
Executable 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
|
||||
629
socket.c
629
socket.c
@@ -1,5 +1,9 @@
|
||||
/*
|
||||
Copyright (C) Andrew Tridgell 1998
|
||||
/* -*- 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
|
||||
@@ -16,114 +20,368 @@
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
socket functions used in rsync
|
||||
|
||||
*/
|
||||
/**
|
||||
* @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"
|
||||
|
||||
/* open a socket to a tcp remote host with the specified port
|
||||
based on code from Warren */
|
||||
int open_socket_out(char *host, int port)
|
||||
|
||||
/**
|
||||
* Establish a proxy connection on an open socket to a web proxy by
|
||||
* using the HTTP 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(* (unsigned char *) 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;
|
||||
freeaddrinfo(bres_all);
|
||||
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. */
|
||||
freeaddrinfo(bres_all);
|
||||
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;
|
||||
struct sockaddr_in sock_out;
|
||||
int res;
|
||||
struct hostent *hp;
|
||||
|
||||
int error;
|
||||
int s;
|
||||
struct addrinfo hints, *res0, *res;
|
||||
char portbuf[10];
|
||||
char *h;
|
||||
int proxied = 0;
|
||||
char buffer[1024];
|
||||
char *cp;
|
||||
|
||||
res = socket(PF_INET, type, 0);
|
||||
if (res == -1) {
|
||||
/* 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;
|
||||
if (verbose >= 2) {
|
||||
rprintf(FINFO, "connection via http proxy %s port %s\n",
|
||||
h, portbuf);
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
|
||||
hp = gethostbyname(host);
|
||||
if (!hp) {
|
||||
rprintf(FERROR,"unknown host: %s\n", host);
|
||||
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;
|
||||
}
|
||||
|
||||
memcpy(&sock_out.sin_addr, hp->h_addr, hp->h_length);
|
||||
sock_out.sin_port = htons(port);
|
||||
sock_out.sin_family = PF_INET;
|
||||
|
||||
if (connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out))) {
|
||||
close(res);
|
||||
rprintf(FERROR,"failed to connect to %s - %s\n", host, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
set_nonblocking(res);
|
||||
|
||||
return res;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
open a socket of the specified type, port and address for incoming data
|
||||
****************************************************************************/
|
||||
static int open_socket_in(int type, int port)
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
struct hostent *hp;
|
||||
struct sockaddr_in sock;
|
||||
char host_name[MAXHOSTNAMELEN];
|
||||
int res;
|
||||
int one=1;
|
||||
char *prog;
|
||||
|
||||
/* get my host name */
|
||||
if (gethostname(host_name, sizeof(host_name)) == -1) {
|
||||
rprintf(FERROR,"gethostname failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* get host info */
|
||||
if ((hp = gethostbyname(host_name)) == 0) {
|
||||
rprintf(FERROR,"gethostbyname: Unknown host %s\n",host_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset((char *)&sock,0,sizeof(sock));
|
||||
memcpy((char *)&sock.sin_addr,(char *)hp->h_addr, hp->h_length);
|
||||
sock.sin_port = htons(port);
|
||||
sock.sin_family = hp->h_addrtype;
|
||||
sock.sin_addr.s_addr = INADDR_ANY;
|
||||
res = socket(hp->h_addrtype, type, 0);
|
||||
if (res == -1) {
|
||||
rprintf(FERROR,"socket failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one));
|
||||
|
||||
/* now we've got a socket - we need to bind it */
|
||||
if (bind(res, (struct sockaddr * ) &sock,sizeof(sock)) == -1) {
|
||||
rprintf(FERROR,"bind failed on port %d\n", port);
|
||||
close(res);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return res;
|
||||
if ((prog = getenv ("RSYNC_CONNECT_PROG")) != NULL)
|
||||
return sock_exec (prog);
|
||||
else
|
||||
return open_socket_out (host, port, bind_address,
|
||||
af_hint);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
determine if a file descriptor is in fact a socket
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
freeaddrinfo(all_ai);
|
||||
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,l;
|
||||
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 ))
|
||||
void start_accept_loop(int port, int (*fn)(int, int))
|
||||
{
|
||||
int s;
|
||||
extern char *bind_address;
|
||||
extern int default_af_hint;
|
||||
|
||||
/* open an incoming socket */
|
||||
s = open_socket_in(SOCK_STREAM, port);
|
||||
s = open_socket_in(SOCK_STREAM, port, bind_address, default_af_hint);
|
||||
if (s == -1)
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
|
||||
@@ -138,9 +396,15 @@ void start_accept_loop(int port, int (*fn)(int ))
|
||||
for each incoming connection */
|
||||
while (1) {
|
||||
fd_set fds;
|
||||
pid_t pid;
|
||||
int fd;
|
||||
struct sockaddr addr;
|
||||
int in_addrlen = sizeof(addr);
|
||||
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);
|
||||
@@ -151,7 +415,7 @@ void start_accept_loop(int port, int (*fn)(int ))
|
||||
|
||||
if(!FD_ISSET(s, &fds)) continue;
|
||||
|
||||
fd = accept(s,&addr,&in_addrlen);
|
||||
fd = accept(s,(struct sockaddr *)&addr,&addrlen);
|
||||
|
||||
if (fd == -1) continue;
|
||||
|
||||
@@ -161,18 +425,32 @@ void start_accept_loop(int port, int (*fn)(int ))
|
||||
but I have had reports that on Digital Unix zombies
|
||||
are produced, so this ensures that they are reaped */
|
||||
#ifdef WNOHANG
|
||||
waitpid(-1, NULL, WNOHANG);
|
||||
while (waitpid(-1, NULL, WNOHANG) > 0);
|
||||
#endif
|
||||
|
||||
if (fork()==0) {
|
||||
if ((pid = fork()) == 0) {
|
||||
int ret;
|
||||
close(s);
|
||||
|
||||
set_nonblocking(fd);
|
||||
|
||||
_exit(fn(fd));
|
||||
/* open log file in child before possibly giving
|
||||
up privileges */
|
||||
log_open();
|
||||
ret = fn(fd, fd);
|
||||
close_all();
|
||||
_exit(ret);
|
||||
} else if (pid < 0) {
|
||||
rprintf(FERROR,
|
||||
RSYNC_NAME
|
||||
": could not create child server process: %s\n",
|
||||
strerror(errno));
|
||||
close(fd);
|
||||
/* This might have happened because we're
|
||||
* overloaded. Sleep briefly before trying to
|
||||
* accept again. */
|
||||
sleep(2);
|
||||
} else {
|
||||
/* Parent doesn't need this fd anymore. */
|
||||
close(fd);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,9 +499,9 @@ struct
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
set user socket options
|
||||
****************************************************************************/
|
||||
/**
|
||||
* Set user socket options
|
||||
**/
|
||||
void set_socket_options(int fd, char *options)
|
||||
{
|
||||
char *tok;
|
||||
@@ -274,15 +552,16 @@ void set_socket_options(int fd, char *options)
|
||||
}
|
||||
|
||||
if (ret != 0)
|
||||
rprintf(FERROR,"Failed to set socket option %s\n",tok);
|
||||
rprintf(FERROR, "failed to set socket option %s: %s\n", tok,
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
free(options);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
become a daemon, discarding the controlling terminal
|
||||
****************************************************************************/
|
||||
/**
|
||||
* Become a daemon, discarding the controlling terminal
|
||||
**/
|
||||
void become_daemon(void)
|
||||
{
|
||||
int i;
|
||||
@@ -311,78 +590,112 @@ void become_daemon(void)
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
return the IP addr of the client as a string
|
||||
******************************************************************/
|
||||
char *client_addr(int fd)
|
||||
|
||||
/**
|
||||
* 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])
|
||||
{
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
|
||||
int length = sizeof(sa);
|
||||
static char addr_buf[100];
|
||||
static int initialised;
|
||||
|
||||
if (initialised) return addr_buf;
|
||||
|
||||
initialised = 1;
|
||||
|
||||
if (getpeername(fd, &sa, &length)) {
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
}
|
||||
int listener;
|
||||
struct sockaddr_in sock;
|
||||
struct sockaddr_in sock2;
|
||||
socklen_t socklen = sizeof(sock);
|
||||
int connect_done = 0;
|
||||
|
||||
strlcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr), sizeof(addr_buf));
|
||||
return addr_buf;
|
||||
}
|
||||
fd[0] = fd[1] = listener = -1;
|
||||
|
||||
memset(&sock, 0, sizeof(sock));
|
||||
|
||||
if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
|
||||
|
||||
/*******************************************************************
|
||||
return the DNS name of the client
|
||||
******************************************************************/
|
||||
char *client_name(int fd)
|
||||
{
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
|
||||
int length = sizeof(sa);
|
||||
static char name_buf[100];
|
||||
struct hostent *hp;
|
||||
char **p;
|
||||
char *def = "UNKNOWN";
|
||||
static int initialised;
|
||||
memset(&sock2, 0, sizeof(sock2));
|
||||
#ifdef HAVE_SOCKADDR_LEN
|
||||
sock2.sin_len = sizeof(sock2);
|
||||
#endif
|
||||
sock2.sin_family = PF_INET;
|
||||
|
||||
if (initialised) return name_buf;
|
||||
bind(listener, (struct sockaddr *)&sock2, sizeof(sock2));
|
||||
|
||||
initialised = 1;
|
||||
if (listen(listener, 1) != 0) goto failed;
|
||||
|
||||
strcpy(name_buf,def);
|
||||
if (getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0) goto failed;
|
||||
|
||||
if (getpeername(fd, &sa, &length)) {
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
}
|
||||
if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
|
||||
|
||||
/* Look up the remote host name. */
|
||||
if ((hp = gethostbyaddr((char *) &sockin->sin_addr,
|
||||
sizeof(sockin->sin_addr),
|
||||
AF_INET))) {
|
||||
strlcpy(name_buf,(char *)hp->h_name,sizeof(name_buf));
|
||||
}
|
||||
set_nonblocking(fd[1]);
|
||||
|
||||
sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
|
||||
/* do a forward lookup as well to prevent spoofing */
|
||||
hp = gethostbyname(name_buf);
|
||||
if (!hp) {
|
||||
strcpy(name_buf,def);
|
||||
rprintf(FERROR,"reverse name lookup failed\n");
|
||||
if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) == -1) {
|
||||
if (errno != EINPROGRESS) goto failed;
|
||||
} else {
|
||||
for (p=hp->h_addr_list;*p;p++) {
|
||||
if (memcmp(*p, &sockin->sin_addr, hp->h_length) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!*p) {
|
||||
strcpy(name_buf,def);
|
||||
rprintf(FERROR,"reverse name lookup mismatch - spoofed address?\n");
|
||||
}
|
||||
connect_done = 1;
|
||||
}
|
||||
|
||||
return name_buf;
|
||||
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];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
77
syscall.c
77
syscall.c
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright (C) Andrew Tridgell 1998
|
||||
Copyright (C) 2002 by Martin Pool
|
||||
|
||||
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
|
||||
@@ -16,15 +17,19 @@
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
syscall wrappers to ensure that nothing gets done in dry_run mode
|
||||
*/
|
||||
/**
|
||||
* @file syscall.c
|
||||
*
|
||||
* Syscall wrappers to ensure that nothing gets done in dry_run mode
|
||||
* and to handle system peculiarities.
|
||||
**/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
extern int dry_run;
|
||||
extern int read_only;
|
||||
extern int list_only;
|
||||
extern int preserve_perms;
|
||||
|
||||
#define CHECK_RO if (read_only || list_only) {errno = EROFS; return -1;}
|
||||
|
||||
@@ -76,21 +81,30 @@ int do_rmdir(char *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
|
||||
CHECK_RO
|
||||
/* some systems can't handle a double / */
|
||||
if (pathname[0] == '/' && pathname[1] == '/') pathname++;
|
||||
|
||||
return open(pathname, flags, mode);
|
||||
}
|
||||
|
||||
#if HAVE_CHMOD
|
||||
int do_chmod(const char *path, mode_t mode)
|
||||
{
|
||||
int code;
|
||||
if (dry_run) return 0;
|
||||
CHECK_RO
|
||||
return chmod(path, mode);
|
||||
code = chmod(path, mode);
|
||||
if ((code != 0) && preserve_perms)
|
||||
return code;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -101,18 +115,57 @@ int do_rename(char *fname1, char *fname2)
|
||||
return rename(fname1, fname2);
|
||||
}
|
||||
|
||||
|
||||
void trim_trailing_slashes(char *name)
|
||||
{
|
||||
int l;
|
||||
/* Some BSD systems cannot make a directory if the name
|
||||
* contains a trailing slash.
|
||||
* <http://www.opensource.apple.com/bugs/X/BSD%20Kernel/2734739.html> */
|
||||
|
||||
/* Don't change empty string; and also we can't improve on
|
||||
* "/" */
|
||||
|
||||
l = strlen(name);
|
||||
while (l > 1) {
|
||||
if (name[--l] != '/')
|
||||
break;
|
||||
name[l] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int do_mkdir(char *fname, mode_t mode)
|
||||
{
|
||||
if (dry_run) return 0;
|
||||
CHECK_RO
|
||||
if (dry_run)
|
||||
return 0;
|
||||
CHECK_RO;
|
||||
trim_trailing_slashes(fname);
|
||||
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;
|
||||
if (read_only) {errno = EROFS; 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) && preserve_perms) {
|
||||
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)
|
||||
|
||||
44
t_stub.c
Normal file
44
t_stub.c
Normal file
@@ -0,0 +1,44 @@
|
||||
/* -*- 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 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"
|
||||
|
||||
/**
|
||||
* @file t_stub.c
|
||||
*
|
||||
* This file contains really simple implementations for rsync global
|
||||
* functions, so that module test harnesses can run standalone.
|
||||
**/
|
||||
|
||||
int modify_window = 0;
|
||||
|
||||
void rprintf(enum logcode UNUSED(code), const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vfprintf(stderr, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void _exit_cleanup(int code, const char *file, int line)
|
||||
{
|
||||
fprintf(stderr, "exit(%d): %s(%d)\n",
|
||||
code, file, line);
|
||||
exit(code);
|
||||
}
|
||||
45
t_unsafe.c
Normal file
45
t_unsafe.c
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2002 by Martin Pool
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Test harness for unsafe_symlink(). Not linked into @c rsync itself.
|
||||
*
|
||||
* Prints either "safe" or "unsafe" depending on the two arguments.
|
||||
* Always returns 0 unless something extraordinary happens.
|
||||
**/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
int dry_run, read_only, list_only, verbose;
|
||||
int preserve_perms = 0;
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "usage: t_unsafe LINKDEST SRCDIR\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("%s\n",
|
||||
unsafe_symlink(argv[1], argv[2]) ? "unsafe" : "safe");
|
||||
|
||||
return 0;
|
||||
}
|
||||
119
test.sh
119
test.sh
@@ -1,7 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright (C) 1998 Philip Hands <http://www.hands.com/~phil/>
|
||||
# Copyright (C) 1998,1999 Philip Hands <phil@hands.com>
|
||||
#
|
||||
# This program is distributable under the terms of the GNU GPL (see COPYING)
|
||||
#
|
||||
@@ -10,7 +9,15 @@
|
||||
#
|
||||
#
|
||||
|
||||
cat <<EOF
|
||||
# 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
|
||||
@@ -18,7 +25,19 @@ do not indicate a problem with rsync.
|
||||
|
||||
EOF
|
||||
|
||||
export PATH=.:$PATH
|
||||
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
|
||||
@@ -35,37 +54,60 @@ mkdir ${FROM}/emptydir
|
||||
ps ax > ${FROM}/pslist
|
||||
echo -n "This file has no trailing lf" > ${FROM}/nolf
|
||||
ln -s nolf ${FROM}/nolf-symlink
|
||||
cat /etc/inittab /etc/services /etc/resolv.conf > ${FROM}/${F1}
|
||||
|
||||
# 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
|
||||
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() {
|
||||
echo -n "Test $4: $5:"
|
||||
log=${LOG}.$4
|
||||
testnum=`expr 0${testnum} + 1`
|
||||
log=${LOG}.${testnum}
|
||||
failed=
|
||||
echo "Running: \"$1\"" >${log}
|
||||
echo "">>${log}
|
||||
eval "$1 || failed=YES" >>${log} 2>&1
|
||||
|
||||
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} || failed=YES
|
||||
diff -ur $2 $3 >>${log} 2>&1 || failed=YES
|
||||
echo "-------------">>${log}
|
||||
echo "check how the directory listings compare with diff:">>${log}
|
||||
echo "">>${log}
|
||||
ls -la $2 > ${TMP}/ls-from
|
||||
ls -la $3 > ${TMP}/ls-to
|
||||
diff -u ${TMP}/ls-from ${TMP}/ls-to >>${log} || failed=YES
|
||||
( 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
|
||||
echo " done."
|
||||
test -z "${Debian}" && echo " done."
|
||||
rm $log
|
||||
return 0
|
||||
else
|
||||
echo " FAILED."
|
||||
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
|
||||
|
||||
@@ -87,44 +129,45 @@ EOF
|
||||
|
||||
# Main script starts here
|
||||
|
||||
checkit "rsync -av ${FROM}/ ${TO}" ${FROM}/ ${TO} \
|
||||
1 "basic operation"
|
||||
runtest "basic operation" 'checkit "$RSYNC -av ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
|
||||
ln ${FROM}/pslist ${FROM}/dir
|
||||
checkit "rsync -avH ${FROM}/ ${TO}" ${FROM}/ ${TO} \
|
||||
2 "hard links"
|
||||
runtest "hard links" 'checkit "$RSYNC -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
|
||||
rm ${TO}/${F1}
|
||||
checkit "rsync -avH ${FROM}/ ${TO}" ${FROM}/ ${TO} \
|
||||
3 "one file"
|
||||
runtest "one file" 'checkit "$RSYNC -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
|
||||
echo "extra line" >> ${TO}/${F1}
|
||||
checkit "rsync -avH ${FROM}/ ${TO}" ${FROM}/ ${TO} \
|
||||
4 "extra data"
|
||||
runtest "extra data" 'checkit "$RSYNC -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
|
||||
cp ${FROM}/${F1} ${TO}/ThisShouldGo
|
||||
checkit "rsync --delete -avH ${FROM}/ ${TO}" ${FROM}/ ${TO} \
|
||||
5 " --delete"
|
||||
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
|
||||
checkit "rsync --delete -avH ${FROM}/ ${TO}" ${FROM}/ ${TO} \
|
||||
6 "long paths"
|
||||
runtest "long paths" 'checkit "$RSYNC --delete -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
|
||||
if type ssh >/dev/null ; then
|
||||
rm -rf ${TO}
|
||||
checkit "rsync -avH -e ssh ${FROM}/ localhost:${TO}" ${FROM}/ ${TO} \
|
||||
7 "ssh: basic test"
|
||||
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
|
||||
checkit "rsync --delete -avH -e ssh ${FROM}/ localhost:${TO}" ${FROM}/ ${TO}\
|
||||
8 "ssh: renamed file"
|
||||
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
|
||||
echo ""
|
||||
echo "**** Skipping SSH tests because ssh is not in the path ****"
|
||||
echo ""
|
||||
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}.?
|
||||
|
||||
133
testhelp/maketree.py
Normal file
133
testhelp/maketree.py
Normal file
@@ -0,0 +1,133 @@
|
||||
#! /usr/bin/python2.2
|
||||
|
||||
# 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 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.
|
||||
|
||||
# Populate a tree with pseudo-randomly distributed files to test
|
||||
# rsync.
|
||||
|
||||
from __future__ import generators
|
||||
import random, string, os, os.path
|
||||
|
||||
nfiles = 10000
|
||||
depth = 5
|
||||
n_children = 20
|
||||
n_files = 20
|
||||
n_symlinks = 10
|
||||
|
||||
name_chars = string.digits + string.letters
|
||||
|
||||
abuffer = 'a' * 1024
|
||||
|
||||
def random_name_chars():
|
||||
a = ""
|
||||
for i in range(10):
|
||||
a = a + random.choice(name_chars)
|
||||
return a
|
||||
|
||||
|
||||
def generate_names():
|
||||
n = 0
|
||||
while 1:
|
||||
yield "%05d_%s" % (n, random_name_chars())
|
||||
n += 1
|
||||
|
||||
|
||||
class TreeBuilder:
|
||||
def __init__(self):
|
||||
self.n_children = 20
|
||||
self.n_files = 100
|
||||
self.total_entries = 100000 # long(1e8)
|
||||
self.actual_size = 0
|
||||
self.name_gen = generate_names()
|
||||
self.all_files = []
|
||||
self.all_dirs = []
|
||||
self.all_symlinks = []
|
||||
|
||||
|
||||
def random_size(self):
|
||||
return random.lognormvariate(4, 4)
|
||||
|
||||
|
||||
def random_symlink_target(self):
|
||||
what = random.choice(['directory', 'file', 'symlink', 'none'])
|
||||
try:
|
||||
if what == 'directory':
|
||||
return random.choice(self.all_dirs)
|
||||
elif what == 'file':
|
||||
return random.choice(self.all_files)
|
||||
elif what == 'symlink':
|
||||
return random.choice(self.all_symlinks)
|
||||
elif what == 'none':
|
||||
return self.name_gen.next()
|
||||
except IndexError:
|
||||
return self.name_gen.next()
|
||||
|
||||
|
||||
def can_continue(self):
|
||||
self.total_entries -= 1
|
||||
return self.total_entries > 0
|
||||
|
||||
|
||||
def build_tree(self, prefix, depth):
|
||||
"""Generate a breadth-first tree"""
|
||||
for count, function in [[n_files, self.make_file],
|
||||
[n_children, self.make_child_recurse],
|
||||
[n_symlinks, self.make_symlink]]:
|
||||
for i in range(count):
|
||||
if not self.can_continue():
|
||||
return
|
||||
name = os.path.join(prefix, self.name_gen.next())
|
||||
function(name, depth)
|
||||
|
||||
|
||||
def print_summary(self):
|
||||
print "total bytes: %d" % self.actual_size
|
||||
|
||||
|
||||
def make_child_recurse(self, dname, depth):
|
||||
if depth > 1:
|
||||
self.make_dir(dname)
|
||||
self.build_tree(dname, depth-1)
|
||||
|
||||
|
||||
def make_dir(self, dname, depth='ignore'):
|
||||
print "%s/" % (dname)
|
||||
os.mkdir(dname)
|
||||
self.all_dirs.append(dname)
|
||||
|
||||
|
||||
def make_symlink(self, lname, depth='ignore'):
|
||||
print "%s -> %s" % (lname, self.random_symlink_target())
|
||||
|
||||
|
||||
def make_file(self, fname, depth='ignore'):
|
||||
size = long(self.random_size())
|
||||
print "%-70s %d" % (fname, size)
|
||||
f = open(fname, 'w')
|
||||
f.truncate(size)
|
||||
self.fill_file(f, size)
|
||||
self.all_files.append(fname)
|
||||
self.actual_size += size
|
||||
|
||||
def fill_file(self, f, size):
|
||||
while size > 0:
|
||||
f.write(abuffer[:size])
|
||||
size -= len(abuffer)
|
||||
|
||||
|
||||
tb = TreeBuilder()
|
||||
tb.build_tree('/tmp/foo', 3)
|
||||
tb.print_summary()
|
||||
5
testsuite/00-hello.test
Normal file
5
testsuite/00-hello.test
Normal file
@@ -0,0 +1,5 @@
|
||||
#! /bin/sh
|
||||
|
||||
echo $0 running
|
||||
|
||||
$RSYNC --version || exit 1
|
||||
30
testsuite/README.testsuite
Normal file
30
testsuite/README.testsuite
Normal file
@@ -0,0 +1,30 @@
|
||||
automatic testsuite for rsync -*- text -*-
|
||||
|
||||
We're trying to develop some more substantial tests to prevent rsync
|
||||
regressions. Ideally, all code changes or bug reports would come with
|
||||
an appropriate test suite.
|
||||
|
||||
You can run these tests by typing "make check" in the build directory.
|
||||
The tests will run using the rsync binary in the build directory, so
|
||||
you do not need to do "make install" first. Indeed, you probably
|
||||
should not install rsync before running the tests.
|
||||
|
||||
If you instead type "make installcheck" then the suite will test the
|
||||
rsync binary from its installed location (e.g. /usr/local/bin/rsync).
|
||||
You can use this to test a distribution build, or perhaps to run a new
|
||||
test suite against an old version of rsync. Note that in accordance
|
||||
with the GNU Standards, installcheck does not look for rsync on the
|
||||
path.
|
||||
|
||||
If the tests pass, you should see a report to that effect. Some tests
|
||||
require being root or some other precondition, and so will normally be
|
||||
checked -- look at the test scripts for more information.
|
||||
|
||||
If the tests fail, you will see rather more output. The scratch
|
||||
directory will remain in the build directory. It would be useful if
|
||||
you could include the log messages when reporting a failure.
|
||||
|
||||
These tests also run automatically on the build farm, and you can see
|
||||
the results on http://build.samba.org/.
|
||||
|
||||
|
||||
38
testsuite/chgrp.test
Normal file
38
testsuite/chgrp.test
Normal 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 that rsync with -gr will preserve groups when the user running
|
||||
# the test is a member of them. Hopefully they're in at least one
|
||||
# test.
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
|
||||
set -x
|
||||
|
||||
# Build some hardlinks
|
||||
|
||||
fromdir="$scratchdir/from"
|
||||
todir="$scratchdir/to"
|
||||
|
||||
# TODO: I guess some systems will not have 'id', and therefore we have
|
||||
# to ship or emulate it.
|
||||
mygrps="`rsync_getgroups`" || fail "Can't get groups"
|
||||
mkdir "$fromdir"
|
||||
|
||||
for g in $mygrps
|
||||
do
|
||||
name="$fromdir/foo-$g"
|
||||
date > "$name"
|
||||
chgrp "$g" "$name" || fail "Can't chgrp"
|
||||
done
|
||||
sleep 2
|
||||
|
||||
checkit "$RSYNC -rtgvvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
|
||||
|
||||
exit 0
|
||||
# last [] may have failed but if we get here then we've won
|
||||
|
||||
38
testsuite/chown.test
Normal file
38
testsuite/chown.test
Normal 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 that when rsync is running as root and has -a it correctly sets
|
||||
# the ownership of the destination.
|
||||
|
||||
# We don't know what users will be present on this system, so we just
|
||||
# use random numeric uids and gids.
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
|
||||
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"
|
||||
echo "This is the other file" > "$name2"
|
||||
|
||||
chown 5000 "$name1" || test_skipped "Can't chown (probably need root)"
|
||||
chown 5001 "$name2" || test_skipped "Can't chown (probably need root)"
|
||||
chgrp 5002 "$name1" || test_skipped "Can't chgrp (probably need root)"
|
||||
chgrp 5003 "$name2" || test_skipped "Can't chgrp (probably need root)"
|
||||
|
||||
checkit "$RSYNC -aHvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
|
||||
|
||||
exit 0
|
||||
# last [] may have failed but if we get here then we've won
|
||||
|
||||
31
testsuite/daemon-gzip-download.test
Normal file
31
testsuite/daemon-gzip-download.test
Normal file
@@ -0,0 +1,31 @@
|
||||
#!/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 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.
|
||||
|
||||
# This test tries to download a tree over a compressed connection from
|
||||
# the server. This ought to exercise (exorcise?) a bug in 2.5.3.
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
build_rsyncd_conf
|
||||
|
||||
RSYNC_CONNECT_PROG="$RSYNC --config=$conf --daemon"
|
||||
export RSYNC_CONNECT_PROG
|
||||
|
||||
hands_setup
|
||||
checkit "$RSYNC -avvz localhost::test-from/ \"$TO/\"" "$FROM" "$TO"
|
||||
|
||||
25
testsuite/daemon-gzip-upload.test
Normal file
25
testsuite/daemon-gzip-upload.test
Normal file
@@ -0,0 +1,25 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Copyright (C) 2001, 2002 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.
|
||||
|
||||
# This test tries to upload a file over a compressed connection to the
|
||||
# server. This ought to exercise (exorcise?) a bug in 2.5.3.
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
build_rsyncd_conf
|
||||
|
||||
RSYNC_CONNECT_PROG="$RSYNC --config=$conf --daemon"
|
||||
export RSYNC_CONNECT_PROG
|
||||
|
||||
hands_setup
|
||||
checkit "$RSYNC -avvz \"$FROM/\" localhost::test-to/" "$FROM" "$TO"
|
||||
|
||||
32
testsuite/daemon.test
Normal file
32
testsuite/daemon.test
Normal 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 --config=$conf --daemon"
|
||||
export RSYNC_CONNECT_PROG
|
||||
|
||||
$RSYNC -v localhost::
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user