jsvc 是在apache的daemon項目下開源項目,主要功能可以使一些運行在普通用戶下的java進程獲取一些root權限下的權利,比如端口在1024下等。
如何運行
在自己的java代碼中,實現start, init , stop,destroy的方法,將自己的編譯打成jar文件, 通過調用jsvc 來啟動
./jsvc -java-home /usr/java/jdk1.7.0_09/ -user nobody -pidfile /opt/apache-tomcat_1/logs/catalina-daemon1.pid -wait 10 -errfile "/tmp/error" -outfile "/tmp/output" -debug -classpath /root/test.jar:/root/commons-daemon.jar test
幾個注意點:
commons_daemon.jar文件是用於調用你的class文件,
關於-java-home, 在這裡有一個bug(https://issues.apache.org/jira/browse/DAEMON-268),哪怕指定,也會指定為默認的/usr/java
其他的請參考jsvc --help
實現原理
jsvc 是一個源碼是c的程序,通過fork出子進程去啟動java,而進程成為控制進程,可以實現監視java子進程的目地。
改變啟動虛擬機的進程的用戶id, 和用戶組
通過調用setgid,setuid來改變當前進程的用戶id,和組,這裡要注意的是當改變用戶id,和組的時候,當前進程會改變進程的capability, 所以需要reset 進程的capability。
查看進程的capability 可以通過調用內核調用 __NR_capget / __NR_capset 的方式
static int get_legacy_caps(){
struct __user_cap_header_struct caphead;
struct __user_cap_data_struct cap;
memset(&caphead, 0, sizeof caphead);
caphead.version = LEGACY_CAP_VERSION;
if (syscall(__NR_capget, &caphead, &cap) < 0)
log_error("capget failed: %m");
log_debug("PID is %d print the cap 0x%x, 0x%x, 0x%x\n", getpid(), cap.effective, cap.permitted, cap.inheritable);
return 0;
}
啟動java
通過調用JNI_CreateJavaVM 啟動虛擬機器,同時調用包common-daemon裡的DaemonLoader class, 調用你所寫的類中的start,...這些方法。
碰到的問題
在jsvc 裡在啟動java以後就將jvm的虛擬機的進程的capability 設置成了0, 導致在虛擬機裡的創建線程受到max process 的控制, ulimit -u
已經創建issue: https://issues.apache.org/jira/browse/DAEMON-270, 短期解決辦法可以設置ulimit 到比較大的值。