| 1 | #!/usr/bin/env bash
 | 
| 2 | #
 | 
| 3 | # Demo of traps.
 | 
| 4 | 
 | 
| 5 | # BUG: OSH doesn't run the trap because of KeyboardInterrupt!
 | 
| 6 | 
 | 
| 7 | # BUG interactively too:
 | 
| 8 | #
 | 
| 9 | # osh$ trap 'echo INT' SIGINT; sleep 5 & wait
 | 
| 10 | 
 | 
| 11 | sigint-batch() {
 | 
| 12 |   trap 'echo [got SIGINT]' INT
 | 
| 13 |   echo "Registered SIGINT trap.  Hit Ctrl-C or Run 'kill -INT $$' to see a message."
 | 
| 14 |   sleep 5
 | 
| 15 | }
 | 
| 16 | 
 | 
| 17 | sigterm-batch() {
 | 
| 18 |   trap 'echo [got SIGTERM]' TERM
 | 
| 19 |   echo "Registered SIGTERM trap.  Run 'kill -TERM $$' to see a message."
 | 
| 20 |   sleep 5
 | 
| 21 | }
 | 
| 22 | 
 | 
| 23 | # BUG: OSH gets two sigterms?
 | 
| 24 | sigterm-then-kill-test() {
 | 
| 25 |   local sh=${1:-bash}
 | 
| 26 |   #### SIGTERM trap should run upon 'kill'
 | 
| 27 |   $sh -c 'echo "> PID $$ started";
 | 
| 28 |     echo $$ > _tmp/pid.txt;
 | 
| 29 |     trap "echo SIGTERM" TERM;
 | 
| 30 |     sleep 1;
 | 
| 31 |     echo "< PID $$ done"' &
 | 
| 32 | 
 | 
| 33 |   sleep 0.5
 | 
| 34 |   local pid=$(cat _tmp/pid.txt)
 | 
| 35 |   echo "killing $pid"
 | 
| 36 |   kill -TERM $pid
 | 
| 37 |   wait
 | 
| 38 |   echo status=$?
 | 
| 39 | }
 | 
| 40 | 
 | 
| 41 | sigterm() {
 | 
| 42 |   echo "sigterm [$@] $?"
 | 
| 43 |   # quit the process -- otherwise we resume!
 | 
| 44 |   exit
 | 
| 45 | }
 | 
| 46 | 
 | 
| 47 | child() {
 | 
| 48 |   trap 'sigterm x y' SIGTERM
 | 
| 49 |   echo child
 | 
| 50 |   for i in $(seq 5); do
 | 
| 51 |     sleep 1
 | 
| 52 |   done
 | 
| 53 | }
 | 
| 54 | 
 | 
| 55 | 
 | 
| 56 | readonly SH=bash
 | 
| 57 | #readonly SH=dash  # bad trap
 | 
| 58 | #readonly SH=mksh
 | 
| 59 | #readonly SH=zsh
 | 
| 60 | 
 | 
| 61 | child2() {
 | 
| 62 |   $SH -c '
 | 
| 63 |   sigterm() {
 | 
| 64 |     echo "sigterm [$@] $?"
 | 
| 65 |     # quit the process -- otherwise we resume!
 | 
| 66 |     exit
 | 
| 67 |   }
 | 
| 68 | 
 | 
| 69 |   trap "sigterm x y" SIGTERM
 | 
| 70 |   trap -p
 | 
| 71 |   echo child
 | 
| 72 |   for i in $(seq 5); do
 | 
| 73 |     sleep 1
 | 
| 74 |   done
 | 
| 75 |   ' &
 | 
| 76 | }
 | 
| 77 | 
 | 
| 78 | start-and-kill() {
 | 
| 79 |   $0 child &
 | 
| 80 | 
 | 
| 81 |   #child2 
 | 
| 82 | 
 | 
| 83 |   echo "started $!"
 | 
| 84 |   sleep 0.1  # a little race to allow things to be printed
 | 
| 85 | 
 | 
| 86 |   # NOTE: The process only dies after one second.  The "sleep 1" is run until
 | 
| 87 |   # completion, and then the signal handler is run, which calls "exit".
 | 
| 88 | 
 | 
| 89 |   echo "killing $!"
 | 
| 90 |   kill -s SIGTERM $!
 | 
| 91 |   wait $!
 | 
| 92 |   echo status=$?
 | 
| 93 | }
 | 
| 94 | 
 | 
| 95 | num_signals=0
 | 
| 96 | 
 | 
| 97 | ignore-n-times() {
 | 
| 98 |   (( num_signals++ ))
 | 
| 99 | 
 | 
| 100 |   if [[ $num_signals -le 2 ]]; then
 | 
| 101 |     echo "Received signal $num_signals -- IGNORING"
 | 
| 102 |   else
 | 
| 103 |     echo "Removing this signal handler; next one will be the default"
 | 
| 104 |     trap - TERM
 | 
| 105 |   fi
 | 
| 106 | }
 | 
| 107 | 
 | 
| 108 | # In bash: Run this and hit Ctrl-C four times to see the handler in action!
 | 
| 109 | #
 | 
| 110 | # NOTE: Ctrl-C doesn't work in Python because Python does stuff with SIGINT!
 | 
| 111 | # We could disable KeyboardInterrupt entirely in the OVM build?  But still need
 | 
| 112 | # the signal module!
 | 
| 113 | 
 | 
| 114 | sleep-and-ignore() {
 | 
| 115 |   trap ignore-n-times TERM
 | 
| 116 |   for i in $(seq 10); do
 | 
| 117 |     echo $i
 | 
| 118 |     sleep 0.2
 | 
| 119 |   done
 | 
| 120 | }
 | 
| 121 | 
 | 
| 122 | # NOTE: osh has EINTR problems here!
 | 
| 123 | #
 | 
| 124 | # File "/home/andy/git/oilshell/oil/bin/../core/process.py", line 440, in WaitUntilDone
 | 
| 125 | # if not waiter.Wait():
 | 
| 126 | # File "/home/andy/git/oilshell/oil/bin/../core/process.py", line 632, in Wait
 | 
| 127 | #   pid, status = os.wait()
 | 
| 128 | # OSError: [Errno 4] Interrupted system call
 | 
| 129 | 
 | 
| 130 | kill-sleep-and-ignore() {
 | 
| 131 |   sleep-and-ignore &
 | 
| 132 |   local last_pid=$!
 | 
| 133 | 
 | 
| 134 |   echo "Started $last_pid"
 | 
| 135 | 
 | 
| 136 |   # Hm sometimes the signal gets ignored?  You can't just kill it 3 times?
 | 
| 137 |   for i in $(seq 5); do
 | 
| 138 |     kill -s SIGTERM $last_pid
 | 
| 139 |     echo kill status=$?
 | 
| 140 |     sleep 0.1
 | 
| 141 |   done
 | 
| 142 | 
 | 
| 143 |   wait
 | 
| 144 |   echo wait status=$?
 | 
| 145 | }
 | 
| 146 | 
 | 
| 147 | "$@"
 | 
| 148 | 
 |