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