JSch

2012-02-13, jsch java

Jsch未分類

JschはJavaによるSSHの実装です。EclipseやANT内部で利用されているそうです。非常に便利なAPIですが、ソースコードにもほとんどコメントがない上、ドキュメントが少なく中々調査が進みません…。

リモートのcrontabを更新する

SSH経由で接続し、crontabコマンドを利用して接続したユーザのcrontabを書き換えるサンプル。標準入力やエディタ経由での書き込みは出来なかったのでechoコマンド出力をパイプするという荒業を使っている。

JSch jsch = new JSch();
Session session = null;
ChannelExec channel = null;
try {
  session = jsch.getSession(user, host, port);
  session.setUserInfo(new SshUtilities.SimpleUserInfo(pass
      .toCharArray()));
  session.connect();
  channel = (ChannelExec) session.openChannel("exec");
  channel.setCommand("echo \\"" + crontab + "\\" | crontab");
  channel.connect();
} finally {
  if (channel != null)
    channel.disconnect();
  if (session != null)
    session.disconnect();
}

リモートにファイルを送信する

ローカルマシンのファイルをリモートに送信するためのコードです。大まかな流れを示すため、ChannelのInputStreamを使用したエラーチェックや例外処理を省略しています。ファイルのパーミションは「0644」に設定されます。

JSch jsch = new JSch();
Session session = jsch.getSession(USER, HOST, PORT);
session.setUserInfo(new SshUtilities.SimpleUserInfo(PASS));
session.connect();

// リモートで「scp -t file」コマンドを実行
System.out.print("「scp -p -t "+REMOTE_FILE+"」 .. ");
ChannelExec channel = (ChannelExec) session.openChannel("exec");
channel.setCommand("scp -p -t " + REMOTE_FILE);

// リモートscpのストリームを取得
OutputStream out = channel.getOutputStream();
InputStream in = channel.getInputStream();

channel.connect();
System.out.println("Ok.");

// ストリームに「C0644 filesize filename」コマンドを送信
// ※filenameに「/」が含まれていてはいけない
long filesize = (new File(LOCAL_FILE)).length();
String command = "C0644 " + filesize + " ";
if (LOCAL_FILE.lastIndexOf('/') > 0) {
  command += LOCAL_FILE.substring(LOCAL_FILE.lastIndexOf('/') + 1);
} else {
  command += LOCAL_FILE;
}
System.out.print("「"+command+"」 .. ");
command += "\\n";
out.write(command.getBytes());
out.flush();
System.out.println("Ok.");

System.out.print("Sending content .. ");
// ストリームにローカルファイルの内容を送信
FileInputStream fis = new FileInputStream(LOCAL_FILE);
byte[] buf = new byte[1024];
while (true) {
  int len = fis.read(buf, 0, buf.length);
  if (len <= 0)
    break;
  out.write(buf, 0, len);
}
fis.close();

// ストリームに「\\0(EOF)」を送信
buf[0] = 0;
out.write(buf, 0, 1);
out.flush();
out.close();
System.out.println("Ok.");
channel.disconnect();
session.disconnect();

鍵ペアを使ってホストに接続する

秘密鍵をローカルに、公開鍵をリモートに設置して、パスフェーズのみでリモートホストに接続する方法です。パスフェーズを空にすると、常時接続ができるようになります。

1.鍵ペアの作成

File keyfile = new File("id_rsa");
final int type = KeyPair.RSA;
final String passphrase = "";
JSch jsch = new JSch();

KeyPair kpair = KeyPair.genKeyPair(jsch, type);
kpair.setPassphrase(passphrase);
kpair.writePrivateKey(keyfile.getAbsolutePath());
kpair.writePublicKey(keyfile.getAbsolutePath() + ".pub", System.getProperty("user.name"));
String fingerPrint = kpair.getFingerPrint();
kpair.dispose();

2.公開鍵の登録 「ssh-copy-id」コマンドが実行する手順を実施します。公開鍵を対象のホストに転送し、.ssh/autorized_keysファイルの末尾に追加します(ファイルが無い場合は生成して下さい)。同ファイルにグループやその他ユーザの書き込み権限が無いことを確認して下さい。

3.鍵ペアを使用したログイン

JSch jsch = new JSch();
jsch.setKnownHosts(new File("known_hosts").getAbsolutePath());
jsch.addIdentity(new File("id_rsa").getAbsolutePath());
Session session = jsch.getSession("user", "hostname",22);
session.setUserInfo(new MyUserInfo());
session.connect();

コマンドの終了ステータスを取得する

getExitStatusというメソッドを使用します。{strong:このメソッドはチャネルの切断後に呼び出して下さい。}切断前に呼び出すと、戻り値が不定な状態になります(正しいステータスを返す場合が10%、「-1」を返す場合が90%といった状態)。

channel.disconnect();
int status = channel.getExitStatus();

リモートファイルのタイムスタンプを取得する

Sftpチャネルではlsメソッドでファイルの情報(名前や属性)を取得できますが、getMTimeで得られるのはint型の値です。Javaのlong型のタイムスタンプとして利用するには単純に1000倍すれば良いようです。

ChannelSftp channel = (ChannelSftp) session.openChannel("sftp");
channel.connect();
Vector<LsEntry> vector = channel.ls(".");
for (LsEntry lsEntry : vector) {
  Date date =new Date(lsEntry.getAttrs().getMTime()*1000L);
}

この記事は役に立ちましたか?