2

I have two scripts. These are simplified. The root-script.sh calls userscript.sh:

root-script.sh:

 #!/bin/bash 
 su - user1 -c "/user1path/user-script.sh"

user-script.sh:

 #!/bin/bash
 trap 'echo please use x for exit' 2
 while x=0; do
    read -p "enter x for exit:" answer
    if [[ $answer = 'x' ]]; then
            echo "exit now"
            exit 0
    fi
 done

If I call user-script.sh it just works as it should:

 enter x for exit:
 enter x for exit: ^C_please use x for exit
^C_please use x for exit
x
exit now

If I call root-script.sh as root and enter a Ctrl-C I get

 enter x for exit: ^C
Session terminated, killing shell... ...killed.

Than I get back the root-prompt but the prompt is blocked. With ps I don't see the root-script, only the user-script. If I kill the user-script the root-prompt is usable again.

How can I prevent the root-script-user-script-construction from hanging after SIGINT? Means for me

  1. Exiting root-script.sh and user-script.sh or
  2. the root-script-user-script-construction should work as same as user-script.sh

    • bash-version: 3.2.51(1)-release (x86_64-suse-linux-gnu)
    • os-version: sles11 3.0.93-0.8-default
Jolta
  • 2,620
  • 1
  • 29
  • 42
Frank
  • 21
  • 1
  • 3
  • I imagine `su` sets its own `SIGINT` handler which you cannot easily override. Why are you allowing users to run an interactive shell script as another user anyway? You should probably rethink the logic. Possibly `read input; su - user1 otherscript "$input"` – tripleee Jan 12 '14 at 12:03
  • Both scripts are pure simplification. So all other stuff are stripped out. This kind of logic nearly can't modified. – Frank Jan 12 '14 at 12:38

2 Answers2

2

I just tested:

su -c 'trap /bin/true 2; while true; do sleep 1; done' user

verses

su -c 'while true; do sleep 1; done' user

and found that the former could not be terminated via SIGINT but the latter could. My guess is that perhaps su -c opens the user's shell to run the command passed by -c, and that is what will catch the SIGINT and terminate - but your script only captures the SIGINT in a subshell - which is maybe passed SIGTERM by the parent shell's SIGINT handler.

Hopefully that works for you.

EDIT:

su -c 'echo $0; echo $SHELL' user

confirms that the command is run with the user's shell.

Perhaps you will find

su -c 'exec my_script.sh' user

To be a more elegant solution. I think it will work but have not tested it. exec will replace the current shell process with your script's process, though, so I think it should work.

EDIT 2:

Looking back at your question, you just need the trap in the root script, I think. Or maybe:

exec 'su -c "exec script.sh" user'

If you want to completely inherit the script's trap behaviour.

xyrix
  • 51
  • 2
  • The `su -c 'exec my_script.sh' user ` terminated both scripts. I found out on linux there is an option `su -C (capital)` – Frank Jan 12 '14 at 14:09
  • With this option the scripts will not terminate and work as expected. But the script has to run on solaris too and there is no such option. – Frank Jan 12 '14 at 14:17
  • trap in the root-script does not help. I got the root-script-trap-text after the killing-message. – Frank Jan 12 '14 at 14:24
  • I don't know what to suggest then. I have now tested two scripts, one.sh contains #!/bin/bash \n trap 'echo hello' 2 \n while true; do sleep 1; done. and two.sh contains #!/bin/bash \n su -c 'exec ./one.sh' user. When I execute two.sh and send a SIGINT it is processed by one.sh for me. Bizarre :-/. – xyrix Jan 12 '14 at 14:37
  • `su -c 'while true; do sleep 1; done' user` seems not to work `while: Expression Syntax.` – Frank Jan 12 '14 at 14:39
  • That works in dash and bash for me... What do you get when you run `su -c 'echo $0; echo $SHELL' user`? – xyrix Jan 12 '14 at 14:42
1

This article explains why SIGINT is not passed into su -c and gives a solution:

http://sethmiller.org/it/su-forking-and-the-incorrect-trapping-of-sigint-ctrl-c/

In your case: su - user1 --session-command "/user1path/user-script.sh"

As --session-command is a discouraged option (see man su), if you don't feel safe, it's also possible, in your case, to use the -s option:

su - user1 -s /user1path/user-script.sh

Ling
  • 11
  • 1
  • After a long search, I found that --session-command wasn't on su on Ubuntu 16.04, but in runuser (which can only be run by root). – Silfheed Aug 17 '18 at 00:26
  • This command works on **raspberryOS** *(linux/arm/v7)* but does not work in a docker container build on **ubuntu:20.04** *(linux/arm/v7)* (https://hub.docker.com/_/ubuntu?tab=tags&name=latest). The PID changed. – Antoine Apr 06 '21 at 07:39
  • 1
    For posterity: [Seth Miller's su Forking and the Incorrect Trapping of SIGINT (CTRL-C)](https://web.archive.org/web/20170528071900/http://sethmiller.org:80/it/su-forking-and-the-incorrect-trapping-of-sigint-ctrl-c) – JimB Jun 01 '22 at 15:37