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

net.oneandone.sushi.fs.ssh.Process Maven / Gradle / Ivy

/**
 * Copyright 1&1 Internet AG, https://github.com/1and1/
 *
 * Licensed 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 net.oneandone.sushi.fs.ssh;

import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSchException;
import net.oneandone.sushi.launcher.ExitCode;
import net.oneandone.sushi.launcher.Launcher;
import net.oneandone.sushi.util.Separator;

import java.io.OutputStream;

/** Process on the remote host */
public class Process {
    public static Process start(SshRoot root, boolean tty, OutputStream out, String ... command)
    throws JSchException {
        TimedOutputStream dest;
        ChannelExec channel;

        dest = new TimedOutputStream(out);
        channel = root.createChannelExec();
        // tty=true propagates ctrl-c to the remote host:
        // (unfortunately, this causes ssh servers to send cr/lf, and I didn't find
        // a way to stop this - I tried setPtyType and setTerminalMode)
        channel.setPty(tty);
        // TODO: http://tools.ietf.org/html/rfc4250
        // TODO: channel.setTerminalMode(new byte[] { 70, 0, 0, 0, 0, /*71, 0, 0, 0, 0,*/ 0 });
        channel.setCommand(Separator.SPACE.join(command));
        channel.setInputStream(null);
        channel.setOutputStream(dest);
        channel.setExtOutputStream(dest);
        channel.connect();
        return new Process(root, command, channel, dest);
    }

    private final SshRoot root;
    private final String[] command;
    private final TimedOutputStream dest;
    private final ChannelExec channel;

    public Process(SshRoot root, String[] command, ChannelExec channel, TimedOutputStream dest) {
        if (channel == null) {
            throw new IllegalArgumentException();
        }
        this.root = root;
        this.command = command;
        this.channel = channel;
        this.dest = dest;
    }

    public SshRoot getRoot() {
        return root;
    }

    public boolean isTerminated() {
        return channel.isClosed();
    }

    public void waitFor() throws JSchException, ExitCode {
        try {
            waitFor(1000L * 60 * 60 * 24); // 1 day
        } catch (InterruptedException e) {
            throw new RuntimeException("unexpected", e);
        }
    }

    /**
     * Waits for termination.
     *
     * @param timeout CAUTION: <= 0 immediately times out */
    public void waitFor(long timeout) throws JSchException, ExitCode, InterruptedException {
        long deadline;

        try {
            deadline = System.currentTimeMillis() + timeout;
            while (!channel.isClosed()) {
                if (System.currentTimeMillis() >= deadline) {
                    throw new TimeoutException(this);
                }
                Thread.sleep(100); // throws InterruptedException
            }
            if (channel.getExitStatus() != 0) {
                throw new ExitCode(new Launcher(command), channel.getExitStatus());
            }
        } finally {
            channel.disconnect();
        }
    }

    public long duration() {
        return dest.duration;
    }

    @Override
    public String toString() {
        return root.getUser() + '@' + root.getHost() + "# " + Separator.SPACE.join(command);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy