diff options
author | Adrian Dudau <adrian.dudau@enea.com> | 2013-12-12 13:36:50 +0100 |
---|---|---|
committer | Adrian Dudau <adrian.dudau@enea.com> | 2013-12-12 15:25:03 +0100 |
commit | 41ac47d732eed8392d60d0f6773e5a279d49b999 (patch) | |
tree | cf19d099db9cfdb8d73aa21c31e7aa1cc86ff860 /plugins/org.yocto.remote.utils/src/org/yocto/remote/utils/ShellSession.java | |
download | eclipse-poky-juno-master.tar.gz |
Migrated from the internal git server on the dora-enea branch
Signed-off-by: Adrian Dudau <adrian.dudau@enea.com>
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.java | 332 |
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 | *******************************************************************************/ | ||
12 | package org.yocto.remote.utils; | ||
13 | |||
14 | import java.io.BufferedReader; | ||
15 | import java.io.File; | ||
16 | import java.io.IOException; | ||
17 | import java.io.InputStream; | ||
18 | import java.io.InputStreamReader; | ||
19 | import java.io.OutputStream; | ||
20 | import java.io.OutputStreamWriter; | ||
21 | import java.lang.reflect.InvocationTargetException; | ||
22 | import java.util.regex.Matcher; | ||
23 | import java.util.regex.Pattern; | ||
24 | |||
25 | import org.eclipse.swt.widgets.Display; | ||
26 | |||
27 | public 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 | } | ||