/******************************************************************************* * Copyright (c) 2011 IBM Corporation * 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: * Otavio Busatto Pontes <obusatto@br.ibm.com> - initial API and implementation *******************************************************************************/ package org.eclipse.linuxtools.tools.launch.core.factory; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.URI; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.StringTokenizer; import org.eclipse.cdt.utils.pty.PTY; import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.linuxtools.profiling.launch.IRemoteCommandLauncher; import org.eclipse.linuxtools.profiling.launch.IRemoteFileProxy; import org.eclipse.linuxtools.profiling.launch.RemoteProxyManager; /* * Create process using Runtime.getRuntime().exec and prepends the * 'Linux tools path' project property to the environment PATH. * Use this factory instead of Runtime.getRuntime().exec if the command you * are running may be in the linux tools path selected in the project property * page. */ public class RuntimeProcessFactory extends LinuxtoolsProcessFactory { private static RuntimeProcessFactory instance = null; private static final String WHICH_CMD = "which"; //$NON-NLS-1$ private static final String WHERE_CMD = "where"; //$NON-NLS-1$ private String[] tokenizeCommand(String command) { StringTokenizer tokenizer = new StringTokenizer(command); String[] cmdarray = new String[tokenizer.countTokens()]; for (int i = 0; tokenizer.hasMoreElements(); i++) { cmdarray[i] = tokenizer.nextToken(); } return cmdarray; } private String[] fillPathCommand(String[] cmdarray, IProject project) throws IOException { cmdarray[0] = whichCommand(cmdarray[0], project); return cmdarray; } private String[] fillPathSudoCommand(String[] cmdarray, IProject project) throws IOException { cmdarray[1] = whichCommand(cmdarray[1], project); return cmdarray; } /** * Used to get the full command path. It will look for the command in the * system path and in the path selected in 'Linux Tools Path' preference page * in the informed project. * * @param command The desired command * @param project The current project. If null, only system path will be * used to look for the command. * @return The full command path if command was found or the command if * command was not found. * @throws IOException If problem executing the command occured. * * @since 1.1 */ public String whichCommand(String command, IProject project) throws IOException { String[] envp = updateEnvironment(null, project); try { IRemoteFileProxy proxy = RemoteProxyManager.getInstance().getFileProxy(project); URI whichUri; // For Windows, we use the where command, otherwise, we use the Unix which command if ((project != null && Platform.OS_WIN32.equals(RemoteProxyManager.getInstance().getOS(project))) || Platform.OS_WIN32.equals(Platform.getOS())) { whichUri = URI.create(WHERE_CMD); } else { whichUri = URI.create(WHICH_CMD); } IPath whichPath = new Path(proxy.toPath(whichUri)); IRemoteCommandLauncher launcher = RemoteProxyManager.getInstance().getLauncher(project); Process pProxy = launcher.execute(whichPath, new String[]{command}, envp, null, new NullProgressMonitor()); if (pProxy != null) { ArrayList<String> lines = new ArrayList<>(); try (BufferedReader reader = new BufferedReader( new InputStreamReader(pProxy.getInputStream()))) { String readLine = reader.readLine(); while (readLine != null) { lines.add(readLine); readLine = reader.readLine(); } } if (!lines.isEmpty()) { if (project != null && project.getLocationURI() != null) { if (project.getLocationURI().toString() .startsWith("rse:")) { //$NON-NLS-1$ // RSE output if (lines.size() > 1) { command = lines.get(lines.size() - 2); } } else { // Remotetools or o.e.Remote output command = lines.get(0); } } else { // Local output command = lines.get(0); } } } } catch (CoreException e) { throw new IOException(e); } // Command is not found return command; } /** * @return The default instance of the RuntimeProcessFactory. */ public static RuntimeProcessFactory getFactory() { if (instance == null) { instance = new RuntimeProcessFactory(); } return instance; } /** * Execute one command using the path selected in 'Linux Tools Path' preference page * in the informed project. * @param cmd The desired command * @param project The current project. If null, only system path will be * used to look for the command. * @return The process started by exec. * @throws IOException If problem executing the command occured. */ public Process exec(String cmd, IProject project) throws IOException { return exec(cmd, null, (IFileStore)null, project); } /** * Execute one command using the path selected in 'Linux Tools Path' preference page * in the informed project. * @param cmdarray An array with the command to be executed and its params. * @param project The current project. If null, only system path will be * used to look for the command. * @return The process started by exec. * @throws IOException If problem executing the command occured. */ public Process exec(String[] cmdarray, IProject project) throws IOException { return exec(cmdarray, null, project); } /** * Execute one command using the path selected in 'Linux Tools Path' preference page * in the informed project. * @param cmdarray An array with the command to be executed and its params. * @param envp An array with extra enviroment variables to be used when running * the command * @param project The current project. If null, only system path will be * used to look for the command. * @return The process started by exec. * @throws IOException If problem executing the command occured. */ public Process exec(String[] cmdarray, String[] envp, IProject project) throws IOException { return exec(cmdarray, envp, (IFileStore)null, project); } /** * Execute one command using the path selected in 'Linux Tools Path' preference page * in the informed project. * @param cmd The desired command * @param envp An array with extra enviroment variables to be used when running * the command * @param project The current project. If null, only system path will be * used to look for the command. * @return The process started by exec. * @throws IOException If problem executing the command occured. */ public Process exec(String cmd, String[] envp, IProject project) throws IOException { return exec(cmd, envp, (IFileStore)null, project); } /** * Execute one command using the path selected in 'Linux Tools Path' preference page * in the informed project. * @param cmd The desired command * @param envp An array with extra enviroment variables to be used when running * the command * @param dir The directory used as current directory to run the command. * @param project The current project. If null, only system path will be * used to look for the command. * @return The process started by exec. * * @since 1.1 */ private Process exec(String cmd, String[] envp, IFileStore dir, IProject project) throws IOException { return exec(tokenizeCommand(cmd), envp, dir, project); } /** * Execute one command using the path selected in 'Linux Tools Path' preference page * in the informed project. * @param cmdarray An array with the command to be executed and its params. * @param envp An array with extra enviroment variables to be used when running * the command * @param dir The directory used as current directory to run the command. * @param project The current project. If null, only system path will be * used to look for the command. * @return The process started by exec. * @throws IOException If problem executing the command occured. * * @since 1.1 */ public Process exec(String[] cmdarray, String[] envp, IFileStore dir, IProject project) throws IOException { return exec(cmdarray, envp, dir, project, null); } /** * Execute one command using the path selected in 'Linux Tools Path' preference page * in the informed project. * @param cmdarray An array with the command to be executed and its params. * @param envp An array with extra enviroment variables to be used when running * the command * @param dir The directory used as current directory to run the command. * @param project The current project. If null, only system path will be * used to look for the command. * @param pty PTY for use with Eclipse Console. * @return The process started by exec. * @throws IOException If problem executing the command occured. * * @since 3.0 */ public Process exec(String[] cmdarray, String[] envp, IFileStore dir, IProject project, PTY pty) throws IOException { Process p = null; try { cmdarray = fillPathCommand(cmdarray, project); String command = cmdarray[0]; URI uri = URI.create(command); IPath changeToDir = null; IPath path; IRemoteCommandLauncher launcher; envp = updateEnvironment(envp, project); if (project != null) { IRemoteFileProxy proxy = RemoteProxyManager.getInstance().getFileProxy(project); path = new Path(proxy.toPath(uri)); launcher = RemoteProxyManager.getInstance().getLauncher(project); if (dir != null) { changeToDir = new Path(proxy.toPath(dir.toURI())); } } else { path = new Path(uri.getPath()); launcher = RemoteProxyManager.getInstance().getLauncher(uri); if (dir != null) { changeToDir = new Path(dir.toURI().getPath()); } } List<String> cmdlist = new ArrayList<>(Arrays.asList(cmdarray)); cmdlist.remove(0); cmdlist.toArray(cmdarray); cmdarray = cmdlist.toArray(new String[0]); if (pty == null) { p = launcher.execute(path, cmdarray, envp, changeToDir, new NullProgressMonitor()); } else { p = launcher.execute(path, cmdarray, envp, changeToDir, new NullProgressMonitor(), pty); } } catch (CoreException e) { e.printStackTrace(); } return p; } /** * Execute one command, as root, using the path selected in 'Linux Tools Path' * preference page in the informed project. * @param cmdarray An array with the command to be executed and its params. * @param project The current project. If null, only system path will be * used to look for the command. * @return The process started by sudoExec * @throws IOException If problem executing the command occured. */ public Process sudoExec(String[] cmdarray, IProject project) throws IOException { return sudoExec(cmdarray, null, null, project); } /** * Execute one command, as root, using the path selected in 'Linux Tools Path' * preference page in the informed project. * @param cmdarray An array with the command to be executed and its params. * @param envp An array with extra enviroment variables to be used when running * the command * @param dir The directory used as current directory to run the command. * @param project The current project. If null, only system path will be * used to look for the command. * @return The process started by sudoExec * * @since 1.1 */ private Process sudoExec(String[] cmdarray, String[] envp, IFileStore dir, IProject project) throws IOException { URI uri = URI.create("sudo"); //$NON-NLS-1$ List<String> cmdList = Arrays.asList(cmdarray); ArrayList<String> cmdArrayList = new ArrayList<>(cmdList); cmdArrayList.add(0, "-n"); //$NON-NLS-1$ String[] cmdArraySudo = new String[cmdArrayList.size()]; cmdArrayList.toArray(cmdArraySudo); Process p = null; try { cmdArraySudo = fillPathSudoCommand(cmdArraySudo, project); IRemoteCommandLauncher launcher; IPath changeToDir = null, path; if (project != null) { IRemoteFileProxy proxy = RemoteProxyManager.getInstance().getFileProxy(project); path = new Path(proxy.toPath(uri)); launcher = RemoteProxyManager.getInstance().getLauncher(project); envp = updateEnvironment(envp, project); if (dir != null) { changeToDir = new Path(proxy.toPath(dir.toURI())); } } else { launcher = RemoteProxyManager.getInstance().getLauncher(uri); path = new Path(uri.getPath()); if (dir != null) { changeToDir = new Path(dir.toURI().getPath()); } } List<String> cmdlist = new ArrayList<>(Arrays.asList(cmdArraySudo)); cmdlist.remove(0); cmdlist.toArray(cmdArraySudo); cmdArraySudo = cmdlist.toArray(new String[0]); p = launcher.execute(path, cmdArraySudo, envp, changeToDir , new NullProgressMonitor()); } catch (CoreException e) { e.printStackTrace(); } return p; } }