finding the process group id created through setsid - linux

In a shell script, I see that using setsid, we could create a new process group. I am not able to find a reliable way to get the group id after the creation. My requirement is simple, launch a process, and after it is done, clean up any descendant (if any). I dont want to kill the main process, hence I have to wait for the main process to end. After which, I can kill the leftover child processes if I had somehow got the group id. which can be done with kill -- -pgid. The missing piece is how do I get the group id ?

This script is what I came up with finally. Hope this helps someone.
$! will give the pid, and a ps has to be used to find its gid.
there was an extra space in front while using ps,the next line of variable expansion removes the leading space.
Finally after waiting for the main process,it kills the group.
#!/bin/sh -x
setsid "$#" &
pid=$!
gidspace=$(ps -o pgid= $pid)
gid="${gidspace## }"
echo "gid $gid"
echo "waiting"
wait $pid
ps -s $gid -o pid,ppid,pgid,command
kill -- -$gid

Related

Running strace in the background

I want to rut strace in the background. For example,
I'm running
strace -esetsid setsid sleep 123
but I want to continue running other things until setsid returns. Obviously, simply appending & to
sleep 123
is interpreted as part of the command to trace.
So, how do I run this in the background?
I use strace just to get the pid of the new session started by setsid. If there's a better way to do this than strace, I'd like to know too :)
Thanks.
Try this:
setsid -w sleep 123 &
ppid=$! # get the pid of the setsid command that we just launched
pid=`ps --ppid $ppid --no-headers | awk '{ print $1 }'`
(with -w, setsid waits for the process to exit - and stays on as its parent; ps --ppid N is used to select the processes whose parent is the setsid process - there should be only one of those - or none, if the child process exits before the shell gets to execute ps. Be sure to check for this - $pid will be empty, then).

How to kill processes from bash from newest to oldest

Hello i am searching for a method to kill a browser's tabs (no preassinged processes) from bash terminal, by name not pid, and i want to delete them by order from newest to oldest. I tried
pkill -f -n -9
and the browser's name but it doesn't kill all of them . I can't use killall because i want a short time of sleep between every killing of each process. Any suggestions?
while [[ $(pgrep -c "chromium") != 0 ]]
do
pkill -n -9 "chromium"
sleep 1
done
This will loop as long as there is a chromium process running. It waits 1 second between each kill. Also bash commands are space-sensitive ;-) . Keep spaces around brackets and comparison operators at all times.

what's the difference when calling kill from a shell script or directly in the terminal

