All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.netbeans.modules.nativeexecution.LocalNativeProcess Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.netbeans.modules.nativeexecution;

import com.sun.jna.Pointer;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.SequenceInputStream;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.logging.Level;
import org.netbeans.modules.nativeexecution.api.ExecutionEnvironmentFactory;
import org.netbeans.modules.nativeexecution.api.HostInfo.OSFamily;
import org.netbeans.modules.nativeexecution.support.EnvWriter;
import org.netbeans.modules.nativeexecution.api.util.MacroMap;
import org.netbeans.modules.nativeexecution.api.util.UnbufferSupport;
import org.netbeans.modules.nativeexecution.api.util.WindowsSupport;
import org.netbeans.modules.nativeexecution.pty.PtyUtility;
import org.netbeans.modules.nativeexecution.support.Win32APISupport;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;

public final class LocalNativeProcess extends AbstractNativeProcess {

    private Process process = null;
    private PipedInputStream errorPipedInputStream = null;
    private PipedOutputStream errorPipedOutputStream = null;
    private boolean win1073741515added = false;

    public LocalNativeProcess(NativeProcessInfo info) {
        super(info);
    }

    @Override
    protected void create() throws Throwable {
        if (hostInfo.getOSFamily() == OSFamily.WINDOWS) {
            createWin();
        } else {
            createNonWin();
        }
    }

    private void createNonWin() throws IOException, InterruptedException {
        final MacroMap env = info.getEnvironment().clone();

        if (info.isUnbuffer()) {
            UnbufferSupport.initUnbuffer(info.getExecutionEnvironment(), env);
        }

        final ProcessBuilder pb = new ProcessBuilder(hostInfo.getShell(), "-s"); // NOI18N

        // Get working directory ....
        String workingDirectory = info.getWorkingDirectory(true);

        if (workingDirectory != null) {
            File wd = new File(workingDirectory);
            if (!wd.exists()) {
                throw new FileNotFoundException(loc("NativeProcess.noSuchDirectoryError.text", wd.getAbsolutePath())); // NOI18N
            }
            pb.directory(wd);
        }

        if (isInterrupted()) {
            throw new InterruptedException();
        }

        process = pb.start();

        OutputStream toProcessStream = process.getOutputStream();
        InputStream fromProcessStream = process.getInputStream();

        setErrorStream(process.getErrorStream());
        setInputStream(fromProcessStream);
        setOutputStream(toProcessStream);

        toProcessStream.write("echo $$\n".getBytes()); // NOI18N
        toProcessStream.flush();

        EnvWriter ew = new EnvWriter(toProcessStream, false);
        ew.write(env);

        if (info.getInitialSuspend()) {
            toProcessStream.write("ITS_TIME_TO_START=\n".getBytes()); // NOI18N
            toProcessStream.write("trap 'ITS_TIME_TO_START=1' CONT\n".getBytes()); // NOI18N
            toProcessStream.write("while [ -z \"$ITS_TIME_TO_START\" ]; do sleep 1; done\n".getBytes()); // NOI18N
        }

        if (info.isRedirectError()) {
            toProcessStream.write(("exec 2>&1\n").getBytes()); // NOI18N
        }

        toProcessStream.write(("exec " + info.getCommandLineForShell() + "\n").getBytes()); // NOI18N
        toProcessStream.flush();

        creation_ts = System.nanoTime();

        readPID(fromProcessStream);
    }

