syncing a shell script with kernel operations - linux

For stopping activity in my embedded Linux system, I have the following shell script (interpreted by busybox):
#!/bin/sh
pkill usefulp_program
swapoff /home/.swapfile
umount -l /home
sleep 3 # While I can't find a way to sync, sleep
If I take off the sleep line, the script returns immediately, without waiting even for the umount (which is lazy, as for some reason it refuses to unmount otherwise). Do you know how can I wait for all the three operations to complete before finishing the script? Resorting to an arbitrary sleep does not look like a good solution.
Also, any hint on why I can not umount without the -l?

You need to wait for the killed process to terminate. As per your comment...
wait <pid>
...doesn't work! So, could loop ala:
while ps -p <pid> > /dev/null; do sleep 1; done
to wait for the killed process to terminate before doing the swapoff and umount.

As others already mentioned you should and only the -l when the process is terminated. An option if it takes long/it just ignores you polite request to stop itself is using a different signal. The option would be -9 to the kill/killall/pkill command to send the SIGKILL instead of SIGTERM. If you dont want to use the hammer on your first try you could do something like
pkill your_programm
sleep 10
pkill -9 your_programm

Related

How to kill a process by its pid in linux

I'm new in linux and I'm building a program that receives the name of a process, gets its PID (i have no problem with that part) and then pass the PID to the kill command but its not working. It goes something like this:
read -p "Process to kill: " proceso
proid= pidof $proceso
echo "$proid"
kill $proid
Can someone tell me why it isn't killing it ? I know that there are some other ways to do it, even with the PID, but none of them seems to work for me. I believe it's some kind of problem with the Bash language (which I just started learning).
Instead of this:
proid= pidof $proceso
You probably meant this:
proid=$(pidof $proceso)
Even so,
the program might not get killed.
By default, kill PID sends the TERM signal to the specified process,
giving it a chance to shut down in an orderly manner,
for example clean up resources it's using.
The strongest signal to send a process to kill without graceful cleanup is KILL, using kill -KILL PID or kill -9 PID.
I believe it's some kind of problem with the bash language (which I just started learning).
The original line you posted, proid= pidof $proceso should raise an error,
and Bash would print an error message about it.
Debugging problems starts by reading and understanding the error messages the software is trying to tell you.
kill expects you to tell it **how to kill*, so there must be 64 different ways to kill your process :) They have names and numbers. The most lethal is -9. Some interesting ones include:
SIGKILL - The SIGKILL (also -9) signal forces the process to stop executing immediately. The program cannot ignore this signal. This process does not get to clean-up either.
SIGHUP - The SIGHUP signal disconnects a process from the parent process. This an also be used to restart processes. For example, "killall -SIGUP compiz" will restart Compiz. This is useful for daemons with memory leaks.
SIGINT - This signal is the same as pressing ctrl-c. On some systems, "delete" + "break" sends the same signal to the process. The process is interrupted and stopped. However, the process can ignore this signal.
SIGQUIT - This is like SIGINT with the ability to make the process produce a core dump.
use the following command to display the port and PID of the process:
sudo netstat -plten
AND THEN
kill -9 PID
Here is an example to kill a process running on port 8283 and has PID=25334
You have to send the SIGKILL flag with the kill statement.
kill -9 [pid]
If you don't the operating system will choose to kill the process at its convenience, SIGKILL (-9) will tell the os to kill the process NOW without ignoring the command until later.
Try this
kill -9
It will kill any process with PID given in brackets
Try "kill -9 $proid" or "kill -SIGKILL $proid" commands. If you want more information, click.
Based on what you have there, it looks like you aren't getting the actual PID in your proid variable. If you want to capture the output of pidof, you will need to enclose that command in backtics for the old form of command substitution ...
proid=`pidof $proceso`
... or like so for the new form of command substitution.
proid=$(pidof $proceso)
I had a similar problem, only wanting to run monitor (Video surveillance) for several hours a day.
Wrote two sh scripts;
cat startmotion.sh
#!/bin/sh
motion -c /home/username/.config/motion/motion.conf
And the second;
cat killmotion.sh
#!/bin/sh
OA=$(cat /var/run/motion/motion.pid)
kill -9 $OA
These were called from crontab at the scheduled time
ctontab -e
0 15 * * * /home/username/startmotion.sh
0 17 * * * /home/username/killmotion.sh
Very simple, but that's all I needed.

