/*******************************************************************************
* Copyright (c) 2011, 2012 Red Hat Inc and Others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat Incorporated - initial API and implementation
* IBM Corporation - Adapting to ssh
*******************************************************************************/
package org.eclipse.linuxtools.internal.ssh.proxy;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.linuxtools.profiling.launch.IRemoteCommandLauncher;
import org.eclipse.linuxtools.profiling.launch.IRemoteEnvProxyManager;
import org.eclipse.linuxtools.profiling.launch.IRemoteFileProxy;
public class SSHProxyManager implements IRemoteEnvProxyManager {
private final String SCHEME_ID = "ssh"; //$NON-NLS-1$
@Override
public IRemoteFileProxy getFileProxy(URI uri) {
return new SSHFileProxy(sanitizeURI(uri));
}
@Override
public IRemoteFileProxy getFileProxy(IProject project) {
return new SSHFileProxy(project.getLocationURI());
}
@Override
public IRemoteCommandLauncher getLauncher(URI uri) {
return new SSHCommandLauncher(sanitizeURI(uri));
}
@Override
public IRemoteCommandLauncher getLauncher(IProject project) {
return new SSHCommandLauncher(project.getLocationURI());
}
@Override
public String getOS(URI uri) throws CoreException {
SSHCommandLauncher cmdLauncher = new SSHCommandLauncher(sanitizeURI(uri));
Process p = cmdLauncher.execute(new Path("/bin/uname"), new String[] {"-s"}, new String[0], null, null); //$NON-NLS-1$ //$NON-NLS-2$
String os = ""; //$NON-NLS-1$
try {
InputStream in = p.getInputStream();
int exit = p.waitFor();
if (exit == 0) {
byte bytes[] = new byte[15];
int len;
while ((len = in.read(bytes)) != -1) {
os = os + new String(bytes, 0, len);
}
os = os.substring(0, os.indexOf('\n'));
}
} catch (InterruptedException|IOException e) {
//ignore
}
return os;
}
@Override
public String getOS(IProject project) throws CoreException {
URI uri = project.getLocationURI();
return getOS(uri);
}
@Override
public Map<String, String> getEnv(URI uri) throws CoreException {
Map<String, String> env = Collections.emptyMap();
SSHCommandLauncher cmdLauncher = new SSHCommandLauncher(sanitizeURI(uri));
Process p = cmdLauncher.execute(new Path("/bin/env"), new String[] {}, new String[] {}, null, null); //$NON-NLS-1$
String errorLine;
try (BufferedReader error = new BufferedReader(new InputStreamReader(p.getErrorStream()))){
if((errorLine = error.readLine()) != null){
throw new IOException(errorLine);
}
error.close();
} catch (IOException e) {
Status status = new Status(IStatus.ERROR, e.getMessage(), Activator.PLUGIN_ID);
Activator.getDefault().getLog().log(status);
return Collections.emptyMap();
}
/*
* It is common to export functions declaration in the environment so
* this pattern filters out them because they get truncated
* and might end up on failure.
*
* Patterns added in the env list:
* var=value
* var=value
*
* Patterns not added in the env list:
* var=() { something
*
* TODO: implement a parser for function declarations so that they do not need to be excluded
*/
Pattern variablePattern = Pattern.compile("^(.+)=([^\\(\\)\\s{].*|)$"); //$NON-NLS-1$
Matcher m;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(
p.getInputStream()))) {
String readLine = reader.readLine();
while (readLine != null) {
m = variablePattern.matcher(readLine);
if (m.matches()) {
env.put(m.group(1), m.group(2));
}
readLine = reader.readLine();
}
} catch (IOException e) {
Status status = new Status(IStatus.ERROR, e.getMessage(),
Activator.PLUGIN_ID);
Activator.getDefault().getLog().log(status);
return Collections.emptyMap();
}
return env;
}
@Override
public Map<String, String> getEnv(IProject project) throws CoreException {
URI uri = project.getLocationURI();
return getEnv(uri);
}
/*
* It happens that two or more proxy's implementation can handle same (real)
* scheme id. Conflicts can be avoided by calling the manager using an URI
* with a "fake" scheme ID, to differentiate implementations.
* So this manager can receive an URI which scheme ID is not recognized
* by the JSch implementation. As a result, we must sanitize the URI to
* use the real ID onward.
*/
private URI sanitizeURI(URI uri) {
if(uri != null && ! uri.getScheme().equals(SCHEME_ID)) {
try {
return new URI(SCHEME_ID, uri.getRawUserInfo(), uri.getHost(), uri.getPort(), uri.getRawPath()
, uri.getRawQuery(), uri.getRawFragment());
} catch (URISyntaxException e) {
Status status = new Status(IStatus.ERROR, e.getMessage(), Activator.PLUGIN_ID);
Activator.getDefault().getLog().log(status);
}
}
return uri;
}
}