popen意外返回-1

时间:2019-01-14 21:07:42

标签: c linux popen

我有一个程序,该程序需要一个最容易由脚本生成的文件列表(除了生成列表之外,它还需要执行一些可配置的事情)

本质上我是

Map<String, Integer> mapCustomers = new HashMap<>();

for (Customer c : customers) {
    mapCustomers.put(c.getCustomerId(), c.getYardId());
}

for (Map.Entry<String, Trailer> entry : map.entrySet()) {
    Integer yardId = mapCustomers.get(entry.getKey());
    yardId = yardId == null ? entry.getValue().getYardId() : yardId;
    entry.getValue().setYardId(yardId);
}

然后

fp = popen ("thescript", "r");

并处理各行,最后:

while (fgets (buf, 1024, fp))

(bash)脚本以rv = pclose (fp); 结尾。但是,当“正常”运行时,pclose调用返回-1,ECHILD:无子进程。

我对Linux的喜好是,我通常可以通过运行strace来发现此类问题,并查看实际发生的情况。这次不行:以普通用户身份运行strace时,脚本中的安装失败,因此脚本执行exit 0exit 1反映了这一点。当我将其更改为退出0(挂载失败!)时,返回值rv反映了这一信息({rv,gui不显示错误消息)。当我在跟踪时以root用户身份运行整个程序时,它可以正常工作(rv == 0,不显示任何错误消息)。

我编写了简短的测试程序,所有程序均按预期工作。

起初我写的代码是专有的。决定发布起来很简单...这是“故障”的实际代码。 “ get_str_param”将返回要运行的脚本的名称。

rv == 0

“ fl_add_browser_line”来自“ xforms”库。

那么...仅当不使用strace跟踪程序时,才可能导致ECHILD的原因?

1 个答案:

答案 0 :(得分:2)

它在发布的代码摘录中没有显示,但是显然程序的其他部分建立了一个SIGCHLD处理程序。这将干扰pclose()system()之类的功能。 documentation说:

  

pclose()函数等待关联的进程终止,并返回wait4(2)返回的命令的退出状态。

如果还有另一个SIGCHLD处理程序,并且它调用wait(),那么当pclose()试图获取退出状态本身时,子代将消失,它将得到{{1} }。

您需要在运行使用ECHILDpopen()的函数时禁用此处理程序。或编写自己的代码来运行子进程,并与处理分叉的其余代码协同工作。

您需要注意在此代码周围设置pclose()。如果在此期间退出了其他子进程,则我认为重新建立处理程序时不会通知您的常规处理程序。我认为您可以通过在添加处理程序后显式调用常规处理程序来解决此问题;当它调用signal(SIGCHLD, SIG_DFL)时,它将提取所有未完成的终止进程。