Daemon won't kill children that are reading from a named pipe - linux

I've written this bash daemon that keeps an eye on a named pipe, logs everything it sees on a file named $LOG_FILE_BASENAME.$DATE, and it also creates a filtered version of it in $ACTIONABLE_LOG_FILE:
while true
do
DATE=`date +%Y%m%d`
cat $NAMED_PIPE | tee -a "$LOG_FILE_BASENAME.$DATE" | grep -P -v "$EXCEPTIONS" >> "$ACTIONABLE_LOG_FILE"
done
pkill -P $$ # Here it's where it should kill it's children
exit 0
When the daemon is running, this is how the process table looks:
/bin/sh the_daemon.sh
\_ cat the_fifo_queue
\_ tee -a log_file.20150807
\_ grep -P -v "regexp" > filtered_log_file
The problem is that when I kill the daemon (SIGTERM), the cat, the tee, and the grep processes that where spawned by the daemon are not collected by the parent. Instead, they become orphans and keep on waiting for input on the named pipe.
Once the FIFO receives some input, then they process that input as instructed and die.
How can I make the daemon kill its children before dying? Why aren't they dying with pkill -P $$?

You want to setup a signal handler for your script which kills all members of its process group (its children) in case the script itself gets signalled:
#!/bin/bash
function handle_sigterm()
{
pkill -P $$
exit 0
}
trap handle_sigterm SIGTERM
while true
do
DATE=`date +%Y%m%d`
cat $NAMED_PIPE | tee -a "$LOG_FILE_BASENAME.$DATE" | grep -P -v "$EXCEPTIONS" >> "$ACTIONABLE_LOG_FILE"
done
handle_sigterm
exit 0
Update:
As per pilcrow's comment replace
cat $NAMED_PIPE | tee -a "$LOG_FILE_BASENAME.$DATE" | grep -P -v "$EXCEPTIONS" >> "$ACTIONABLE_LOG_FILE"
by
cat $NAMED_PIPE | tee -a "$LOG_FILE_BASENAME.$DATE" | grep -P -v "$EXCEPTIONS" >> "$ACTIONABLE_LOG_FILE" &
wait $!

Related

how to kill process groups in trap?

In a bash script I normally use trap to clean up spawned processes:
function cleanup()
{
jobs -l
jobs -p | xargs -r -I {} kill -TERM {}
jobs -l
echo "do something after kill all jobs."
}
trap cleanup EXIT
However this does not work for process groups:
function cleanup()
{
jobs -l
jobs -p | xargs -r -I {} kill -TERM {}
jobs -l
echo "do something after kill all jobs."
}
trap cleanup EXIT
(sleep 100 | tee /tmp/sleep_test.log) | tee sleep_test2.log &
ps -ax -o pid,pgid,ppid,args | grep sleep
jobs -l
sleep 1
the jobs -p give out a ppid of process group of (sleep 100 | tee ...) and a process of tee ... The process group cannot be killed as above. It need to do kill -TERM -PGID. Is there any easy way to let jobs output process group PGID? Or is there any command can kill process group via PPID and process PID with a uniform interface?
update:
kill -TERM 0 does not work here since it kill itself also. But I still need to do something after kill all jobs.
The only way I found is killing sub-processes directly.
#!/usr/bin/env bash
function cleanup()
{
jobs -l
for p in $(jobs -p); do
kill $(pgrep -P $p)
done
jobs -l
echo "do something after kill all jobs."
}
trap cleanup EXIT
(sleep 100 | tee /tmp/sleep_test.log) | tee sleep_test2.log &
ps -ax -o pid,pgid,ppid,args | grep sleep
jobs -l
sleep 1
I tried to kill PGID, which didn't work for me.

Don't kill created processes, which created by ps - linux

give some advice, please.
I am trying to kill processes remotely (ssh to hostname), find some processes and kill them. But I have a condition: Do not kill java process, sshd and gnome.
Here is example (I just do echo except kill):
#/bin/sh -x.
HOSTFILE=$1
vars=`cat $HOSTFILE`
for i in $vars; do
ssh "$i" /bin/bash <<'EOF'
echo $(hostname)
ps aux | grep -e '^sys_ctl'| grep -v "java" | grep -v "sshd" | \
grep -v "gnome" | awk '{print $2$11}'| for i in `xargs echo`; do echo $i; done;
EOF
done
The result is:
host1:
21707/bin/bash
21717ps
21718grep
21722awk
21723/bin/bash
21724xargs
host2:
15241/bin/bash
15251ps
15252grep
15256awk
15257/bin/bash
15258xargs
89740-bash
98467sleep
98469sleep
98471sleep
98472sleep
98474sleep
98475sleep
I want to kill (output), only sleep processes, not grep,awk,bash,xargs,ps
Can you suggest something elegant?
why not just : kill $(pgrep -f sleep)
or : pkill -f sleep

