summaryrefslogtreecommitdiffstats
path: root/plugins/org.yocto.remote.utils/src/org/yocto/remote/utils/ShellSession.java
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/org.yocto.remote.utils/src/org/yocto/remote/utils/ShellSession.java')
-rw-r--r--plugins/org.yocto.remote.utils/src/org/yocto/remote/utils/ShellSession.java332
1 files changed, 332 insertions, 0 deletions
diff --git a/plugins/org.yocto.remote.utils/src/org/yocto/remote/utils/ShellSession.java b/plugins/org.yocto.remote.utils/src/org/yocto/remote/utils/ShellSession.java
new file mode 100644
index 0000000..0922824
--- /dev/null
+++ b/plugins/org.yocto.remote.utils/src/org/yocto/remote/utils/ShellSession.java
@@ -0,0 +1,332 @@
1/*****************************************************************************
2 * Copyright (c) 2013 Ken Gilmer
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * Ken Gilmer - initial API and implementation
10 * Jessica Zhang - Adopt for Yocto Tools plugin
11 *******************************************************************************/
12package org.yocto.remote.utils;
13
14import java.io.BufferedReader;
15import java.io.File;
16import java.io.IOException;
17import java.io.InputStream;
18import java.io.InputStreamReader;
19import java.io.OutputStream;
20import java.io.OutputStreamWriter;
21import java.lang.reflect.InvocationTargetException;
22import java.util.regex.Matcher;
23import java.util.regex.Pattern;
24
25import org.eclipse.swt.widgets.Display;
26
27public class ShellSession {
28 /**
29 * Bash shell
30 */
31 public static final int SHELL_TYPE_BASH = 1;
32 /**
33 * sh shell
34 */
35 public static final int SHELL_TYPE_SH = 2;
36 private volatile boolean interrupt = false;
37 /**
38 * String used to isolate command execution
39 */
40 public static final String TERMINATOR = "build$";
41 public static final String LT = System.getProperty("line.separator");
42 private Process process;
43
44 private OutputStream pos = null;
45
46 private String shellPath = null;
47 private final String initCmd;
48 private final File root;
49 private final File builddir;
50
51 private OutputStreamWriter out;
52
53 public static String getFilePath(String file) throws IOException {
54 File f = new File(file);
55
56 if (!f.exists() || f.isDirectory()) {
57 throw new IOException("Path passed is not a file: " + file);
58 }
59
60 StringBuffer sb = new StringBuffer();
61
62 String elems[] = file.split(File.separator);
63
64 for (int i = 0; i < elems.length - 1; ++i) {
65 sb.append(elems[i]);
66 sb.append(File.separator);
67 }
68
69 return sb.toString();
70 }
71
72 public ShellSession(int shellType, File root, File builddir, String initCmd, OutputStream out) throws IOException {
73 this.root = root;
74 this.builddir = builddir;
75 this.initCmd = initCmd;
76 if (out == null) {
77 this.out = new OutputStreamWriter(null);
78 } else {
79 this.out = new OutputStreamWriter(out);
80 }
81 if (shellType == SHELL_TYPE_SH) {
82 shellPath = "/bin/sh";
83 }
84 shellPath = "/bin/bash";
85
86 initializeShell();
87 }
88
89 private void initializeShell() throws IOException {
90 process = Runtime.getRuntime().exec(shellPath);
91 pos = process.getOutputStream();
92
93 if (root != null) {
94 execute("cd " + root.getAbsolutePath());
95 }
96
97 if (initCmd != null) {
98 execute("source " + initCmd + " " + builddir.getAbsolutePath());
99 }
100 }
101
102 synchronized
103 public String execute(String command, int[] retCode) throws IOException {
104 String errorMessage = null;
105
106 interrupt = false;
107 out.write(command);
108 out.write(LT);
109
110 sendToProcessAndTerminate(command);
111
112 if (process.getErrorStream().available() > 0) {
113 byte[] msg = new byte[process.getErrorStream().available()];
114
115 process.getErrorStream().read(msg, 0, msg.length);
116 String msg_str = new String(msg);
117 out.write(msg_str);
118 out.write(LT);
119 if (!msg_str.contains("WARNING"))
120 errorMessage = "Error while executing: " + command + LT + new String(msg);
121 }
122
123 BufferedReader br = new BufferedReader(new InputStreamReader(process
124 .getInputStream()));
125
126 StringBuffer sb = new StringBuffer();
127 String line = null;
128
129 while (true) {
130 line = br.readLine();
131 if (line != null) {
132 sb.append(line);
133 sb.append(LT);
134 out.write(line);
135 out.write(LT);
136 }
137 if (line.endsWith(TERMINATOR))
138 break;
139 }
140 if (interrupt) {
141 process.destroy();
142 initializeShell();
143 interrupt = false;
144 }else if (line != null && retCode != null) {
145 try {
146 retCode[0]=Integer.parseInt(line.substring(0,line.lastIndexOf(TERMINATOR)));
147 }catch (NumberFormatException e) {
148 throw new IOException("Can NOT get return code" + command + LT + line);
149 }
150 }
151 out.flush();
152 if (errorMessage != null) {
153 throw new IOException(errorMessage);
154 }
155 return sb.toString();
156 }
157
158 synchronized
159 public void execute(String command) throws IOException {
160 interrupt = false;
161 String errorMessage = null;
162
163 sendToProcessAndTerminate(command);
164 boolean cancel = false;
165 try {
166 InputStream is = process.getInputStream();
167 InputStream es = process.getErrorStream();
168 String info;
169 while (!cancel) {
170 info = null;
171 StringBuffer buffer = new StringBuffer();
172 int c;
173 while (is.available() > 0) {
174 c = is.read();
175 char ch = (char) c;
176 buffer.append(ch);
177 if (ch == '\n') {
178 info = buffer.toString();
179 if (!info.trim().endsWith(TERMINATOR)) {
180 out.write(info);
181 out.write(LT);
182 buffer.delete(0, buffer.length());
183 } else {
184 cancel = true;
185 break;
186 }
187 }
188 }
189 while (es.available() > 0) {
190 c = es.read();
191 char ch = (char) c;
192 buffer.append(ch);
193 if (ch == '\n') {
194 info = buffer.toString();
195 if (!info.contains("WARNING"))
196 errorMessage += info;
197 out.write(info);
198 out.write(LT);
199 buffer.delete(0, buffer.length());
200 }
201 }
202 }
203 } catch (IOException e) {
204 try {
205 throw new InvocationTargetException(e);
206 } catch (InvocationTargetException e1) {
207 e1.printStackTrace();
208 }
209 }
210 out.flush();
211 if (errorMessage != null) {
212 throw new IOException(errorMessage);
213 }
214 if (interrupt) {
215 process.destroy();
216 initializeShell();
217 interrupt = false;
218 }
219 }
220 synchronized
221 public boolean ensureKnownHostKey(String user, String host) throws IOException {
222
223 boolean loadKeysMatch = false;
224 boolean accepted = false;
225 Process proc = Runtime.getRuntime().exec("ssh -o LogLevel=DEBUG3 " + user + "@" + host);
226 Pattern patternLoad = Pattern.compile("^debug3: load_hostkeys: loaded (\\d+) keys");
227 Pattern patternAuthSucceeded = Pattern.compile("^debug1: Authentication succeeded.*");
228
229 try {
230 InputStream es = proc.getErrorStream();
231 String info;
232 while (!loadKeysMatch) {
233 info = null;
234 StringBuffer buffer = new StringBuffer();
235 int c;
236 while (es.available() > 0) {
237 c = es.read();
238 char ch = (char) c;
239 buffer.append(ch);
240 if (ch == '\r') {
241 info = buffer.toString().trim();
242 Matcher m = patternLoad.matcher(info);
243 if(m.matches()) {
244 int keys = new Integer(m.group(1));
245 if (keys == 0) {
246 proc.destroy();
247 DialogRunnable runnable = new DialogRunnable("Host authenticity", "The authenticity of host '" + host + "(" + host + ")' can't be established.\nAre you sure you want to continue connecting ?", DialogRunnable.QUESTION);
248 Display.getDefault().syncExec(runnable);
249 accepted = runnable.result;
250 if (accepted){
251 proc = Runtime.getRuntime().exec("ssh -o StrictHostKeyChecking=no " + user + "@" + host);//add host key to known_hosts
252 try {
253 Thread.sleep(2000); //wait for process to finish
254 } catch (InterruptedException e) {
255 e.printStackTrace();
256 }
257 proc.destroy();
258 } else {
259 Display.getDefault().syncExec( new DialogRunnable("Host authenticity", "Host key verification failed.", DialogRunnable.ERROR));
260 }
261 } else {
262 String errorMsg = "";
263 // wait to check if key is the same and authentication succeeds
264 while (es.available() > 0) {
265 c = es.read();
266 ch = (char) c;
267 buffer.append(ch);
268 if (ch == '\r') {
269 info = buffer.toString().trim();
270 Matcher mAuthS = patternAuthSucceeded.matcher(info);
271 if(mAuthS.matches()) {
272 accepted = true;
273 break;
274 } else {
275 if (!info.startsWith("debug"))
276 errorMsg += info + "\n";
277 }
278 try {
279 Thread.sleep(100);
280 } catch (InterruptedException e) {
281 // TODO Auto-generated catch block
282 e.printStackTrace();
283 }
284 buffer.delete(0, buffer.length());
285 }
286 }
287 if (!accepted && !errorMsg.isEmpty()) {
288 Display.getDefault().syncExec( new DialogRunnable("Host authenticity", errorMsg, DialogRunnable.ERROR));
289 }
290 }
291 loadKeysMatch = true;
292 break;
293 }
294 buffer.delete(0, buffer.length());
295 }
296 }
297 }
298 es.close();
299 } catch (IOException e) {
300 try {
301 throw new InvocationTargetException(e);
302 } catch (InvocationTargetException e1) {
303 e1.printStackTrace();
304 }
305 }
306 return accepted;
307 }
308
309 /**
310 * Send command string to shell process and add special terminator string so
311 * reader knows when output is complete.
312 *
313 * @param command
314 * @throws IOException
315 */
316 private void sendToProcessAndTerminate(String command) throws IOException {
317 pos.write(command.getBytes());
318 pos.write(LT.getBytes());
319 pos.flush();
320 pos.write("echo $?".getBytes());
321 pos.write(TERMINATOR.getBytes());
322 pos.write(LT.getBytes());
323 pos.flush();
324 }
325
326 /**
327 * Interrupt any running processes.
328 */
329 public void interrupt() {
330 interrupt = true;
331 }
332}