/********************************************************************************
* Copyright (c) 2009, 2015 MontaVista Software, Inc. and others.
* 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:
* Anna Dushistova (MontaVista) - initial API and implementation
* Anna Dushistova (Mentor Graphics) - [314659] moved common methods for DSF and CDI launches to this class
* Anna Dushistova (Mentor Graphics) - changed spaceEscapify visibility
* Anna Dushistova (MontaVista) - [318051][remote debug] Terminating when "Remote shell" process is selected doesn't work
* Wainer Moschetta(IBM) - [452356] replace RSE with org.eclipse.remote
********************************************************************************/
package org.eclipse.cdt.launch.remote;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
import org.eclipse.cdt.internal.launch.remote.Activator;
import org.eclipse.cdt.internal.launch.remote.Messages;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.filesystem.IFileSystem;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.osgi.util.NLS;
import org.eclipse.remote.core.IRemoteCommandShellService;
import org.eclipse.remote.core.IRemoteConnection;
import org.eclipse.remote.core.IRemoteConnectionHostService;
import org.eclipse.remote.core.IRemoteFileService;
import org.eclipse.remote.core.IRemoteProcess;
import org.eclipse.remote.core.IRemoteProcessBuilder;
import org.eclipse.remote.core.IRemoteServicesManager;
import org.eclipse.remote.core.RemoteProcessAdapter;
public class RemoteHelper {
private final static String EXIT_CMD = "exit"; //$NON-NLS-1$
private final static String CMD_DELIMITER = ";"; //$NON-NLS-1$
public static IRemoteConnection getRemoteConnectionByName(String remoteConnection) {
if (remoteConnection == null)
return null;
IRemoteServicesManager manager = Activator.getService(IRemoteServicesManager.class);
if (manager == null) {
return null;
}
List<IRemoteConnection> conns = manager.getAllRemoteConnections();
for (IRemoteConnection conn: conns) {
if (conn.getName().contentEquals(remoteConnection)) {
return conn;
}
}
return null;
}
public static IRemoteFileService getFileSubsystem(IRemoteConnection conn) {
if (conn == null) {
return null;
}
return conn.getService(IRemoteFileService.class);
}
public static IRemoteConnection[] getSuitableConnections() {
IRemoteServicesManager manager = Activator.getService(IRemoteServicesManager.class);
if (manager == null)
return null;
ArrayList<IRemoteConnection> suitableConnections = new ArrayList<>();
List<IRemoteConnection> allConnections = manager.getAllRemoteConnections();
for (IRemoteConnection conn: allConnections) {
if (conn.hasService(IRemoteCommandShellService.class)) {
suitableConnections.add(conn);
}
}
return suitableConnections.toArray(new IRemoteConnection[]{});
}
public static void remoteFileDownload(ILaunchConfiguration config,
ILaunch launch, String localExePath, String remoteExePath,
IProgressMonitor monitor) throws CoreException {
boolean skipDownload = config
.getAttribute(
IRemoteConnectionConfigurationConstants.ATTR_SKIP_DOWNLOAD_TO_TARGET,
false);
if (skipDownload)
// Nothing to do. Download is skipped.
return;
monitor.beginTask(Messages.RemoteRunLaunchDelegate_2, 100);
try {
IRemoteConnection conn = getCurrentConnection(config);
IRemoteFileService fs = conn.getService(IRemoteFileService.class);
IFileStore remoteFile = fs.getResource(remoteExePath);
IFileSystem localfs = EFS.getLocalFileSystem();
IFileStore localFile = localfs.getStore(new Path(localExePath));
if (!localFile.fetchInfo().exists()) {
return;
}
localFile.copy(remoteFile, EFS.OVERWRITE, monitor);
// Need to change the permissions to match the original file
// permissions because of a bug in upload
Process p = remoteShellExec(
config,
"", "chmod", "+x " + spaceEscapify(remoteExePath), new SubProgressMonitor(monitor, 5)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
// Wait if necessary for the permission change
try {
int timeOut = 10;
boolean exited = p.waitFor(timeOut, TimeUnit.SECONDS);
if (!exited) {
Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR,
"Failed to change file permissions in the remote system, path: " + remoteExePath, //$NON-NLS-1$
null);
throw new CoreException(status);
}
} catch (InterruptedException e) {
Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR,
"Interrupted while changing file permissions in the remote system, path: " //$NON-NLS-1$
+ remoteExePath,
e);
throw new CoreException(status);
}
} catch (CoreException e) {
abort(Messages.RemoteRunLaunchDelegate_6, e,
ICDTLaunchConfigurationConstants.ERR_INTERNAL_ERROR);
} finally {
monitor.done();
}
}
public static String spaceEscapify(String inputString) {
if (inputString == null)
return null;
return inputString.replaceAll(" ", "\\\\ "); //$NON-NLS-1$ //$NON-NLS-2$
}
public static IRemoteConnection getCurrentConnection(ILaunchConfiguration config)
throws CoreException {
String remoteConnection = config.getAttribute(
IRemoteConnectionConfigurationConstants.ATTR_REMOTE_CONNECTION,
""); //$NON-NLS-1$
IRemoteConnection connection = getRemoteConnectionByName(remoteConnection);
if (connection == null) {
abort(Messages.RemoteRunLaunchDelegate_13, null,
ICDTLaunchConfigurationConstants.ERR_INTERNAL_ERROR);
}
return connection;
}
public static Process remoteShellExec(ILaunchConfiguration config,
String prelaunchCmd, String remoteCommandPath, String arguments,
IProgressMonitor monitor) throws CoreException {
// The exit command is called to force the remote shell to close after
// our command
// is executed. This is to prevent a running process at the end of the
// debug session.
// See Bug 158786.
monitor.beginTask(NLS.bind(Messages.RemoteRunLaunchDelegate_8,
remoteCommandPath, arguments), 10);
String realRemoteCommand = arguments == null ? spaceEscapify(remoteCommandPath)
: spaceEscapify(remoteCommandPath) + " " + arguments; //$NON-NLS-1$
String remoteCommand = realRemoteCommand + CMD_DELIMITER + EXIT_CMD + "\r\n"; //$NON-NLS-1$
if (!prelaunchCmd.trim().equals("")) //$NON-NLS-1$
remoteCommand = prelaunchCmd + CMD_DELIMITER + remoteCommand;
IRemoteConnection conn = getCurrentConnection(config);
IRemoteCommandShellService shellService = conn.getService(IRemoteCommandShellService.class);
IRemoteProcess remoteProcess = null;
Process p = null;
try {
remoteProcess = shellService.getCommandShell(IRemoteProcessBuilder.ALLOCATE_PTY);
p = new RemoteProcessAdapter(remoteProcess);
OutputStream os = remoteProcess.getOutputStream();
os.write(remoteCommand.getBytes());
os.flush();
} catch (IOException e) {
abort(Messages.RemoteRunLaunchDelegate_7, e,
ICDTLaunchConfigurationConstants.ERR_INTERNAL_ERROR);
}
monitor.done();
return p;
}
public static IRemoteProcess execCmdInRemoteShell(ILaunchConfiguration config,
String prelaunchCmd, String remoteCommandPath, String arguments,
IProgressMonitor monitor) throws Exception {
// The exit command is called to force the remote shell to close after
// our command
// is executed. This is to prevent a running process at the end of the
// debug session.
// See Bug 158786.
monitor.beginTask(NLS.bind(Messages.RemoteRunLaunchDelegate_8,
remoteCommandPath, arguments), 10);
String realRemoteCommand = arguments == null ? spaceEscapify(remoteCommandPath)
: spaceEscapify(remoteCommandPath) + " " + arguments; //$NON-NLS-1$
String remoteCommand = realRemoteCommand + CMD_DELIMITER + EXIT_CMD + "\r\n"; //$NON-NLS-1$
if (!prelaunchCmd.trim().equals("")) //$NON-NLS-1$
remoteCommand = prelaunchCmd + CMD_DELIMITER + remoteCommand;
IRemoteConnection conn = getCurrentConnection(config);
if (!conn.isOpen()) {
conn.open(monitor);
}
IRemoteCommandShellService shellService = conn.getService(IRemoteCommandShellService.class);
IRemoteProcess p = null;
p = shellService.getCommandShell(IRemoteProcessBuilder.ALLOCATE_PTY);
OutputStream os = p.getOutputStream();
os.write(remoteCommand.getBytes());
os.flush();
monitor.done();
return p;
}
public static String getRemoteHostname(ILaunchConfiguration config)
throws CoreException {
IRemoteConnection currentConnection = getCurrentConnection(config);
IRemoteConnectionHostService hostService = currentConnection.getService(IRemoteConnectionHostService.class);
return hostService.getHostname();
}
/**
* Throws a core exception with an error status object built from the given
* message, lower level exception, and error code.
*
* @param message
* the status message
* @param exception
* lower level exception associated with the error, or
* <code>null</code> if none
* @param code
* error code
*/
public static void abort(String message, Throwable exception, int code) throws CoreException {
IStatus status;
if (exception != null) {
MultiStatus multiStatus = new MultiStatus(Activator.PLUGIN_ID, code, message, exception);
multiStatus.add(new Status(IStatus.ERROR, Activator.PLUGIN_ID, code, exception.getLocalizedMessage(), exception));
status= multiStatus;
} else {
status= new Status(IStatus.ERROR, Activator.PLUGIN_ID, code, message, null);
}
throw new CoreException(status);
}
}