How to get right PID of a group of background command and kill it?

Ok, just like in this thread, How to get PID of background process?, I know how to get the PID of background process. However, what I need to do countains more than one operation.
{
sleep 300;
echo "Still running after 5 min, killing process manualy.";
COMMAND COMMAND COMMAND
echo "Shutdown complete"
}&
PID_CHECK_STOP=$!
some stuff...
kill -9 $PID_CHECK_STOP
But it doesn't work. It seems i get either a bad PID or I just can't kill it. I tried to run ps | grep sleep and the pid it gives is always right next to the one i get in PID_CHECK_STOP. Is there a way to make it work? Can i wrap those commands an other way so i can kill them all when i need to?
Thx guys!
kill -9 kills the process before it can do anything else, including signalling its children to exit. Use a gentler signal (kill by itself, which sends a TERM, should be sufficient). You do need to have the process signal its children to exit (if any) explicitly, though, via a trap command.
I'm assuming sleep is a placeholder for the real command. sleep is tricky, however, as it ignores any signals until it returns (i.e., it is non-interruptible). To make your example work, put sleep itself in the background and immediately wait on it. When you kill the "outer" background process, it will interrupt the wait call, which will allow sleep to be killed as well.
{
trap 'kill $(jobs -p)' EXIT
sleep 300 & wait
echo "Still running after 5 min, killing process manualy.";
COMMAND COMMAND COMMAND
echo "Shutdown complete"
}&
PID_CHECK_STOP=$!
some stuff...
kill $PID_CHECK_STOP
UPDATE: COMMAND COMMAND COMMAND includes a command that runs via sudo. To kill that process, kill must also be run via sudo. Keep in mind that doing so will run the external kill program, not the shell built-in (there is little difference between the two; the built-in exists to allow you to kill a process when your process quota has been reached).
You can have another script containing those commands and kill that script. If you are dynamically generating code for the block, just write out a script, execute it and kill when you are done.
The { ... } surrounding the statements starts a new shell, and you get its PID afterwards. sleep and other commands within the block get separate PIDs.
To illustrate, look for your process in ps afux | less - the parent shell process (above the sleep) has the PID you were just given.

Automating Killall then Killall level 9

Sometimes I want to killall of a certain process, but running killall doesn't work. So when I try to start the process again, it fails because the previous session is still running. Then I have to tediously run killall -9 on it. So to simplify my life, I created a realkill script and it goes like this:
PIDS=$(ps aux | grep -i "$#" | awk '{ print $2 }') # Get matching pid's.
kill $PIDS 2> /dev/null # Try to kill all pid's.
sleep 3
kill -9 $PIDS 2> /dev/null # Force quit any remaining pid's.
So, Is this the best way to be doing this? In what ways can I improve this script?
Avoid killall if you can since there is not a consistent implementation across all UNIX platforms. Proctools' pkill and pgrep are preferable:
for procname; do
pkill "$procname"
done
sleep 3
for procname; do
# Why check if the process exists if you're just going to `SIGKILL` it?
pkill -9 "$procname"
done
(Edit) If you have processes that are supposed to restart after being killed, you may not want to blindly kill them, so you can gather the PIDs first:
pids=()
for procname; do
pids+=($(pgrep "$procname"))
done
# then proceed with `kill`
That said, you should really try to avoid using SIGKILL if you can. It does not give software a chance to clean up after itself. If a program won't quit shortly after receiving a SIGTERM it is probably waiting for something. Find out what it's waiting for (hardware interrupt? open file?) and fix that, and you can let it close cleanly.
Without understanding what exactly the process does, I would say it probably isn't ideal cos you may have a situation where the processes you are killing are really doing some useful shutdown/cleanup work. Forcing it down with kill -9 may short-circuit that work and could cause corruption if your process is in fact writing data.
Assuming there is no danger of data corruption and it's ok to short-circuit the shutdown, can you just kill -9 the process the first time and be done with it. Do you have access to the developers of the process you are killing to understand what is going on that might prevent the shutdown from happening? The process might have blocked the INT and TERM for good reason.
It is unlikely, but it is possible that in that 3 second wait, a new process could have taken over that PID and the second kill would kill it.