    private void createWin() throws IOException, InterruptedException {
        // Don't use shell wrapping on Windows...
        // Mostly this is because exec works not as expected and we cannot
        // control processes started with exec method....

        // Suspend is not supported on Windows.

        final ProcessBuilder pb = new ProcessBuilder(); // NOI18N

        final MacroMap jointEnv = MacroMap.forExecEnv(ExecutionEnvironmentFactory.getLocal());
        jointEnv.putAll(info.getEnvironment());

        if (isInterrupted()) {
            throw new InterruptedException();
        }

        if (info.isUnbuffer()) {
            UnbufferSupport.initUnbuffer(info.getExecutionEnvironment(), jointEnv);
        }

        pb.environment().clear();

        for (Entry envEntry : jointEnv.entrySet()) {
            pb.environment().put(envEntry.getKey(), envEntry.getValue());
        }

        pb.redirectErrorStream(info.isRedirectError());
        pb.command(info.getCommand());

        if (LOG.isLoggable(Level.FINEST)) {
            LOG.finest(String.format("Command: %s", info.getCommand())); // NOI18N
        }

        String wdir = info.getWorkingDirectory(true);
        if (wdir != null) {
            File wd = new File(wdir);
            if (!wd.exists()) {
                throw new FileNotFoundException(loc("NativeProcess.noSuchDirectoryError.text", wd.getAbsolutePath())); // NOI18N
            }
            pb.directory(wd);
            if (LOG.isLoggable(Level.FINEST)) {
                LOG.finest(String.format("Working directory: %s", wdir)); // NOI18N
            }
        }

        process = pb.start();

        creation_ts = System.nanoTime();

        errorPipedOutputStream = new PipedOutputStream();
        errorPipedInputStream = new PipedInputStream(errorPipedOutputStream);

        setErrorStream(new SequenceInputStream(process.getErrorStream(), errorPipedInputStream));
        setInputStream(process.getInputStream());
        setOutputStream(process.getOutputStream());

        int newPid = 12345;

        try {
            String className = process.getClass().getName();
            if ("java.lang.Win32Process".equals(className) || "java.lang.ProcessImpl".equals(className)) { // NOI18N
                Field f = process.getClass().getDeclaredField("handle"); // NOI18N
                f.setAccessible(true);
                long phandle = f.getLong(process);

                Win32APISupport kernel = Win32APISupport.INSTANCE;
                Win32APISupport.HANDLE handle = new Win32APISupport.HANDLE();
                handle.setPointer(Pointer.createConstant(phandle));
                newPid = kernel.GetProcessId(handle);
            }
        } catch (Throwable e) {
        }

        ByteArrayInputStream bis = new ByteArrayInputStream(("" + newPid).getBytes()); // NOI18N

        readPID(bis);
    }

    @Override
    public final int waitResult() throws InterruptedException {
        if (process == null) {
            return -1;
        }

        try {
            int exitcode = process.waitFor();
            finishing();
            /*
             * Bug 179555 - Qt application fails to run in case of default qt sdk installation
             */

            if (exitcode == -1073741515 && Utilities.isWindows()) {
                // This means Initialization error. May be the reason is that no required dll found
                // Several threads may be here.
                // Must be sure that message is added only once.
                synchronized (this) {
                    if (!win1073741515added && errorPipedOutputStream != null) {
                        StringBuilder cmd = new StringBuilder();
                        Iterator iterator = info.getCommand().iterator();
                        String exec;

                        if (info.isPtyMode()) {
                            exec = iterator.next();
                            String ptyUtilityPath = null;

                            try {
                                ptyUtilityPath = PtyUtility.getInstance().getPath(ExecutionEnvironmentFactory.getLocal());
                            } catch (IOException ex) {
                            }

                            if (ptyUtilityPath != null && exec.equals(ptyUtilityPath)) {
                                exec = iterator.next(); // quoted executable
                                exec = exec.substring(1, exec.length() - 1); // remove quotes before converting
                                // remove quotes before converting
                                exec = WindowsSupport.getInstance().convertToWindowsPath(exec);
                            }
                        } else {
                            exec = iterator.next();
                        }

                        if (exec.contains(" ")) { // NOI18N
                            cmd.append('"').append(exec).append('"').append(' '); // NOI18N
                        } else {
                            cmd.append(exec).append(' ');
                        }

                        while (iterator.hasNext()) {
                            cmd.append(iterator.next()).append(' ');
                        }

                        String errorMsg = loc("LocalNativeProcess.windowsProcessStartFailed.1073741515.text", cmd.toString()); // NOI18N
                        if (info.isPtyMode()) {
                            errorMsg = errorMsg.replace("\n", "\n\r"); // NOI18N
                        }

                        try {
                            errorPipedOutputStream.write(errorMsg.getBytes(StandardCharsets.UTF_8));
                            errorPipedOutputStream.flush();
                        } catch (IOException ex) {
                            Exceptions.printStackTrace(ex);
                        }

                        win1073741515added = true;
                    }
                }
            }
            return exitcode;
        } finally {
            try {
                if (errorPipedOutputStream != null) {
                    errorPipedOutputStream.close();
                }
            } catch (IOException ex) {
                // Exceptions.printStackTrace(ex);
            }
        }
    }

    @Override
    protected int destroyImpl() {
        if (process != null) {
            process.destroy();
            return 1;
        }

        return 0;
    }

    private static String loc(String key, String... params) {
        return NbBundle.getMessage(LocalNativeProcess.class, key, params);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy