Return-Path: X-Original-To: apmail-ant-notifications-archive@minotaur.apache.org Delivered-To: apmail-ant-notifications-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id EC7B2EEDA for ; Fri, 11 Jan 2013 21:29:39 +0000 (UTC) Received: (qmail 99417 invoked by uid 500); 11 Jan 2013 21:29:39 -0000 Delivered-To: apmail-ant-notifications-archive@ant.apache.org Received: (qmail 99363 invoked by uid 500); 11 Jan 2013 21:29:39 -0000 Mailing-List: contact notifications-help@ant.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@ant.apache.org Delivered-To: mailing list notifications@ant.apache.org Received: (qmail 99356 invoked by uid 99); 11 Jan 2013 21:29:39 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 11 Jan 2013 21:29:39 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.115] (HELO eir.zones.apache.org) (140.211.11.115) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 11 Jan 2013 21:29:37 +0000 Received: by eir.zones.apache.org (Postfix, from userid 80) id D353040F3; Fri, 11 Jan 2013 21:29:17 +0000 (UTC) From: bugzilla@apache.org To: notifications@ant.apache.org Subject: [Bug 54408] New: SSHExec task reverses input and output stream from JSCH Date: Fri, 11 Jan 2013 21:29:15 +0000 X-Bugzilla-Reason: AssignedTo X-Bugzilla-Type: new X-Bugzilla-Watch-Reason: None X-Bugzilla-Product: Ant X-Bugzilla-Component: Optional Tasks X-Bugzilla-Keywords: X-Bugzilla-Severity: normal X-Bugzilla-Who: dickey@freeshell.org X-Bugzilla-Status: NEW X-Bugzilla-Priority: P2 X-Bugzilla-Assigned-To: notifications@ant.apache.org X-Bugzilla-Target-Milestone: --- X-Bugzilla-Changed-Fields: bug_id short_desc product version rep_platform op_sys bug_status bug_severity priority component assigned_to reporter classification Message-ID: Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: 7bit X-Bugzilla-URL: https://issues.apache.org/bugzilla/ Auto-Submitted: auto-generated MIME-Version: 1.0 X-Virus-Checked: Checked by ClamAV on apache.org https://issues.apache.org/bugzilla/show_bug.cgi?id=54408 Bug ID: 54408 Summary: SSHExec task reverses input and output stream from JSCH Product: Ant Version: 1.8.4 Hardware: All OS: All Status: NEW Severity: normal Priority: P2 Component: Optional Tasks Assignee: notifications@ant.apache.org Reporter: dickey@freeshell.org Classification: Unclassified Created attachment 29848 --> https://issues.apache.org/bugzilla/attachment.cgi?id=29848&action=edit build file and accompanying documents exercising 3 examples of SSHExec task When using the SSHExec task to try to pass a password to the sudo command using inputproperty attribute my password was being printed to the tasks logging, and my sudo command would never complete. I found that the InputStream and OutputStream of the JSch ChannelExec object where configured reverse to how they should be according to the JSch Sudo Example at http://www.jcraft.com/jsch/examples/Sudo.java I developed the following patch to address the issue, and have attached a test case using the 3 input styles (inputproperty, inputstring, and input attributes). $ svn diff SSHExec.java Index: SSHExec.java =================================================================== --- SSHExec.java (revision 1431539) +++ SSHExec.java (working copy) @@ -28,6 +28,8 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.StringReader; +import java.io.OutputStream; +import java.util.ArrayList; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; @@ -63,7 +65,7 @@ private File outputFile = null; // like private String inputProperty = null; private String inputString = null; // like - private File inputFile = null; // like + private Resource inputFile = null; private boolean append = false; // like private boolean usePty = false; @@ -125,7 +127,7 @@ * @since Ant 1.8.0 */ public void setInput(File input) { - inputFile = input; + inputFile = new FileResource(input); } /** @@ -181,11 +183,11 @@ } /** - * Execute the command on the remote host. + * Has the user set all necessary attributes? * - * @exception BuildException Most likely a network error or bad parameter. + * @exception BuildException if there are missing required parameters. */ - public void execute() throws BuildException { + private void checkConfiguration() throws BuildException { if (getHost() == null) { throw new BuildException("Host is required."); } @@ -208,40 +210,37 @@ + " inputFile, inputProperty and" + " inputString."); } - if (inputFile != null && !inputFile.exists()) { + if (inputFile != null && !inputFile.isExists()) { throw new BuildException("The input file " - + inputFile.getAbsolutePath() + + ((FileResource)inputFile).getFile().getAbsolutePath() + " does not exist."); } + } + + /** + * Execute the command on the remote host. + * + * @exception BuildException Most likely a network error or bad parameter. + */ + public void execute() throws BuildException { + checkConfiguration(); + ArrayList inputs = getInputs(); + ArrayList cmds = getCmds(); + checkInputCmdCounts(inputs, cmds); Session session = null; StringBuffer output = new StringBuffer(); try { - session = openSession(); - /* called once */ - if (command != null) { - log("cmd : " + command, Project.MSG_INFO); - executeCommand(session, command, output); - } else { // read command resource and execute for each command - try { - BufferedReader br = new BufferedReader( - new InputStreamReader(commandResource.getInputStream())); - String cmd; - while ((cmd = br.readLine()) != null) { - log("cmd : " + cmd, Project.MSG_INFO); - output.append(cmd).append(" : "); - executeCommand(session, cmd, output); - output.append("\n"); - } - FileUtils.close(br); - } catch (IOException e) { - if (getFailonerror()) { - throw new BuildException(e); - } else { - log("Caught exception: " + e.getMessage(), - Project.MSG_ERR); - } - } + session = openSession(); /* called once */ + for(int i = 0; i < cmds.size(); i++) { + String cmd = (String)cmds.get(i); + String input = null; + if (inputs.size() > 0 && i < inputs.size()) + input=(String)inputs.get(i); + log("cmd : " + cmd, Project.MSG_INFO); + output.append(cmd).append(" : "); + executeCommand(session, cmd, input, output); + output.append("\n"); } } catch (JSchException e) { if (getFailonerror()) { @@ -259,17 +258,35 @@ } } - private void executeCommand(Session session, String cmd, StringBuffer sb) - throws BuildException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - TeeOutputStream tee = - new TeeOutputStream(out, - KeepAliveOutputStream.wrapSystemOut()); + private void checkInputCmdCounts(ArrayList inputs, ArrayList cmds) { + int cmdsCnt = cmds.size(); + if (cmdsCnt == 0) { + throw new BuildException("There are no commands to execute in " + + ((FileResource)commandResource).getFile().getAbsolutePath()); + } + int diff = cmdsCnt-inputs.size(); + if (diff > 0 && cmdsCnt > 1) { + log("There are fewer inputs than commands provided so the last "+diff + +" commands won't be provided any input", Project.MSG_WARN); + } + if (diff < 0) { + log("There are more inputs than commands provided so the last "+Math.abs(diff) + +" inputs won't used", Project.MSG_WARN); - InputStream istream = null ; + } + } + + private ArrayList getInputs() { + ArrayList inputData = new ArrayList(); if (inputFile != null) { try { - istream = new FileInputStream(inputFile) ; + String line; + BufferedReader lines = new BufferedReader( + new InputStreamReader(inputFile.getInputStream())); + while ((line = lines.readLine()) != null) { + inputData.add(line+"\n"); + } + FileUtils.close(lines); } catch (IOException e) { // because we checked the existence before, this one // shouldn't happen What if the file exists, but there @@ -278,37 +295,111 @@ + e.getMessage(), Project.MSG_WARN); } } - if (inputProperty != null) { - String inputData = getProject().getProperty(inputProperty) ; - if (inputData != null) { - istream = new ByteArrayInputStream(inputData.getBytes()) ; - } + else if (inputProperty != null) { + String propertyValue = getProject().getProperty(inputProperty); + if (propertyValue != null) + inputData.add(propertyValue+"\n"); } - if (inputString != null) { - istream = new ByteArrayInputStream(inputString.getBytes()); + else if (inputString != null) { + inputData.add(inputString+"\n"); } + return inputData; + } + private ArrayList getCmds() { + ArrayList cmds = new ArrayList(); + if (commandResource != null) { + try { + BufferedReader br = new BufferedReader( + new InputStreamReader(commandResource.getInputStream())); + String cmd; + while ((cmd = br.readLine()) != null) { + cmds.add(cmd); + } + FileUtils.close(br); + } catch (IOException e) { + if (getFailonerror()) { + throw new BuildException(e); + } else { + log("Caught exception: " + e.getMessage(), + Project.MSG_ERR); + } + } + } + else if (command != null) { + cmds.add(command); + } + return cmds; + } + + private InputStream inputFromCmd = null; + private OutputStream outputToCmd = null; + private TeeOutputStream teeToSysOut = null; + + private void executeCommand(Session session, String cmd, String input, StringBuffer sb) + throws BuildException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + teeToSysOut = new TeeOutputStream(out, + KeepAliveOutputStream.wrapSystemOut()); + ByteArrayOutputStream err = new ByteArrayOutputStream(); + TeeOutputStream teeToSysErr = new TeeOutputStream(err, + KeepAliveOutputStream.wrapSystemErr()); + try { final ChannelExec channel; session.setTimeout((int) maxwait); /* execute the command */ channel = (ChannelExec) session.openChannel("exec"); channel.setCommand(cmd); - channel.setOutputStream(tee); - channel.setExtOutputStream(tee); - if (istream != null) { - channel.setInputStream(istream); - } channel.setPty(usePty); + + if (input != null) { + outputToCmd = channel.getOutputStream(); + } else + channel.setOutputStream(null); + + inputFromCmd = channel.getInputStream(); + channel.setErrStream(teeToSysErr); channel.connect(); + log("successfully connected"); + if (input != null) { + outputToCmd.write(input.getBytes()); + outputToCmd.flush(); + } + // wait for it to finish thread = new Thread() { public void run() { - while (!channel.isClosed()) { + byte[] tmp = new byte[1024]; + while (true) { + log("attempting to read input from SSHExec command", Project.MSG_DEBUG); + try { + while (inputFromCmd.available() > 0) { + int read = inputFromCmd.read(tmp); + if (read < 0) + break; + // sb.append((char[]) tmp, 0, read); + teeToSysOut.write(tmp, 0, read); + } + } catch (IOException ioe) { + handleErrorFlush("Error handling output from cmd:" + + ioe.getMessage()); + } if (thread == null) { return; } + if (channel.isClosed()) { + String str = "cmd exited with status: " + + channel.getExitStatus(); + try { + teeToSysOut.write(str.getBytes()); + } catch (IOException ioe) { + handleErrorFlush("Error handling channel close message:" + + ioe.getMessage()); + } + return; + } try { sleep(RETRY_INTERVAL); } catch (Exception e) { @@ -372,7 +463,6 @@ } } finally { sb.append(out.toString()); - FileUtils.close(istream); } } @@ -407,4 +497,4 @@ } } } -} \ No newline at end of file +} -- You are receiving this mail because: You are the assignee for the bug.