tags:

views:

920

answers:

4

I'm having trouble calling rsync from java on windows vista with cygwin installed. Its strange as pasting the exact same command into a command shell works fine.

My test java call looks like this.

String[] envVars = {"PATH=c:/cygwin/bin;%PATH%"};
File workingDir = new File("c:/cygwin/bin/");
Process p = Runtime.getRuntime().exec("c:/cygwin/bin/rsync.exe -verbose -r -t -v --progress -e ssh /cygdrive/c/Users/dokeeffe/workspace/jrsync/ www.servername.net:/home/dokeeffe/rsync/",envVars,workingDir);

Then I start 2 stream reader threads to capture and log the inputStream and errorStream of the Process p.

Here is the output....

DEBUG: com.mddc.client.rsync.StreamGobbler - opening connection using: ssh www.servername.net rsync --server -vvtre.iLs . /home/dokeeffe/rsync/
DEBUG: com.mddc.client.rsync.StreamGobbler - rsync: pipe: Operation not permitted (1)
DEBUG: com.mddc.client.rsync.StreamGobbler - rsync error: error in IPC code (code 14) at /home/lapo/packaging/rsync-3.0.4-1/src/rsync-3.0.4/pipe.c(57) [sender=3.0.4]

The rsync code where the error happens is pipe.c(57) which is this.

if (fd_pair(to_child_pipe) < 0 || fd_pair(from_child_pipe) < 0) {
    rsyserr(FERROR, errno, "pipe");
    exit_cleanup(RERR_IPC);
}

So, for some reason fd_pair(to_child_pipe) is < 0 or fd_pair(from_child_pipe) < 0.

If anyone has any suggestions it would be great as I'm stuck now. Thanks,

A: 

Do you have ssh private/public keystore somewhere that you have forgotten about?

Michael Sharek
Yes I have the keystore setup and the command works fine (no password needed) when I enter in the cmd window or cygwin shell
Derek
A: 

I've never tried reading/writing using a different thread, only the same thread that executed the command. Could this be causing your problem?

You can also try passing -v to ssh to get debug output. That has helped me in the past to resolve ssh connection problems. You would pass -e "ssh -v".

sjbotha
A: 

Does cygwin's binary distribution of rsync recognize the ssh command? The command you are trying to execute probably works fine when you put into the shell because something like bash knows how to interpret the ssh command to establish a connection, i.e. use the ssh program to create a connection for the rsync program. From your debugging information I think rsync is expecting a connection but instead receives a string "ssh ..." which it fails to pipe.

To get around this you have to let bash do the work for you. Look at this page in the section on threads to tend the child. You would need to fork an instance of a command shell and write your command to the shell subprocess. So something like this:

Process p = Runtime.getRuntime().exec("c:/cygwin/bin/bash.exe");
OutputStreamWriter osw = new OutputStreamWriter(p.getOutputStream());
BufferedWriter bw = new BufferedWriter( osw, 100);
try{
    bw.write(command);
      bw.close();
}catch(IOExeception e){
    System.out.println("Problem writing command.");
}

You would probably want to read the processes output too because it will stop executing if you do not read it. The link provided covers the topic well.

Daniel Nesbitt
I'm glad this helps. I had a similar problem trying to execute "program < somefile" as the redirection operator '<' is a shell function.
Daniel Nesbitt
A: 

Thanks everyone esp Daniel. The link you sent me is great. In the end I used ProcessBuilder instead of Runtime.exec. Here is the code if its any help to anyone.....

      ProcessBuilder pb = new ProcessBuilder(new String[]{"c:/cygwin/bin/rsync.exe"
                ,"-verbose",
                "-r",
                "-t",
                "-v",
                "--progress",
                "-e",
                "ssh",
                "/cygdrive/c/Users/dokeeffe/workspace/jrsync/",
                "www.servername.net:/home/dokeeffe/rsync/"});
  Map<String, String> env = pb.environment();
  env.put("PATH","/cygwin/bin;%PATH%");
  pb.directory(new File("c:/cygwin/bin/"));
  Process p = pb.start();
  StreamGobbler outputGobbler = new StreamGobbler(p.getInputStream(),"OUTPUT");
  StreamGobbler errorGobbler = new StreamGobbler(p.getErrorStream(),"ERROR");
  outputGobbler.start();
  errorGobbler.start();
  int val = p.waitFor();
  if(val!=0){
   throw new Exception("Rsync return code="+val);
  }
Derek