Commit | Line | Data |
---|---|---|
c0c7984e WD |
1 | This patch implements a new --remote-option (-M) option that allows the |
2 | user to override certain settings on the remote system. For instance, it | |
3 | is now easier to pass -M--fake-super or "-M --log-file=/tmp/foo" instead of | |
4 | kluging up an --rsync-path setting. This also solves the case where we | |
5 | want local --one-file-system (-x) but not remote ("-x -M--no-x"), or visa | |
6 | versa ("-M-x"). | |
7 | ||
8 | To use this patch, run these commands for a successful build: | |
9 | ||
10 | patch -p1 <patches/remote-option.diff | |
11 | ./configure (optional if already run) | |
12 | make | |
13 | ||
14 | diff --git a/options.c b/options.c | |
15 | --- a/options.c | |
16 | +++ b/options.c | |
17 | @@ -174,6 +174,10 @@ int link_dest = 0; | |
18 | int basis_dir_cnt = 0; | |
19 | char *dest_option = NULL; | |
20 | ||
21 | +#define MAX_REMOTE_ARGS (MAX_SERVER_ARGS/2) | |
22 | +int remote_option_cnt = 0; | |
23 | +const char *remote_options[MAX_SERVER_ARGS+1] = { "ARG0" }; | |
24 | + | |
25 | int verbose = 0; | |
26 | int quiet = 0; | |
27 | int output_motd = 1; | |
28 | @@ -387,6 +391,7 @@ void usage(enum logcode F) | |
29 | rprintf(F," --timeout=SECONDS set I/O timeout in seconds\n"); | |
30 | rprintf(F," --contimeout=SECONDS set daemon connection timeout in seconds\n"); | |
31 | rprintf(F," -I, --ignore-times don't skip files that match in size and mod-time\n"); | |
32 | + rprintf(F," -M, --remote-option=OPTION send OPTION to the remote side only\n"); | |
33 | rprintf(F," --size-only skip files that match in size\n"); | |
34 | rprintf(F," --modify-window=NUM compare mod-times with reduced accuracy\n"); | |
35 | rprintf(F," -T, --temp-dir=DIR create temporary files in directory DIR\n"); | |
36 | @@ -645,6 +650,7 @@ static struct poptOption long_options[] = { | |
37 | {"password-file", 0, POPT_ARG_STRING, &password_file, 0, 0, 0 }, | |
38 | {"blocking-io", 0, POPT_ARG_VAL, &blocking_io, 1, 0, 0 }, | |
39 | {"no-blocking-io", 0, POPT_ARG_VAL, &blocking_io, 0, 0, 0 }, | |
40 | + {"remote-option", 'M', POPT_ARG_STRING, 0, 'M', 0, 0 }, | |
41 | {"protocol", 0, POPT_ARG_INT, &protocol_version, 0, 0, 0 }, | |
42 | {"checksum-seed", 0, POPT_ARG_INT, &checksum_seed, 0, 0, 0 }, | |
43 | {"server", 0, POPT_ARG_NONE, 0, OPT_SERVER, 0, 0 }, | |
44 | @@ -1140,6 +1146,20 @@ int parse_arguments(int *argc_p, const char ***argv_p) | |
45 | } | |
46 | break; | |
47 | ||
48 | + case 'M': | |
49 | + arg = poptGetOptArg(pc); | |
50 | + if (*arg != '-') { | |
51 | + snprintf(err_buf, sizeof err_buf, | |
52 | + "Remote option must start with a dash: %s\n", arg); | |
53 | + return 0; | |
54 | + } | |
55 | + if (remote_option_cnt >= MAX_REMOTE_ARGS) { | |
56 | + rprintf(FERROR, "too many remote options specified.\n"); | |
57 | + exit_cleanup(RERR_SYNTAX); | |
58 | + } | |
59 | + remote_options[++remote_option_cnt] = arg; | |
60 | + break; | |
61 | + | |
62 | case OPT_WRITE_BATCH: | |
63 | /* batch_name is already set */ | |
64 | write_batch = 1; | |
65 | @@ -1826,6 +1846,11 @@ void server_options(char **args, int *argc_p) | |
66 | #endif | |
67 | argstr[x] = '\0'; | |
68 | ||
69 | + if (x > (int)sizeof argstr) { /* Not possible... */ | |
70 | + rprintf(FERROR, "argstr overflow in server_options().\n"); | |
71 | + exit_cleanup(RERR_MALLOC); | |
72 | + } | |
73 | + | |
74 | args[ac++] = argstr; | |
75 | ||
76 | #ifdef ICONV_OPTION | |
77 | @@ -2048,6 +2073,21 @@ void server_options(char **args, int *argc_p) | |
78 | else if (remove_source_files) | |
79 | args[ac++] = "--remove-sent-files"; | |
80 | ||
81 | + if (ac > MAX_SERVER_ARGS) { /* Not possible... */ | |
82 | + rprintf(FERROR, "argc overflow in server_options().\n"); | |
83 | + exit_cleanup(RERR_MALLOC); | |
84 | + } | |
85 | + | |
86 | + if (remote_option_cnt) { | |
87 | + int j; | |
88 | + if (ac + remote_option_cnt > MAX_SERVER_ARGS) { | |
89 | + rprintf(FERROR, "too many remote options specified.\n"); | |
90 | + exit_cleanup(RERR_SYNTAX); | |
91 | + } | |
92 | + for (j = 1; j <= remote_option_cnt; j++) | |
93 | + args[ac++] = (char*)remote_options[j]; | |
94 | + } | |
95 | + | |
96 | *argc_p = ac; | |
97 | return; | |
98 | ||
99 | diff --git a/pipe.c b/pipe.c | |
100 | --- a/pipe.c | |
101 | +++ b/pipe.c | |
102 | @@ -22,12 +22,15 @@ | |
103 | ||
104 | #include "rsync.h" | |
105 | ||
106 | +extern int am_root; | |
107 | extern int am_sender; | |
108 | extern int am_server; | |
109 | extern int blocking_io; | |
110 | extern int filesfrom_fd; | |
111 | extern mode_t orig_umask; | |
112 | extern char *logfile_name; | |
113 | +extern int remote_option_cnt; | |
114 | +extern const char *remote_options[]; | |
115 | extern struct chmod_mode_struct *chmod_modes; | |
116 | ||
117 | /** | |
118 | @@ -139,6 +142,18 @@ pid_t local_child(int argc, char **argv, int *f_in, int *f_out, | |
119 | logfile_close(); | |
120 | } | |
121 | ||
122 | + if (am_root < 0) | |
123 | + am_root = 0; | |
124 | + | |
125 | + if (remote_option_cnt) { | |
126 | + int rc = remote_option_cnt + 1; | |
127 | + const char **rv = remote_options; | |
128 | + if (!parse_arguments(&rc, &rv)) { | |
129 | + option_error(); | |
130 | + exit_cleanup(RERR_SYNTAX); | |
131 | + } | |
132 | + } | |
133 | + | |
134 | if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 || | |
135 | close(to_child_pipe[1]) < 0 || | |
136 | close(from_child_pipe[0]) < 0 || | |
137 | diff --git a/rsync.yo b/rsync.yo | |
138 | --- a/rsync.yo | |
139 | +++ b/rsync.yo | |
140 | @@ -412,6 +412,7 @@ to the detailed description below for a complete description. verb( | |
141 | --progress show progress during transfer | |
142 | -P same as --partial --progress | |
143 | -i, --itemize-changes output a change-summary for all updates | |
144 | + -M, --remote-option=OPTION send OPTION to the remote side only | |
145 | --out-format=FORMAT output updates using the specified FORMAT | |
146 | --log-file=FILE log what we're doing to the specified FILE | |
147 | --log-file-format=FMT log updates using the specified FMT | |
148 | @@ -1020,16 +1021,13 @@ This is a good way to backup data without using a super-user, and to store | |
149 | ACLs from incompatible systems. | |
150 | ||
151 | The bf(--fake-super) option only affects the side where the option is used. | |
152 | -To affect the remote side of a remote-shell connection, specify an rsync | |
153 | -path: | |
154 | +To affect the remote side of a remote-shell connection, use the | |
155 | +bf(--remote-option) (bf(-M)) option: | |
156 | ||
157 | -quote(tt( rsync -av --rsync-path="rsync --fake-super" /src/ host:/dest/)) | |
158 | +quote(tt( rsync -av -M--fake-super /src/ host:/dest/)) | |
159 | ||
160 | -Since there is only one "side" in a local copy, this option affects both | |
161 | -the sending and receiving of files. You'll need to specify a copy using | |
162 | -"localhost" if you need to avoid this, possibly using the "lsh" shell | |
163 | -script (from the support directory) as a substitute for an actual remote | |
164 | -shell (see bf(--rsh)). | |
165 | +For a local copy, this option affects only the source. Specify a | |
166 | +bf(--remote-option) to affect the destination. | |
167 | ||
168 | This option is overridden by both bf(--super) and bf(--no-super). | |
169 | ||
170 | @@ -1275,6 +1273,36 @@ machine for use with the bf(--relative) option. For instance: | |
171 | ||
172 | quote(tt( rsync -avR --rsync-path="cd /a/b && rsync" host:c/d /e/)) | |
173 | ||
174 | +dit(bf(-M, --remote-option=OPTION)) This option is used for more advanced | |
175 | +situations where you want certain effects to be limited to one side of the | |
176 | +transfer only. For instance, if you want to pass bf(--log-file=FILE) and | |
177 | +bf(--fake-super) to the remote system, specify it like this: | |
178 | + | |
179 | +quote(tt( rsync -av -M --log-file=foo -M--fake-super src/ dest/)) | |
180 | + | |
181 | +If you want to have an option affect only the local side of a transfer when | |
182 | +it normally affects both sides, send its negation to the remote side. Like | |
183 | +this: | |
184 | + | |
185 | +quote(tt( rsync -av -x -M--no-x src/ dest/)) | |
186 | + | |
187 | +Be cautious using this, as it is possible to toggle an option that will cause | |
188 | +rsync to have a different idea about what data to expect next over the socket, | |
189 | +and that will make it fail in a cryptic fashion. | |
190 | + | |
191 | +Note that it is best to use a separate bf(--remote-option) for each option you | |
192 | +want to pass. This makes your useage compatible with the bf(--preserve-spaces) | |
193 | +option. If that option is off, any spaces in your remote options will be split | |
194 | +by the remote shell unless you take steps to protect them. | |
195 | + | |
196 | +When performing a local transfer, the "local" side is the sender and the | |
197 | +"remote" side is the receiver. | |
198 | + | |
199 | +Note some versions of the popt option-parsing library have a bug in them that | |
200 | +prevents you from using an adjacent arg with an equal in it next to a short | |
201 | +option letter (e.g. tt(-M--log-file=/tmp/foo). If this bug affects your | |
202 | +version of popt, you can use the version of popt that is included with rsync. | |
203 | + | |
204 | dit(bf(-C, --cvs-exclude)) This is a useful shorthand for excluding a | |
205 | broad range of files that you often don't want to transfer between | |
206 | systems. It uses a similar algorithm to CVS to determine if | |
207 | @@ -1746,7 +1774,7 @@ option if you wish to override this. | |
208 | Here's a example command that requests the remote side to log what is | |
209 | happening: | |
210 | ||
211 | -verb( rsync -av --rsync-path="rsync --log-file=/tmp/rlog" src/ dest/) | |
212 | +verb( rsync -av --remote-option=--log-file=/tmp/rlog src/ dest/) | |
213 | ||
214 | This is very useful if you need to debug why a connection is closing | |
215 | unexpectedly. | |
216 | diff --git a/testsuite/chown.test b/testsuite/chown.test | |
217 | --- a/testsuite/chown.test | |
218 | +++ b/testsuite/chown.test | |
219 | @@ -16,7 +16,7 @@ | |
220 | case $0 in | |
221 | *fake*) | |
222 | $RSYNC --version | grep ", xattrs" >/dev/null || test_skipped "Rsync needs xattrs for fake device tests" | |
223 | - RSYNC="$RSYNC --fake-super" | |
224 | + RSYNC="$RSYNC --fake-super -M--fake-super" | |
225 | TLS_ARGS=--fake-super | |
226 | case "`xattr 2>&1`" in | |
227 | *--list:*) | |
228 | diff --git a/testsuite/devices.test b/testsuite/devices.test | |
229 | --- a/testsuite/devices.test | |
230 | +++ b/testsuite/devices.test | |
231 | @@ -17,7 +17,7 @@ outfile="$scratchdir/rsync.out" | |
232 | case $0 in | |
233 | *fake*) | |
234 | $RSYNC --version | grep ", xattrs" >/dev/null || test_skipped "Rsync needs xattrs for fake device tests" | |
235 | - RSYNC="$RSYNC --fake-super" | |
236 | + RSYNC="$RSYNC --fake-super -M--fake-super" | |
237 | TLS_ARGS=--fake-super | |
238 | case "`xattr 2>&1`" in | |
239 | *--list:*) |