我有一个长期运行的Java服务器应用程序,它启动一个子进程来执行特定任务(在这种情况下,使用7z
命令行实用程序提取7zip文件的内容,但是细节不应该与此相关)。
7z
程序将尝试向终端显示提示输入密码的消息,然后从中读取密码终端<Enter>
两次,否则子进程将挂起并且不会完成。基本问题似乎是7z
实用程序使用getpass系统调用来显示提示和读取用户输入。根据文件:
getpass()函数打开/ dev / tty(进程的控制终端),输出字符串提示,关闭回显,读取一行(&#34;密码&#34;),恢复终端状态并再次关闭/ dev / tty。
由于这是一个服务器应用程序,因此让子进程块等待来自Java终端的输入是不可接受的。我想要的是以编程方式关闭子进程终端上的输入,以便getpass
调用立即返回而没有输入,并且子进程以错误代码退出。不幸的是,我关闭输入到子流程终端的所有尝试都产生了与上述相同的行为:
Process.getOutputStream()
返回的流。ProcessBuilder.redirectInput
将子流程输入重定向为从空文件读取,并从/dev/null
重新定位。Redirect.INHERIT
传递给ProcessBuilder,即使它看起来并不像我想要的那样远。似乎这个应该是可行的,因为当7z
使用与a的子进程完全相同的命令行启动{I}}时,我观察到了所需的行为终端输入连接到socat
的守护进程/dev/null
进程,但是如果使用我可以使用的工具在Java中完成此操作,我感到很茫然。
答案 0 :(得分:0)
为了防止 getpass()函数打开/ dev / tty(进程的控制终端),我们必须安排该实用程序没有控制tty,这可以通过以下方法实现:呼叫setsid()。此C程序(将其命名为int main(int argc, char *argv[])
{
setsid(); // get rid of the controlling tty
close(0); // preclude reading STDIN as well
execvp(argv[1], argv+1); // execute the given program file
}
)进行此调用,然后执行给定的实用程序:
ProcessBuilder pb = new ProcessBuilder("notty", "7z", … /*arguments*/);
我们可以在Java应用程序中使用它,方法是将其添加到ProcessBuilder命令的前面。 g。:
Compiler.java