You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@ant.apache.org by bu...@apache.org on 2013/01/11 22:29:15 UTC
[Bug 54408] New: SSHExec task reverses input and output stream from
JSCH
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 <exec>
private String inputProperty = null;
private String inputString = null; // like <exec>
- private File inputFile = null; // like <exec>
+ private Resource inputFile = null;
private boolean append = false; // like <exec>
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.
[Bug 54408] SSHExec task reverses input and output stream from JSCH
Posted by bu...@apache.org.
https://issues.apache.org/bugzilla/show_bug.cgi?id=54408
--- Comment #2 from Atsuhiko Yamanaka <ym...@jcraft.com> ---
I'm the author of JSch, and have also tried the attached build.xml with Apache
Ant 1.9.3, but I can't find the problem for the test case of sudo. I think the
status should be changed to "NEEDINFO".
--
You are receiving this mail because:
You are the assignee for the bug.
[Bug 54408] SSHExec task reverses input and output stream from JSCH
Posted by bu...@apache.org.
https://issues.apache.org/bugzilla/show_bug.cgi?id=54408
Jesse Glick <jg...@apache.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
Keywords| |PatchAvailable
CC| |jglick@apache.org
--
You are receiving this mail because:
You are the assignee for the bug.
[Bug 54408] SSHExec task reverses input and output stream from JSCH
Posted by bu...@apache.org.
https://issues.apache.org/bugzilla/show_bug.cgi?id=54408
Stefan Bodewig <bo...@apache.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
Status|NEW |NEEDINFO
--- Comment #3 from Stefan Bodewig <bo...@apache.org> ---
Thanks for checking!
--
You are receiving this mail because:
You are the assignee for the bug.
[Bug 54408] SSHExec task reverses input and output stream from JSCH
Posted by bu...@apache.org.
https://issues.apache.org/bugzilla/show_bug.cgi?id=54408
Antoine Levy-Lambert <an...@apache.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
Version|1.8.4 |1.9.0
--
You are receiving this mail because:
You are the assignee for the bug.
[Bug 54408] SSHExec task reverses input and output stream from JSCH
Posted by bu...@apache.org.
https://issues.apache.org/bugzilla/show_bug.cgi?id=54408
--- Comment #1 from Antoine Levy-Lambert <an...@apache.org> ---
Ben, I am not able to reproduce your problem using Java 1.7 or Java 1.6 and
jsch 0.1.49 and the current code of Ant. I have targetted my own Mac and an
ubuntu VM, running the build file on Mac if this matters.
--
You are receiving this mail because:
You are the assignee for the bug.
[Bug 54408] SSHExec task reverses input and output stream from JSCH
Posted by bu...@apache.org.
https://issues.apache.org/bugzilla/show_bug.cgi?id=54408
Antoine Levy-Lambert <an...@apache.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
Version|1.9.0 |1.9.1
--
You are receiving this mail because:
You are the assignee for the bug.