Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'core/org.eclipse.cdt.core.native/src')
-rw-r--r--core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/core/IProcessInfo.java20
-rw-r--r--core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/core/IProcessList.java19
-rw-r--r--core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/internal/core/natives/CNativePlugin.java92
-rw-r--r--core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/internal/core/natives/Messages.java28
-rw-r--r--core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/internal/core/natives/messages.properties16
-rw-r--r--core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/WindowsRegistry.java116
-rw-r--r--core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/pty/PTY.java275
-rw-r--r--core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/pty/PTYInputStream.java97
-rw-r--r--core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/pty/PTYOutputStream.java90
-rw-r--r--core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/spawner/EnvironmentReader.java78
-rw-r--r--core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/spawner/ProcessFactory.java101
-rw-r--r--core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/spawner/Spawner.java517
-rw-r--r--core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/spawner/SpawnerInputStream.java118
-rw-r--r--core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/spawner/SpawnerOutputStream.java91
14 files changed, 1658 insertions, 0 deletions
diff --git a/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/core/IProcessInfo.java b/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/core/IProcessInfo.java
new file mode 100644
index 00000000000..f2592a4714a
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/core/IProcessInfo.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 QNX Software Systems 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:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.core;
+
+/**
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IProcessInfo {
+ public int getPid();
+ public String getName();
+}
diff --git a/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/core/IProcessList.java b/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/core/IProcessList.java
new file mode 100644
index 00000000000..fcc2897345a
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/core/IProcessList.java
@@ -0,0 +1,19 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 QNX Software Systems 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:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.core;
+
+/**
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IProcessList {
+ public IProcessInfo[] getProcessList();
+}
diff --git a/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/internal/core/natives/CNativePlugin.java b/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/internal/core/natives/CNativePlugin.java
new file mode 100644
index 00000000000..98eb24cf92e
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/internal/core/natives/CNativePlugin.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 IBM Corporation 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:
+ * IBM Corporation - initial API and implementation
+ * Martin Oberhuber (Wind River) - [303083] Split out from CCorePlugin
+ *******************************************************************************/
+package org.eclipse.cdt.internal.core.natives;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.core.runtime.Status;
+
+/**
+ * CNativePlugin is the life-cycle owner of the plug-in, and also holds
+ * utility methods for logging.
+ *
+ * @noextend This class is not intended to be subclassed by clients.
+ * @noinstantiate This class is not intended to be instantiated by clients.
+ */
+public class CNativePlugin extends Plugin {
+
+ public static final String PLUGIN_ID = "org.eclipse.cdt.core.native"; //$NON-NLS-1$
+
+ private static CNativePlugin fgPlugin;
+
+ // NON-API
+
+ /**
+ * @noreference This constructor is not intended to be referenced by clients.
+ */
+ public CNativePlugin() {
+ super();
+ fgPlugin = this;
+ }
+
+ public static CNativePlugin getDefault() {
+ return fgPlugin;
+ }
+
+ /**
+ * @noreference This method is not intended to be referenced by clients.
+ */
+ public static void log(String e) {
+ log(createStatus(e));
+ }
+
+ /**
+ * @noreference This method is not intended to be referenced by clients.
+ */
+ public static void log(Throwable e) {
+ String msg= e.getMessage();
+ if (msg == null) {
+ log("Error", e); //$NON-NLS-1$
+ } else {
+ log("Error: " + msg, e); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * @noreference This method is not intended to be referenced by clients.
+ */
+ public static void log(String message, Throwable e) {
+ log(createStatus(message, e));
+ }
+
+ /**
+ * @noreference This method is not intended to be referenced by clients.
+ */
+ public static IStatus createStatus(String msg) {
+ return createStatus(msg, null);
+ }
+
+ /**
+ * @noreference This method is not intended to be referenced by clients.
+ */
+ public static IStatus createStatus(String msg, Throwable e) {
+ return new Status(IStatus.ERROR, PLUGIN_ID, msg, e);
+ }
+
+ /**
+ * @noreference This method is not intended to be referenced by clients.
+ */
+ public static void log(IStatus status) {
+ getDefault().getLog().log(status);
+ }
+
+}
diff --git a/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/internal/core/natives/Messages.java b/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/internal/core/natives/Messages.java
new file mode 100644
index 00000000000..ae5b834be9e
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/internal/core/natives/Messages.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2014 Wind River Systems, 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:
+ * Martin Oberhuber (Wind River) - [303083] Split out the Spawner
+ *******************************************************************************/
+package org.eclipse.cdt.internal.core.natives;
+
+import org.eclipse.osgi.util.NLS;
+
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.cdt.internal.core.natives.messages"; //$NON-NLS-1$
+ public static String Util_exception_cannotCreatePty;
+ public static String Util_exception_cannotSetTerminalSize;
+ public static String Util_error_cannotRun;
+ public static String Util_exception_closeError;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/internal/core/natives/messages.properties b/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/internal/core/natives/messages.properties
new file mode 100644
index 00000000000..e1ab7f1ac42
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/internal/core/natives/messages.properties
@@ -0,0 +1,16 @@
+###############################################################################
+# Copyright (c) 2000, 2014 QNX Software Systems 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:
+# QNX Software Systems - Initial API and implementation
+# Martin Oberhuber (Wind River) - [303083] Split from CCorePluginResources.properties
+###############################################################################
+
+Util_exception_cannotCreatePty=Cannot create pty
+Util_exception_closeError=close error
+Util_exception_cannotSetTerminalSize=Setting terminal size is not supported
+Util_error_cannotRun=Cannot run program "{0}": {1}
diff --git a/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/WindowsRegistry.java b/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/WindowsRegistry.java
new file mode 100644
index 00000000000..cc216e2095b
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/WindowsRegistry.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2009 QNX Software Systems
+ * 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:
+ * QNX Software Systems - initial API and implementation
+ *******************************************************************************/
+/**
+ *
+ */
+package org.eclipse.cdt.utils;
+
+import org.eclipse.core.runtime.Platform;
+
+/**
+ * @author DSchaefer
+ * @noextend This class is not intended to be subclassed by clients.
+ * @noinstantiate This class is not intended to be instantiated by clients.
+ */
+public class WindowsRegistry {
+
+ private static boolean failed = false;
+ private static WindowsRegistry registry;
+
+ private WindowsRegistry() {
+ }
+
+ public static WindowsRegistry getRegistry() {
+ if (registry == null && !failed) {
+ if (Platform.getOS().equals(Platform.OS_WIN32)) {
+ try {
+ System.loadLibrary("winreg"); //$NON-NLS-1$
+ registry = new WindowsRegistry();
+ } catch (UnsatisfiedLinkError e) {
+ failed = true;
+ return null;
+ }
+ } else
+ failed = true;
+ }
+
+ return registry;
+ }
+
+ /**
+ * Gets the registry value for the subkey of HKEY_LOCAL_MACHINE with the
+ * given name. If problems occur, like the name is not found, null is returned.
+ *
+ * @param subkey subkey of HKEY_LOCAL_MACHINE
+ * @param name name of the registry value
+ * @return registry value or null if not found
+ */
+ public native String getLocalMachineValue(String subkey, String name);
+
+ /**
+ * Given a subkey of HKEY_LOCAL_MACHINE, and an index (starting from 0)
+ * to the key's array of values, return the name of the indexed value.
+ * The return value is null on any error or when the index is invalid.
+ * The value name can be used in the above getLocalMachineValue() to retrieve
+ * the value data.
+ * @param subkey subkey of HKEY_LOCAL_MACHINE
+ * @param index index to the subkey's array of values, starting from 0.
+ * @return name of registry value or null if not found
+ */
+ public native String getLocalMachineValueName(String subkey, int index);
+
+ /**
+ * Given a subkey of HKEY_LOCAL_MACHINE, and an index (starting from 0)
+ * to the key's array of sub keys, return the name of the indexed key.
+ * The return value is null on any error or when the index is invalid.
+ * The key name can be used in the above getLocalMachineValueName()
+ * to retrieve value names.
+ * @param subkey subkey of HKEY_CURRENT_USER
+ * @param index index to the subkey's array of values, starting from 0.
+ * @return name of registry value or null if not found
+ */
+ public native String getLocalMachineKeyName(String subkey, int index);
+
+ /**
+ * Gets the registry value for the subkey of HKEY_CURRENT_USER with the
+ * given name. If problems occur, like the name is not found, null is returned.
+ *
+ * @param subkey subkey of HKEY_CURRENT_USER
+ * @param name name of the registry value
+ * @return registry value or null if not found
+ */
+ public native String getCurrentUserValue(String subkey, String name);
+
+ /**
+ * Given a subkey of HKEY_CURRENT_USER, and an index (starting from 0)
+ * to the key's array of values, return the name of the indexed value.
+ * The return value is null on any error or when the index is invalid.
+ * The value name can be used in the above getCurrentUserValue() to retrieve
+ * the value data.
+ * @param subkey subkey of HKEY_CURRENT_USER
+ * @param index index to the subkey's array of values, starting from 0.
+ * @return name of registry value or null if not found
+ */
+ public native String getCurrentUserValueName(String subkey, int index);
+
+ /**
+ * Given a subkey of HKEY_CURRENT_USER, and an index (starting from 0)
+ * to the key's array of sub keys, return the name of the indexed key.
+ * The return value is null on any error or when the index is invalid.
+ * The key name can be used in the above getCurrentUserValueName()
+ * to retrieve value names.
+ * @param subkey subkey of HKEY_CURRENT_USER
+ * @param index index to the subkey's array of values, starting from 0.
+ * @return name of registry value or null if not found
+ */
+ public native String getCurrentUserKeyName(String subkey, int index);
+
+}
diff --git a/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/pty/PTY.java b/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/pty/PTY.java
new file mode 100644
index 00000000000..abef9e9e54f
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/pty/PTY.java
@@ -0,0 +1,275 @@
+/*******************************************************************************
+ * Copyright (c) 2002, 2014 QNX Software Systems 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:
+ * QNX Software Systems - Initial API and implementation
+ * Wind River Systems, Inc. - bug 248071
+ * Martin Oberhuber (Wind River) - [303083] Split out the Spawner
+ *******************************************************************************/
+package org.eclipse.cdt.utils.pty;
+
+import java.io.IOException;
+
+import org.eclipse.cdt.internal.core.natives.CNativePlugin;
+import org.eclipse.cdt.internal.core.natives.Messages;
+import org.eclipse.cdt.utils.spawner.Spawner;
+import org.eclipse.core.runtime.Platform;
+
+/**
+ * PTY - pseudo terminal support.
+ */
+public class PTY {
+
+ /**
+ * The pty modes.
+ * @since 5.6
+ */
+ public enum Mode {
+ /** This mode is for use with an Eclipse console. */
+ CONSOLE,
+ /** This mode is for use with a terminal emulator. */
+ TERMINAL
+ }
+
+ final boolean console;
+ final String slave;
+ final PTYInputStream in;
+ final PTYOutputStream out;
+
+ /**
+ * NOTE: Field is accessed by the native layer. Do not refactor!
+ */
+ int master;
+
+ private static boolean hasPTY;
+ private static boolean isWinPTY;
+ private static boolean isConsoleModeSupported;
+ private static boolean setTerminalSizeErrorAlreadyLogged;
+
+ /**
+ * The master fd is used on two streams. We need to wrap the fd
+ * so that when stream.close() is called the other stream is disabled.
+ */
+ public class MasterFD {
+
+ public int getFD() {
+ return master;
+ }
+
+ void setFD(int fd) {
+ master = fd;
+ }
+ }
+
+ /**
+ * @return whether PTY support for console mode is available on this platform
+ */
+ public static boolean isSupported() {
+ return isSupported(Mode.CONSOLE);
+ }
+
+ /**
+ * @return whether PTY support for given mode is available on this platform
+ * @since 5.6
+ */
+ public static boolean isSupported(Mode mode ) {
+ return hasPTY && (isConsoleModeSupported || mode == Mode.TERMINAL);
+ }
+
+
+ /**
+ * Create PTY for use with Eclipse console.
+ * Identical to {@link PTY#PTY(boolean) PTY(Mode.CONSOLE)}.
+ */
+ public PTY() throws IOException {
+ this(Mode.CONSOLE);
+ }
+
+ /**
+ * Create PTY for given mode.
+ *
+ * <p>
+ * The provided mode indicates whether the pseudo terminal is used with the interactive
+ * Eclipse console or a terminal emulation:
+ * <ul>
+ * <li><code>CONSOLE</code> - the terminal is configured with no echo and stderr is
+ * redirected to a pipe instead of the PTY. This mode is not supported on windows</li>
+ * <li><code>TERMINAL</code> - the terminal is configured with echo and stderr is
+ * connected to the PTY. This mode is best suited for use with a proper terminal emulation.
+ * Note that this mode might not be supported on all platforms.
+ * Known platforms which support this mode are:
+ * <code>linux-x86</code>, <code>linux-x86_64</code>, <code>solaris-sparc</code>, <code>macosx</code>.
+ * </li>
+ * </ul>
+ * </p>
+ * @param mode the desired mode of operation
+ * @throws IOException if the PTY could not be created
+ * @since 5.6
+ */
+ public PTY(Mode mode) throws IOException {
+ this(mode == Mode.CONSOLE);
+ }
+
+ /**
+ * Create pseudo terminal.
+ *
+ * <p>
+ * The provided flag indicates whether the pseudo terminal is used with the interactive
+ * Eclipse console:
+ * <ul>
+ * <li>If <code>true</code> the terminal is configured with no echo and stderr is
+ * redirected to a pipe instead of the PTY. This mode is not supported on windows</li>
+ * <li>If <code>false</code> the terminal is configured with echo and stderr is
+ * connected to the PTY. This mode is best suited for use with a proper terminal emulation.
+ * Note that this mode might not be supported on all platforms.
+ * Known platforms which support this mode are:
+ * <code>linux-x86</code>, <code>linux-x86_64</code>, <code>solaris-sparc</code>, <code>macosx</code>.
+ * </li>
+ * </ul>
+ * </p>
+ *
+ * @param console whether terminal is used with Eclipse console
+ * @throws IOException if the PTY could not be created
+ * @deprecated Use {@link #PTY(Mode)} instead
+ * @since 5.2
+ */
+ @Deprecated
+ public PTY(boolean console) throws IOException {
+ this.console = console;
+ if (console && !isConsoleModeSupported) {
+ throw new IOException(Messages.Util_exception_cannotCreatePty);
+ }
+ slave= hasPTY ? openMaster(console) : null;
+
+ if (slave == null) {
+ throw new IOException(Messages.Util_exception_cannotCreatePty);
+ }
+
+ in = new PTYInputStream(new MasterFD());
+ out = new PTYOutputStream(new MasterFD());
+ }
+
+ /**
+ * Test whether the slave name can be used as a tty device by external processes (e.g. gdb).
+ * If the slave name is not valid an IOException is thrown.
+ * @throws IOException if the slave name is not valid
+ * @since 5.6
+ */
+ public void validateSlaveName() throws IOException {
+ // on windows the slave name is just an internal identifier
+ // and does not represent a real device
+ if (isWinPTY)
+ throw new IOException("Slave name is not valid"); //$NON-NLS-1$
+ }
+
+ public String getSlaveName() {
+ return slave;
+ }
+
+ public MasterFD getMasterFD() {
+ return new MasterFD();
+ }
+
+ /**
+ * @return whether this pseudo terminal is for use with the Eclipse console.
+ *
+ * @since 5.2
+ */
+ public final boolean isConsole() {
+ return console;
+ }
+
+ public PTYOutputStream getOutputStream() {
+ return out;
+ }
+
+ public PTYInputStream getInputStream() {
+ return in;
+ }
+
+ /**
+ * Change terminal window size to given width and height.
+ * <p>
+ * This should only be used when the pseudo terminal is configured
+ * for use with a terminal emulation, i.e. when {@link #isConsole()}
+ * returns <code>false</code>.
+ * </p>
+ * <p>
+ * <strong>Note:</strong> This method may not be supported on all platforms.
+ * Known platforms which support this method are:
+ * <code>linux-x86</code>, <code>linux-x86_64</code>, <code>solaris-sparc</code>, <code>macosx</code>.
+ * </p>
+ *
+ * @since 5.2
+ */
+ public final void setTerminalSize(int width, int height) {
+ try {
+ change_window_size(master, width, height);
+ } catch (UnsatisfiedLinkError ule) {
+ if (!setTerminalSizeErrorAlreadyLogged) {
+ setTerminalSizeErrorAlreadyLogged = true;
+ CNativePlugin.log(Messages.Util_exception_cannotSetTerminalSize, ule);
+ }
+ }
+ }
+
+ /**
+ * @noreference This method is not intended to be referenced by clients.
+ * @since 5.6
+ */
+ public int exec_pty(Spawner spawner, String[] cmdarray, String[] envp, String dir, int[] chan) throws IOException {
+ if (isWinPTY) {
+ return exec2(cmdarray, envp, dir, chan, slave, master, console);
+ } else {
+ return spawner.exec2(cmdarray, envp, dir, chan, slave, master, console);
+ }
+ }
+
+ /**
+ * @noreference This method is not intended to be referenced by clients.
+ * @since 5.6
+ */
+ public int waitFor(Spawner spawner, int pid) {
+ if (isWinPTY) {
+ return waitFor(master, pid);
+ } else {
+ return spawner.waitFor(pid);
+ }
+ }
+
+ native String openMaster(boolean console);
+
+ native int change_window_size(int fdm, int width, int height);
+
+ /**
+ * Native method when executing with a terminal emulation (winpty only).
+ */
+ native int exec2(String[] cmdarray, String[] envp, String dir, int[] chan, String slaveName, int masterFD, boolean console) throws IOException;
+
+ /**
+ * Native method to wait for process to terminate (winpty only).
+ */
+ native int waitFor(int masterFD, int processID);
+
+ static {
+ try {
+ System.loadLibrary("pty"); //$NON-NLS-1$
+ hasPTY = true;
+ isWinPTY = Platform.OS_WIN32.equals(Platform.getOS());
+ // on windows console mode is not supported except for experimental use
+ // to enable it, set system property org.eclipse.cdt.core.winpty_console_mode=true
+ isConsoleModeSupported = !isWinPTY || Boolean.getBoolean("org.eclipse.cdt.core.winpty_console_mode"); //$NON-NLS-1$
+ } catch (SecurityException e) {
+ // Comment out it worries the users too much
+ //CCorePlugin.log(e);
+ } catch (UnsatisfiedLinkError e) {
+ // Comment out it worries the users too much
+ //CCorePlugin.log(e);
+ }
+ }
+
+}
diff --git a/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/pty/PTYInputStream.java b/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/pty/PTYInputStream.java
new file mode 100644
index 00000000000..2c4abffa73e
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/pty/PTYInputStream.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 QNX Software Systems 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:
+ * QNX Software Systems - Initial API and implementation
+ * Wind River Systems - bug 286162
+ * Martin Oberhuber (Wind River) - [303083] Split out the Spawner
+ *******************************************************************************/
+package org.eclipse.cdt.utils.pty;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.eclipse.cdt.utils.pty.PTY.MasterFD;
+
+class PTYInputStream extends InputStream {
+
+ MasterFD master;
+
+ /**
+ * From a Unix valid file descriptor set a Reader.
+ * @param fd file descriptor.
+ */
+ public PTYInputStream(MasterFD fd) {
+ master = fd;
+ }
+
+ /**
+ * Implementation of read for the InputStream.
+ *
+ * @exception IOException on error.
+ */
+ @Override
+ public int read() throws IOException {
+ byte b[] = new byte[1];
+ if (1 != read(b, 0, 1))
+ return -1;
+ return b[0];
+ }
+
+ /**
+ * @see InputStream#read(byte[], int, int)
+ */
+ @Override
+ public int read(byte[] buf, int off, int len) throws IOException {
+ if (buf == null) {
+ throw new NullPointerException();
+ } else if ((off < 0) || (off > buf.length)
+ || (len < 0) || ((off + len) > buf.length)
+ || ((off + len) < 0)) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return 0;
+ }
+ byte[] tmpBuf = new byte[len];
+
+ len = read0(master.getFD(), tmpBuf, len);
+ if (len <= 0)
+ return -1;
+
+ System.arraycopy(tmpBuf, 0, buf, off, len);
+ return len;
+ }
+
+ /**
+ * Close the Reader
+ * @exception IOException on error.
+ */
+ @Override
+ public void close() throws IOException {
+ if (master.getFD() == -1)
+ return;
+ close0(master.getFD());
+ // ignore error on close - see bug 286162
+// if (status == -1)
+// throw new IOException(Messages.Util_exception_closeError);
+ master.setFD(-1);
+ }
+
+ @Override
+ protected void finalize() throws IOException {
+ close();
+ }
+
+ private native int read0(int fd, byte[] buf, int len) throws IOException;
+ private native int close0(int fd) throws IOException;
+
+ static {
+ System.loadLibrary("pty"); //$NON-NLS-1$
+ }
+
+}
diff --git a/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/pty/PTYOutputStream.java b/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/pty/PTYOutputStream.java
new file mode 100644
index 00000000000..f6096e5a443
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/pty/PTYOutputStream.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 QNX Software Systems 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:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.utils.pty;
+
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.eclipse.cdt.utils.pty.PTY.MasterFD;
+
+public class PTYOutputStream extends OutputStream {
+
+ MasterFD master;
+
+ /**
+ * From a Unix valid file descriptor set a Reader.
+ * @param fd file descriptor.
+ */
+ public PTYOutputStream(MasterFD fd) {
+ master = fd;
+ }
+
+ /**
+ * @see OutputStream#write(byte[], int, int)
+ */
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ if (b == null) {
+ throw new NullPointerException();
+ } else if (
+ (off < 0)
+ || (off > b.length)
+ || (len < 0)
+ || ((off + len) > b.length)
+ || ((off + len) < 0)) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return;
+ }
+ byte[] tmpBuf = new byte[len];
+ System.arraycopy(b, off, tmpBuf, off, len);
+ write0(master.getFD(), tmpBuf, len);
+ }
+ /**
+ * Implementation of read for the InputStream.
+ *
+ * @exception IOException on error.
+ */
+ @Override
+ public void write(int b) throws IOException {
+ byte[] buf = new byte[1];
+ buf[0] = (byte) b;
+ write(buf, 0, 1);
+ }
+
+ /**
+ * Close the Reader
+ * @exception IOException on error.
+ */
+ @Override
+ public void close() throws IOException {
+ if (master.getFD() == -1)
+ return;
+ int status = close0(master.getFD());
+ if (status == -1)
+ throw new IOException("close error"); //$NON-NLS-1$
+ master.setFD(-1);
+ }
+
+ @Override
+ protected void finalize() throws IOException {
+ close();
+ }
+
+ private native int write0(int fd, byte[] b, int len) throws IOException;
+ private native int close0(int fd) throws IOException;
+
+ static {
+ System.loadLibrary("pty"); //$NON-NLS-1$
+ }
+
+}
diff --git a/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/spawner/EnvironmentReader.java b/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/spawner/EnvironmentReader.java
new file mode 100644
index 00000000000..39c94d806e9
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/spawner/EnvironmentReader.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 QNX Software Systems 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:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.utils.spawner;
+
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.Properties;
+
+import org.eclipse.core.runtime.Platform;
+
+/**
+ * This class provides environment variables supplied as {@link Properties} class.
+ *
+ * @noextend This class is not intended to be subclassed by clients.
+ * @noinstantiate This class is not intended to be instantiated by clients.
+ */
+public class EnvironmentReader {
+ private static Properties envVars = null;
+ private static Properties envVarsNormalized = null;
+ private static ArrayList<String> rawVars = null;
+
+ private static synchronized void init() {
+ if (envVars==null) {
+ envVars = new Properties();
+ // on Windows environment variable names are case-insensitive
+ if (Platform.getOS().equals(Platform.OS_WIN32)) {
+ envVarsNormalized = new Properties();
+ } else {
+ envVarsNormalized = envVars;
+ }
+ rawVars = new ArrayList<String>();
+ Map<String, String> envMap = System.getenv();
+ for (String var : envMap.keySet()) {
+ String value = envMap.get(var);
+ envVars.setProperty(var, value);
+ if (envVarsNormalized!=envVars) {
+ envVarsNormalized.setProperty(var.toUpperCase(), value);
+ }
+ rawVars.add(var + "=" + value); //$NON-NLS-1$
+ }
+ rawVars.trimToSize();
+ }
+ }
+
+ /**
+ * @return list of environment variables.
+ */
+ public static Properties getEnvVars() {
+ init();
+ return (Properties) envVars.clone();
+ }
+
+ /**
+ * @param key - name of environment variable (without $ sign).
+ * @return value of environment variable.
+ */
+ public static String getEnvVar(String key) {
+ init();
+ return envVarsNormalized.getProperty(key);
+ }
+
+ /**
+ * @deprecated since CDT 6.1. {@link #getEnvVars()} provides all the data.
+ */
+ @Deprecated
+ public static String[] getRawEnvVars() {
+ init();
+ return rawVars.toArray(new String[rawVars.size()]);
+ }
+}
diff --git a/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/spawner/ProcessFactory.java b/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/spawner/ProcessFactory.java
new file mode 100644
index 00000000000..7784db6b527
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/spawner/ProcessFactory.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 QNX Software Systems 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:
+ * QNX Software Systems - Initial API and implementation
+ * Martin Oberhuber (Wind River) - [303083] Split out the Spawner
+ *******************************************************************************/
+package org.eclipse.cdt.utils.spawner;
+
+
+import java.io.File;
+import java.io.IOException;
+
+import org.eclipse.cdt.internal.core.natives.CNativePlugin;
+import org.eclipse.cdt.internal.core.natives.Messages;
+import org.eclipse.cdt.utils.pty.PTY;
+
+/**
+ * @noextend This class is not intended to be subclassed by clients.
+ * @noinstantiate This class is not intended to be instantiated by clients.
+ */
+public class ProcessFactory {
+
+ static private ProcessFactory instance;
+ private boolean hasSpawner;
+ private Runtime runtime;
+
+ private ProcessFactory() {
+ hasSpawner = false;
+ String OS = System.getProperty("os.name").toLowerCase(); //$NON-NLS-1$
+ runtime = Runtime.getRuntime();
+ try {
+ // Spawner does not work for Windows 98 fallback
+ if (OS != null && OS.equals("windows 98")) { //$NON-NLS-1$
+ hasSpawner = false;
+ } else {
+ System.loadLibrary("spawner"); //$NON-NLS-1$
+ hasSpawner = true;
+ }
+ } catch (SecurityException e) {
+ e.printStackTrace();
+ } catch (UnsatisfiedLinkError e) {
+ CNativePlugin.log(e.getMessage());
+ }
+ }
+
+ public static ProcessFactory getFactory() {
+ if (instance == null)
+ instance = new ProcessFactory();
+ return instance;
+ }
+
+ public Process exec(String cmd) throws IOException {
+ if (hasSpawner)
+ return new Spawner(cmd);
+ return runtime.exec(cmd);
+ }
+
+ public Process exec(String[] cmdarray) throws IOException {
+ if (hasSpawner)
+ return new Spawner(cmdarray);
+ return runtime.exec(cmdarray);
+ }
+
+ public Process exec(String[] cmdarray, String[] envp) throws IOException {
+ if (hasSpawner)
+ return new Spawner(cmdarray, envp);
+ return runtime.exec(cmdarray, envp);
+ }
+
+ public Process exec(String cmd, String[] envp) throws IOException {
+ if (hasSpawner)
+ return new Spawner(cmd, envp);
+ return runtime.exec(cmd, envp);
+ }
+
+ public Process exec(String cmd, String[] envp, File dir)
+ throws IOException {
+ if (hasSpawner)
+ return new Spawner(cmd, envp, dir);
+ return runtime.exec(cmd, envp, dir);
+ }
+
+ public Process exec(String cmdarray[], String[] envp, File dir)
+ throws IOException {
+ if (hasSpawner)
+ return new Spawner(cmdarray, envp, dir);
+ return runtime.exec(cmdarray, envp, dir);
+ }
+
+ public Process exec(String cmdarray[], String[] envp, File dir, PTY pty)
+ throws IOException {
+ if (hasSpawner)
+ return new Spawner(cmdarray, envp, dir, pty);
+ throw new UnsupportedOperationException(Messages.Util_exception_cannotCreatePty);
+ }
+}
diff --git a/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/spawner/Spawner.java b/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/spawner/Spawner.java
new file mode 100644
index 00000000000..c0149136d2d
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/spawner/Spawner.java
@@ -0,0 +1,517 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 QNX Software Systems 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:
+ * QNX Software Systems - Initial API and implementation
+ * Wind River Systems - bug 248071, bug 286162
+ * Martin Oberhuber (Wind River) - [303083] Split out the Spawner
+ *******************************************************************************/
+package org.eclipse.cdt.utils.spawner;
+
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.StringTokenizer;
+
+import org.eclipse.cdt.internal.core.natives.CNativePlugin;
+import org.eclipse.cdt.internal.core.natives.Messages;
+import org.eclipse.cdt.utils.pty.PTY;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.osgi.util.NLS;
+
+public class Spawner extends Process {
+
+ public int NOOP = 0;
+ public int HUP = 1;
+ public int KILL = 9;
+ public int TERM = 15;
+
+ /**
+ * On Windows, what this does is far from easy to explain.
+ * Some of the logic is in the JNI code, some in the spawner.exe code.
+ *
+ * <ul>
+ * <li>If the process this is being raised against was launched by us (the Spawner)
+ * <ul>
+ * <li>If the process is a cygwin program (has the cygwin1.dll loaded), then issue a 'kill -SIGINT'. If
+ * the 'kill' utility isn't available, send the process a CTRL-C
+ * <li>If the process is <i>not</i> a cygwin program, send the process a CTRL-C
+ * </ul>
+ * <li>If the process this is being raised against was <i>not</i> launched by us, use
+ * DebugBreakProcess to interrupt it (sending a CTRL-C is easy only if we share a console
+ * with the target process)
+ * </ul>
+ *
+ * On non-Windows, raising this just raises a POSIX SIGINT
+ *
+ */
+ public int INT = 2;
+
+ /**
+ * A fabricated signal number for use on Windows only. Tells the starter program to send a CTRL-C
+ * regardless of whether the process is a Cygwin one or not.
+ *
+ * @since 5.2
+ */
+ public int CTRLC = 1000; // arbitrary high number to avoid collision
+
+ int pid = 0;
+ int status;
+ final int[] fChannels = { -1, -1, -1 };
+ boolean isDone;
+ OutputStream out;
+ InputStream in;
+ InputStream err;
+ private PTY fPty;
+
+ public Spawner(String command, boolean bNoRedirect) throws IOException {
+ StringTokenizer tokenizer = new StringTokenizer(command);
+ String[] cmdarray = new String[tokenizer.countTokens()];
+ for (int n = 0; tokenizer.hasMoreTokens(); n++)
+ cmdarray[n] = tokenizer.nextToken();
+ if (bNoRedirect)
+ exec_detached(cmdarray, new String[0], "."); //$NON-NLS-1$
+ else
+ exec(cmdarray, new String[0], "."); //$NON-NLS-1$
+ }
+ /**
+ * Executes the specified command and arguments in a separate process with the
+ * specified environment and working directory.
+ **/
+ protected Spawner(String[] cmdarray, String[] envp, File dir) throws IOException {
+ String dirpath = "."; //$NON-NLS-1$
+ if (dir != null)
+ dirpath = dir.getAbsolutePath();
+ exec(cmdarray, envp, dirpath);
+ }
+
+ protected Spawner(String[] cmdarray, String[] envp, File dir, PTY pty) throws IOException {
+ String dirpath = "."; //$NON-NLS-1$
+ if (dir != null)
+ dirpath = dir.getAbsolutePath();
+ fPty = pty;
+ exec_pty(cmdarray, envp, dirpath, pty);
+ }
+ /**
+ * Executes the specified string command in a separate process.
+ **/
+ protected Spawner(String command) throws IOException {
+ this(command, null);
+ }
+
+ /**
+ * Executes the specified command and arguments in a separate process.
+ **/
+ protected Spawner(String[] cmdarray) throws IOException {
+ this(cmdarray, null);
+ }
+
+ /**
+ * Executes the specified command and arguments in a separate process with the
+ * specified environment.
+ **/
+ protected Spawner(String[] cmdarray, String[] envp) throws IOException {
+ this(cmdarray, envp, null);
+ }
+
+ /**
+ * Executes the specified string command in a separate process with the specified
+ * environment.
+ **/
+ protected Spawner(String cmd, String[] envp) throws IOException {
+ this(cmd, envp, null);
+ }
+
+ /**
+ * Executes the specified string command in a separate process with the specified
+ * environment and working directory.
+ **/
+ protected Spawner(String command, String[] envp, File dir) throws IOException {
+ StringTokenizer tokenizer = new StringTokenizer(command);
+ String[] cmdarray = new String[tokenizer.countTokens()];
+ for (int n = 0; tokenizer.hasMoreTokens(); n++)
+ cmdarray[n] = tokenizer.nextToken();
+ String dirpath = "."; //$NON-NLS-1$
+ if (dir != null)
+ dirpath = dir.getAbsolutePath();
+ exec(cmdarray, envp, dirpath);
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ closeUnusedStreams();
+ }
+
+ /**
+ * See java.lang.Process#getInputStream ();
+ * The client is responsible for closing the stream explicitly.
+ **/
+ @Override
+ public synchronized InputStream getInputStream() {
+ if(null == in) {
+ if (fPty != null) {
+ in = fPty.getInputStream();
+ } else {
+ in = new SpawnerInputStream(fChannels[1]);
+ }
+ }
+ return in;
+ }
+
+ /**
+ * See java.lang.Process#getOutputStream ();
+ * The client is responsible for closing the stream explicitly.
+ **/
+ @Override
+ public synchronized OutputStream getOutputStream() {
+ if(null == out) {
+ if (fPty != null) {
+ out = fPty.getOutputStream();
+ } else {
+ out = new SpawnerOutputStream(fChannels[0]);
+ }
+ }
+ return out;
+ }
+
+ /**
+ * See java.lang.Process#getErrorStream ();
+ * The client is responsible for closing the stream explicitly.
+ **/
+ @Override
+ public synchronized InputStream getErrorStream() {
+ if(null == err) {
+ if (fPty != null && !fPty.isConsole()) {
+ // If PTY is used and it's not in "Console" mode, then stderr is
+ // redirected to the PTY's output stream. Therefore, return a
+ // dummy stream for error stream.
+ err = new InputStream() {
+ @Override
+ public int read() throws IOException {
+ return -1;
+ }
+ };
+ } else {
+ err = new SpawnerInputStream(fChannels[2]);
+ }
+ }
+ return err;
+ }
+
+ /**
+ * See java.lang.Process#waitFor ();
+ **/
+ @Override
+ public synchronized int waitFor() throws InterruptedException {
+ while (!isDone) {
+ wait();
+ }
+
+ // For situations where the user does not call destroy(),
+ // we try to kill the streams that were not used here.
+ // We check for streams that were not created, we create
+ // them to attach to the pipes, and then we close them
+ // to release the pipes.
+ // Streams that were created by the client need to be
+ // closed by the client itself.
+ //
+ // But 345164
+ closeUnusedStreams();
+ return status;
+ }
+
+ /**
+ * See java.lang.Process#exitValue ();
+ **/
+ @Override
+ public synchronized int exitValue() {
+ if (!isDone) {
+ throw new IllegalThreadStateException("Process not Terminated"); //$NON-NLS-1$
+ }
+ return status;
+ }
+
+ /**
+ * See java.lang.Process#destroy ();
+ *
+ * Clients are responsible for explicitly closing any streams
+ * that they have requested through
+ * getErrorStream(), getInputStream() or getOutputStream()
+ **/
+ @Override
+ public synchronized void destroy() {
+ // Sends the TERM
+ terminate();
+
+ // Close the streams on this side.
+ //
+ // We only close the streams that were
+ // never used by any client.
+ // So, if the stream was not created yet,
+ // we create it ourselves and close it
+ // right away, so as to release the pipe.
+ // Note that even if the stream was never
+ // created, the pipe has been allocated in
+ // native code, so we need to create the
+ // stream and explicitly close it.
+ //
+ // We don't close streams the clients have
+ // created because we don't know when the
+ // client will be finished using them.
+ // It is up to the client to close those
+ // streams.
+ //
+ // But 345164
+ closeUnusedStreams();
+
+ // Grace before using the heavy gone.
+ if (!isDone) {
+ try {
+ wait(1000);
+ } catch (InterruptedException e) {
+ }
+ }
+ if (!isDone) {
+ kill();
+ }
+ }
+
+ /**
+ * On Windows, interrupt the spawned program by using Cygwin's utility 'kill -SIGINT' if it's a Cgywin
+ * program, otherwise send it a CTRL-C. If Cygwin's 'kill' command is not available, send a CTRL-C. On
+ * linux, interrupt it by raising a SIGINT.
+ */
+ public int interrupt() {
+ return raise(pid, INT);
+ }
+
+ /**
+ * On Windows, interrupt the spawned program by send it a CTRL-C (even if it's a Cygwin program). On
+ * linux, interrupt it by raising a SIGINT.
+ *
+ * @since 5.2
+ */
+ public int interruptCTRLC() {
+ if (Platform.getOS().equals(Platform.OS_WIN32)) {
+ return raise(pid, CTRLC);
+ }
+ else {
+ return interrupt();
+ }
+ }
+
+ public int hangup() {
+ return raise(pid, HUP);
+ }
+
+ public int kill() {
+ return raise(pid, KILL);
+ }
+
+ public int terminate() {
+ return raise(pid, TERM);
+ }
+
+ public boolean isRunning() {
+ return (raise(pid, NOOP) == 0);
+ }
+
+ private void exec(String[] cmdarray, String[] envp, String dirpath) throws IOException {
+ String command = cmdarray[0];
+ SecurityManager s = System.getSecurityManager();
+ if (s != null)
+ s.checkExec(command);
+ if (envp == null)
+ envp = new String[0];
+
+ Reaper reaper = new Reaper(cmdarray, envp, dirpath);
+ reaper.setDaemon(true);
+ reaper.start();
+
+ // Wait until the subprocess is started or error.
+ synchronized (this) {
+ while (pid == 0) {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ // Check for errors.
+ if (pid == -1) {
+ throw new IOException(reaper.getErrorMessage());
+ }
+ }
+
+ private void exec_pty(String[] cmdarray, String[] envp, String dirpath, final PTY pty) throws IOException {
+ String command = cmdarray[0];
+ SecurityManager s = System.getSecurityManager();
+ if (s != null)
+ s.checkExec(command);
+ if (envp == null)
+ envp = new String[0];
+
+ Reaper reaper = new Reaper(cmdarray, envp, dirpath) {
+ @Override
+ int execute(String[] cmd, String[] env, String dir, int[] channels) throws IOException {
+ return pty.exec_pty(Spawner.this, cmd, env, dir, channels);
+ }
+
+ @Override
+ protected int waitFor(int pid) {
+ return pty.waitFor(Spawner.this, pid);
+ }
+ };
+ reaper.setDaemon(true);
+ reaper.start();
+
+ // Wait until the subprocess is started or error.
+ synchronized (this) {
+ while (pid == 0) {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ // Check for errors.
+ if (pid == -1) {
+ throw new IOException("Exec_tty error:" + reaper.getErrorMessage()); //$NON-NLS-1$
+ }
+ }
+
+ public void exec_detached(String[] cmdarray, String[] envp, String dirpath) throws IOException {
+ String command = cmdarray[0];
+ SecurityManager s = System.getSecurityManager();
+ if (s != null)
+ s.checkExec(command);
+
+ if (envp == null)
+ envp = new String[0];
+ pid = exec1(cmdarray, envp, dirpath);
+ if (pid == -1) {
+ throw new IOException("Exec error"); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Close any streams not used by clients.
+ */
+ private synchronized void closeUnusedStreams() {
+ try {
+ if(null == err)
+ getErrorStream().close();
+ } catch (IOException e) {}
+ try {
+ if(null == in)
+ getInputStream().close();
+ } catch (IOException e) {}
+ try {
+ if(null == out)
+ getOutputStream().close();
+ } catch (IOException e) {}
+ }
+
+ /**
+ * Native method use in normal exec() calls.
+ */
+ native int exec0( String[] cmdarray, String[] envp, String dir, int[] chan) throws IOException;
+
+ /**
+ * Native method use in no redirect meaning to streams will created.
+ */
+ native int exec1( String[] cmdarray, String[] envp, String dir) throws IOException;
+
+ /**
+ * Native method when executing with a terminal emulation.
+ * @noreference This method is not intended to be referenced by clients.
+ */
+ public native int exec2( String[] cmdarray, String[] envp, String dir, int[] chan, String slaveName, int masterFD, boolean console) throws IOException;
+
+ /**
+ * Native method to drop a signal on the process with pid.
+ */
+ public native int raise(int processID, int sig);
+
+ /**
+ * Native method to wait(3) for process to terminate.
+ * @noreference This method is not intended to be referenced by clients.
+ */
+ public native int waitFor(int processID);
+
+ static {
+ try {
+ System.loadLibrary("spawner"); //$NON-NLS-1$
+ } catch (SecurityException e) {
+ CNativePlugin.log(e);
+ } catch (UnsatisfiedLinkError e) {
+ CNativePlugin.log(e);
+ }
+ }
+
+ // Spawn a thread to handle the forking and waiting
+ // We do it this way because on linux the SIGCHLD is
+ // send to the one thread. So do the forking and
+ // the wait in the same thread.
+ class Reaper extends Thread {
+ String[] fCmdarray;
+ String[] fEnvp;
+ String fDirpath;
+ volatile Throwable fException;
+
+ public Reaper(String[] array, String[] env, String dir) {
+ super("Spawner Reaper"); //$NON-NLS-1$
+ fCmdarray = array;
+ fEnvp = env;
+ fDirpath = dir;
+ fException = null;
+ }
+
+ int execute(String[] cmdarray, String[] envp, String dir, int[] channels) throws IOException {
+ return exec0(cmdarray, envp, dir, channels);
+ }
+
+ int waitFor(int pid) {
+ return Spawner.this.waitFor(pid);
+ }
+
+ @Override
+ public void run() {
+ int _pid;
+ try {
+ _pid = execute(fCmdarray, fEnvp, fDirpath, fChannels);
+ } catch (Exception e) {
+ _pid = -1;
+ fException= e;
+ }
+
+ // Tell spawner that the process started.
+ synchronized (Spawner.this) {
+ pid = _pid;
+ Spawner.this.notifyAll();
+ }
+
+ if (_pid != -1) {
+ // Sync with spawner and notify when done.
+ status = waitFor(pid);
+ synchronized (Spawner.this) {
+ isDone = true;
+ Spawner.this.notifyAll();
+ }
+ }
+ }
+
+ public String getErrorMessage() {
+ final String reason= fException != null ? fException.getMessage() : "Unknown reason"; //$NON-NLS-1$
+ return NLS.bind(Messages.Util_error_cannotRun, fCmdarray[0], reason);
+ }
+ }
+}
diff --git a/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/spawner/SpawnerInputStream.java b/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/spawner/SpawnerInputStream.java
new file mode 100644
index 00000000000..fd96e424263
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/spawner/SpawnerInputStream.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 QNX Software Systems 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:
+ * QNX Software Systems - Initial API and implementation
+ * Martin Oberhuber (Wind River) - [303083] Split out the Spawner
+ *******************************************************************************/
+package org.eclipse.cdt.utils.spawner;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.eclipse.cdt.internal.core.natives.Messages;
+
+class SpawnerInputStream extends InputStream {
+ private int fd;
+
+ /**
+ * From a Unix valid file descriptor set a Reader.
+ * @param fd file descriptor.
+ */
+ public SpawnerInputStream(int fd) {
+ this.fd = fd;
+ }
+
+ /**
+ * Implementation of read for the InputStream.
+ *
+ * @exception IOException on error.
+ */
+ @Override
+ public int read() throws IOException {
+ byte b[] = new byte[1];
+ if (1 != read(b, 0, 1))
+ return -1;
+ return b[0];
+ }
+
+ /**
+ * @see InputStream#read(byte[], int, int)
+ */
+ @Override
+ public int read(byte[] buf, int off, int len) throws IOException {
+ if (fd == -1) {
+ return -1;
+ }
+ if (buf == null) {
+ throw new NullPointerException();
+ } else if (
+ (off < 0)
+ || (off > buf.length)
+ || (len < 0)
+ || ((off + len) > buf.length)
+ || ((off + len) < 0)) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return 0;
+ }
+ byte[] tmpBuf = off > 0 ? new byte[len] : buf;
+
+ len = read0(fd, tmpBuf, len);
+ if (len <= 0)
+ return -1;
+
+ if (tmpBuf != buf) {
+ System.arraycopy(tmpBuf, 0, buf, off, len);
+ }
+ return len;
+ }
+
+ /**
+ * Close the Reader
+ * @exception IOException on error.
+ */
+ @Override
+ public void close() throws IOException {
+ if (fd == -1)
+ return;
+ int status = close0(fd);
+ if (status == -1)
+ throw new IOException(Messages.Util_exception_closeError);
+ fd = -1;
+ }
+
+ @Override
+ public int available() throws IOException {
+ if (fd == -1) {
+ return 0;
+ }
+ try {
+ return available0(fd);
+ }
+ catch (UnsatisfiedLinkError e) {
+ // for those platforms that do not implement available0
+ return super.available();
+ }
+ }
+
+ @Override
+ protected void finalize() throws IOException {
+ close();
+ }
+
+ private native int read0(int fileDesc, byte[] buf, int len) throws IOException;
+ private native int close0(int fileDesc) throws IOException;
+ private native int available0(int fileDesc) throws IOException;
+
+ static {
+ System.loadLibrary("spawner"); //$NON-NLS-1$
+ }
+
+
+}
diff --git a/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/spawner/SpawnerOutputStream.java b/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/spawner/SpawnerOutputStream.java
new file mode 100644
index 00000000000..e3c8014f6c8
--- /dev/null
+++ b/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/spawner/SpawnerOutputStream.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2011 QNX Software Systems 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:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.utils.spawner;
+
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * @noextend This class is not intended to be subclassed by clients.
+ * @noinstantiate This class is not intended to be instantiated by clients.
+ */
+public class SpawnerOutputStream extends OutputStream {
+ private int fd;
+
+ /**
+ * From a Unix valid file descriptor set a Reader.
+ * @param fd file descriptor.
+ */
+ public SpawnerOutputStream(int fd) {
+ this.fd = fd;
+ }
+
+ /**
+ * @see OutputStream#write(byte[], int, int)
+ */
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ if (b == null) {
+ throw new NullPointerException();
+ } else if (
+ (off < 0)
+ || (off > b.length)
+ || (len < 0)
+ || ((off + len) > b.length)
+ || ((off + len) < 0)) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return;
+ }
+ byte[] tmpBuf = new byte[len];
+ System.arraycopy(b, off, tmpBuf, off, len);
+ write0(fd, tmpBuf, len);
+ }
+ /**
+ * Implementation of read for the InputStream.
+ *
+ * @exception IOException on error.
+ */
+ @Override
+ public void write(int b) throws IOException {
+ byte[] buf = new byte[1];
+ buf[0] = (byte) b;
+ write(buf, 0, 1);
+ }
+
+ /**
+ * Close the Reader
+ * @exception IOException on error.
+ */
+ @Override
+ public void close() throws IOException {
+ if (fd == -1)
+ return;
+ int status = close0(fd);
+ if (status == -1)
+ throw new IOException("close error"); //$NON-NLS-1$
+ fd = -1;
+ }
+
+ @Override
+ protected void finalize() throws IOException {
+ close();
+ }
+
+ private native int write0(int fd, byte[] b, int len) throws IOException;
+ private native int close0(int fd);
+
+ static {
+ System.loadLibrary("spawner"); //$NON-NLS-1$
+ }
+
+}

Back to the top