第一个:
exec su -s /bin/sh -c 'exec "$0" "$@"' username -- /path/to/command [parameters]
以非 root 用户身份启动 upstart 作业旨在允许更改用户 ID 而不会留下中间进程;所以它以以下方式运行:
-
exec su -s sh
用 su 替换调用此命令的进程,运行 shell sh
-
-c 'exec "$0" "$@"'
从shell的调用shexec在--之后传递的命令和参数($0是命令行上的第一个参数,在--之后,$@是之后的一切那个)
其最终产品正在运行/path/to/command 就好像它是直接从命令中调用的username 指定的;留下一个进程树看起来像:
su [as root] -> /path/to/command [as username]
如果您没有使用exec 调用它,那么您最终会得到一个看起来像这样的进程树:
upstart_launcher [as root] -> su [as root] -> sh [as username] -> /path/to/command [as username]
(此时我不知道 upstart_launcher 进程会是什么样子;我没有带有 upstart 的系统来检查这一点;但会有一个进程剩余)
现在,其中一个重要元素是它只调用exec /path/to/command [arguments…],就好像它是从命令行输入的一样。
当我们将此与第二个命令行进行比较时;大多数发生的事情相似,但并不完全相同:
su -s /bin/bash -c bash username -- /path/to/command [parameters...]
为什么它不起作用?好吧,您已经要求它做一些不同的事情;在这种情况下;您要求它从 shell bash 运行命令 bash。
因为您没有传入$0 或$@,所以-- 之后的所有内容都将被忽略,因为它没有传入-c 以供调用的shell。
有和没有 exec 的例子
这会折叠进程树,删除中间的sh - 这是一种防止深进程树的内务管理机制。
跳过所有高管 (su -s /bin/sh -c '"$0" "$@"' proxy -- pstree -aApl):
bash,1
`-bash,1014
`-su,1017 -s /bin/sh -c "$0" "$@" proxy -- pstree -aApl
`-sh,1018 -c "$0" "$@" pstree -aApl
`-pstree,1019 -aApl
添加内部 exec (su -s /bin/sh -c 'exec "$0" "$@"' proxy -- pstree -aApl) - 注意缺少的第二级 sh:
bash,1
`-bash,1014
`-su,1020 -s /bin/sh -c exec "$0" "$@" proxy -- pstree -aApl
`-pstree,1021 -aApl
添加内部和外部 exec (exec su -s /bin/sh -c 'exec "$0" "$@"' proxy -- pstree -aApl) - 注意缺少的外部级别 bash,以及 1014 pid 与先前 bash 调用中存在的 pid 相同的事实:
bash,1
`-su,1014 -s /bin/sh -c exec "$0" "$@" proxy -- pstree -aApl
`-pstree,1022 -aApl