My bash script won't execute commands after kill command

I am trying to make a bash script that is killing a process and then it's going to do other stuff.
PID=`ps -ef | grep logstash | grep -v "grep" | awk '{print $2}'`
echo $PID
kill -9 $PID
echo "logstash process is stopped"
rm /home/user/test.csv
echo "test.csv is deleted."
rm /home/example.txt
echo "example.txt is deleted."
When I run the script, it kills logstash as exptected but it terminates also my whole script.
I've also tried: kill -9 $(ps aux | grep 'logstash' | awk '{print $2}').
With this command, my script will be terminated as well.
it looks like your script name includes "logstash".
As a consequence, PID is filled with 2 values, and the kill command kills your script as well.
Rename your script without "logstash" in the name should fix the issue.
This should correct your issue :
PID=$( ps -ef | grep -E '[ ]logstash[ ]' | grep -v "grep" | head -1 | awk '{print $2}')
echo $PID
kill -9 $PID
echo "logstash process is stopped"
rm /home/user/test.csv
echo "test.csv is deleted."
rm /home/example.txt
echo "example.txt is deleted."
Regards!

Bash daemon doesn't collect its chilidren

I've written this bash daemon that keeps an eye on a named pipe, logs everything it sees on a file named $LOG_FILE_BASENAME.$DATE, and it also creates a filtered version of it in $LOG_FILE_BASENAME.$DATE :
while true
do
DATE=`date +%Y%m%d`
cat $NAMED_PIPE | tee -a "$LOG_FILE_BASENAME.$DATE" | grep -P -v "$EXCEPTIONS" >> "$ACTIONABLE_LOG_FILE"
done
When the daemon is running, this is how the process table looks:
/bin/sh the_daemon.sh
\_ cat the_fifo_queue
\_ tee -a log_file.20150807
\_ grep -P -v "regexp" > filtered_log_file
The problem is that when I kill the deamon (SIGTERM), the cat, the tee, and the grep processes that where spawned by the daemon are not collected by the parent. Instead, they become orphans and keep on waiting for input on the named pipe.
Once the FIFO receives some input, then they process that input as instructed and die.
How can make the daemon kill it's children before dying?
I know I could have the daemon manually collect the PIDs of its children and kill them before kicking the bucket, but isn't there an automated way to do this?
Thanks

How to get PID from remote executed command?

If I do the following in Bash, then I get the PID of the remotely started mbuffer, and even though mbuffer is still running, I get the terminal back, which is what I want.
read -r pid < <(ssh 10.10.10.47 'nohup /opt/omni/bin/mbuffer -4 -s 128k -m 2G -v 0 -q -I 8023 >/tmp/mtest </dev/null 2>/tmp/mtest.err & echo $!')
echo $pid
Now I would like to do the same in Perl, so I try
use Capture::Tiny 'capture';
my ($stdout, $stderr, $exit) = capture {
system("read -r pid < <(ssh 10.10.10.47 'nohup /opt/omni/bin/mbuffer -4 -s 128k -m 2G -v 0 -q -I 8023 >/tmp/mtest </dev/null 2>/tmp/mtest.err & echo $!'); echo \$pid");
};
print "stdout $stdout\n";
print "stderr $stderr\n";
print "exit $exit\n";
Here I would have expected that $stdout would have given me the PID from the last echo command, but I got nothing.
Question
How do I get the PID of the remotely executed mbuffer in Perl, and so the Perl script isn't waiting for mbuffer to exit before continuing?
The problem seams to be that it is not possible to execute two commands in one system() or maybe it is, but not possible to get the output from the last command.
Creating a local helper script solved the problem.
#!/usr/bin/bash
# Redirection of stdin and stderr to files (preventing them from holding
# handles that connect, eventually, to the terminal).
read -r pid < <(ssh $1 "/usr/gnu/bin/nohup /opt/omni/bin/mbuffer -4 -s 128k -m 2G -v 0 -q -I 8023 >/tmp/mtest$2 </dev/null 2>/tmp/mtest.err & echo \$!")
echo $pid
and in Perl
my ($stdout, $stderr, $exit) = capture {
system("/comp/mbuffer-zfs-listen.sh 10.10.10.47 11");
};

Resources