Bug 1924 - unable to rsync between a PC with cygwin and a unix machine using rsh
Summary: unable to rsync between a PC with cygwin and a unix machine using rsh
Alias: None
Product: rsync
Classification: Unclassified
Component: core (show other bugs)
Version: 2.6.3
Hardware: x86 Windows 2000
: P3 major (vote)
Target Milestone: ---
Assignee: Wayne Davison
QA Contact: Rsync QA Contact
Depends on:
Reported: 2004-10-13 08:20 UTC by Patrick Fernandez-Canal
Modified: 2005-04-01 11:21 UTC (History)
0 users

See Also:


Note You need to log in before you can comment on or make changes to this bug.
Description Patrick Fernandez-Canal 2004-10-13 08:20:34 UTC
unable to rsync between a PC with cygwin and a unix machine using rsh
The problems occurs only when using rsync with rsh from cygwin, because the rsh 
syntax on cygwin requires that the command shall be quoted.
But when rsync fork/exec the rsh the command apears without quote (as set set 
of argv) and rsh wants the full command as a unique argv entry.

Doing that leads to the follwing message:

$ rsync -av --no-whole-file --rsync-path=/usr/local/bin/rsync -e rsh Partitions
/  wtcrep@pdmread1:/local/home/wtcrep/pfc_tst_rsync
rsh: unknown option -- server
Try `rsh --help' for more information.
rsync: read error: Connection reset by peer
rsync error: error in rsync protocol data stream (code 12) at /home/lapo/packagi

In fact fork exec uses done is the following:
rsh -l wtcrep pdmread1 /usr/local/bin/rsync --server \
     -vvlogDtpr . /local/home/wtcrep/pfc_tst_rsync

and in fact what rsh is waiting for is 
rsh -l wtcrep pdmread1 \
"/usr/local/bin/rsync --server -vvlogDtpr . /local/home/wtcrep/pfc_tst_rsync"

I did tests also between 2 Unix workstations (1 HP & 1 Sun) the rsync works 
fine. There is not the problem described above. I think that rsh 
implementations on Sun & HP are less strict therefore the problem does not 
But it should appear on Linux machine that uses the same implementation as 

I did a change in the main.c to get rid of the problem.
My change resides completely  in the do_cmd function
Hoping this can help.

Don't hesitate to contact me if you want additionnal information
kind regards

PS: Here is the my code change.
/* 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)
	int i, argc = 0;
	char *args[100];
	pid_t ret;
	char *tok, *dir = NULL;
	int dash_l_set = 0;
        /* Start ofc PFC  patched section
	to handle the of the whole command under cygwin rsh
	char *other_args[100] ;
	int other_argc = 0 ;
	char the_cmd[1024] ;
        /*  End of PFC patched section */

	if (!read_batch && !local_server) {
		char *rsh_env = getenv(RSYNC_RSH_ENV);
		if (!cmd)
			cmd = rsh_env;
		if (!cmd)
			cmd = RSYNC_RSH;
		cmd = strdup(cmd);
		if (!cmd)
			goto oom;

		for (tok = strtok(cmd, " "); tok; tok = strtok(NULL, " "))
			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;

		/* remsh (on HPUX) takes the arguments the other way around */
		args[argc++] = machine;
		if (user && !(daemon_over_rsh && dash_l_set)) {
			args[argc++] = "-l";
			args[argc++] = user;
		if (user && !(daemon_over_rsh && dash_l_set)) {
			args[argc++] = "-l";
			args[argc++] = user;
		args[argc++] = machine;

Start ofc PFC patched section 
to handle the of the whole command under cygwin rsh 
		other_args[other_argc++] = rsync_path;

		if (blocking_io < 0) {
			char *cp;
			if ((cp = strrchr(cmd, '/')) != NULL)
				cp = cmd;
			if (strcmp(cp, "rsh") == 0 || strcmp(cp, "remsh") == 0)
				blocking_io = 1;


	other_args[other_argc++] = ".";

	if (!daemon_over_rsh && path && *path)
		other_args[other_argc++] = path;

	if (!read_batch && !local_server) {
		strcpy(the_cmd, "");
		for (i=0;i<other_argc;i++){
			strcat(the_cmd, other_args[i] ) ;
			strcat(the_cmd, " " ) ;			
		args[argc++] = the_cmd ;
	else {
		for (i=0;i<other_argc;i++)
			args[argc++] =other_args[i] ;
	} ;
End of PFC patched section 
	if (argc >= (int)(sizeof args / sizeof args[0])) {
		rprintf(FERROR, "internal: args[] overflowed in do_cmd()\n");
		exit_cleanup(RERR_MALLOC); /* XXX Need better RERR? */

	args[argc] = NULL;

	if (verbose > 3) {
		for (i=0;i<argc;i++)
			rprintf(FINFO,"%s ",args[i]);

	if (local_server) {
		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);

	if (dir) free(dir);

	return ret;

	return 0; /* not reached */

Comment 1 Wayne Davison 2004-10-13 09:09:33 UTC
This is a bug in cygwin's rsh program that they should fix.  When they changed
their getopt library to one that does command-line reordering, the same problem
showed up for ssh, and I managed to talk them into fixing it.  You should
request that the same change be made to cygwin's rsh.

Work arounds are:

- Specify --rsh="rsh --" option to rsync (this should work if they fixed the bug
in how the -- option is parsed that was present back when ssh was similarly broken).

- Export POSIXLY_CORRECT in your environment.  This will prevent all commands
from reordering their command-line arguments and affects other program aspects,
so this is probably not a good way to go.

- Create a shell script that exports POSIXLY_CORRECT and then execs the real rsh
with the supplied command-line args. Rename the rsh program and name the new
shell script "rsh".  This fixes rsh for everyone on your system.

Also, please do not put large amounts of patch data in the comments -- that's
what attachments are for.
Comment 2 Wayne Davison 2004-10-13 09:23:38 UTC
I just tried running rsh on the latest cygwin, and it is not reordering the
command-line arguments, so it appears that the cygwin folks have already fixed
this problem.  Note also that rsh doesn't accept the "--" argument, so that
suggestion from my previous comment doesn't work.