Проблема с вызовом rsync + ssh из Java на Windows - PullRequest
1 голос
/ 26 марта 2009

У меня проблемы с вызовом rsync из Java на Windows Vista с установленным Cygwin. Странно, что вставка точно такой же команды в командную оболочку работает нормально.

Мой тестовый вызов 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 потока для чтения потоков, чтобы записывать и регистрировать inputStream и errorStream процесса p.

Вот вывод ....

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) равен <0 или fd_pair (from_child_pipe) <0. </p>

Если у кого-нибудь есть предложения, было бы здорово, потому что я застрял сейчас. Спасибо,

Ответы [ 6 ]

0 голосов
/ 25 октября 2016

Недавно я реализовал нечто подобное и подумал, что поделюсь своим опытом, поскольку для устранения проблемы потребовалось довольно много времени. Этот вопрос является одним из немногих случаев этой проблемы в Google.

Мое приложение запускалось как сервис. При выполнении команды whoami результатом было «nt полномочия \ система». После установки моих ключей SSH в /home/myusername/.ssh, команда rsync не работала, так как в /home/SYSTEM/.ssh не было задано ни одной конфигурации.

Копирование моего каталога /home/myusername/.ssh в /home/SYSTEM/.ssh и использование следующего массива String сработало для моих целей. Замените PORT вашим ssh-портом.

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

См. Ссылку здесь для получения подробной информации о запуске cmd.exe в системных привилегиях для целей тестирования, если это ваша проблема.

0 голосов
/ 01 августа 2012

Мой опыт с похожей проблемой:

Мои константы:

  1. система сборки была ANT, работающей в Гудзоне

  2. сервером сборки является Windows Server

  3. удаленным тестовым сервером является Linux

  4. запрещено использовать только демон rsync rsync через ssh

Что мы сделали

  1. Установлен DeltaCopy на сервер Windows

  2. Следуйте этим инструкциям для настройки DeltaCopy, чтобы он работал с SSH

  3. Я собрал следующий макрос ANT и запустил его в hudson. Сначала это висело на мне, без ответа.

    Добавление -vvv вместо -v сделало другое. Это привело к добавлению дополнительной информации в журнал hudson.

    <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. Затем я вручную запустил команду rsync на сервере Windows, ее файл known_hosts обновляется с удаленного хоста. Это должно было быть сделано как пользователь hudson. Мы использовали команду runas в windows для запуска консоли cygwin от имени пользователя hudson.

0 голосов
/ 27 марта 2009

Спасибо всем, особенно Дэниел. Ссылка, которую вы мне прислали, отличная. В конце концов я использовал 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);
        }
0 голосов
/ 27 марта 2009

Распознает ли бинарный дистрибутив cygwin rsync команду ssh? Команда, которую вы пытаетесь выполнить, вероятно, работает нормально, когда вы помещаете ее в оболочку, потому что что-то вроде bash знает, как интерпретировать команду ssh для установления соединения, т.е. использовать программу ssh для создания соединения для программы rsync. Из вашей отладочной информации я думаю, что rsync ожидает соединения, но вместо этого получает строку "ssh ...", которую он не может передать.

Чтобы обойти это, вы должны позволить bash сделать всю работу за вас. Посмотрите на эту страницу в разделе, посвященном теме ухода за ребенком. Вам нужно будет форкнуть экземпляр командной оболочки и записать вашу команду в подпроцесс оболочки. Вот как то так:

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

Возможно, вы также захотите прочитать вывод процессов, потому что он перестанет выполняться, если вы его не прочитаете. Приведенная ссылка хорошо освещает тему.

0 голосов
/ 27 марта 2009

Я никогда не пробовал читать / писать, используя другой поток, только тот, который выполнял команду. Может ли это быть причиной вашей проблемы?

Вы также можете попробовать передать -v в ssh, чтобы получить выходные данные отладки. В прошлом это помогло мне решить проблемы с ssh-соединением. Вы пройдете -e "ssh -v".

0 голосов
/ 26 марта 2009

Есть ли у вас хранилище закрытых / открытых ключей ssh, о котором вы забыли?

...