13

I've created a script in /etc/init.d/ which has to run several other scripts from other (non-root privileged) users from their home directories, as if they started them.

I launch these scripts with: sudo -b -u <username> <script_of_a_particular_user>

And it works. But for every user script that continues running(for example some watchdog) I see a corresponding parent sudo process, still alive and running as root. This creates a mess in the active processes list.

So my question is: How can I launch(fork) another script from existing bash script as another user and leave it as an orphaned(stand alone) process?

More detailed explanation:
I'm basically trying to provide to other users on the machine a mean to run stuff upon system start or system shutdown by running executable files found in respective subdirectories found in their home directory, named .startUp and .shutDown. Since I did not find any other means to do that I wrote my bash script that does exactly that and I've configured it as a service script (by following the skeleton example) in /etc/init.d/ so when it is run with start argument it launches everything from .startUp directories and when it is run with stop argument it launches everything from .shutDown directories of all users as them.

Alternatively I'm also interested if I could have used some existing solution to solve this problem.

UPDATE
I've looked around a bit and I found this question: https://unix.stackexchange.com/questions/22478/detach-a-daemon-using-sudo

Accepted answer there, to use: sudo -u user sh -c "daemon & disown %1", works for me to. But I also tried without disown %1 and it is the same. So this is what works for me as I expected:

sudo -u <username> bash -c "<script_of_a_particular_user> &"

My additional question now is, why is it working without disown? should I still leave the disown call, regardless, for some potential special case?

UPDATE 2

Apparently this works too:

su <username> -c "<script_of_a_particular_user> &"

Is there any difference between this call and the sudo call? I know this is potentially an entire different question. But since I'm finding the answers here myself maybe for the sake of this topic someone could clarify this here.

UPDATE 3
Both of these methods with either su or sudo now produce a new startpar process (single process that runs as root) after I boot the machine. Visible in process list as:

startpar -f -- <name_of_my_init.d_script>

Why is this process spawned? Obviously I'm doing something wrong since no other init.d script has this process running.

UPDATE 4
The issue with startpar is resolved. I've started another question for that:
startpar process left hanging when starting processes from rc.local or init.d

And another question to further discuss launching mechanisms for non privileged users:
Providing normal users(non-root) with initialization and shutdown auto-run capabilities

Ivan Kovacevic
  • 1,671
  • 3
  • 14
  • 19

4 Answers4

19

The correct answer for this was that for proper "daemonization", standard input, standard output and standard error need to be redirected to /dev/null (or some real file):

su someuser -c "nohup some_script.sh >/dev/null 2>&1 &"

su - substitute user identity to someuser
-c - su argument to run specified command
nohup - Run a command immune to hangups. To prevent cases where parent process will terminate the child process. Added here just in case. But actually has no effect in my particular case. Whether it is needed depends on the environment(check shopt)
>/dev/null - Redirect standard output to nothing, basically disabling it.
2>&1 - Redirect standard error(2) output to standard output(1), which is redirected to null
& - detach to background, this will redirect standard input also to /dev/null.

This is essentially exactly what start-stop-daemon utility from Debian dpkg does at its core. That is why I prefer starting scripts in this way rather then introducing another external utility call in my code. start-stop-daemon is useful in cases where you have full blown daemon programs that you need to start and where you then need additional functionality that start-stop-daemon provides (for example checking if the specified process is already running so that it doesn't launch it again).

It is also worth noting that you can also close file descriptors of your process instead of redirecting them to /dev/null, for example:

su someuser -c "some_script.sh 0<&- 1>&- 2>&- &"

0<&- Close standard input(0)
1>&- Close standard output(1)
2>&- Close standard error(2) output

The direction of < > signs does not matter as long file descriptor number is specified. So this is equally good:

su someuser -c "some_script.sh 0>&- 1>&- 2>&- &"

or

su someuser -c "some_script.sh 0<&- 1<&- 2<&- &"

However there is a bit shorter way to write that, without numbers for stdin and stdout, where direction does matter:

su someuser -c "some_script.sh <&- >&- 2>&- &" 

When the file descriptors are either closed or redirected to /dev/null (start-stop-daemon is doing the redirection to /dev/null) the process is safe to run in background as a daemon. So that is what is needed to avoid problems(startpar) with launching scripts during boot time.

I've implemented the whole solution from my initial idea and placed it on GitHub:
https://github.com/ivankovacevic/userspaceServices

Ivan Kovacevic
  • 1,671
  • 3
  • 14
  • 19
  • Ivan, is it better to use su or su -login ? I read the man of su but I cannot understand for this specific case. – Massimo Aug 08 '18 at 07:33
  • 1
    @Massimo, sorry for the delay in my response! Check this question out: https://unix.stackexchange.com/questions/318572/whats-the-difference-between-su-and-su-login there is a better manual page there explaining it. Basically the difference is in setting the working directory and environment variables. I would say for use cases like this(doing something as another user) it might be a preferable option to actually use -login – Ivan Kovacevic Aug 09 '18 at 11:24
3

You can use the start-stop-daemon out of init.d with the --user option.

dmourati
  • 24,720
  • 2
  • 40
  • 69
  • I've commented about start-stop-daemon on Mr Shark's answer and I also made an update to my answer and my question(update 4) – Ivan Kovacevic Apr 02 '14 at 22:26
2

I haven't fully tested this, but I think that something like:

/sbin/start-stop-daemon --background --start --exec /home/USER/.startUp --user USER --pidfile=/home/USER/.startUp.pid --make-pidfile

at startup and then

/sbin/start-stop-daemon --stop --user USER --pidfile=/home/USER/.startUp.pid

when shutting down.

Handling the .shutDown script could be done by something like the startup thing, but you cant be sure that the scripts run to end since shutdown should happen anyway :-)

should do the trick, perhaps you should throw in some input redirection, but then you would have to worry about log files being filled.

Mr Shark
  • 346
  • 3
  • 10
  • 2
    Essentially, this would work! start-stop-daemon can launch processes successfully at boot or otherwise. I've tested it. And it also gets rid of that problem with hanging startpar process. However you are missing also a --chuid USER in your start call. Without it, it would launch the process as root. The pid file should also probably be written to /var/run/ since otherwise it generates a root owned file in users home directory. But, in my mind, for generic script launching start-stop-daemon seems to be a bit of an overkill. Check my answer where I tried to elaborate why. – Ivan Kovacevic Apr 02 '14 at 21:57
1

Have you tried using su?

su -c /home/user/.startUp/executable - user

-c tells su to execute the command, and the last parameter is the user to execute it as.

Tero Kilkanen
  • 34,499
  • 3
  • 38
  • 58
  • yes, that works but with some quotation and added ampersand. And I find it cleaner to write it like so: su -c "/some/path/script.sh &" Basically I've used sudo since it seemed to be cleaner but now this seems better then using: sudo -u bash -c "/some/path/script.sh &" . Don't know if there are any differences in those two though – Ivan Kovacevic Mar 31 '14 at 23:12