Usually executing Jobs as other user we can do sudo -u <user> <cmd>
. However in case of forever process we have to do this way:
exec su -s /bin/sh -c 'exec "$0" "$@"' username -- /path/to/command [parameters...]
Ref: https://superuser.com/questions/213416/running-upstart-jobs-as-unprivileged-users
How is this different? What does this mean? Furthermore:
su -s /bin/bash -c bash username -- /path/to/command [parameters...]
does not seem to work!
The first one:
exec su -s /bin/sh -c 'exec "$0" "$@"' username -- /path/to/command [parameters]
for starting upstart
jobs as a user other than root is intended to allow changing the userid without leaving intermediate processes in the way; so it runs in the following way:
exec su -s sh
sh
-c 'exec "$0" "$@"'
sh
exec
the command and parameters being passed after the --
(the $0
is the first parameter on the command line, after the --
, the $@
is everything after that)The end product of this is running /path/to/command
as if it was invoked directly from the command as the username
specified; leaving a process tree looking like:
su [as root] -> /path/to/command [as username]
If you didn't invoke it using exec
, then you would end up with a process tree looking like:
upstart_launcher [as root] -> su [as root] -> sh [as username] -> /path/to/command [as username]
(I don't know what the upstart_launcher process will look like at this point; I don't have a system with upstart on it to check this; but there will be a process left over)
Now, an important element of this is that it just calls exec /path/to/command [arguments…]
, as if it was typed like that from the command line.
When we compare this with the second command line; most of what's happening is similar, but not quite the same:
su -s /bin/bash -c bash username -- /path/to/command [parameters...]
Why doesn't it work? Well you've asked it to do something different; in this case; you're asking it to run the command bash
from the shell bash
.
Because you didn't pass in the $0
or the $@
, everything after the --
is ignored, because it's not passed into the -c
for the shell being invoked.
This collapses the process tree, removing the intermediate sh
- it's a housekeeping mechanism to prevent deep process trees.
skipping all the execs (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
Adding the internal exec (su -s /bin/sh -c 'exec "$0" "$@"' proxy -- pstree -aApl
) - note the missing second level sh
:
bash,1
`-bash,1014
`-su,1020 -s /bin/sh -c exec "$0" "$@" proxy -- pstree -aApl
`-pstree,1021 -aApl
Adding the internal and external exec (exec su -s /bin/sh -c 'exec "$0" "$@"' proxy -- pstree -aApl
) - note the missing outer level bash
, and the fact that the 1014
pid is the same as the pid that had been present in the previous bash invocation:
bash,1
`-su,1014 -s /bin/sh -c exec "$0" "$@" proxy -- pstree -aApl
`-pstree,1022 -aApl