package org.rzo.yajsw.os.posix; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.rzo.yajsw.io.CyclicBufferFileInputStream; import org.rzo.yajsw.io.CyclicBufferFilePrintStream; import org.rzo.yajsw.os.AbstractProcess; import org.rzo.yajsw.os.OperatingSystem; import org.rzo.yajsw.os.Process; import org.rzo.yajsw.util.DaemonThreadFactory; import com.sun.jna.Library; import com.sun.jna.Memory; import com.sun.jna.Native; import com.sun.jna.NativeLibrary; import com.sun.jna.Platform; import com.sun.jna.Pointer; import com.sun.jna.Structure; import com.sun.jna.ptr.IntByReference; public class PosixProcess extends AbstractProcess { protected int[] _inPipe = new int[2]; protected int[] _outPipe = new int[2]; protected int[] _errPipe = new int[2]; public IntByReference status = new IntByReference(); int _exitCodeKill = -1; protected static final Executor executor = Executors.newCachedThreadPool(new DaemonThreadFactory("posix.process.terminate")); protected boolean lock = true; volatile protected boolean _terminated = false; protected Utils _utils = new Utils(); boolean _stopWaiter = false; String[] _env = null; public interface CLibrary extends Library { CLibrary INSTANCE = (CLibrary) Native.loadLibrary(Platform.isLinux() ? "libc.so.6" : "c", CLibrary.class); int fork(); void exit(int status); String strerror(int errnum); /* * int readlink (const char *filename, char *buffer, size_t size) */ short readlink(String filename, Memory buffer, short size); /* * int execv (const charfilename, charconst argv[]) */ int execvp(String filename, String[] argv); /* * execve (const char *filename, char *const argv[], char *const env[]) */ int execve(String path, String[] argv, String[] envp); /* * int pipe (int filedes[2]) */ int pipe(int filedes[]); /* * int dup2(int oldfd, int newfd) */ int dup2(int oldfd, int newfd); /* * int close(int fd) */ int close(Pointer fd); int close(int fd); /* * mode_t umask (mode_t mask) */ void umask(int mask); int setsid(); /* * FILE freopen ( const char filename, const char mode, FILE stream ); */ Pointer freopen(String filename, String mode, int stream); /* * int kill (pid_t pid, int signum) */ int kill(int pid, int signum); static final int SIGTERM = 15; static final int SIGKILL = 9; /* * pid_t waitpid(pid_t pid, intstat_loc, int options); */ int waitpid(int pid, IntByReference stat_loc, int options); static final int ESRCH = 3; /* * int chdir(const charpath); */ int chdir(String path); static final int WNOHANG = 1; /* don't hang in wait */ static final int WUNTRACED = 2; /* * tell about stopped, untraced * children */ /* * int fputc (int c, FILEstream) */ int fputc(int c, Pointer stream); /* * FILEfdopen(int fildes, const chartype); */ Pointer fdopen(Pointer fildes, String type); /* * int fileno(FILEstream); */ int fileno(Pointer stream); /* * struct dirent64 { __u64 d_ino; __s64 d_off; unsigned short d_reclen; * unsigned char d_type; char d_name[256]; }; */ class dirent64 extends Structure { public long d_ino; public long d_off; public short d_reclen; public char d_type; public char[] d_name = new char[256]; public String getName() { return getPointer().getString(8 + 8 + 2 + 1, false); } }; /* * struct dirent { long d_ino; off_t d_off; unsigned short d_reclen; * char d_name[NAME_MAX+1]; }; */ class dirent extends Structure { public int d_ino; public int d_off; public short d_reclen; public String d_name; }; /* * DIR opendir (const chardirname) */ Pointer opendir(String dirname); /* * struct dirent64 readdir64 (DIRdirstream) */ dirent64 readdir64(Pointer dirstream); /* * int closedir (DIRdirstream) */ int closedir(Pointer dirstream); /* * int nice (int increment) */ int nice(int increment); /* * int sched_setaffinity (pid_t pid, size_t cpusetsize, const cpu_set_t * cpuset) */ int sched_setaffinity(int pid, int cpusetsize, IntByReference cpuset); /* * pid_t getpid(void); */ int getpid(); /* * int symlink (const charoldname, const charnewname) */ int symlink(String oldname, String newname); /* * struct passwd * * The passwd data structure is used to hold information about entries * in the system user data base. It has at least the following members: * * charpw_name The user's login name. charpw_passwd. The encrypted * password string. uid_t pw_uid The user ID number. gid_t pw_gid The * user's default group ID number. charpw_gecos A string typically * containing the user's real name, and possibly other information such * as a phone number. charpw_dir The user's home directory, or initial * working directory. This might be a null pointer, in which case the * interpretation is system-dependent. charpw_shell The user's default * shell, or the initial program run when the user logs in. This might * be a null pointer, indicating that the system default should be used. */ public static class passwd extends Structure { public passwd(Pointer p) { super(); if (p != null) { this.useMemory(p); this.read(); } } public String pw_name; public String pw_passwd; public int pw_uid; public int pw_gid; public String pw_gecos; public String pw_dir; public String pw_shell; public String getName() { return pw_name; } public int getUid() { return pw_uid; } public int getGid() { return pw_gid; } } /* * struct passwd getpwnam (const charname) This function returns a * pointer to a statically-allocated structure containing information * about the user whose user name is name. This structure may be * overwritten on subsequent calls to getpwnam. * * A null pointer return indicates there is no user named name. */ Pointer getpwnam(String name); /* * uid_t geteuid (void) * * The geteuid function returns the effective user ID of the process. */ int geteuid(); /* * struct passwd getpwuid (uid_t uid) * * This function returns a pointer to a statically-allocated structure * containing information about the user whose user ID is uid. This * structure may be overwritten on subsequent calls to getpwuid. * * A null pointer value indicates there is no user in the data base with * user ID uid. */ Pointer getpwuid(int uid); /* * int setreuid (uid_t ruid, uid_t euid) */ int setreuid(int ruid, int euid); /* * struct group * getgrgid (gid_t gid) This function returns a pointer * to a statically-allocated structure containing information about the * group whose group ID is gid. This structure may be overwritten by * subsequent calls to getgrgid. A null pointer indicates there is no * group with ID gid. */ Pointer getgrgid(int gid); /* * gid_t getegid (void) The getegid function returns the effective group * ID of the process. */ int getegid(); /* * struct group The group structure is used to hold information about an * entry in the system group database. It has at least the following * members: char *gr_name - The name of the group. gid_t gr_gid - The * group ID of the group. char **gr_mem - A vector of pointers to the * names of users in the group. Each user name is a null-terminated * string, and the vector itself is terminated by a null pointer. */ public static class group extends Structure { public group(Pointer p) { super(); if (p != null) { this.useMemory(p); this.read(); } // for (int i = 0; i<this.size(); i++) // System.out.println(i+" "+p.getByte(i)); } public String gr_name = null; public String gr_password = null; public int gr_gid = 0; public Pointer gr_mem = null; public String getName() { return gr_name; } public int getGid() { return gr_gid; } } /* * struct group * getgrnam (const char *name) This function returns a * pointer to a statically-allocated structure containing information * about the group whose group name is name. This structure may be * overwritten by subsequent calls to getgrnam. A null pointer indicates * there is no group named name. */ Pointer getgrnam(String name); /* * int setregid (gid_t rgid, gid_t egid) This function sets the real * group ID of the process to rgid and the effective group ID to egid. * If rgid is -1, it means not to change the real group ID; likewise if * egid is -1, it means not to change the effective group ID. The * setregid function is provided for compatibility with 4.3 BSD Unix, * which does not support file IDs. You can use this function to swap * the effective and real group IDs of the process. (Privileged * processes are not limited to this usage.) If file IDs are supported, * you should use that feature instead of using this function. See * Enable/Disable Setuid. The return values and error conditions for * setregid are the same as those for setreuid. */ int setregid(int rgid, int egid); /* * int chmod (const charfilename, mode_t mode) */ int chmod(String filename, int mode); public static final int S_IFIFO = 0010000; // named // pipe // (fifo) public static final int S_IFCHR = 0020000; // character // special public static final int S_IFDIR = 0040000; // directory public static final int S_IFBLK = 0060000; // block // special public static final int S_IFREG = 0100000; // regular public static final int S_IFLNK = 0120000; // symbolic // link public static final int S_IFSOCK = 0140000; // socket public static final int S_IFMT = 0170000; // file // mask // for // type // checks public static final int S_ISUID = 0004000; // set // user // id // on // execution public static final int S_ISGID = 0002000; // set // group // id // on // execution public static final int S_ISVTX = 0001000; // save // swapped // text // even // after // use public static final int S_IRUSR = 0000400; // read // permission, // owner public static final int S_IWUSR = 0000200; // write // permission, // owner public static final int S_IXUSR = 0000100; // execute/search // permission, // owner public static final int S_IRGRP = 0000040; // read // permission, // group public static final int S_IWGRP = 0000020; // write // permission, // group public static final int S_IXGRP = 0000010; // execute/search // permission, // group public static final int S_IROTH = 0000004; // read // permission, // other public static final int S_IWOTH = 0000002; // write // permission, // other public static final int S_IXOTH = 0000001; // execute // permission, // other public static final int ALL_READ = S_IRUSR | S_IRGRP | S_IROTH; public static final int ALL_WRITE = S_IWUSR | S_IWGRP | S_IWOTH; public static final int S_IXUGO = S_IXUSR | S_IXGRP | S_IXOTH; public static class stat64 extends Structure { public long st_dev; public long st_ino; public long st_nlink; public int st_mode; public int st_uid; public int st_gid; public long st_rdev; public long st_size; public long st_blksize; public long st_blocks; public long st_atime; // Time of last access (time_t) public long st_atimensec; // Time of last access (nanoseconds) public long st_mtime; // Last data modification time (time_t) public long st_mtimensec; // Last data modification time // (nanoseconds) public long st_ctime; // Time of last status change (time_t) public long st_ctimensec; // Time of last status change // (nanoseconds) public long __unused4; public long __unused5; public long __unused6; public boolean isSocket() { return (st_mode & S_IFMT) == S_IFSOCK; } } public static class stat extends Structure { public long st_dev; public short __pad1; public int st_ino; public int st_mode; public int st_nlink; public int st_uid; public int st_gid; public long st_rdev; public short __pad2; public int st_size; public int st_blksize; public int st_blocks; public int st_atime; // Time of last access (time_t) public int st_atimensec; // Time of last access (nanoseconds) public int st_mtime; // Last data modification time // (time_t) public int st_mtimensec; // Last data modification time // (nanoseconds) public int st_ctime; // Time of last status change // (time_t) public int st_ctimensec; // Time of last status change // (nanoseconds) public int __unused4; public int __unused5; public boolean isSocket() { return (st_mode & S_IFMT) == S_IFSOCK; } } /* * int fstat (int filedes, struct stat *buf) */ int fstat(int filedes, Pointer buf); }// CLibrary public void destroy() { if (_outputStream != null) try { _outputStream.close(); } catch (IOException e) { e.printStackTrace(); } if (_inputStream != null) try { _inputStream.close(); } catch (IOException e) { e.printStackTrace(); } if (_errorStream != null) try { _errorStream.close(); } catch (IOException e) { e.printStackTrace(); } CLibrary.INSTANCE.close(_inPipe[1]); CLibrary.INSTANCE.close(_outPipe[0]); CLibrary.INSTANCE.close(_errPipe[0]); CLibrary.INSTANCE.close(_inPipe[0]); CLibrary.INSTANCE.close(_outPipe[1]); CLibrary.INSTANCE.close(_errPipe[1]); } public Collection getChildren() { // TODO Auto-generated method stub return null; } public int getCurrentPageFaults() { // TODO Auto-generated method stub return 0; } public int getCurrentPhysicalMemory() { // TODO Auto-generated method stub return 0; } public int getCurrentVirtualMemory() { int result = -1; if (!isRunning()) return result; String stat = _utils.readFile("/proc/" + _pid + "/stat"); // System.out.println("status "+status); if (status != null) try { // vsize (23th) String sp = "(?:[^\\s]+[\\s]+){22}(\\d+).+"; Pattern p = Pattern.compile(sp, Pattern.DOTALL); Matcher m = p.matcher(stat); m.find(); // get threads result = Integer.parseInt(m.group(1).trim()); } catch (Exception ex) { if (_logger != null) _logger.info("Error in getCurrentVirtualMemory() " + ex.getMessage()); } return result; } public boolean isRunning() { if (_pid < 1) return false; return _exitCode < 0; } public int getExitCode() { if (_exitCodeKill >= 0) return _exitCodeKill; return _exitCode; } public boolean kill(int code) { if (_logger != null) _logger.info("killing " + _pid); int count = 0; while (_exitCode < 0 && count < 3) { count++; if (_logger != null) _logger.info("send kill sig"); int r = CLibrary.INSTANCE.kill(_pid, CLibrary.SIGKILL); if (r == 0) { _exitCodeKill = code; return true; } else { if (_logger != null) _logger.fine("error calling kill: " + r); } if (_exitCode < 0) try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); Thread.currentThread().interrupt(); } } return false; } public boolean killTree(int code) { // TODO Auto-generated method stub return false; } public boolean start() { // log(">> env 1 " +_environment.size()); if (_arrCmd == null && _cmd == null) return false; if (_arrCmd == null) { _arrCmd = _cmd.split(" "); log("exec: " + _cmd); } else { String cmd = ""; for (String c : _arrCmd) { if (c != null) cmd += c + " "; } // if (_debug) log("exec:" + cmd); } if (_environment.size() > 0) { _env = new String[_environment.size()]; int i = 0; for (String[] entry : _environment) _env[i++] = entry[0] + "=" + entry[1]; } else _env = null; int pid = 0; _exitCode = -2; String title = _title == null ? "yajsw" : _title; _terminated = false; if (_visible) setCommand(String.format("xterm -hold -sb -T %1$s -e %2$s", title, getCommand())); // System.out.println("exec \n"+getCommand()); // System.out.println("working dir\n"+getWorkingDir()); if (_visible) _pipeStreams = false; // if (_pipeStreams) { CLibrary.INSTANCE.pipe(_inPipe); CLibrary.INSTANCE.pipe(_outPipe); CLibrary.INSTANCE.pipe(_errPipe); // System.out.println(_outPipe[0]+" "+_outPipe[1]); } String forkLogName = "forkLog" + System.currentTimeMillis() + ".log"; // fork a child process if ((pid = CLibrary.INSTANCE.fork()) == 0) { int stdout = getStdOutNo(); int stderr = getStdErrNo();// CLibrary.INSTANCE.fileno(NativeLibrary.getInstance("c").getFunction(getStdErrName()).getPointer(0)); int stdin = getStdInNo();// CLibrary.INSTANCE.fileno(NativeLibrary.getInstance("c").getFunction(getStdInName()).getPointer(0)); // closeDescriptors(); // set working dir if (getWorkingDir() != null) if (CLibrary.INSTANCE.chdir(getWorkingDir()) != 0) log("could not set working dir"); // set priority if (_priority == PRIORITY_BELOW_NORMAL) { if (CLibrary.INSTANCE.nice(1) == -1) log("could not set priority "); } else if (_priority == PRIORITY_LOW) { if (CLibrary.INSTANCE.nice(2) == -1) log("could not set priority "); } else if (_priority == PRIORITY_ABOVE_NORMAL) { if (CLibrary.INSTANCE.nice(-1) == -1) log("could not set priority "); } else if (_priority == PRIORITY_HIGH) { if (CLibrary.INSTANCE.nice(-2) == -1) log("could not set priority "); } if (getUser() != null) switchUser(getUser(), getPassword()); // try // { // closeDescriptors(new int[]{ // stdin, stdout, stderr, _inPipe[1], _inPipe[0], // _outPipe[0], _outPipe[1], _errPipe[0], // _errPipe[1] // }); // } // catch (Throwable ex) // { // ex.printStackTrace(); // } // pipe streams to OS pipes // if (_pipeStreams) { CLibrary.INSTANCE.close(_inPipe[1]); moveDescriptor(_inPipe[0], stdin); CLibrary.INSTANCE.close(_outPipe[0]); moveDescriptor(_outPipe[1], stdout); CLibrary.INSTANCE.close(_errPipe[0]); moveDescriptor(_errPipe[1], stderr); } try { int res; // disconect from parent CLibrary.INSTANCE.umask(0); if (CLibrary.INSTANCE.setsid() < 0) CLibrary.INSTANCE.exit(-1); if (_env != null) { res = CLibrary.INSTANCE.execve(_arrCmd[0], _arrCmd, _env); } else { res = CLibrary.INSTANCE.execvp(_arrCmd[0], _arrCmd); } int err = Native.getLastError(); log("error in execv: errno " + err + " " + CLibrary.INSTANCE.strerror(err)); log("exec res " + res); } catch (Exception ex) { ex.printStackTrace(); } lock = false; // CLibrary.INSTANCE.exit(-1); } // child code else if (pid > 0) { _pid = pid; try { Thread.sleep(500); } catch (InterruptedException e1) { } // or pipe streams to cyclic buffer files if (_teeName != null && _tmpPath != null) { // System.out.println("opening tee streams"); File f = new File(_tmpPath); try { if (!f.exists()) f.mkdir(); } catch (Exception ex) { if (_logger != null) _logger.throwing(PosixProcess.class.getName(), "start", ex); Thread.currentThread().interrupt(); } try { // System.out.println("opening tee streams out"); _inputStream = new CyclicBufferFileInputStream(createRWfile(_tmpPath, "out_" + _teeName)); } catch (Exception e) { e.printStackTrace(); } try { // System.out.println("opening tee streams err"); _errorStream = new CyclicBufferFileInputStream(createRWfile(_tmpPath, "err_" + _teeName)); } catch (Exception e) { if (_logger != null) _logger.throwing(PosixProcess.class.getName(), "start", e); } try { // System.out.println("opening tee streams in"); _outputStream = new CyclicBufferFilePrintStream(createRWfile(_tmpPath, "in_" + _teeName)); } catch (Exception e) { if (_logger != null) _logger.throwing(PosixProcess.class.getName(), "start", e); } // System.out.println("- opening tee streams"); } /* * if (!_pipeStreams) { * System.out.println("setting out streams to /dev/null/"); * CLibrary.INSTANCE.freopen("/dev/null", "w", _outPipe[0]); * System.out.println("setting err streams to /dev/null/"); * CLibrary.INSTANCE.freopen("/dev/null", "w", _errPipe[0]); * //System.out.println("setting streams to /dev/null/"); * //CLibrary.INSTANCE.freopen("/dev/null", "r", _inPipe[1]); * System.out.println("- setting streams to /dev/null/"); } */ // System.out.println("parent"); if (_pipeStreams && _teeName == null && _tmpPath == null) { writefd(in_fd, _inPipe[1]); writefd(out_fd, _outPipe[0]); writefd(err_fd, _errPipe[0]); _outputStream = new BufferedOutputStream(new FileOutputStream(in_fd)); _inputStream = new BufferedInputStream(new FileInputStream(out_fd)); _errorStream = new BufferedInputStream(new FileInputStream(err_fd)); CLibrary.INSTANCE.close(_inPipe[0]); CLibrary.INSTANCE.close(_outPipe[1]); CLibrary.INSTANCE.close(_errPipe[1]); } if (_cpuAffinity != AFFINITY_UNDEFINED) { IntByReference affinity = new IntByReference(); affinity.setValue(_cpuAffinity); if (CLibrary.INSTANCE.sched_setaffinity(_pid, 4, affinity) == -1) log("error setting affinity"); } _stopWaiter = true; executor.execute(new Runnable() { public void run() { int r = CLibrary.INSTANCE.waitpid(_pid, status, 0); // System.out.println("wait for "+r); if (r == _pid) _exitCode = status.getValue(); if (_logger != null) _logger.info("exit code linux process " + _exitCode); _terminated = true; } }); if (_logger != null) _logger.info("started process " + _pid); return true; } // parent process else if (pid < 0) { if (_logger != null) _logger.info("failed to fork: " + pid); return false; } return false; } protected File createRWfile(String path, String fname) throws IOException { File result = new File(path, fname); if (!result.exists()) { // result.createNewFile(); } String name = result.getCanonicalPath(); // System.out.println("chmod 777 " + name); // Runtime.getRuntime().exec("chmod 777 " + name); // int res = CLibrary.INSTANCE.chmod(name, 777); // if (res != 0) // System.out.println("chmod failed "+res); return result; } public boolean stop(int timeout, int code) { if (_logger != null) _logger.info("killing " + _pid); if (!isRunning()) return true; int r = CLibrary.INSTANCE.kill(_pid, CLibrary.SIGTERM); waitFor(timeout); int count = 0; while (isRunning() && count++ < 4) { CLibrary.INSTANCE.kill(_pid, CLibrary.SIGKILL); if (isRunning()) try { Thread.sleep(100); } catch (InterruptedException e) { if (_logger != null) _logger.throwing(PosixProcess.class.getName(), "stop", e); Thread.currentThread().interrupt(); } } return !isRunning(); } protected void moveDescriptor(int fd_from, int fd_to) { // System.out.println("move desc "+fd_from+" "+fd_to); if (fd_from != fd_to) { CLibrary.INSTANCE.dup2(fd_from, fd_to); CLibrary.INSTANCE.close(fd_from); } } int closeDescriptors(int[] avoid) { // Pointer dir; // CLibrary.dirent64 dirp; // int from_fd = FAIL_FILENO + 1; /* * We're trying to close all file descriptors, but opendir() might * itself be implemented using a file descriptor, and we certainly don't * want to close that while it's in use. We assume that if opendir() is * implemented using a file descriptor, then it uses the lowest numbered * file descriptor, just like open(). So we close a couple explicitly. */ // close(from_fd); /* for possible use by opendir() */ // close(from_fd + 1); /* another one for good luck */ /* * if ((dir = CLibrary.INSTANCE.opendir("/proc/self/fd")) == null) { * //log("error in opendir(/proc/self/fd) "+dir); return 0; } * * * /* We use readdir64 instead of readdir to work around Solaris bug * 6395699: /proc/self/fd fails to report file descriptors >= 1024 on * Solaris 9 */ /* * while ((dirp = CLibrary.INSTANCE.readdir64(dir)) != null) try { * log("readdir64 dir "+dir); dirp.read(); String name = dirp.getName(); * if (name == null) return 0; if (name.contains(".")) continue; * log("closing "+name); int fd = Integer.parseInt(name); * log("closing "+fd); //int r = CLibrary.INSTANCE.close(fd); * //log("closing "+name+" "+r); } catch (Exception ex){ * ex.printStackTrace(); } * * CLibrary.INSTANCE.closedir(dir); */ /* * File f = new File("/proc/self/fd"); String[] ff = f.list(); f = null; * int start = 19; //if (start < 0) //start = 0; for (int j = * ff.length-2; j>=0; j--) { String x = ff[j]; if (x == null || * "".equals(x)) continue; //CLibrary.stat buf = new CLibrary.stat(); * //buf.size(); * * short BUFSIZE = 512; Memory result = new Memory(BUFSIZE); * result.clear(); String readLink = null; short size = * CLibrary.INSTANCE.readlink("/proc/self/fd/"+x, result, * (short)(BUFSIZE-1)); if (size <= 0) { * System.out.println("error reading /proc/self/fd/"+x); } else { * result.setByte((long)size, (byte)0); * System.out.println(x+" -> "+result.getString(0)); readLink = * result.getString(0); } * * * try { int xx = Integer.parseInt(x); /* int res = * CLibrary.INSTANCE.fstat(xx, buf.getPointer()); if (res == 0) { * buf.read(); System.out.println("mode "+xx+" "+buf.st_mode); if * (buf.isSocket()) System.out.println("is socket "+xx); } else * System.out.println("error in fstat "+res+" "+xx); */ /* * boolean remove = true; for (int i=0; i<avoid.length; i++) { if (xx == * avoid[i]) { remove = false; break; } * * } //* //if (xx > 34) if (readLink != null && (!(xx < 2 || * readLink.contains("rt.jar") || readLink.contains("wrapper.jar") || * readLink.contains("jna-") || readLink.contains("jnacontrib") ))) // * if (readLink != null && (readLink.startsWith("socket:["))) { * System.out.println("closing "+xx); //CLibrary.INSTANCE.close(xx); } * else System.out.println("not closing "+xx); //* } catch (Throwable * ex) { ex.printStackTrace(); } * * } */ for (int i = 10; i < 54; i++) CLibrary.INSTANCE.close(i); for (int i = 56; i < 76; i++) CLibrary.INSTANCE.close(i); return 1; } public void waitFor() { waitFor(Integer.MAX_VALUE); } public void waitFor(long timeout) { long start = System.currentTimeMillis(); File f = new File("/proc/" + _pid); while (System.currentTimeMillis() - start < timeout) { if (!isRunning() || !f.exists()) return; try { Thread.sleep(100); } catch (InterruptedException e) { if (_logger != null) _logger.throwing(PosixProcess.class.getName(), "waitFor", e); Thread.currentThread().interrupt(); } } } // test /** * The main method. * * @param args * the arguments * @throws IOException */ public static void main(String[] args) throws IOException { PosixProcess[] p = new PosixProcess[1]; boolean pipe = true; for (int i = 0; i < p.length; i++) { p[i] = new PosixProcess(); // p[i].setPipeStreams(true, false); // p[i].setCommand("xeyes");// "java -cp yajsw.jar // org.rzo.yajsw.HelloWorld > // t.log"); // p[i].setCommand("/usr/java/jre1.5.0_10/bin/java -classpath ./bin test.HelloWorld"); p[i] .setCommand("/usr/java/jre1.5.0_10/bin/java -classpath /home/test/rzodyndns/test/wrapper.jar -Dwrapper.config=/home/test/rzodyndns/test/bat/../conf/wrapper.conf -Dwrapper.port=15003 -Dwrapper.key=6566092584194115879 -Dwrapper.teeName=6566092584194115879$1225016378236 -Dwrapper.tmpPath=/tmp org.rzo.yajsw.app.WrapperJVMMain"); // p[i].setWorkingDir("/home/test/rzodyndns/test/bat/."); p[i].setVisible(false); // p[i].setPriority(PRIORITY_BELOW_NORMAL); // p[i].setCpuAffinity(1); p[i].setPipeStreams(pipe, false); } boolean doit = true; while (doit) { doit = false; // System.out.println("START"); // doit = false; for (int i = 0; i < p.length; i++) { p[i].start(); // p[i].getPid(); // Runtime.getRuntime().exec(p[i].getCommand()); // System.out.println("started"); // for (int j=0; i<10000; j++) // { // System.out.println("b"+j); // try // { // Thread.sleep(00); // } // catch (InterruptedException e) // { // // TODO Auto-generated catch block // e.printStackTrace(); // } // } // return; try { Thread.yield(); Thread.sleep(1000); } catch (InterruptedException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } if (pipe) { InputStreamReader isr = new InputStreamReader(p[i].getInputStream()); // System.out.println("in stream " + p[i].getInputStream() + // " " + p[i].getInputStream().available()); BufferedReader br = new BufferedReader(isr); String line = "?"; int k = 0; try { while (k < 10 && (line = br.readLine()) != null) { System.out.println(line); k++; } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } p[0].waitFor(1000); // System.out.println("exit code "+p[0].getExitCode()); System.out.println("KILL"); for (int i = 0; i < p.length; i++) { // System.out.println(p[i].isRunning()); p[i].kill(999); System.out.println("exit code " + p[i].getExitCode()); // System.out.println(p[i].isRunning()); // p[i].destory(); } try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } // p.setCommand("java -classpath z:\dev\yajsw\wrapper.jar org.rzo." ) } /** * Writefd. * * @param fd * the fd * @param pointer * the pointer */ protected void writefd(FileDescriptor fd, int pointer) { try { // Field[] fields = FileDescriptor.class.getDeclaredFields(); // System.out.println("fields"); // for (Field field : fields){ // System.out.println(field.getName()); // } // System.out.println("writefd"); Field handleField = FileDescriptor.class.getDeclaredField("fd"); handleField.setAccessible(true); Field peerField = Pointer.class.getDeclaredField("peer"); peerField.setAccessible(true); long value = pointer;// peerField.getLong(pointer); // System.out.println(value); // System.out.flush(); handleField.setInt(fd, (int) value); // System.out.println(fd.valid()); // Method sync = FileDescriptor.class.getDeclaredMethod("sync", new // Class[0]); // sync.setAccessible(true); // sync.invoke(fd, new Object[0]); } catch (Exception e) { e.printStackTrace(); } } public boolean reconnectStreams() { if (_teeName != null) try { _inputStream = new CyclicBufferFileInputStream(new File(_tmpPath, "out_" + _teeName)); _errorStream = new CyclicBufferFileInputStream(new File(_tmpPath, "err_" + _teeName)); _outputStream = new CyclicBufferFilePrintStream(new File(_tmpPath, "in_" + _teeName)); return true; } catch (Exception ex) { ex.printStackTrace(); } return false; } private String getCommandInternal() { String result = _utils.readFile("/proc/" + getPid() + "/cmdline"); if (result == null) result = "?"; // System.out.println("cmd line: "+result); return result; } private List<String[]> getEnvironmentInternal() { String result = _utils.readFile("/proc/" + getPid() + "/environ"); return parseEnvironment(result); } private List<String[]> parseEnvironment(String env) { List<String[]> result = new ArrayList<String[]>(); if (env == null || "".equals(env)) return result; String sp = "(\\S+)=([^=.]+)( |$)"; Pattern p = Pattern.compile(sp, Pattern.DOTALL); Matcher m = p.matcher(env); while (m.find()) { String[] str = m.group().trim().split("=", 2); if (str.length == 2) { result.add(new String[] { str[0], str[1] }); } } return result; } protected String getWorkingDirInternal() { String result = null; File f = new File("/proc/" + getPid() + "/cwd"); try { result = f.getCanonicalPath(); } catch (IOException e) { e.printStackTrace(); } return result; } public String getWorkingDir() { return _workingDir; } public static Process getProcess(int pid) { PosixProcess result = null; File f = new File("/proc/" + pid); if (f.exists()) { // TODO this may not always work result = (PosixProcess) OperatingSystem.instance().processManagerInstance().createProcess(); result._pid = pid; result._user = result.getUserInternal(); result._cmd = result.getCommandInternal(); result._workingDir = result.getWorkingDirInternal(); result._environment = result.getEnvironmentInternal(); } return result; } public static int currentProcessId() { return CLibrary.INSTANCE.getpid(); } public String currentUser() { int euid = CLibrary.INSTANCE.geteuid(); // log("current user euid "+ euid); Pointer p = CLibrary.INSTANCE.getpwuid(euid); if (p == null) log("could not get current user"); return new CLibrary.passwd(p).getName(); } public String currentGroup() { int egid = CLibrary.INSTANCE.getegid(); // System.out.println("current group egid "+ egid); Pointer pg = CLibrary.INSTANCE.getgrgid(egid); if (pg == null) { log("could not get current group"); return null; } return new CLibrary.group(pg).getName(); } public String defaultGroup(String user) { Pointer p = CLibrary.INSTANCE.getpwnam(user); if (p == null) { log("could not get user " + user); return null; } int gid = new CLibrary.passwd(p).getGid(); System.out.println("default group gid " + gid); Pointer pg = CLibrary.INSTANCE.getgrgid(gid); if (pg == null) { log("could not get default group for user " + user); return null; } return new CLibrary.group(pg).getName(); } public void switchUser(String name, String password) { if (name == null || "".equals(name)) return; String[] x = name.split("\\\\"); String user = x.length == 1 ? x[0] : x[1]; String group = x.length == 1 ? null : x[0]; if (group == null) group = defaultGroup(user); String currentUser = currentUser(); String currentGroup = currentGroup(); log("switch group " + currentGroup + " -> " + group); if (currentGroup != null && !currentGroup.equals(group)) { Pointer p = CLibrary.INSTANCE.getgrnam(group); CLibrary.group g = new CLibrary.group(p); int newGid = g.getGid(); String nam = g.getName(); if (newGid == 0) log("could not get group " + group); // System.out.println("switching to group name/id "+nam+"/"+newGid); int res = CLibrary.INSTANCE.setregid(newGid, newGid); if (res != 0) log("could not change to group " + group); } log("switch user " + currentUser + " -> " + user); if (currentUser != null && !currentUser.equals(user)) { Pointer p = CLibrary.INSTANCE.getpwnam(user); int newUid = new CLibrary.passwd(p).getUid(); if (newUid == 0) log("could not get user " + user); int res = CLibrary.INSTANCE.setreuid(newUid, newUid); if (res != 0) log("could not change to user " + user); } currentUser = currentUser(); if (!user.equals(currentUser)) log("could not set user. current user: " + currentUser); currentGroup = currentGroup(); if (!group.equals(currentGroup)) log("could not set group. current group: " + currentGroup); } public String getUserInternal() { String status = _utils.readFile("/proc/" + _pid + "/status"); // System.out.println("status "+status); if (status != null) try { // ruid, euid, suid fuid String sp = ".*[U|u]id:\\s*(\\d+)\\s*(\\d+)\\s*(\\d+)\\s*(\\d+).*"; Pattern p = Pattern.compile(sp, Pattern.DOTALL); Matcher m = p.matcher(status); m.find(); // get ruid int ruid = Integer.parseInt(m.group(1)); System.out.println("rudi " + ruid); Pointer po = CLibrary.INSTANCE.getpwuid(ruid); if (po == null) System.out.println("could not get user"); return new CLibrary.passwd(po).getName().trim(); } catch (Exception ex) { log("Error in getUser() " + ex.getMessage()); } return ""; } public String getUser() { return _user; } public String getStdInName() { return "stdin"; } public String getStdOutName() { return "stdout"; } public String getStdErrName() { return "stderr"; } public int getStdOutNo() { return CLibrary.INSTANCE.fileno(NativeLibrary.getInstance("c").getFunction(getStdOutName()).getPointer(0)); } public int getStdErrNo() { return CLibrary.INSTANCE.fileno(NativeLibrary.getInstance("c").getFunction(getStdErrName()).getPointer(0)); } public int getStdInNo() { return CLibrary.INSTANCE.fileno(NativeLibrary.getInstance("c").getFunction(getStdInName()).getPointer(0)); } public int getCurrentHandles() { if (!isRunning()) return -1; File f = new File("/proc/" + _pid + "/fd"); if (!f.exists() || !f.isDirectory()) return -1; return f.list().length; } public int getCurrentThreads() { int result = -1; if (!isRunning()) return result; String status = _utils.readFile("/proc/" + _pid + "/status"); // System.out.println("status "+status); if (status != null) try { // thread count String sp = ".*[T|t]hreads:\\s*(\\d+).*"; Pattern p = Pattern.compile(sp, Pattern.DOTALL); Matcher m = p.matcher(status); m.find(); // get threads result = Integer.parseInt(m.group(1)); } catch (Exception ex) { if (_logger != null) _logger.info("Error in getCurrentThreads() " + ex.getMessage()); } return result; } long _currentTotalCPU = -1; long _oldTotalCPU = -1; long _lastCPUReadTime = Long.MAX_VALUE; public int getCurrentCpu() { int result = -1; if (!isRunning()) return result; String stat = _utils.readFile("/proc/" + _pid + "/stat"); // System.out.println("status "+status); if (status != null) try { // ucpu scpu (13th) String sp = "(?:[^\\s]+[\\s]+){13}(\\d+)\\s+(\\d+).+"; Pattern p = Pattern.compile(sp, Pattern.DOTALL); Matcher m = p.matcher(stat); m.find(); // get threads int ucpu = Integer.parseInt(m.group(1).trim()); int scpu = Integer.parseInt(m.group(2).trim()); // System.out.println(ucpu + "<<" + scpu); _oldTotalCPU = _currentTotalCPU; _currentTotalCPU = ucpu + scpu; double elapsed = ((double) (System.currentTimeMillis() - _lastCPUReadTime)) / 1000; double used = _currentTotalCPU - _oldTotalCPU; // System.out.println(elapsed + "<<" + used); if (elapsed > 0) result = (int) (used / elapsed); _lastCPUReadTime = System.currentTimeMillis(); } catch (Exception ex) { if (_logger != null) _logger.info("Error in getCurrentCPU() " + ex.getMessage()); } return result; } public boolean isTerminated() { return _terminated; } public boolean setWorkingDirectory(String name) { File f = new File(name); String dir; if (!f.exists() || !f.isDirectory()) { log("setWorkingDirectory failed. file not found " + name); return false; } else try { dir = f.getCanonicalPath(); } catch (IOException e) { if (_logger != null) _logger.throwing(PosixProcess.class.getName(), "setWorkingDirectory", e); return false; } boolean result = CLibrary.INSTANCE.chdir(name) == 0; if (result) System.setProperty("user.dir", dir); return result; } public void setTerminated(boolean terminated) { _terminated = terminated; } @Override public void setLogger(Logger logger) { super.setLogger(logger); _utils.setLog(logger); } }