package javaforce.jni.lnx; /** Linux PTY support. * * @author pquiring * * Created : Jan 17, 2014 */ import java.io.*; import java.util.*; import javaforce.*; import javaforce.jni.*; public class LnxPty { public static boolean init() { return true; } /** Spawns cmd with args and env (both must be null terminated arrays) and returns new pty. */ public static LnxPty exec(String cmd, String args[], String env[]) { LnxPty pty = new LnxPty(); if (!pty.fork(cmd, args, env)) return null; return pty; } /** Spawns cmd with args and env (both must be null terminated arrays). * Captures all output (stdout and stderr) and returns it. * Does not return until child process exits. */ public static String execOutput(String cmd, String args[], String env[]) { LnxPty pty = new LnxPty(); if (!pty.fork(cmd, args, env)) return null; StringBuilder sb = new StringBuilder(); byte data[] = new byte[1024]; while (true) { int read = pty.read(data); if (read == -1) break; sb.append(new String(data, 0, read)); } pty.close(); return sb.toString(); } public boolean isClosed() { return closed; } private boolean closed = false; private long ctx; private Process p; /** Spawns a new process with a new pty. * Note:args, env MUST be null terminated. */ private boolean fork(String cmd, String args[], String env[]) { ctx = LnxNative.ptyAlloc(); String slaveName = LnxNative.ptyOpen(ctx); if (slaveName == null) return false; ArrayList<String> cmdline = new ArrayList<String>(); cmdline.add("java"); cmdline.add("-cp"); cmdline.add("/usr/share/java/javaforce.jar:/usr/share/java/jna.jar"); cmdline.add("javaforce.jna.LnxPty"); cmdline.add(slaveName); cmdline.add(cmd); cmdline.add("" + (args.length-1)); //# args for(int a=0;a<args.length;a++) { if (args[a] == null) break; cmdline.add(args[a]); } for(int a=0;a<env.length;a++) { if (env[a] == null) break; cmdline.add(env[a]); } String cl[] = cmdline.toArray(new String[0]); /* for(int a=0;a<cl.length;a++) { JFLog.log("cmd=" + cl[a]); } */ try { ProcessBuilder pb = new ProcessBuilder(cl); String user = System.getenv("USER"); if (user != null) { if (user.equals("root")) { pb.directory(new File("/root")); } else { pb.directory(new File("/home/" + user)); } } p = pb.start(); } catch (Exception e) { JFLog.log(e); return false; } new Thread() { public void run() { try {p.waitFor();} catch (Exception e) {} close(); } }.start(); return true; } /** This is the child process for fork() implementation. */ public static void main(String args[]) { if (args == null || args.length < 3) { System.out.println("Usage : LnxPty slaveName, cmd, #args, [args...], [env...]"); return; } init(); String slaveName = args[0]; String cmd = args[1]; int noArgs = JF.atoi(args[2]); int p = 3; ArrayList<String> process_args = new ArrayList<String>(); ArrayList<String> process_env = new ArrayList<String>(); for(int a=0;a<noArgs;a++) { process_args.add(args[p++]); } while (p < args.length) { process_env.add(args[p++]); } try { LnxNative.ptyChildExec(slaveName, cmd, process_args.toArray(new String[0]), process_env.toArray(new String[0])); System.exit(0); //should not happen } catch (Exception e) { e.printStackTrace(); System.exit(0); } } /** Frees resources */ public synchronized void close() { if (closed) return; LnxNative.ptyClose(ctx); closed = true; } /** Writes to child process (max 1024 bytes) */ public void write(byte buf[]) { LnxNative.ptyWrite(ctx, buf); } /** Reads from child process (max 1024 bytes) */ public int read(byte buf[]) { if (closed) return -1; return LnxNative.ptyRead(ctx, buf); } /** Sets the size of the pty */ public void setSize(int x, int y) { LnxNative.ptySetSize(ctx, x, y); } /** Returns current processes environment variables plus those passed in extra. * extra overrides current variables. */ public static String[] makeEnvironment(String extra[]) { ArrayList<String> env = new ArrayList<String>(); Map<String, String> old = System.getenv(); Set<String> set = old.keySet(); String keys[] = (String[])set.toArray(new String[0]); for(int a=0;a<keys.length;a++) { String key = keys[a]; env.add(key + "=" + old.get(key)); } if (extra != null) { for(int a=0;a<extra.length;a++) { int idx = extra[a].indexOf("="); if (idx == -1) continue; //bad string String key = extra[a].substring(0, idx+1); int cnt = env.size(); boolean found = false; for(int b=0;b<cnt;b++) { if (env.get(b).startsWith(key)) { env.set(b, extra[a]); found = true; break; } } if (!found) { env.add(extra[a]); } } } env.add(null); return env.toArray(new String[0]); } public static String[] makeEnvironment() { return makeEnvironment(null); } }