Bash 若进程告诉自己停止运行,Runit将带错误退出

Bash 若进程告诉自己停止运行,Runit将带错误退出,bash,ubuntu,unix,runit,Bash,Ubuntu,Unix,Runit,我看到runit出现了一些意想不到的行为,不知道如何让它在终止过程中不抛出错误就完成我想要的任务。我有一个进程,它有时知道它应该停止自己,而不是让自己重新启动(因此应该对自己调用svd)。如果我从未更改用户,但如果在运行时切换到非root用户,则会产生错误,则此操作有效 对于这两个示例,我将使用相同的finish脚本: #!/bin/bash -e echo "downtest finished with exit code $1 and exit status $2" 按预期工作的run脚本

我看到runit出现了一些意想不到的行为,不知道如何让它在终止过程中不抛出错误就完成我想要的任务。我有一个进程,它有时知道它应该停止自己,而不是让自己重新启动(因此应该对自己调用
svd
)。如果我从未更改用户,但如果在运行时切换到非root用户,则会产生错误,则此操作有效

对于这两个示例,我将使用相同的
finish
脚本:

#!/bin/bash -e
echo "downtest finished with exit code $1 and exit status $2"
按预期工作的
run
脚本(将退出代码0和退出状态0的
downstest完成打印到syslog):

无法按预期工作的
运行
脚本(将退出代码-1和退出状态15完成的
向下测试打印到syslog):

如果我使用
suubuntu
而不是
chpst
,我会得到同样的结果


如果调用
sudo sv d downstest
会导致一个干净的进程退出,而不是返回错误状态代码,那么关于我为什么会看到这种行为以及如何修复它的任何想法?

sv d
会在进程仍在运行时发送一个SIGTERM。这是信号15,因此以所讨论的方式处理错误

相比之下,要告诉正在运行的程序在其自行退出后不要再次启动(从而允许该机会),请使用
svo
一次

或者,您可以在需要时在脚本中设置SIGTERM:

trap 'exit 0' TERM

如果要将此设置为有条件的:

trap 'if [[ $ignore_sigterm ]]; then exit 0; fi' TERM
…然后跑

ignore_sigterm=1
在触发
sv d

之前,有一个解决方法,请尝试运行
(chpst-u ubuntu sudo sv d downstest)
的子shell,这将有助于允许调用最后一个
退出0
,因为现在没有被调用,因为它在之前退出

事实上,如果你想停止或控制服务,而另一个用户只需要调整
/supervise
目录的权限,你就不需要
chpst-u ubuntu
,这就是为什么你可能会得到退出代码-1

检查
runsv
man:

为./finish提供了两个参数。第一个是./run的退出代码,如果./run没有正常退出,则为-1。第二个是由waitpid(2)确定的退出状态的最低有效字节;例如./run正常退出时为0,如果./run被信号终止时为信号号。如果runsv由于某种原因无法启动./run,则退出代码为111,状态为0

从以下方面:


是否允许root以外的用户控制服务 使用sv程序控制服务或查询其状态信息只能作为根用户使用。是否允许非root用户也控制服务?

答:是的,您只需要调整服务目录中./supervise/子目录的文件系统权限。例如:要允许用户burdon控制dhcp服务,请更改为dhcp服务目录,然后执行以下操作

# chmod 755 ./supervise
# chown burdon ./supervise/ok ./supervise/control ./supervise/status

如果您想完全停止/启动,您可以删除
运行
服务的符号链接,但这意味着您需要在服务启动时再次创建该符号链接


以防万一,由于这一点和其他原因,我提出了一种简化停止/启动/重新启动/服务的方法,它没有根权限,完全基于daemontools&runit,只是适应了一些新的流。

顺便说一句--
set-e
容易。。。意外的后果。请参阅中的练习,以及Hmm中不同Shell行为的比较,尝试了它,但不幸的是仍然产生了相同的结果。@GGordonWorleyIII如果您只是
退出0
将其放在
(chpst…
?如果这样做有效,请尝试捕获退出代码nope,这会将服务置于一个无限循环中,在该循环中它会不断死亡,然后运行它尝试重新启动它,因为
sv d
行永远不会执行,因为它位于退出的出口0之后。我喜欢这样的想法,它可能是一个竞争条件,这也有助于解释w为什么陷阱会起作用,为什么分叉会起作用,但它没有。@GGordonWorleyIII好的,至少你可以退出,但子外壳应该抓住出口,然后允许你用0退出。在你的情况下,使用
sudo sv d downstest
,你真的不需要
chpst
提供更好的实践替代方案ely给出了一个更有力的答案——如果它只提供了新的(
supervise/*
和/或
finish
)接近时,它绝对会有我的+1。所以这在技术上是可行的,但它最终会屏蔽脚本的退出状态。我仍然想知道运行脚本是否存在错误,我只是希望它在执行
sv d
时不会带错误退出。我不希望这会屏蔽退出状态,除非被SIGTERM终止,作为触发器通过
sv d
sv t
kill-TERM
进行编辑。其他情况应该正常退出……也就是说,您可以轻松设置一个标志,以指示何时需要屏蔽状态;适当地进行修改。嗯,这是一个很好的观点。我想实际上我也应该期望陷阱只在这种情况下或在我已经有tr的情况下起作用ap:通常运行它的脚本以一个
exec
结尾,这通常意味着如果你试图在调用脚本中捕获信号,它无论如何都不会命中陷阱,因为脚本正在忙于执行
exec
,然后会直接从exec退出。
chpst-u sudo
是一个可怕的做法,所以我没有太多动机去做这件事想想看;如果努力遵循最佳实践,很难不遇到“不要那样做”。(这就是为什么我在回答中避免引用该代码的部分原因,以防止任何隐含的认可)。也就是说,如果你想追踪事件链,
sysdig
是你的朋友。
ignore_sigterm=1
#!/bin/sh
exec 2>&1
echo "running downtest"
(sudo sv d downtest)
exit 0
# chmod 755 ./supervise
# chown burdon ./supervise/ok ./supervise/control ./supervise/status