当前位置:  开发笔记 > 编程语言 > 正文

在Ubuntu 15.10中无法终止使用python创建的sudo进程

如何解决《在Ubuntu15.10中无法终止使用python创建的sudo进程》经验,为你挑选了1个好方法。

我刚刚更新到Ubuntu 15.10并突然在Python 2.7中我无法终止我在创建root时创建的进程.例如,这不会终止tcpdump:

import subprocess, shlex, time
tcpdump_command = "sudo tcpdump -w example.pcap -i eth0 -n icmp"
tcpdump_process = subprocess.Popen(
                                shlex.split(tcpdump_command),
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE)
time.sleep(1)
tcpdump_process.terminate()
tcpdump_out, tcpdump_err = tcpdump_process.communicate()

发生了什么?它适用于以前的版本.



1> jfs..:

TL; DR:sudo不转发自2014年5月28日发布的命令进程组中的进程发送的信号sudo 1.8.11- python进程(sudo的父进程)和tcpdump进程(grandchild)默认位于同一进程组中,因此sudo不会将SIGTERM发送的信号转发.terminate()tcpdump进程.


当作为root用户运行该代码并且作为常规用户+ sudo时,它显示相同的行为

以普通用户身份运行会引发OSError: [Errno 1] Operation not permitted异常.terminate()(如预期的那样).

运行时会root重现问题:sudo并且tcpdump不会终止进程.terminate()并且代码会停留.communicate()在Ubuntu 15.10上.

相同的代码会杀死Ubuntu 12.04上的两个进程.

tcpdump_processname是误导性的,因为变量引用sudo进程(子进程),而不是tcpdump(孙进程):

python
?? sudo tcpdump -w example.pcap -i eth0 -n icmp
   ?? tcpdump -w example.pcap -i eth0 -n icmp          

正如@E先生在评论中指出的那样,你不需要sudo在这里:你已经是根(虽然你不应该 - 你可以在没有root的情况下嗅探网络).如果你掉下来sudo; .terminate()作品.

通常,.terminate()不会递归地杀死整个进程树,因此预计孙子进程会幸存.虽然sudo是一个特例,但是从sudo(8)手册页:

当命令作为sudo进程的子进程运行时,sudo会将 收到的信号中继到命令.重点是我的

即,sudo应该传达SIGTERMtcpdumptcpdump应该停止抓包SIGTERM,tcpdump的距离(8)手册页:

Tcpdump将继续捕获数据包,直到被SIGINT信号(例如,通过键入中断字符,通常是control-C生成)或SIGTERM信号(通常使用kill(1)命令生成)中断为止. ;

即,预期的行为是:tcpdump_process.terminate()发送SIGTERM,继续捕获应该停止捕获sudo的信号,tcpdump并且两个进程都退出并将stderr输出.communicate()返回tcpdump到python脚本.

注意:原则上,可以在不创建子进程的情况下运行命令,来自同一个sudo(8)手册页:

作为特殊情况,如果策略插件没有定义close函数并且不需要pty,sudo则将直接执行命令而不是首先调用fork(2)

因此.terminate()可以tcpdump直接将SIGTERM发送到进程 - 虽然它不是解释:sudo tcpdump在我的测试中在Ubuntu 12.04和15.10上创建两个进程.

如果我sudo tcpdump -w example.pcap -i eth0 -n icmp在shell中运行,则kill -SIGTERM终止两个进程.它看起来不像Python问题(Python 2.7.3(在Ubuntu 12.04上使用)在Ubuntu 15.10上表现相同.Python 3也在这里失败).

它是处理组(相关作业控制):通过preexec_fn=os.setpgrpsubprocess.Popen()使sudo会在它的领导者在shell一个新的进程组(作业),使tcpdump_process.terminate()工作在这种情况下.

发生了什么?它适用于以前的版本.

解释是在sudo的源代码中:

不要转发命令进程组中进程发送的信号,不要转发它,因为我们不希望子进程间接自杀.例如,某些版本的reboot可以调用kill(-1,SIGTERM)来杀死所有其他进程.重点是我的

preexec_fn=os.setpgrp变更sudo的过程组.sudotcpdump进程这样的后代继承了这个组.pythontcpdump是相同的处理组中不再并因此通过发送的信号.terminate()是通过中继sudotcpdump和它退出.

Ubuntu 15.04使用Sudo version 1.8.9p5问题代码的工作原理.

Ubuntu 15.10使用Sudo version 1.8.12包含提交的内容.

sudo(8)wily中的手册页(15.10)仍然只讨论子进程本身 - 没有提到进程组:

作为一种特殊情况,sudo不会中继由其运行的命令发送的信号.

它应该是:

作为一种特殊情况,sudo不会中继由正在运行的命令的进程组中的进程发送的信号.

您可以在Ubuntu的错误跟踪器和/或上游错误跟踪器上打开文档问题.

推荐阅读
ifx0448363
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有