繁体   English   中英

如何使用sudo杀死用Popen调用的Shell脚本?

[英]How to kill a shell script invoked with Popen with sudo?

我用Python编写了一个GTK GUI应用程序,它只是调用外壳程序脚本并将调用参数从GUI传递到脚本,然后在文本窗口中返回脚本结果。

现在,我希望允许用户从GUI取消正在运行的Shell脚本。 该脚本从Popen开始。 如果我以普通用户身份调用它(在下面的代码中为sudo = False),它会很好地工作。 当我使用sudo调用脚本时,无法再取消它。 我发现有人报告说如果我使用shell = True,杀死将不起作用,所以我用shell = False对其进行了测试,但它也不起作用。

我将问题简化为以下代码段:

import os
import signal
import subprocess
import time
import sys
import shlex

bashScriptFileName="t.sh"

f = open(bashScriptFileName,'w')

f.write("""#!/bin/bash
on_die()
{
    echo "Dying..."
    exit 0
}  

trap 'on_die' TERM

SEC=0
while true ; do
    sleep 1
    SEC=$((SEC+1))
    echo "I'm PID# $$, and I'm alive for $SEC seconds now!"
done

exit 0""")
f.close()
os.chmod(bashScriptFileName, 0755)

shell=True      # flag to enable/disable shell invocation of Popen
sudo=True       # flag to invoke command with sudo

if sudo:
    commandToExecute='sudo -S '+ bashScriptFileName
else:
    commandToExecute='./' + bashScriptFileName

if not shell:
    commandToExecute = shlex.split(commandToExecute)

print "Command: %s" % (commandToExecute)                                

proc = subprocess.Popen(commandToExecute, stdin=subprocess.PIPE, close_fds=False,shell=shell, preexec_fn=os.setsid)
print >> proc.stdin, "secretPassword"                
print 'PARENT      : Pausing before sending signal to child %s...' % proc.pid
sys.stdout.flush()
time.sleep(5)
print 'PARENT      : Signaling child %s' % proc.pid
sys.stdout.flush()
os.killpg(proc.pid, signal.SIGTERM)
time.sleep(3)
print "Done"

我实际上已经遇到问题,无法以os.kill的普通用户身份取消脚本,但是后来发现我必须使用os.setuid和killpg来杀死正在运行的shell。 我是线程技术的新手,从我的角度来看,这可能只是一个简单的Linux线程误解...

如果您使用sudo启动它,则必须具有root特权才能将其杀死。 基本上,您必须执行以下操作:

os.system("sudo kill %d"%(pid))

另外,出于安全性考虑,我建议您以root用户身份创建bash脚本,将其放置在方便的地方,不给用户对其写权限,最后设置sudo来运行它而无需输入密码。 这将不需要在此python脚本中存储密码。

TL; DR;

解决此问题的一种更为优雅的方法是使用pyexpect而不是“ subprocess.Popen”启动进程。

spawnProcess = pexpect.spawn(command)

然后,当您想“杀死”该过程时,您所要做的就是:

spawnProcess.sendcontrol("c")

说明:

从os.system运行sudo kill是一个肮脏的黑客,它要求用户再次输入密码,或者要求您存储root密码只是为了允许您杀死子进程。 在我的情况下,情况甚至更糟,因为该过程不是以sudo开始的,而是setuid根可执行文件,因此目标用户确实没有sudo访问权限。

事实证明,bash中的“ CTRL + C”与kill -INT不同,因为很多人都让您相信。 您可以“ CTRL + C”以sudo或setuid root开头的进程,但不能将SIGINT发送到该进程。 我在这里找到了对此的解释:

https://www.reddit.com/r/linux/comments/2av912/how_does_sudo_get_signals_from_the_controlling/ciz574v

知道只有“ CTRL + C”才真正起作用,所以我设计了一个解决方案,模仿用户的操作,它就像一个魅力!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM