| 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 | +static int remote_option_alloc = 0; |
| 22 | +int remote_option_cnt = 0; |
| 23 | +const char **remote_options = NULL; |
| 24 | + |
| 25 | int verbose = 0; |
| 26 | int quiet = 0; |
| 27 | int output_motd = 1; |
| 28 | @@ -388,6 +392,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 | @@ -646,6 +651,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 | @@ -1141,6 +1147,26 @@ 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+2 >= remote_option_alloc) { |
| 56 | + remote_option_alloc += 16; |
| 57 | + remote_options = realloc_array(remote_options, |
| 58 | + const char *, remote_option_alloc); |
| 59 | + if (!remote_options) |
| 60 | + out_of_memory("parse_arguments"); |
| 61 | + if (!remote_option_cnt) |
| 62 | + remote_options[0] = "ARG0"; |
| 63 | + } |
| 64 | + remote_options[++remote_option_cnt] = arg; |
| 65 | + remote_options[remote_option_cnt+1] = NULL; |
| 66 | + break; |
| 67 | + |
| 68 | case OPT_WRITE_BATCH: |
| 69 | /* batch_name is already set */ |
| 70 | write_batch = 1; |
| 71 | @@ -2063,6 +2089,16 @@ void server_options(char **args, int *argc_p) |
| 72 | else if (remove_source_files) |
| 73 | args[ac++] = "--remove-sent-files"; |
| 74 | |
| 75 | + if (remote_option_cnt) { |
| 76 | + int j; |
| 77 | + if (ac + remote_option_cnt > MAX_SERVER_ARGS) { |
| 78 | + rprintf(FERROR, "too many remote options specified.\n"); |
| 79 | + exit_cleanup(RERR_SYNTAX); |
| 80 | + } |
| 81 | + for (j = 1; j <= remote_option_cnt; j++) |
| 82 | + args[ac++] = (char*)remote_options[j]; |
| 83 | + } |
| 84 | + |
| 85 | if (ac > MAX_SERVER_ARGS) { /* Not possible... */ |
| 86 | rprintf(FERROR, "argc overflow in server_options().\n"); |
| 87 | exit_cleanup(RERR_MALLOC); |
| 88 | diff --git a/pipe.c b/pipe.c |
| 89 | --- a/pipe.c |
| 90 | +++ b/pipe.c |
| 91 | @@ -28,6 +28,8 @@ extern int blocking_io; |
| 92 | extern int filesfrom_fd; |
| 93 | extern mode_t orig_umask; |
| 94 | extern char *logfile_name; |
| 95 | +extern int remote_option_cnt; |
| 96 | +extern const char **remote_options; |
| 97 | extern struct chmod_mode_struct *chmod_modes; |
| 98 | |
| 99 | /** |
| 100 | @@ -139,6 +141,15 @@ pid_t local_child(int argc, char **argv, int *f_in, int *f_out, |
| 101 | logfile_close(); |
| 102 | } |
| 103 | |
| 104 | + if (remote_option_cnt) { |
| 105 | + int rc = remote_option_cnt + 1; |
| 106 | + const char **rv = remote_options; |
| 107 | + if (!parse_arguments(&rc, &rv)) { |
| 108 | + option_error(); |
| 109 | + exit_cleanup(RERR_SYNTAX); |
| 110 | + } |
| 111 | + } |
| 112 | + |
| 113 | if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 || |
| 114 | close(to_child_pipe[1]) < 0 || |
| 115 | close(from_child_pipe[0]) < 0 || |
| 116 | diff --git a/rsync.yo b/rsync.yo |
| 117 | --- a/rsync.yo |
| 118 | +++ b/rsync.yo |
| 119 | @@ -416,6 +416,7 @@ to the detailed description below for a complete description. verb( |
| 120 | --progress show progress during transfer |
| 121 | -P same as --partial --progress |
| 122 | -i, --itemize-changes output a change-summary for all updates |
| 123 | + -M, --remote-option=OPTION send OPTION to the remote side only |
| 124 | --out-format=FORMAT output updates using the specified FORMAT |
| 125 | --log-file=FILE log what we're doing to the specified FILE |
| 126 | --log-file-format=FMT log updates using the specified FMT |
| 127 | @@ -1030,16 +1031,16 @@ This is a good way to backup data without using a super-user, and to store |
| 128 | ACLs from incompatible systems. |
| 129 | |
| 130 | The bf(--fake-super) option only affects the side where the option is used. |
| 131 | -To affect the remote side of a remote-shell connection, specify an rsync |
| 132 | -path: |
| 133 | +To affect the remote side of a remote-shell connection, use the |
| 134 | +bf(--remote-option) (bf(-M)) option: |
| 135 | |
| 136 | -quote(tt( rsync -av --rsync-path="rsync --fake-super" /src/ host:/dest/)) |
| 137 | +quote(tt( rsync -av -M--fake-super /src/ host:/dest/)) |
| 138 | |
| 139 | -Since there is only one "side" in a local copy, this option affects both |
| 140 | -the sending and receiving of files. You'll need to specify a copy using |
| 141 | -"localhost" if you need to avoid this, possibly using the "lsh" shell |
| 142 | -script (from the support directory) as a substitute for an actual remote |
| 143 | -shell (see bf(--rsh)). |
| 144 | +For a local copy, this option affects both the source and the destination. |
| 145 | +If you wish a local copy to enable this option just for the destination |
| 146 | +files, specify bf(-M--fake-super). If you wish a local copy to enable |
| 147 | +this option just for the source files, combine bf(--fake-super) with |
| 148 | +bf(-M--super). |
| 149 | |
| 150 | This option is overridden by both bf(--super) and bf(--no-super). |
| 151 | |
| 152 | @@ -1292,6 +1293,36 @@ machine for use with the bf(--relative) option. For instance: |
| 153 | |
| 154 | quote(tt( rsync -avR --rsync-path="cd /a/b && rsync" host:c/d /e/)) |
| 155 | |
| 156 | +dit(bf(-M, --remote-option=OPTION)) This option is used for more advanced |
| 157 | +situations where you want certain effects to be limited to one side of the |
| 158 | +transfer only. For instance, if you want to pass bf(--log-file=FILE) and |
| 159 | +bf(--fake-super) to the remote system, specify it like this: |
| 160 | + |
| 161 | +quote(tt( rsync -av -M --log-file=foo -M--fake-super src/ dest/)) |
| 162 | + |
| 163 | +If you want to have an option affect only the local side of a transfer when |
| 164 | +it normally affects both sides, send its negation to the remote side. Like |
| 165 | +this: |
| 166 | + |
| 167 | +quote(tt( rsync -av -x -M--no-x src/ dest/)) |
| 168 | + |
| 169 | +Be cautious using this, as it is possible to toggle an option that will cause |
| 170 | +rsync to have a different idea about what data to expect next over the socket, |
| 171 | +and that will make it fail in a cryptic fashion. |
| 172 | + |
| 173 | +Note that it is best to use a separate bf(--remote-option) for each option you |
| 174 | +want to pass. This makes your useage compatible with the bf(--protect-args) |
| 175 | +option. If that option is off, any spaces in your remote options will be split |
| 176 | +by the remote shell unless you take steps to protect them. |
| 177 | + |
| 178 | +When performing a local transfer, the "local" side is the sender and the |
| 179 | +"remote" side is the receiver. |
| 180 | + |
| 181 | +Note some versions of the popt option-parsing library have a bug in them that |
| 182 | +prevents you from using an adjacent arg with an equal in it next to a short |
| 183 | +option letter (e.g. tt(-M--log-file=/tmp/foo). If this bug affects your |
| 184 | +version of popt, you can use the version of popt that is included with rsync. |
| 185 | + |
| 186 | dit(bf(-C, --cvs-exclude)) This is a useful shorthand for excluding a |
| 187 | broad range of files that you often don't want to transfer between |
| 188 | systems. It uses a similar algorithm to CVS to determine if |
| 189 | @@ -1768,7 +1799,7 @@ option if you wish to override this. |
| 190 | Here's a example command that requests the remote side to log what is |
| 191 | happening: |
| 192 | |
| 193 | -verb( rsync -av --rsync-path="rsync --log-file=/tmp/rlog" src/ dest/) |
| 194 | +verb( rsync -av --remote-option=--log-file=/tmp/rlog src/ dest/) |
| 195 | |
| 196 | This is very useful if you need to debug why a connection is closing |
| 197 | unexpectedly. |