I'm trying to kill a process by ID from this shell script.
# based on
# http://stackoverflow.com/questions/6437602/shell-script-to-get-the-process-id-on-linux
output=`ps -ax|grep Ad[o]be\ After\ Effects\ CS6`;
# set -- parses the ps output into words,
# and $1 is the first word on the line
# which happens to be the process ID
set -- $output;
pid=$1;
echo "I'm about to kill process " $pid;
killall -SEGV $pid;
But that gives me that result
No matching processes belonging to you were found
When I use the same ID my script echoed and execute the command directly it does what it should.
kill -SEGV 50283
So whats the difference?
And what do I have to do to make my script behave as if it where 'me' (I think it's something with user rights)?
In your script you say killall which looks for a process by name. In your terminal you say kill which takes a PID. The former is erroneous, though arguably you should use killall in your script instead of implementing something similar yourself.

In Linux, how to start a process in its own process group? and more

I would like to start a process in its own process group (or, alternatively, change its group once started) and:
have the processes in the group respond to Ctrl + C from the terminal
get the id of the process group so that I can terminate all the processes in the group via the kill command.
Note: I tried setsid prog [args] but the processes do not respond to Ctrl+C from the terminal nor I could get the new process group id.
I also tried to change the process group via Perl's setpgrp($pid, $pid) and POSIX::setpgid($pid, $pid), to no avail.
Edit: The larger problem:
I have a process (single-threaded; let's call it the "prolific" process P) that starts many child processes synchronously (one after another; it starts a new one when the previous child process terminates). From the terminal, I want to be able to kill P and the tree of processes below it. To do that, I could simply arrange to kill the processes in P's group. However, the default behavior is that P is in the group of its parent process. That means that P's parent will be killed if I kill all the processes in P's group, unless I have P and its tree be in their own group.
My intention is to kill P and the tree below it, but not P's parent. Also, I cannot modify P's code itself.
What do you mean "start a process in its own process group"? The shell launches processes in their own process groups, that's how it does job control (by having a process group for processes in the foreground, and several process groups for every pipeline launched on the background).
To see that the shell launches a new process group for every pipeline, you can do this:
ps fax -o pid,pgid,cmd | less
which will show something like:
11816 11816 | \_ /bin/bash
4759 4759 | \_ ps fax -o pid,pgid,cmd
4760 4759 | \_ less
Note that the shell has created a new process group for the pipeline, and every process in the pipeline shares the process group.
Edit:
I think I know what you are getting at. You are calling system from Perl. Apparently, sh -c doesn't create new process groups, since it's a shell without job control.
What I would do would be to fork, then on the child:
setpgrp;
system("ps fax -o pid,pgid,cmd");
and wait on the parent.
EDIT: If what you wanted to do was use setsid but find the session id and/or pid of the resulting process:
If you launch a process through the setsid command it won't be attached to your terminal, so of course it won't respond to ctrl-c.
You could find it by grepping through the output of
ps x -O sid
or something more limited like
ps x -o %c,%p,sid
Or simple trolling through proc/[pid]/stat for all entries and looking at the session id and whatever else is of interest (see man proc for details)
The man page for setsid is not giving any flags to directly generate output, but you could trivially make your own version that prints out the desired information, by modifying the standard.
For example, grab a copy of setsid.c from one of the results for
http://www.google.com/codesearch?as_q=setsid&as_package=util-linux
Comment out the nls include, the locale stuff and the _("") error macro which will cause problems and then add this right before the execvp line:
printf("process will be pid %d sid %d\n", getpid(), getsid(0));
Here is the answer in Perl code following ninjalj's suggestions above:
prolific_wrapper.pl
my $pid = fork();
if (not defined $pid) {
die 'resources not available';
} elsif ($pid == 0) {
# CHILD
setpgrp;
exit system(prolific => #ARGV);
} else {
# PARENT
my $was_killed = 0;
local $SIG{INT} = sub {
say 'kill prolific and its tree ...';
kill KILL => -$pid;
$was_killed = 1;
};
wait;
my $child_status = $?;
$SIG{INT} = 'DEFAULT';
if ($was_killed) {kill INT => $$}
else {exit $child_status}
}
Many thanks again!

Kill bash script foreground children when a signal comes

I am wrapping a fastcgi app in a bash script like this:
#!/bin/bash
# stuff
./fastcgi_bin
# stuff
As bash only executes traps for signals when the foreground script ends I can't just kill -TERM scriptpid because the fastcgi app will be kept alive.
I've tried sending the binary to the background:
#!/bin/bash
# stuff
./fastcgi_bin &
PID=$!
trap "kill $PID" TERM
# stuff
But if I do it like this, apparently the stdin and stdout aren't properly redirected because it does not connect with lighttpds mod_fastgi, the foreground version does work.
EDIT: I've been looking at the problem and this happens because bash redirects /dev/null to stdin when a program is launched in the background, so any way of avoiding this should solve my problem as well.
Any hint on how to solve this?
There are some options that come to my mind:
When a process is launched from a shell script, both belong to the same process group. Killing the parent process leaves the children alive, so the whole process group should be killed. This can be achieved by passing the negated PGID (Process Group ID) to kill, which is the same as the parent's PID. ej: kill -TERM -$PARENT_PID
Do not execute the binary as
a child, but replacing the script
process with exec. You lose the
ability to execute stuff afterwards
though, because exec completely
replaces the parent process.
Do not kill the shell script process, but the FastCGI binary. Then, in the script, examine the return code and act accordingly. e.g: ./fastcgi_bin || exit -1
Depending on how mod_fastcgi handles worker processes, only the second option might be viable.
I have no idea if this is an option for you or not, but since you have a bounty I am assuming you might go for ideas that are outside the box.
Could you rewrite the bash script in Perl? Perl has several methods of managing child processes. You can read perldoc perlipc and more specifics in the core modules IPC::Open2 and IPC::Open3.
I don't know how this will interface with lighttpd etc or if there is more functionality in this approach, but at least it gives you some more flexibility and some more to read in your hunt.
I wrote this script just minutes ago to kill a bash script and all of its children...
#!/bin/bash
# This script will kill all the child process id for a given pid
# based on http://www.unix.com/unix-dummies-questions-answers/5245-script-kill-all-child-process-given-pid.html
ppid=$1
if [ -z $ppid ] ; then
echo "This script kills the process identified by pid, and all of its kids";
echo "Usage: $0 pid";
exit;
fi
for i in `ps j | awk '$3 == '$ppid' { print $2 }'`
do
$0 $i
kill -9 $i
done
Make sure the script is executable, or you will get an error on the $0 $i
You can override the implicit </dev/null for a background process by redirecting stdin yourself, for example:
sh -c 'exec 3<&0; { read x; echo "[$x]"; } <&3 3<&- & exec 3<&-; wait'
I'm not sure I fully get your point, but here's what I tried and the process seems to be able to manage the trap (call it trap.sh):
#!/bin/bash
trap "echo trap activated" TERM INT
echo begin
time sleep 60
echo end
Start it:
./trap.sh &
And play with it (only one of those commands at once):
kill -9 %1
kill -15 %1
Or start in foreground:
./trap.sh
And interrupt with control-C.
Seems to work for me.
What exactly does not work for you?
Try keeping the original stdin using ./fastcgi_bin 0<&0 &:
#!/bin/bash
# stuff
./fastcgi_bin 0<&0 &
PID=$!./fastcgi_bin 0<&0 &
trap "kill $PID" TERM
# stuff
# test
#sh -c 'sleep 10 & lsof -p ${!}'
#sh -c 'sleep 10 0<&0 & lsof -p ${!}'
You can do that with a coprocess.
Edit: well, coprocesses are background processes that can have stdin and stdout open (because bash prepares fifos for them). But you still need to read/write to those fifos, and the only useful primitive for that is bash's read (possibly with a timeout or a file descriptor); nothing robust enough for a cgi. So on second thought, my advice would be not to do this thing in bash. Doing the extra work in the fastcgi, or in an http wrapper like WSGI, would be more convenient.

Resources