bash: run a command for n minutes, then SIGHUP it

Is there any bash/linux command to launch a long-running command, then kill it after n minutes? I guess I could hack something up with perl using fork and kill, but does anyone know of something already out there?
See the timeout command now in most GNU/Linux distros.
timeout -sHUP 10m command
The same functionality can be achieved with http://www.pixelbeat.org/scripts/timeout
Try it with this one, it starts your command in the background, stores it's PID in $P, waits for some time and kills it with a SIGHUP.
yourCommand & PID=$!
sleep ${someMinutes}m
kill -HUP $PID
Cheers
PS: that assumes a sleep that knows about Nm (minutes), else, you might want to do some math :)
n=5
some_command &
pid=$!
at now + $n minutes <<<"kill -HUP $pid"
The benefit of using at over waiting for sleep is that your script wont block waiting for the sleep to expire. You can go and do other things and at will asynchronously fire at the specified time. Depending on your script that may be a very important feature to have.

Limiting the time a program runs in Linux

In Linux I would like to run a program but only for a limited time, like 1 second. If the program exceeds this running time I would like to kill the process and show an error message.
Ah well. timeout(1).
DESCRIPTION
Start COMMAND, and kill it if still running after DURATION.
StackOverflow won't allow me to delete my answer since it's the accepted one. It's garnering down-votes since it's at the top of the list with a better solution below it. If you're on a GNU system, please use timeout instead as suggested by #wRAR. So in the hopes that you'll stop down-voting, here's how it works:
timeout 1s ./myProgram
You can use s, m, h or d for seconds (the default if omitted), minutes, hours or days. A nifty feature here is that you may specify another option -k 30s (before the 1s above) in order to kill it with a SIGKILL after another 30 seconds, should it not respond to the original SIGTERM.
A very useful tool. Now scroll down and up-vote #wRAR's answer.
For posterity, this was my original - inferior - suggestion, it might still be if some use for someone.
A simple bash-script should be able to do that for you
./myProgram &
sleep 1
kill $! 2>/dev/null && echo "myProgram didn't finish"
That ought to do it.
$! expands to the last backgrounded process (through the use of &), and kill returns false if it didn't kill any process, so the echo is only executed if it actually killed something.
2>/dev/null redirects kill's stderr, otherwise it would print something telling you it was unable to kill the process.
You might want to add a -KILL or whichever signal you want to use to get rid of your process too.
EDIT
As ephemient pointed out, there's a race here if your program finishes and the some other process snatches the pid, it'll get killed instead. To reduce the probability of it happening, you could react to the SIGCHLD and not try to kill it if that happens. There's still chance to kill the wrong process, but it's very remote.
trapped=""
trap 'trapped=yes' SIGCHLD
./myProgram &
sleep 1
[ -z "$trapped" ] && kill $! 2>/dev/null && echo '...'
Maybe CPU time limit (ulimit -t/setrlimit(RLIMIT_CPU)) will help?
you could launch it in a shell script using &
your_program &
pid=$!
sleep 1
if [ `pgrep $pid` ]
then
kill $pid
echo "killed $pid because it took too long."
fi
hope you get the idea, I'm not sure this is correct my shell skills need some refresh :)
tail -f file & pid=$!
sleep 10
kill $pid 2>/dev/null && echo '...'
If you have the sources, you can fork() early in main() and then have the parent process measure the time and possibly kill the child process. Just use standard system calls fork(), waitpid(), kill(), ... maybe some standard Unix signal handling. Not too complicated but takes some effort.
You can also script something on the shell although I doubt it will be as accurate with respect to the time of 1 second.
If you just want to measure the time, type time <cmd ...> on the shell.
Ok, so just write a short C program that forks, calls execlp or something similar in the child, measures the time in the parent and kills the child. Should be easy ...

Resources