在Windows上从java调用rsync + ssh的问题

时间:2009-03-26 17:05:56

标签: java ssh rsync

我在安装了cygwin的windows vista上从java调用rsync时遇到问题。 奇怪的是将完全相同的命令粘贴到命令shell中工作正常。

我的测试java调用看起来像这样。

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);

然后我启动2个流读取器线程来捕获并记录Process p的inputStream和errorStream。

这是输出....

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]

发生错误的rsync代码是pipe.c(57)就是这个。

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

因此,由于某种原因,fd_pair(to_child_pipe)是&lt; 0或fd_pair(from_child_pipe)&lt; 0

如果有人有任何建议,那么现在我就会被困住。 谢谢,

6 个答案:

答案 0 :(得分:0)

你有忘记的某个私人/公共密钥库吗?

答案 1 :(得分:0)

我从未尝试使用不同的线程进行读/写,只是执行命令的同一线程。这会导致你的问题吗?

您也可以尝试将-v传递给ssh以获取调试输出。这帮助我解决了ssh连接问题。你会通过-e "ssh -v"

答案 2 :(得分:0)

cygwin的rsync二进制分发是否识别ssh命令?当您放入shell时,您尝试执行的命令可能正常工作,因为像bash这样的东西知道如何解释ssh命令以建立连接,即使用ssh程序为rsync程序创建连接。根据您的调试信息,我认为rsync期望连接,但是收到一个字符串“ssh ...”,它无法管道。

要解决这个问题,你必须让bash为你工作。请查看有关线程的部分中的this page以了解孩子。您需要派生命令shell的实例并将命令写入shell子进程。所以像这样:

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.");
}

您可能也想要读取进程输出,因为如果您不读它,它将停止执行。提供的链接很好地涵盖了这个主题。

答案 3 :(得分:0)

谢谢大家,特别是丹尼尔。你发给我的链接很棒。 最后我使用了ProcessBuilder而不是Runtime.exec。 如果对任何人有任何帮助,这是代码.....

            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);
        }

答案 4 :(得分:0)

我对类似问题的经验:

我的常数:

  1. 构建系统是ANT,在Hudson中运行

  2. 构建服务器是Windows Server

  3. 远程测试服务器是Linux

  4. 不允许仅通过ssh使用rsync守护进程rsync

  5. 我们做了什么

    1. 将DeltaCopy安装到Windows服务器

    2. 按照这些说明设置DeltaCopy,以便它可以使用SSH

    3. 我构建了以下ANT宏,并在hudson中运行它。 起初这件事挂在我身上,没有回应。

      添加-vvv而不是-v会有所不同。这导致更多信息被添加到哈德森日志中。

      <macrodef name="rsync">
      <attribute name="username"/>
      <attribute name="remoteServer"/>
      <attribute name="remoteDir"/>
      <attribute name="sourceDir"/> <!-- relative to basedir start and end with / (e.g. "/html/resources/" -->
      <sequential>
          <echo message="Starting rsync @{sourceDir} to @{remoteDir} on server @{remoteServer} as user @{username} at ${release.start}"/>
      
          <pathconvert property="cygwinbasepath" dirsep="/" pathsep="" description="Replace ':' '\' with '/' and assign value to property">
              <path path="${basedir}" description="Original version" />
              <!--Pathconvert will try to add the root directory to the "path", replace with empty string --> 
              <filtermapper> 
                  <replacestring from=":" to="" />  
              </filtermapper>
          </pathconvert>
          <echo message="${basedir} converted to ${cygwinbasepath}"/>
      
          <property name="rsync.cygwinSourcePath" value="/cygdrive/${cygwinbasepath}@{sourceDir}" />
          <!-- ${rsync.user}@${rsync.server}:${rsync.dir} -->
          <property name="rsync.remoteDestinationPath" value="@{remoteServer}:@{remoteDir}" />
      
          <echo message="trying to run:" />
          <!-- &quot; is escaped quote -->
          <echo>cmd /C rsync -avz -e &quot;ssh -v -l ${deployment.rsync.username} -i /cygdrive/C/cygwin/home/service-tomcat/.ssh/id_rsa&quot; --recursive --chmod=a=rw,Da+x ${rsync.cygwinSourcePath} ${rsync.remoteDestinationPath}</echo>
          <echo>
          </echo>
          <!-- 10 minute timeout -->
          <exec executable="C:\cygwin\bin\mintty.exe"
              timeout="300000"
          >
              <arg value="rsync"/>
                <arg value="-avvvz"/>
                <arg value="-e" />
                <arg value="ssh -v -l ${deployment.rsync.username} -i /cygdrive/C/cygwin/home/vj-service-tomcat/.ssh/id_rsa" />
                <arg value="--recursive"/>
                <arg value="--chmod=a=rw,Da+x"/> 
                <arg value="${rsync.cygwinSourcePath}"/>
                <arg value="${rsync.remoteDestinationPath}"/>
          </exec>
      
          <echo>
          </echo>
      
      </sequential>
      

      实现这一目标的关键是执行C:\cygwin\bin\mintty.exe而不是cmd

    4. 然后我在Windows服务器上手动运行rsync命令,使用远程主机更新其known_hosts文件。 这必须以hudson用户身份完成。我们在windows中使用runas命令以hudson用户身份启动cygwin控制台。

答案 5 :(得分:0)

我最近实现了类似的东西,并认为我会分享我的经验,因为它需要相当长的时间来调试问题。这个问题是google上这个问题的唯一例子之一。

我的应用程序是作为服务启动的。运行whoami命令时,结果是&#34; nt authority \ system&#34;。在/home/myusername/.ssh下设置了我的SSH密钥后,rsync命令失败,因为在/home/SYSTEM/.ssh下没有设置任何配置。

将我的/home/myusername/.ssh目录复制到/home/SYSTEM/.ssh并使用以下字符串数组可用于我的目的。用您的ssh端口替换PORT。

new String[]{"rsync", "-z", "-I", "-e", "ssh -p PORT", server + ":" + serverPath, clientPath}

有关在系统权限下启动cmd.exe以进行测试的详细信息,请参阅链接here。如果这是您的问题。